From e384f1e5020f48b20819c024afc2968ffa0739b2 Mon Sep 17 00:00:00 2001
From: Gunar Schorcht <gunar@schorcht.net>
Date: Wed, 23 Jan 2019 10:32:44 +0100
Subject: [PATCH] cpu/esp8266: send timeout handling in esp_wifi

A timeout was introduced if sending a frame takes to long time. In that case the WiFi interface disconnects and reconnects automatically to recover.
---
 cpu/esp8266/esp-wifi/esp_wifi_netdev.c | 26 +++++++++++++++++++++-----
 1 file changed, 21 insertions(+), 5 deletions(-)

diff --git a/cpu/esp8266/esp-wifi/esp_wifi_netdev.c b/cpu/esp8266/esp-wifi/esp_wifi_netdev.c
index 2e8f846207..cd1d58561f 100644
--- a/cpu/esp8266/esp-wifi/esp_wifi_netdev.c
+++ b/cpu/esp8266/esp-wifi/esp_wifi_netdev.c
@@ -64,6 +64,8 @@
 #define ESP_WIFI_SOFTAP_IF          (SOFTAP_IF)
 
 #define ESP_WIFI_RECONNECT_TIME     (20 * US_PER_SEC)
+#define ESP_WIFI_SEND_TIMEOUT       (MS_PER_SEC)
+
 #define MAC_STR                     "%02x:%02x:%02x:%02x:%02x:%02x"
 #define MAC_STR_ARG(m)              m[0], m[1], m[2], m[3], m[4], m[5]
 /** Timer used to reconnect automatically after 20 seconds if not connected */
@@ -380,9 +382,22 @@ static int IRAM _send(netdev_t *netdev, const iolist_t *iolist)
 #endif /* ENABLE_DEBUG */
 
     int res = ieee80211_output_pbuf(sta_netif, pb);
+
+    /*
+     * Attempting to send the next frame before completing the transmission
+     * of the previous frame may result in a complete blockage of the send
+     * function. To avoid this blockage, we have to wait here until the frame
+     * has been sent. The frame has been sent when pb->ref becomes 1.
+     * We wait for a maximum time of ESP_WIFI_SEND_TIMEOUT milliseconds.
+     */
+    unsigned _timeout = ESP_WIFI_SEND_TIMEOUT;
+    while (pb->ref > 1 && --_timeout && dev->state == ESP_WIFI_CONNECTED) {
+        xtimer_usleep(US_PER_MS);
+    }
     pbuf_free(pb);
 
-    if (res == ERR_OK) {
+    if (res == ERR_OK && _timeout) {
+        /* There was no ieee80211_output_pbuf error and no send timeout. */
 #ifdef MODULE_NETSTATS_L2
         netdev->stats.tx_bytes += iol_len;
         netdev->event_callback(netdev, NETDEV_EVENT_TX_COMPLETE);
@@ -392,16 +407,17 @@ static int IRAM _send(netdev_t *netdev, const iolist_t *iolist)
         return iol_len;
     }
     else {
+        /* There was either a ieee80211_output_pbuf error or send timed out. */
 #ifdef MODULE_NETSTATS_L2
         netdev->stats.tx_failed++;
 #endif
         _in_send = false;
         critical_exit();
         /*
-         * This error usually happens because we run into out of memory. We have
-         * to wait until lwIP pbuf has been flushed. For that purpose, we
-         * have to disconnect from AP and wait for a short time. The node will
-         * then reconnect to AP automatically.
+         * ieee80211_output_pbuf usually happens because we run into out of
+         * memory. We have to wait until lwIP pbuf has been flushed. For that
+         * purpose, we have to disconnect from AP and wait for a short time.
+         * The node will then reconnect to AP automatically.
          */
         wifi_station_disconnect();
         return -EIO;
-- 
GitLab