1
1
#include " CNetIf.h"
2
+ #include < functional>
2
3
3
4
IPAddress CNetIf::default_ip (" 192.168.0.10" );
4
5
IPAddress CNetIf::default_nm (" 255.255.255.0" );
@@ -9,7 +10,6 @@ CNetIf* CLwipIf::net_ifs[] = { nullptr };
9
10
bool CLwipIf::wifi_hw_initialized = false ;
10
11
bool CLwipIf::connected_to_access_point = false ;
11
12
WifiStatus_t CLwipIf::wifi_status = WL_IDLE_STATUS;
12
- std::queue<struct pbuf *> CLwipIf::eth_queue;
13
13
bool CLwipIf::pending_eth_rx = false ;
14
14
15
15
FspTimer CLwipIf::timer;
@@ -69,7 +69,22 @@ CLwipIf::CLwipIf()
69
69
ch = FspTimer::get_available_timer (type, true );
70
70
}
71
71
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);
73
88
timer.setup_overflow_irq ();
74
89
timer.open ();
75
90
timer.start ();
@@ -252,56 +267,48 @@ CNetIf* CLwipIf::get(NetIfType_t type,
252
267
}
253
268
254
269
/* -------------------------------------------------------------------------- */
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 ();
262
288
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 ;
271
293
272
- /* -------------------------------------------------------------------------- */
273
- void CLwipIf::ethFrameRx ()
274
- {
275
- /* -------------------------------------------------------------------------- */
294
+ p = pbuf_alloc (PBUF_RAW, rx_frame_dim, PBUF_RAM);
276
295
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);
291
302
}
292
303
}
293
- }
294
- }
295
304
296
- /* -------------------------------------------------------------------------- */
297
- void CLwipIf::setPendingEthRx ()
298
- {
299
- /* -------------------------------------------------------------------------- */
300
- pending_eth_rx = true ;
305
+ eth_release_rx_buffer ();
306
+ }
307
+ __enable_irq ();
301
308
}
302
309
303
310
/* -------------------------------------------------------------------------- */
304
- err_t CLwipIf::initEth (struct netif * _ni)
311
+ err_t CEth::init (struct netif * _ni)
305
312
{
306
313
/* -------------------------------------------------------------------------- */
307
314
#if LWIP_NETIF_HOSTNAME
@@ -316,7 +323,7 @@ err_t CLwipIf::initEth(struct netif* _ni)
316
323
* from it if you have to do some checks before sending (e.g. if link
317
324
* is available...) */
318
325
_ni->output = etharp_output;
319
- _ni->linkoutput = ouputEth ;
326
+ _ni->linkoutput = CEth::output ;
320
327
321
328
/* set MAC hardware address */
322
329
_ni->hwaddr_len = eth_get_mac_address (_ni->hwaddr );
@@ -328,36 +335,42 @@ err_t CLwipIf::initEth(struct netif* _ni)
328
335
/* don't set NETIF_FLAG_ETHARP if this device is not an ethernet one */
329
336
_ni->flags |= NETIF_FLAG_BROADCAST | NETIF_FLAG_ETHARP;
330
337
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
-
337
338
return ERR_OK;
338
339
}
339
340
340
341
/* -------------------------------------------------------------------------- */
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);
344
360
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 );
349
362
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)) {
353
364
errval = ERR_IF;
354
365
}
366
+ } else {
367
+ errval = ERR_INPROGRESS;
355
368
}
356
369
return errval;
357
370
}
358
371
359
372
/* -------------------------------------------------------------------------- */
360
- err_t CLwipIf::outputWifiStation (struct netif * _ni, struct pbuf *p) {
373
+ err_t CWifiStation::output (struct netif * _ni, struct pbuf *p) {
361
374
/* -------------------------------------------------------------------------- */
362
375
(void )_ni;
363
376
err_t errval = ERR_IF;
@@ -366,8 +379,8 @@ err_t CLwipIf::outputWifiStation(struct netif* _ni, struct pbuf *p) {
366
379
uint16_t bytes_actually_copied = pbuf_copy_partial (p, buf, p->tot_len , 0 );
367
380
if (bytes_actually_copied > 0 ) {
368
381
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 ();
371
384
}
372
385
373
386
#ifdef DEBUG_OUTPUT_DISABLED
@@ -391,7 +404,7 @@ err_t CLwipIf::outputWifiStation(struct netif* _ni, struct pbuf *p) {
391
404
}
392
405
393
406
/* -------------------------------------------------------------------------- */
394
- err_t CLwipIf::initWifiStation (struct netif * _ni)
407
+ err_t CWifiStation::init (struct netif * _ni)
395
408
{
396
409
/* -------------------------------------------------------------------------- */
397
410
#if LWIP_NETIF_HOSTNAME
@@ -406,7 +419,7 @@ err_t CLwipIf::initWifiStation(struct netif* _ni)
406
419
* from it if you have to do some checks before sending (e.g. if link
407
420
* is available...) */
408
421
_ni->output = etharp_output;
409
- _ni->linkoutput = outputWifiStation ;
422
+ _ni->linkoutput = CWifiStation::output ;
410
423
411
424
/* maximum transfer unit */
412
425
_ni->mtu = 1500 ;
@@ -422,7 +435,7 @@ err_t CLwipIf::initWifiStation(struct netif* _ni)
422
435
}
423
436
424
437
/* -------------------------------------------------------------------------- */
425
- err_t CLwipIf::outputWifiSoftAp (struct netif * _ni, struct pbuf * p)
438
+ err_t CWifiSoftAp::output (struct netif * _ni, struct pbuf * p)
426
439
{
427
440
/* -------------------------------------------------------------------------- */
428
441
(void )_ni;
@@ -434,8 +447,8 @@ err_t CLwipIf::outputWifiSoftAp(struct netif* _ni, struct pbuf* p)
434
447
uint16_t bytes_actually_copied = pbuf_copy_partial (p, buf, p->tot_len , 0 );
435
448
if (bytes_actually_copied > 0 ) {
436
449
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 ();
439
452
}
440
453
441
454
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)
449
462
}
450
463
451
464
/* -------------------------------------------------------------------------- */
452
- err_t CLwipIf::initWifiSoftAp (struct netif * _ni)
465
+ err_t CWifiSoftAp::init (struct netif * _ni)
453
466
{
454
467
/* -------------------------------------------------------------------------- */
455
468
#if LWIP_NETIF_HOSTNAME
@@ -464,7 +477,7 @@ err_t CLwipIf::initWifiSoftAp(struct netif* _ni)
464
477
* from it if you have to do some checks before sending (e.g. if link
465
478
* is available...) */
466
479
_ni->output = etharp_output;
467
- _ni->linkoutput = outputWifiSoftAp ;
480
+ _ni->linkoutput = CWifiSoftAp::output ;
468
481
469
482
/* maximum transfer unit */
470
483
_ni->mtu = 1500 ;
@@ -640,8 +653,8 @@ int CLwipIf::connectToAp(const char* ssid, const char* pwd)
640
653
rv = ESP_CONTROL_OK;
641
654
/* when we get the connection to access point we are sure we are STATION
642
655
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 ();
645
658
}
646
659
647
660
}
@@ -762,28 +775,13 @@ int CLwipIf::resetLowPowerMode()
762
775
return rv;
763
776
}
764
777
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
-
780
778
#ifdef LWIP_USE_TIMER
781
779
/* -------------------------------------------------------------------------- */
782
780
void CLwipIf::timer_cb (timer_callback_args_t *arg) {
783
781
/* -------------------------------------------------------------------------- */
784
782
(void )arg;
785
783
CLwipIf::getInstance ().lwip_task ();
786
- }
784
+ }
787
785
#endif
788
786
789
787
/* ***************************************************************************
@@ -1288,7 +1286,7 @@ void CEth::begin(IPAddress _ip, IPAddress _gw, IPAddress _nm)
1288
1286
IP_ADDR4 (&nm, _nm[0 ], _nm[1 ], _nm[2 ], _nm[3 ]);
1289
1287
IP_ADDR4 (&gw, _gw[0 ], _gw[1 ], _gw[2 ], _gw[3 ]);
1290
1288
1291
- netif_add (&ni, &ip, &nm, &gw, NULL , CLwipIf::initEth , ethernet_input);
1289
+ netif_add (&ni, &ip, &nm, &gw, NULL , CEth::init , ethernet_input);
1292
1290
netif_set_default (&ni);
1293
1291
1294
1292
if (netif_is_link_up (&ni)) {
@@ -1303,32 +1301,27 @@ void CEth::begin(IPAddress _ip, IPAddress _gw, IPAddress _nm)
1303
1301
/* Set the link callback function, this function is called on change of link status */
1304
1302
// netif_set_link_callback(ð0if, eht0if_link_toggle_cbk);
1305
1303
#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 ));
1306
1311
}
1307
1312
1308
1313
/* -------------------------------------------------------------------------- */
1309
1314
void CEth::task ()
1310
1315
{
1311
1316
/* -------------------------------------------------------------------------- */
1312
- struct pbuf * p = nullptr ;
1313
1317
1314
1318
eth_execute_link_process ();
1315
1319
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
-
1328
1320
#if LWIP_DHCP
1329
1321
static unsigned long dhcp_last_time_call = 0 ;
1330
1322
if (dhcp_last_time_call == 0 || millis () - dhcp_last_time_call > DHCP_FINE_TIMER_MSECS) {
1331
1323
dhcp_task ();
1324
+ dhcp_last_time_call = millis ();
1332
1325
}
1333
1326
#endif
1334
1327
}
@@ -1351,7 +1344,7 @@ void CWifiStation::begin(IPAddress _ip, IPAddress _gw, IPAddress _nm)
1351
1344
IP_ADDR4 (&nm, _nm[0 ], _nm[1 ], _nm[2 ], _nm[3 ]);
1352
1345
IP_ADDR4 (&gw, _gw[0 ], _gw[1 ], _gw[2 ], _gw[3 ]);
1353
1346
1354
- netif_add (&ni, &ip, &nm, &gw, NULL , CLwipIf::initWifiStation , ethernet_input);
1347
+ netif_add (&ni, &ip, &nm, &gw, NULL , CWifiStation::init , ethernet_input);
1355
1348
netif_set_default (&ni);
1356
1349
1357
1350
if (netif_is_link_up (&ni)) {
@@ -1402,6 +1395,7 @@ void CWifiStation::task()
1402
1395
static unsigned long dhcp_last_time_call = 0 ;
1403
1396
if (dhcp_last_time_call == 0 || millis () - dhcp_last_time_call > DHCP_FINE_TIMER_MSECS) {
1404
1397
dhcp_task ();
1398
+ dhcp_last_time_call = millis ();
1405
1399
}
1406
1400
#endif
1407
1401
}
@@ -1458,7 +1452,7 @@ void CWifiSoftAp::begin(IPAddress _ip, IPAddress _gw, IPAddress _nm)
1458
1452
IP_ADDR4 (&nm, _nm[0 ], _nm[1 ], _nm[2 ], _nm[3 ]);
1459
1453
IP_ADDR4 (&gw, _gw[0 ], _gw[1 ], _gw[2 ], _gw[3 ]);
1460
1454
1461
- netif_add (&ni, &ip, &nm, &gw, NULL , CLwipIf::initWifiSoftAp , ethernet_input);
1455
+ netif_add (&ni, &ip, &nm, &gw, NULL , CWifiSoftAp::init , ethernet_input);
1462
1456
netif_set_default (&ni);
1463
1457
if (netif_is_link_up (&ni)) {
1464
1458
/* When the netif is fully configured this function must be called */
@@ -1478,7 +1472,8 @@ void CWifiSoftAp::begin(IPAddress _ip, IPAddress _gw, IPAddress _nm)
1478
1472
void CWifiSoftAp::task ()
1479
1473
{
1480
1474
/* -------------------------------------------------------------------------- */
1481
- /* get messages and process it */
1475
+ /* get messages and process it
1476
+ * TODO change the algorithm and make it similar to WiFiStation */
1482
1477
uint8_t if_num;
1483
1478
uint16_t dim;
1484
1479
uint8_t * buf = nullptr ;
@@ -1505,6 +1500,7 @@ void CWifiSoftAp::task()
1505
1500
static unsigned long dhcp_last_time_call = 0 ;
1506
1501
if (dhcp_last_time_call == 0 || millis () - dhcp_last_time_call > DHCP_FINE_TIMER_MSECS) {
1507
1502
dhcp_task ();
1503
+ dhcp_last_time_call = millis ();
1508
1504
}
1509
1505
#endif
1510
1506
}
0 commit comments