From 876a397101a09c4e7978c494bb744f5f7bf5d46c Mon Sep 17 00:00:00 2001 From: Veijo Pesonen Date: Wed, 23 Jan 2019 15:11:14 +0200 Subject: [PATCH] ESP8266: handles reset ready as OOB Makes possible to recover from spurious resets addiotionally to planned ones. --- .../wifi/esp8266-driver/ESP8266/ESP8266.cpp | 50 ++++++++++++++++--- .../wifi/esp8266-driver/ESP8266/ESP8266.h | 5 ++ .../wifi/esp8266-driver/ESP8266Interface.cpp | 12 +++++ 3 files changed, 59 insertions(+), 8 deletions(-) diff --git a/components/wifi/esp8266-driver/ESP8266/ESP8266.cpp b/components/wifi/esp8266-driver/ESP8266/ESP8266.cpp index 4b2172b465..77d7430a94 100644 --- a/components/wifi/esp8266-driver/ESP8266/ESP8266.cpp +++ b/components/wifi/esp8266-driver/ESP8266/ESP8266.cpp @@ -25,6 +25,7 @@ #include "PinNames.h" #include "platform/Callback.h" #include "platform/mbed_error.h" +#include "rtos/Kernel.h" #define TRACE_GROUP "ESPA" // ESP8266 AT layer @@ -51,6 +52,8 @@ ESP8266::ESP8266(PinName tx, PinName rx, bool debug, PinName rts, PinName cts) _sock_already(false), _closed(false), _busy(false), + _reset_check(_rmutex), + _reset_done(false), _conn_status(NSAPI_STATUS_DISCONNECTED) { _serial.set_baud(ESP8266_DEFAULT_BAUD_RATE); @@ -71,6 +74,7 @@ ESP8266::ESP8266(PinName tx, PinName rx, bool debug, PinName rts, PinName cts) _parser.oob("UNLINK", callback(this, &ESP8266::_oob_socket_close_err)); _parser.oob("ALREADY CONNECTED", callback(this, &ESP8266::_oob_conn_already)); _parser.oob("ERROR", callback(this, &ESP8266::_oob_err)); + _parser.oob("ready", callback(this, &ESP8266::_oob_reset)); // Don't expect to find anything about the watchdog reset in official documentation //https://techtutorialsx.com/2017/01/21/esp8266-watchdog-functions/ _parser.oob("wdt reset", callback(this, &ESP8266::_oob_watchdog_reset)); @@ -234,20 +238,31 @@ bool ESP8266::startup(int mode) bool ESP8266::reset(void) { + static const int ESP8266_BOOTTIME = 10000; // [ms] bool done = false; _smutex.lock(); - set_timeout(ESP8266_CONNECT_TIMEOUT); - for (int i = 0; i < 2; i++) { - if (_parser.send("AT+RST") - && _parser.recv("OK\n") - && _parser.recv("ready")) { - done = true; - break; - } + unsigned long int start_time = rtos::Kernel::get_ms_count(); + _reset_done = false; + set_timeout(ESP8266_RECV_TIMEOUT); + if (!_parser.send("AT+RST") || !_parser.recv("OK\n")) { + tr_debug("reset(): AT+RST failed or no response"); + goto EXIT; } + _rmutex.lock(); + while ((rtos::Kernel::get_ms_count() - start_time < ESP8266_BOOTTIME) && !_reset_done) { + _process_oob(ESP8266_RECV_TIMEOUT, true); // UART mutex claimed -> need to check for OOBs ourselves + _reset_check.wait_for(100); // Arbitrary relatively short delay + } + + done = _reset_done; + _rmutex.unlock(); + + tr_debug("reset(): done: %s", done ? "OK" : "FAIL"); + +EXIT: _clear_socket_packets(ESP8266_ALL_SOCKET_IDS); set_timeout(); _smutex.unlock(); @@ -963,6 +978,25 @@ void ESP8266::_oob_watchdog_reset() "_oob_watchdog_reset() modem watchdog reset triggered\n"); } +void ESP8266::_oob_reset() +{ + + _rmutex.lock(); + _reset_done = true; + _reset_check.notify_all(); + _rmutex.unlock(); + + for (int i = 0; i < SOCKET_COUNT; i++) { + _sock_i[i].open = false; + } + + // Makes possible to reinitialize + _conn_status = NSAPI_STATUS_ERROR_UNSUPPORTED; + _conn_stat_cb(); + + tr_debug("_oob_reset(): reset detected"); +} + void ESP8266::_oob_busy() { char status[5]; diff --git a/components/wifi/esp8266-driver/ESP8266/ESP8266.h b/components/wifi/esp8266-driver/ESP8266/ESP8266.h index 68eb5f969f..e977c0cb38 100644 --- a/components/wifi/esp8266-driver/ESP8266/ESP8266.h +++ b/components/wifi/esp8266-driver/ESP8266/ESP8266.h @@ -27,6 +27,7 @@ #include "platform/ATCmdParser.h" #include "platform/Callback.h" #include "platform/mbed_error.h" +#include "rtos/ConditionVariable.h" #include "rtos/Mutex.h" // Various timeouts for different ESP8266 operations @@ -396,6 +397,7 @@ private: PinName _serial_rts; PinName _serial_cts; rtos::Mutex _smutex; // Protect serial port access + rtos::Mutex _rmutex; // Reset protection // AT Command Parser mbed::ATCmdParser _parser; @@ -435,6 +437,7 @@ private: void _oob_watchdog_reset(); void _oob_busy(); void _oob_tcp_data_hdlr(); + void _oob_reset(); // OOB state variables int _connect_error; @@ -444,6 +447,8 @@ private: bool _closed; bool _error; bool _busy; + rtos::ConditionVariable _reset_check; + bool _reset_done; // Modem's address info char _ip_buffer[16]; diff --git a/components/wifi/esp8266-driver/ESP8266Interface.cpp b/components/wifi/esp8266-driver/ESP8266Interface.cpp index 02ae6a59db..6e6331f992 100644 --- a/components/wifi/esp8266-driver/ESP8266Interface.cpp +++ b/components/wifi/esp8266-driver/ESP8266Interface.cpp @@ -577,6 +577,10 @@ int ESP8266Interface::socket_send(void *handle, const void *data, unsigned size) return NSAPI_ERROR_NO_SOCKET; } + if (!_sock_i[socket->id].open) { + return NSAPI_ERROR_CONNECTION_LOST; + } + if (!size) { // Firmware limitation return socket->proto == NSAPI_TCP ? 0 : NSAPI_ERROR_UNSUPPORTED; @@ -604,6 +608,10 @@ int ESP8266Interface::socket_recv(void *handle, void *data, unsigned size) return NSAPI_ERROR_NO_SOCKET; } + if (!_sock_i[socket->id].open) { + return NSAPI_ERROR_CONNECTION_LOST; + } + int32_t recv; if (socket->proto == NSAPI_TCP) { recv = _esp.recv_tcp(socket->id, data, size); @@ -791,6 +799,10 @@ void ESP8266Interface::update_conn_state_cb() default: _initialized = false; _conn_stat = NSAPI_STATUS_DISCONNECTED; + for (int i = 0; i < ESP8266_SOCKET_COUNT; i++) { + _sock_i[i].open = false; + _sock_i[i].sport = 0; + } } // Inform upper layers