Skip to content

Commit 6de1568

Browse files
Fix on Ethernet driver and lwip wrapper
This fix aims to solve issues on ethernet on portenta c33. This required some changes in the structure of the library, in order to avoid wasting memory on temporary queues.
1 parent b7c9e9b commit 6de1568

File tree

2 files changed

+133
-130
lines changed

2 files changed

+133
-130
lines changed

libraries/lwIpWrapper/src/CNetIf.cpp

+101-105
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
#include "CNetIf.h"
2+
#include <functional>
23

34
IPAddress CNetIf::default_ip("192.168.0.10");
45
IPAddress CNetIf::default_nm("255.255.255.0");
@@ -9,7 +10,6 @@ CNetIf* CLwipIf::net_ifs[] = { nullptr };
910
bool CLwipIf::wifi_hw_initialized = false;
1011
bool CLwipIf::connected_to_access_point = false;
1112
WifiStatus_t CLwipIf::wifi_status = WL_IDLE_STATUS;
12-
std::queue<struct pbuf*> CLwipIf::eth_queue;
1313
bool CLwipIf::pending_eth_rx = false;
1414

1515
FspTimer CLwipIf::timer;
@@ -69,7 +69,22 @@ CLwipIf::CLwipIf()
6969
ch = FspTimer::get_available_timer(type, true);
7070
}
7171

72-
timer.begin(TIMER_MODE_PERIODIC, type, ch, 10.0, 50.0, timer_cb);
72+
/*
73+
* NOTE Timer and buffer size
74+
* The frequency for the timer highly influences the memory requirements for the desired transfer speed
75+
* You can calculate the buffer size required to achieve that performance from the following formula:
76+
* buffer_size[byte] = Speed[bit/s] * timer_frequency[Hz]^-1 / 8
77+
*
78+
* In the case of portenta C33, the maximum speed achievable was measured with
79+
* iperf2 tool (provided by lwip) and can reach up to 12Mbit/s.
80+
* Further improvements can be made, but if we desire to reach that speed the buffer size
81+
* and the timer frequency should be designed accordingly.
82+
* buffer = 12 * 10^6 bit/s * (100Hz)^-1 / 8 = 15000 Byte = 15KB
83+
*
84+
* Since this is a constrained environment we could accept performance loss and
85+
* delegate lwip to handle lost packets.
86+
*/
87+
timer.begin(TIMER_MODE_PERIODIC, type, ch, 100.0, 50.0, timer_cb);
7388
timer.setup_overflow_irq();
7489
timer.open();
7590
timer.start();
@@ -252,56 +267,48 @@ CNetIf* CLwipIf::get(NetIfType_t type,
252267
}
253268

