mirror of https://github.com/ARMmbed/mbed-os.git
Merge pull request #9473 from VeijoPesonen/feature-esp8266_reset_handling
ESP8266: treats reset-ready-message as OOBpull/9745/head
commit
7dbe541251
|
@ -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_ready));
|
||||
// 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));
|
||||
|
@ -183,14 +187,17 @@ bool ESP8266::start_uart_hw_flow_ctrl(void)
|
|||
bool done = true;
|
||||
|
||||
#if DEVICE_SERIAL_FC
|
||||
_smutex.lock();
|
||||
if (_serial_rts != NC && _serial_cts != NC) {
|
||||
// Start board's flow control
|
||||
_serial.set_flow_control(SerialBase::RTSCTS, _serial_rts, _serial_cts);
|
||||
|
||||
// Start ESP8266's flow control
|
||||
done = _parser.send("AT+UART_CUR=%u,8,1,0,3", ESP8266_DEFAULT_BAUD_RATE)
|
||||
&& _parser.recv("OK\n");
|
||||
|
||||
if (done) {
|
||||
// Start board's flow control
|
||||
_serial.set_flow_control(SerialBase::RTSCTS, _serial_rts, _serial_cts);
|
||||
}
|
||||
|
||||
} else if (_serial_rts != NC) {
|
||||
_serial.set_flow_control(SerialBase::RTS, _serial_rts, NC);
|
||||
|
||||
|
@ -203,7 +210,14 @@ bool ESP8266::start_uart_hw_flow_ctrl(void)
|
|||
done = _parser.send("AT+UART_CUR=%u,8,1,0,1", ESP8266_DEFAULT_BAUD_RATE)
|
||||
&& _parser.recv("OK\n");
|
||||
|
||||
_serial.set_flow_control(SerialBase::CTS, NC, _serial_cts);
|
||||
if (done) {
|
||||
_serial.set_flow_control(SerialBase::CTS, NC, _serial_cts);
|
||||
}
|
||||
}
|
||||
_smutex.unlock();
|
||||
|
||||
if (!done) {
|
||||
tr_debug("Enable UART HW flow control: FAIL");
|
||||
}
|
||||
#else
|
||||
if (_serial_rts != NC || _serial_cts != NC) {
|
||||
|
@ -234,20 +248,35 @@ 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);
|
||||
|
||||
unsigned long int start_time = rtos::Kernel::get_ms_count();
|
||||
_reset_done = false;
|
||||
set_timeout(ESP8266_RECV_TIMEOUT);
|
||||
for (int i = 0; i < 2; i++) {
|
||||
if (_parser.send("AT+RST")
|
||||
&& _parser.recv("OK\n")
|
||||
&& _parser.recv("ready")) {
|
||||
done = true;
|
||||
if (!_parser.send("AT+RST") || !_parser.recv("OK\n")) {
|
||||
tr_debug("reset(): AT+RST failed or no response");
|
||||
continue;
|
||||
}
|
||||
|
||||
_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();
|
||||
if (done) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
tr_debug("reset(): done: %s", done ? "OK" : "FAIL");
|
||||
|
||||
_clear_socket_packets(ESP8266_ALL_SOCKET_IDS);
|
||||
set_timeout();
|
||||
_smutex.unlock();
|
||||
|
@ -963,6 +992,25 @@ void ESP8266::_oob_watchdog_reset()
|
|||
"_oob_watchdog_reset() modem watchdog reset triggered\n");
|
||||
}
|
||||
|
||||
void ESP8266::_oob_ready()
|
||||
{
|
||||
|
||||
_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];
|
||||
|
|
|
@ -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_ready();
|
||||
|
||||
// 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];
|
||||
|
|
|
@ -71,7 +71,7 @@ ESP8266Interface::ESP8266Interface()
|
|||
|
||||
_esp.sigio(this, &ESP8266Interface::event);
|
||||
_esp.set_timeout();
|
||||
_esp.attach(this, &ESP8266Interface::update_conn_state_cb);
|
||||
_esp.attach(this, &ESP8266Interface::refresh_conn_state_cb);
|
||||
|
||||
for (int i = 0; i < ESP8266_SOCKET_COUNT; i++) {
|
||||
_sock_i[i].open = false;
|
||||
|
@ -102,7 +102,7 @@ ESP8266Interface::ESP8266Interface(PinName tx, PinName rx, bool debug, PinName r
|
|||
|
||||
_esp.sigio(this, &ESP8266Interface::event);
|
||||
_esp.set_timeout();
|
||||
_esp.attach(this, &ESP8266Interface::update_conn_state_cb);
|
||||
_esp.attach(this, &ESP8266Interface::refresh_conn_state_cb);
|
||||
|
||||
for (int i = 0; i < ESP8266_SOCKET_COUNT; i++) {
|
||||
_sock_i[i].open = false;
|
||||
|
@ -404,12 +404,7 @@ bool ESP8266Interface::_get_firmware_ok()
|
|||
nsapi_error_t ESP8266Interface::_init(void)
|
||||
{
|
||||
if (!_initialized) {
|
||||
_hw_reset();
|
||||
|
||||
if (!_esp.at_available()) {
|
||||
return NSAPI_ERROR_DEVICE_ERROR;
|
||||
}
|
||||
if (!_esp.reset()) {
|
||||
if (_reset() != NSAPI_ERROR_OK) {
|
||||
return NSAPI_ERROR_DEVICE_ERROR;
|
||||
}
|
||||
if (!_esp.echo_off()) {
|
||||
|
@ -436,7 +431,7 @@ nsapi_error_t ESP8266Interface::_init(void)
|
|||
return NSAPI_ERROR_OK;
|
||||
}
|
||||
|
||||
void ESP8266Interface::_hw_reset()
|
||||
nsapi_error_t ESP8266Interface::_reset()
|
||||
{
|
||||
if (_rst_pin.is_connected()) {
|
||||
_rst_pin.rst_assert();
|
||||
|
@ -445,7 +440,17 @@ void ESP8266Interface::_hw_reset()
|
|||
wait_ms(2); // Documentation says 200 us should have been enough, but experimentation shows that 1ms was not enough
|
||||
_esp.flush();
|
||||
_rst_pin.rst_deassert();
|
||||
} else {
|
||||
_esp.flush();
|
||||
if (!_esp.at_available()) {
|
||||
return NSAPI_ERROR_DEVICE_ERROR;
|
||||
}
|
||||
if (!_esp.reset()) {
|
||||
return NSAPI_ERROR_DEVICE_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
return _esp.at_available() ? NSAPI_ERROR_OK : NSAPI_ERROR_DEVICE_ERROR;
|
||||
}
|
||||
|
||||
struct esp8266_socket {
|
||||
|
@ -577,6 +582,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 +613,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);
|
||||
|
@ -768,15 +781,11 @@ WiFiInterface *WiFiInterface::get_default_instance()
|
|||
|
||||
#endif
|
||||
|
||||
void ESP8266Interface::update_conn_state_cb()
|
||||
void ESP8266Interface::refresh_conn_state_cb()
|
||||
{
|
||||
nsapi_connection_status_t prev_stat = _conn_stat;
|
||||
_conn_stat = _esp.connection_status();
|
||||
|
||||
if (prev_stat == _conn_stat) {
|
||||
return;
|
||||
}
|
||||
|
||||
switch (_conn_stat) {
|
||||
// Doesn't require changes
|
||||
case NSAPI_STATUS_CONNECTING:
|
||||
|
@ -791,8 +800,18 @@ 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;
|
||||
}
|
||||
}
|
||||
|
||||
if (prev_stat == _conn_stat) {
|
||||
return;
|
||||
}
|
||||
|
||||
tr_debug("refresh_conn_state_cb(): changed to %d", _conn_stat);
|
||||
|
||||
// Inform upper layers
|
||||
if (_conn_stat_cb) {
|
||||
_conn_stat_cb(NSAPI_EVENT_CONNECTION_STATUS_CHANGE, _conn_stat);
|
||||
|
|
|
@ -328,7 +328,7 @@ protected:
|
|||
private:
|
||||
// AT layer
|
||||
ESP8266 _esp;
|
||||
void update_conn_state_cb();
|
||||
void refresh_conn_state_cb();
|
||||
|
||||
// HW reset pin
|
||||
class ResetPin {
|
||||
|
@ -365,10 +365,10 @@ private:
|
|||
|
||||
// Driver's state
|
||||
int _initialized;
|
||||
nsapi_error_t _connect_retval;
|
||||
bool _get_firmware_ok();
|
||||
nsapi_error_t _init(void);
|
||||
void _hw_reset();
|
||||
nsapi_error_t _connect_retval;
|
||||
nsapi_error_t _reset();
|
||||
|
||||
//sigio
|
||||
struct {
|
||||
|
|
Loading…
Reference in New Issue