diff --git a/ESP8266/ESP8266.cpp b/ESP8266/ESP8266.cpp index c260b98..291018b 100644 --- a/ESP8266/ESP8266.cpp +++ b/ESP8266/ESP8266.cpp @@ -66,6 +66,7 @@ ESP8266::ESP8266(PinName tx, PinName rx, bool debug, PinName rts, PinName cts) // Don't see a reason to make distiction between software(Software WDT reset) and hardware(wdt reset) watchdog treatment //https://github.com/esp8266/Arduino/blob/4897e0006b5b0123a2fa31f67b14a3fff65ce561/doc/faq/a02-my-esp-crashes.md#watchdog _parser.oob("Soft WDT reset", callback(this, &ESP8266::_oob_watchdog_reset)); + _parser.oob("busy ", callback(this, &ESP8266::_oob_busy)); for(int i= 0; i < SOCKET_COUNT; i++) { _sock_i[i].open = false; @@ -590,18 +591,25 @@ void ESP8266::_process_oob(uint32_t timeout, bool all) { set_timeout(); } +void ESP8266::bg_process_oob(uint32_t timeout, bool all) +{ + _smutex.lock(); + _process_oob(timeout, all); + _smutex.unlock(); +} + int32_t ESP8266::_recv_tcp_passive(int id, void *data, uint32_t amount, uint32_t timeout) { int32_t len; int32_t ret = (int32_t)NSAPI_ERROR_WOULD_BLOCK; + _smutex.lock(); + // No flow control, drain the USART receive register ASAP to avoid data overrun if (_serial_rts == NC) { _process_oob(timeout, true); } - _smutex.lock(); - // NOTE: documentation v3.0 says '+CIPRECVDATA:,' but it's not how the FW responds... bool done = _parser.send("AT+CIPRECVDATA=%d,%lu", id, amount) && _parser.recv("+CIPRECVDATA,%ld:", &len) @@ -832,10 +840,29 @@ void ESP8266::_oob_watchdog_reset() _sock_i[i].open = false; } - _conn_status = NSAPI_STATUS_DISCONNECTED; + // Makes possible to reinitialize + _conn_status = NSAPI_STATUS_ERROR_UNSUPPORTED; _conn_stat_cb(); } +void ESP8266::_oob_busy() +{ + char status[5]; + if (_parser.recv("%4[^\"]\n", status)) { + if (strcmp(status, " s...\n") == 0) { + ; //TODO maybe do something here, or not... + } else if (strcmp(status, "p...\n") == 0) { + ; //TODO maybe do something here, or not... + } else { + MBED_ERROR(MBED_MAKE_ERROR(MBED_MODULE_DRIVER, MBED_ERROR_CODE_EBADMSG), \ + "ESP8266::_oob_busy: unrecognized busy state\n"); + } + } else { + MBED_ERROR(MBED_MAKE_ERROR(MBED_MODULE_DRIVER, MBED_ERROR_CODE_ENOMSG), \ + "ESP8266::_oob_busy: AT timeout\n"); + } +} + void ESP8266::_oob_connect_err() { _fail = false; diff --git a/ESP8266/ESP8266.h b/ESP8266/ESP8266.h index bce2a72..59319e7 100644 --- a/ESP8266/ESP8266.h +++ b/ESP8266/ESP8266.h @@ -18,8 +18,10 @@ #define ESP8266_H #include "ATCmdParser.h" +#include "Mutex.h" #include "nsapi_types.h" #include "rtos.h" +#include "drivers/UARTSerial.h" // Various timeouts for different ESP8266 operations #ifndef ESP8266_CONNECT_TIMEOUT @@ -342,6 +344,14 @@ class ESP8266 */ bool cond_enable_tcp_passive_mode(); + /** + * For executing OOB processing on background + * + * @param timeout AT parser receive timeout + * @param if TRUE, process all OOBs instead of only one + */ + void bg_process_oob(uint32_t timeout, bool all); + static const int8_t WIFIMODE_STATION = 1; static const int8_t WIFIMODE_SOFTAP = 2; static const int8_t WIFIMODE_STATION_SOFTAP = 3; @@ -397,6 +407,7 @@ class ESP8266 void _oob_connection_status(); void _oob_socket_close_err(); void _oob_watchdog_reset(); + void _oob_busy(); // OOB state variables int _connect_error; diff --git a/ESP8266Interface.cpp b/ESP8266Interface.cpp index 166742d..69ff2ac 100644 --- a/ESP8266Interface.cpp +++ b/ESP8266Interface.cpp @@ -15,6 +15,9 @@ */ #include +#include "events/EventQueue.h" +#include "events/mbed_shared_queues.h" +#include "platform/Callback.h" #include "ESP8266.h" #include "ESP8266Interface.h" #include "mbed_debug.h" @@ -49,7 +52,9 @@ ESP8266Interface::ESP8266Interface() _initialized(false), _started(false), _conn_stat(NSAPI_STATUS_DISCONNECTED), - _conn_stat_cb(NULL) + _conn_stat_cb(NULL), + _global_event_queue(NULL), + _oob_event_id(0) { memset(_cbs, 0, sizeof(_cbs)); memset(ap_ssid, 0, sizeof(ap_ssid)); @@ -73,7 +78,9 @@ ESP8266Interface::ESP8266Interface(PinName tx, PinName rx, bool debug, PinName r _initialized(false), _started(false), _conn_stat(NSAPI_STATUS_DISCONNECTED), - _conn_stat_cb(NULL) + _conn_stat_cb(NULL), + _global_event_queue(NULL), + _oob_event_id(0) { memset(_cbs, 0, sizeof(_cbs)); memset(ap_ssid, 0, sizeof(ap_ssid)); @@ -89,6 +96,13 @@ ESP8266Interface::ESP8266Interface(PinName tx, PinName rx, bool debug, PinName r } } +ESP8266Interface::~ESP8266Interface() +{ + if (_oob_event_id) { + _global_event_queue->cancel(_oob_event_id); + } +} + int ESP8266Interface::connect(const char *ssid, const char *pass, nsapi_security_t security, uint8_t channel) { @@ -104,6 +118,17 @@ int ESP8266Interface::connect(const char *ssid, const char *pass, nsapi_security return connect(); } +void ESP8266Interface::_oob2global_event_queue() +{ + _global_event_queue = mbed_event_queue(); + _oob_event_id = _global_event_queue->call_every(ESP8266_RECV_TIMEOUT, callback(this, &ESP8266Interface::proc_oob_evnt)); + + if (!_oob_event_id) { + MBED_ERROR(MBED_MAKE_ERROR(MBED_MODULE_DRIVER, MBED_ERROR_CODE_ENOMEM), \ + "ESP8266::_oob2geq: unable to allocate OOB event"); + } +} + int ESP8266Interface::connect() { nsapi_error_t status; @@ -123,6 +148,10 @@ int ESP8266Interface::connect() return status; } + if (!_oob_event_id) { + _oob2global_event_queue(); + } + if(get_ip_address()) { return NSAPI_ERROR_IS_CONNECTED; } @@ -196,10 +225,16 @@ int ESP8266Interface::set_channel(uint8_t channel) int ESP8266Interface::disconnect() { - _started = false; - _initialized = false; + int ret = _esp.disconnect() ? NSAPI_ERROR_OK : NSAPI_ERROR_DEVICE_ERROR; - return _esp.disconnect() ? NSAPI_ERROR_OK : NSAPI_ERROR_DEVICE_ERROR; + if (ret == NSAPI_ERROR_OK) { + // Try to lure the nw status update from ESP8266, might come later + _esp.bg_process_oob(ESP8266_RECV_TIMEOUT, true); + // In case the status update arrives later + _conn_stat = NSAPI_STATUS_DISCONNECTED; + } + + return ret; } const char *ESP8266Interface::get_ip_address() @@ -613,13 +648,16 @@ void ESP8266Interface::update_conn_state_cb() // Start from scratch if connection drops/is dropped case NSAPI_STATUS_DISCONNECTED: _started = false; - _initialized = false; break; // Handled on AT layer case NSAPI_STATUS_LOCAL_UP: case NSAPI_STATUS_ERROR_UNSUPPORTED: default: - MBED_ASSERT(false); + _started = false; + _initialized = false; + _global_event_queue->cancel(_oob_event_id); + _oob_event_id = 0; + _conn_stat = NSAPI_STATUS_DISCONNECTED; } // Inform upper layers @@ -627,3 +665,10 @@ void ESP8266Interface::update_conn_state_cb() _conn_stat_cb(NSAPI_EVENT_CONNECTION_STATUS_CHANGE, _conn_stat); } } + +void ESP8266Interface::proc_oob_evnt() +{ + if (_initialized) { + _esp.bg_process_oob(ESP8266_RECV_TIMEOUT, true); + } +} diff --git a/ESP8266Interface.h b/ESP8266Interface.h index 52b413c..838ba53 100644 --- a/ESP8266Interface.h +++ b/ESP8266Interface.h @@ -18,8 +18,17 @@ #define ESP8266_INTERFACE_H #include "mbed.h" -#include "ESP8266.h" +#include "events/EventQueue.h" +#include "events/mbed_shared_queues.h" +#include "platform/Callback.h" +#include "netsocket/nsapi_types.h" +#include "netsocket/NetworkInterface.h" +#include "netsocket/NetworkStack.h" +#include "netsocket/WiFiAccessPoint.h" +#include "netsocket/WiFiInterface.h" + +#include "ESP8266.h" #define ESP8266_SOCKET_COUNT 5 @@ -44,6 +53,11 @@ class ESP8266Interface : public NetworkStack, public WiFiInterface */ ESP8266Interface(PinName tx, PinName rx, bool debug=false, PinName rts=NC, PinName cts=NC); + /** + * @brief ESP8266Interface default destructor + */ + ~ESP8266Interface(); + /** Start the interface * * Attempts to connect to a WiFi network. Requires ssid and passphrase to be set. @@ -354,6 +368,13 @@ class ESP8266Interface : public NetworkStack, public WiFiInterface // Connection state reporting to application nsapi_connection_status_t _conn_stat; Callback _conn_stat_cb; + + // Background OOB processing + // Use global EventQueue + events::EventQueue *_global_event_queue; + int _oob_event_id; + void proc_oob_evnt(); + void _oob2global_event_queue(); }; #endif