254269
/* -------------------------------------------------------------------------- */
255-
void CLwipIf::ethLinkUp()
256-
{
257-
/* -------------------------------------------------------------------------- */
258-
if (net_ifs[NI_ETHERNET] != nullptr) {
259-
net_ifs[NI_ETHERNET]->setLinkUp();
260-
}
261-
}
270+
void CEth::handleEthRx()
271+
{
272+
/*
273+
* This function is called by the ethernet driver, when a frame is receiverd,
274+
* as a callback inside an interrupt context.
275+
* It is required to be as fast as possible and not perform busy waits.
276+
*
277+
* The idea is the following:
278+
* - take the rx buffer pointer
279+
* - try to allocate a pbuf of the desired size
280+
* - if it is possible copy the the buffer inside the pbuf and give it to lwip netif
281+
* - release the buffer
282+
*
283+
* If the packet is discarded the upper TCP/IP layers should handle the retransmission of the lost packets.
284+
* This should not happen really often if the buffers and timers are designed taking into account the
285+
* desired performance
286+
*/
287+
__disable_irq();
262288

263-
/* -------------------------------------------------------------------------- */
264-
void CLwipIf::ethLinkDown()
265-
{
266-
/* -------------------------------------------------------------------------- */
267-
if (net_ifs[NI_ETHERNET] != nullptr) {
268-
net_ifs[NI_ETHERNET]->setLinkDown();
269-
}
270-
}
289+
volatile uint32_t rx_frame_dim = 0;
290+
volatile uint8_t* rx_frame_buf = eth_input(&rx_frame_dim);
291+
if (rx_frame_dim > 0 && rx_frame_buf != nullptr) {
292+
struct pbuf* p=nullptr;
271293

272-
/* -------------------------------------------------------------------------- */
273-
void CLwipIf::ethFrameRx()
274-
{
275-
/* -------------------------------------------------------------------------- */
294+
p = pbuf_alloc(PBUF_RAW, rx_frame_dim, PBUF_RAM);
276295

277-
if (pending_eth_rx) {
278-
pending_eth_rx = false;
279-
volatile uint32_t rx_frame_dim = 0;
280-
volatile uint8_t* rx_frame_buf = eth_input(&rx_frame_dim);
281-
if (rx_frame_dim > 0 && rx_frame_buf != nullptr) {
282-
while (rx_frame_dim % 4 != 0) {
283-
rx_frame_dim++;
284-
}
285-
struct pbuf* p = pbuf_alloc(PBUF_RAW, rx_frame_dim, PBUF_RAM);
286-
if (p != NULL) {
287-
/* Copy ethernet frame into pbuf */
288-
pbuf_take((struct pbuf*)p, (uint8_t*)rx_frame_buf, (uint32_t)rx_frame_dim);
289-
eth_release_rx_buffer();
290-
eth_queue.push((struct pbuf*)p);
296+
if (p != NULL) {
297+
/* Copy ethernet frame into pbuf */
298+
pbuf_take((struct pbuf*)p, (uint8_t*)rx_frame_buf, (uint32_t)rx_frame_dim);
299+
300+
if (ni.input((struct pbuf*)p, &ni) != ERR_OK) {
301+
pbuf_free((struct pbuf*)p);
291302
}
292303
}
293-
}
294-
}
295304

296-
/* -------------------------------------------------------------------------- */
297-
void CLwipIf::setPendingEthRx()
298-
{
299-
/* -------------------------------------------------------------------------- */
300-
pending_eth_rx = true;
305+
eth_release_rx_buffer();
306+
}
307+
__enable_irq();
301308
}
302309

303310
/* -------------------------------------------------------------------------- */
304-
err_t CLwipIf::initEth(struct netif* _ni)
311+
err_t CEth::init(struct netif* _ni)
305312
{
306313
/* -------------------------------------------------------------------------- */
307314
#if LWIP_NETIF_HOSTNAME
@@ -316,7 +323,7 @@ err_t CLwipIf::initEth(struct netif* _ni)
316323
* from it if you have to do some checks before sending (e.g. if link
317324
* is available...) */
318325
_ni->output = etharp_output;
319-
_ni->linkoutput = ouputEth;
326+
_ni->linkoutput = CEth::output;
320327

321328
/* set MAC hardware address */
322329
_ni->hwaddr_len = eth_get_mac_address(_ni->hwaddr);
@@ -328,36 +335,42 @@ err_t CLwipIf::initEth(struct netif* _ni)
328335
/* don't set NETIF_FLAG_ETHARP if this device is not an ethernet one */
329336
_ni->flags |= NETIF_FLAG_BROADCAST | NETIF_FLAG_ETHARP;
330337

331-
/* set the callback function that is called when an ethernet frame is physically
332-
received, it is important that the callbacks are set before the initializiation */
333-
eth_set_rx_frame_cbk(setPendingEthRx);
334-
eth_set_link_on_cbk(ethLinkUp);
335-
eth_set_link_off_cbk(ethLinkDown);
336-
337338
return ERR_OK;
338339
}
339340

340341
/* -------------------------------------------------------------------------- */
341-
err_t CLwipIf::ouputEth(struct netif* _ni, struct pbuf *p) {
342-
/* -------------------------------------------------------------------------- */
343-
(void)_ni;
342+
err_t CEth::output(struct netif* _ni, struct pbuf *p) {
343+
/* -------------------------------------------------------------------------- */
344+
/*
345+
* This function is called inside the lwip timeout engine. Since we are working inside
346+
* an environment without threads it is required to not lock. For this reason we should
347+
* avoid busy waiting and instead discard the transmission. Lwip will handle the retransmission
348+
* of the packet.
349+
*/
350+
(void)_ni;
351+
352+
err_t errval = ERR_OK;
353+
354+
if(eth_output_can_transimit()) {
355+
uint16_t tx_buf_dim = 0;
356+
357+
// TODO analyze the race conditions that may arise from sharing a non synchronized buffer
358+
uint8_t *tx_buf = eth_get_tx_buffer(&tx_buf_dim);
359+
assert (p->tot_len <= tx_buf_dim);
344360

345-
err_t errval = ERR_OK;
346-
uint16_t tx_buf_dim = 0;
347-
uint8_t *tx_buf = eth_get_tx_buffer(&tx_buf_dim);
348-
assert (p->tot_len <= tx_buf_dim);
361+
uint16_t bytes_actually_copied = pbuf_copy_partial(p, tx_buf, p->tot_len, 0);
349362

350-
uint16_t bytes_actually_copied = pbuf_copy_partial(p, tx_buf, p->tot_len, 0);
351-
if (bytes_actually_copied > 0) {
352-
if (!eth_output(tx_buf, bytes_actually_copied)) {
363+
if (bytes_actually_copied > 0 && !eth_output(tx_buf, bytes_actually_copied)) {
353364
errval = ERR_IF;
354365
}
366+
} else {
367+
errval = ERR_INPROGRESS;
355368
}
356369
return errval;
357370
}
358371

359372
/* -------------------------------------------------------------------------- */
360-
err_t CLwipIf::outputWifiStation(struct netif* _ni, struct pbuf *p) {
373+
err_t CWifiStation::output(struct netif* _ni, struct pbuf *p) {
361374
/* -------------------------------------------------------------------------- */
362375
(void)_ni;
363376
err_t errval = ERR_IF;
@@ -366,8 +379,8 @@ err_t CLwipIf::outputWifiStation(struct netif* _ni, struct pbuf *p) {
366379
uint16_t bytes_actually_copied = pbuf_copy_partial(p, buf, p->tot_len, 0);
367380
if (bytes_actually_copied > 0) {
368381
int ifn = 0;
369-
if (net_ifs[NI_WIFI_STATION] != nullptr) {
370-
ifn = net_ifs[NI_WIFI_STATION]->getId();
382+
if (CLwipIf::net_ifs[NI_WIFI_STATION] != nullptr) {
383+
ifn = CLwipIf::net_ifs[NI_WIFI_STATION]->getId();
371384
}
372385

373386
#ifdef DEBUG_OUTPUT_DISABLED
@@ -391,7 +404,7 @@ err_t CLwipIf::outputWifiStation(struct netif* _ni, struct pbuf *p) {
391404
}
392405

393406
/* -------------------------------------------------------------------------- */
394-
err_t CLwipIf::initWifiStation(struct netif* _ni)
407+
err_t CWifiStation::init(struct netif* _ni)
395408
{
396409
/* -------------------------------------------------------------------------- */
397410
#if LWIP_NETIF_HOSTNAME
@@ -406,7 +419,7 @@ err_t CLwipIf::initWifiStation(struct netif* _ni)
406419
* from it if you have to do some checks before sending (e.g. if link
407420
* is available...) */
408421
_ni->output = etharp_output;
409-
_ni->linkoutput = outputWifiStation;
422+
_ni->linkoutput = CWifiStation::output;
410423

411424
/* maximum transfer unit */
412425
_ni->mtu = 1500;
@@ -422,7 +435,7 @@ err_t CLwipIf::initWifiStation(struct netif* _ni)
422435
}
423436

424437
/* -------------------------------------------------------------------------- */
425-
err_t CLwipIf::outputWifiSoftAp(struct netif* _ni, struct pbuf* p)
438+
err_t CWifiSoftAp::output(struct netif* _ni, struct pbuf* p)
426439
{
427440
/* -------------------------------------------------------------------------- */
428441
(void)_ni;
@@ -434,8 +447,8 @@ err_t CLwipIf::outputWifiSoftAp(struct netif* _ni, struct pbuf* p)
434447
uint16_t bytes_actually_copied = pbuf_copy_partial(p, buf, p->tot_len, 0);
435448
if (bytes_actually_copied > 0) {
436449
int ifn = 0;
437-
if (net_ifs[NI_WIFI_SOFTAP] != nullptr) {
438-
ifn = net_ifs[NI_WIFI_SOFTAP]->getId();
450+
if (CLwipIf::net_ifs[NI_WIFI_SOFTAP] != nullptr) {
451+
ifn = CLwipIf::net_ifs[NI_WIFI_SOFTAP]->getId();
439452
}
440453

441454
if (CEspControl::getInstance().sendBuffer(ESP_AP_IF, ifn, buf, bytes_actually_copied) == ESP_CONTROL_OK) {
@@ -449,7 +462,7 @@ err_t CLwipIf::outputWifiSoftAp(struct netif* _ni, struct pbuf* p)
449462
}
450463

451464
/* -------------------------------------------------------------------------- */
452-
err_t CLwipIf::initWifiSoftAp(struct netif* _ni)
465+
err_t CWifiSoftAp::init(struct netif* _ni)
453466
{
454467
/* -------------------------------------------------------------------------- */
455468
#if LWIP_NETIF_HOSTNAME
@@ -464,7 +477,7 @@ err_t CLwipIf::initWifiSoftAp(struct netif* _ni)
464477
* from it if you have to do some checks before sending (e.g. if link
465478
* is available...) */
466479
_ni->output = etharp_output;
467-
_ni->linkoutput = outputWifiSoftAp;
480+
_ni->linkoutput = CWifiSoftAp::output;
468481

469482
/* maximum transfer unit */
470483
_ni->mtu = 1500;
@@ -640,8 +653,8 @@ int CLwipIf::connectToAp(const char* ssid, const char* pwd)
640653
rv = ESP_CONTROL_OK;
641654
/* when we get the connection to access point we are sure we are STATION
642655
and we are connected */
643-
if (net_ifs[NI_WIFI_STATION] != nullptr) {
644-
net_ifs[NI_WIFI_STATION]->setLinkUp();
656+
if (CLwipIf::net_ifs[NI_WIFI_STATION] != nullptr) {
657+
CLwipIf::net_ifs[NI_WIFI_STATION]->setLinkUp();
645658
}
646659

647660
}
@@ -762,28 +775,13 @@ int CLwipIf::resetLowPowerMode()
762775
return rv;
763776
}
764777

765-
/* -------------------------------------------------------------------------- */
766-
struct pbuf* CLwipIf::getEthFrame()
767-
{
768-
/* -------------------------------------------------------------------------- */
769-
struct pbuf* rv = nullptr;
770-
if (!CLwipIf::eth_queue.empty()) {
771-
rv = CLwipIf::eth_queue.front();
772-
CLwipIf::eth_queue.pop();
773-
}
774-
else {
775-
CLwipIf::eth_queue = {};
776-
}
777-
return rv;
778-
}
779-
780778
#ifdef LWIP_USE_TIMER
781779
/* -------------------------------------------------------------------------- */
782780
void CLwipIf::timer_cb(timer_callback_args_t *arg) {
783781
/* -------------------------------------------------------------------------- */
784782
(void)arg;
785783
CLwipIf::getInstance().lwip_task();
786-
}
784+
}
787785
#endif
788786

789787
/* ***************************************************************************
@@ -1288,7 +1286,7 @@ void CEth::begin(IPAddress _ip, IPAddress _gw, IPAddress _nm)
12881286
IP_ADDR4(&nm, _nm[0], _nm[1], _nm[2], _nm[3]);
12891287
IP_ADDR4(&gw, _gw[0], _gw[1], _gw[2], _gw[3]);
12901288

1291-
netif_add(&ni, &ip, &nm, &gw, NULL, CLwipIf::initEth, ethernet_input);
1289+
netif_add(&ni, &ip, &nm, &gw, NULL, CEth::init, ethernet_input);
12921290
netif_set_default(&ni);
12931291

12941292
if (netif_is_link_up(&ni)) {
@@ -1303,32 +1301,27 @@ void CEth::begin(IPAddress _ip, IPAddress _gw, IPAddress _nm)
13031301
/* Set the link callback function, this function is called on change of link status */
13041302
// netif_set_link_callback(&eth0if, eht0if_link_toggle_cbk);
13051303
#endif /* LWIP_NETIF_LINK_CALLBACK */
1304+
/*
1305+
* set the callback function that is called when an ethernet frame is physically
1306+
* received, it is important that the callbacks are set before the initializiation
1307+
*/
1308+
eth_set_rx_frame_cbk(std::bind(&CEth::handleEthRx, this));
1309+
eth_set_link_on_cbk(std::bind(&CEth::setLinkUp, this));
1310+
eth_set_link_off_cbk(std::bind(&CEth::setLinkDown, this));
13061311
}
13071312

13081313
/* -------------------------------------------------------------------------- */
13091314
void CEth::task()
13101315
{
13111316
/* -------------------------------------------------------------------------- */
1312-
struct pbuf* p = nullptr;
13131317

13141318
eth_execute_link_process();
13151319

1316-
__disable_irq();
1317-
CLwipIf::ethFrameRx();
1318-
p = (struct pbuf*)CLwipIf::getInstance().getEthFrame();
1319-
__enable_irq();
1320-
if (p != nullptr) {
1321-
1322-
if (ni.input((struct pbuf*)p, &ni) != ERR_OK) {
1323-
pbuf_free((struct pbuf*)p);
1324-
}
1325-
}
1326-
1327-
13281320
#if LWIP_DHCP
13291321
static unsigned long dhcp_last_time_call = 0;
13301322
if (dhcp_last_time_call == 0 || millis() - dhcp_last_time_call > DHCP_FINE_TIMER_MSECS) {
13311323
dhcp_task();
1324+
dhcp_last_time_call = millis();
13321325
}
13331326
#endif
13341327
}
@@ -1351,7 +1344,7 @@ void CWifiStation::begin(IPAddress _ip, IPAddress _gw, IPAddress _nm)
13511344
IP_ADDR4(&nm, _nm[0], _nm[1], _nm[2], _nm[3]);
13521345
IP_ADDR4(&gw, _gw[0], _gw[1], _gw[2], _gw[3]);
13531346

1354-
netif_add(&ni, &ip, &nm, &gw, NULL, CLwipIf::initWifiStation, ethernet_input);
1347+
netif_add(&ni, &ip, &nm, &gw, NULL, CWifiStation::init, ethernet_input);
13551348
netif_set_default(&ni);
13561349

13571350
if (netif_is_link_up(&ni)) {
@@ -1402,6 +1395,7 @@ void CWifiStation::task()
14021395
static unsigned long dhcp_last_time_call = 0;
14031396
if (dhcp_last_time_call == 0 || millis() - dhcp_last_time_call > DHCP_FINE_TIMER_MSECS) {
14041397
dhcp_task();
1398+
dhcp_last_time_call = millis();
14051399
}
14061400
#endif
14071401
}
@@ -1458,7 +1452,7 @@ void CWifiSoftAp::begin(IPAddress _ip, IPAddress _gw, IPAddress _nm)
14581452
IP_ADDR4(&nm, _nm[0], _nm[1], _nm[2], _nm[3]);
14591453
IP_ADDR4(&gw, _gw[0], _gw[1], _gw[2], _gw[3]);
14601454

1461-
netif_add(&ni, &ip, &nm, &gw, NULL, CLwipIf::initWifiSoftAp, ethernet_input);
1455+
netif_add(&ni, &ip, &nm, &gw, NULL, CWifiSoftAp::init, ethernet_input);
14621456
netif_set_default(&ni);
14631457
if (netif_is_link_up(&ni)) {
14641458
/* When the netif is fully configured this function must be called */
@@ -1478,7 +1472,8 @@ void CWifiSoftAp::begin(IPAddress _ip, IPAddress _gw, IPAddress _nm)
14781472
void CWifiSoftAp::task()
14791473
{
14801474
/* -------------------------------------------------------------------------- */
1481-
/* get messages and process it */
1475+
/* get messages and process it
1476+
* TODO change the algorithm and make it similar to WiFiStation */
14821477
uint8_t if_num;
14831478
uint16_t dim;
14841479
uint8_t* buf = nullptr;
@@ -1505,6 +1500,7 @@ void CWifiSoftAp::task()
15051500
static unsigned long dhcp_last_time_call = 0;
15061501
if (dhcp_last_time_call == 0 || millis() - dhcp_last_time_call > DHCP_FINE_TIMER_MSECS) {
15071502
dhcp_task();
1503+
dhcp_last_time_call = millis();
15081504
}
15091505
#endif
15101506
}

0 commit comments

Comments
 (0)