11#include " CNetIf.h"
2+ #include < functional>
23
34IPAddress CNetIf::default_ip (" 192.168.0.10" );
45IPAddress CNetIf::default_nm (" 255.255.255.0" );
@@ -9,7 +10,6 @@ CNetIf* CLwipIf::net_ifs[] = { nullptr };
910bool CLwipIf::wifi_hw_initialized = false ;
1011bool CLwipIf::connected_to_access_point = false ;
1112WifiStatus_t CLwipIf::wifi_status = WL_IDLE_STATUS;
12- std::queue<struct pbuf *> CLwipIf::eth_queue;
1313bool CLwipIf::pending_eth_rx = false ;
1414
1515FspTimer 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/* -------------------------------------------------------------------------- */
782780void 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(ð0if, 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/* -------------------------------------------------------------------------- */
13091314void 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)
14781472void 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