Merge pull request #9421 from VeijoPesonen/feature-esp8266_nonblocking_connect

ESP8266: implements possibility to decide between non-blocking/blocking connect.
pull/9485/head
Cruz Monrreal 2019-01-23 22:47:51 -06:00 committed by GitHub
commit f790fdd1cd
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 122 additions and 6 deletions

View File

@ -55,11 +55,14 @@ ESP8266Interface::ESP8266Interface()
: _esp(MBED_CONF_ESP8266_TX, MBED_CONF_ESP8266_RX, MBED_CONF_ESP8266_DEBUG, MBED_CONF_ESP8266_RTS, MBED_CONF_ESP8266_CTS), : _esp(MBED_CONF_ESP8266_TX, MBED_CONF_ESP8266_RX, MBED_CONF_ESP8266_DEBUG, MBED_CONF_ESP8266_RTS, MBED_CONF_ESP8266_CTS),
_rst_pin(MBED_CONF_ESP8266_RST), // Notice that Pin7 CH_EN cannot be left floating if used as reset _rst_pin(MBED_CONF_ESP8266_RST), // Notice that Pin7 CH_EN cannot be left floating if used as reset
_ap_sec(NSAPI_SECURITY_UNKNOWN), _ap_sec(NSAPI_SECURITY_UNKNOWN),
_if_blocking(true),
_if_connected(_cmutex),
_initialized(false), _initialized(false),
_conn_stat(NSAPI_STATUS_DISCONNECTED), _conn_stat(NSAPI_STATUS_DISCONNECTED),
_conn_stat_cb(NULL), _conn_stat_cb(NULL),
_global_event_queue(NULL), _global_event_queue(NULL),
_oob_event_id(0) _oob_event_id(0),
_connect_event_id(0)
{ {
memset(_cbs, 0, sizeof(_cbs)); memset(_cbs, 0, sizeof(_cbs));
memset(ap_ssid, 0, sizeof(ap_ssid)); memset(ap_ssid, 0, sizeof(ap_ssid));
@ -83,11 +86,14 @@ ESP8266Interface::ESP8266Interface(PinName tx, PinName rx, bool debug, PinName r
: _esp(tx, rx, debug, rts, cts), : _esp(tx, rx, debug, rts, cts),
_rst_pin(rst), _rst_pin(rst),
_ap_sec(NSAPI_SECURITY_UNKNOWN), _ap_sec(NSAPI_SECURITY_UNKNOWN),
_if_blocking(true),
_if_connected(_cmutex),
_initialized(false), _initialized(false),
_conn_stat(NSAPI_STATUS_DISCONNECTED), _conn_stat(NSAPI_STATUS_DISCONNECTED),
_conn_stat_cb(NULL), _conn_stat_cb(NULL),
_global_event_queue(NULL), _global_event_queue(NULL),
_oob_event_id(0) _oob_event_id(0),
_connect_event_id(0)
{ {
memset(_cbs, 0, sizeof(_cbs)); memset(_cbs, 0, sizeof(_cbs));
memset(ap_ssid, 0, sizeof(ap_ssid)); memset(ap_ssid, 0, sizeof(ap_ssid));
@ -111,6 +117,12 @@ ESP8266Interface::~ESP8266Interface()
_global_event_queue->cancel(_oob_event_id); _global_event_queue->cancel(_oob_event_id);
} }
_cmutex.lock();
if (_connect_event_id) {
_global_event_queue->cancel(_connect_event_id);
}
_cmutex.unlock();
// Power down the modem // Power down the modem
_rst_pin.rst_assert(); _rst_pin.rst_assert();
} }
@ -167,9 +179,36 @@ void ESP8266Interface::_oob2global_event_queue()
} }
} }
void ESP8266Interface::_connect_async()
{
_cmutex.lock();
if (!_connect_event_id) {
tr_debug("_connect_async(): cancelled");
_cmutex.unlock();
return;
}
if (_esp.connect(ap_ssid, ap_pass) != NSAPI_ERROR_OK) {
// Postpone to give other stuff time to run
_connect_event_id = _global_event_queue->call_in(ESP8266_CONNECT_TIMEOUT, callback(this, &ESP8266Interface::_connect_async));
if (!_connect_event_id) {
MBED_ERROR(MBED_MAKE_ERROR(MBED_MODULE_DRIVER, MBED_ERROR_CODE_ENOMEM), \
"_connect_async(): unable to add event to queue");
}
} else {
_connect_event_id = 0;
_if_connected.notify_all();
}
_cmutex.unlock();
}
int ESP8266Interface::connect() int ESP8266Interface::connect()
{ {
nsapi_error_t status; nsapi_error_t status = _conn_status_to_error();
if (status != NSAPI_ERROR_NO_CONNECTION) {
return status;
}
if (strlen(ap_ssid) == 0) { if (strlen(ap_ssid) == 0) {
return NSAPI_ERROR_NO_SSID; return NSAPI_ERROR_NO_SSID;
@ -194,11 +233,32 @@ int ESP8266Interface::connect()
return NSAPI_ERROR_DHCP_FAILURE; return NSAPI_ERROR_DHCP_FAILURE;
} }
return _esp.connect(ap_ssid, ap_pass); _cmutex.lock();
MBED_ASSERT(!_connect_event_id);
_connect_event_id = _global_event_queue->call(callback(this, &ESP8266Interface::_connect_async));
if (!_connect_event_id) {
MBED_ERROR(MBED_MAKE_ERROR(MBED_MODULE_DRIVER, MBED_ERROR_CODE_ENOMEM), \
"connect(): unable to add event to queue");
}
while (_if_blocking && (_conn_status_to_error() != NSAPI_ERROR_IS_CONNECTED)) {
_if_connected.wait();
}
_cmutex.unlock();
return NSAPI_ERROR_OK;
} }
int ESP8266Interface::set_credentials(const char *ssid, const char *pass, nsapi_security_t security) int ESP8266Interface::set_credentials(const char *ssid, const char *pass, nsapi_security_t security)
{ {
nsapi_error_t status = _conn_status_to_error();
if (status != NSAPI_ERROR_NO_CONNECTION) {
return status;
}
_ap_sec = security; _ap_sec = security;
if (!ssid) { if (!ssid) {
@ -244,10 +304,16 @@ int ESP8266Interface::set_channel(uint8_t channel)
int ESP8266Interface::disconnect() int ESP8266Interface::disconnect()
{ {
_cmutex.lock();
if (_connect_event_id) {
_global_event_queue->cancel(_connect_event_id);
_connect_event_id = 0; // cancel asynchronous connection attempt if one is ongoing
}
_cmutex.unlock();
_initialized = false; _initialized = false;
if (_conn_stat == NSAPI_STATUS_DISCONNECTED || !get_ip_address()) nsapi_error_t status = _conn_status_to_error();
{ if (status == NSAPI_ERROR_NO_CONNECTION || !get_ip_address()) {
return NSAPI_ERROR_NO_CONNECTION; return NSAPI_ERROR_NO_CONNECTION;
} }
@ -716,4 +782,35 @@ void ESP8266Interface::proc_oob_evnt()
_esp.bg_process_oob(ESP8266_RECV_TIMEOUT, true); _esp.bg_process_oob(ESP8266_RECV_TIMEOUT, true);
} }
nsapi_error_t ESP8266Interface::_conn_status_to_error()
{
nsapi_error_t ret;
_esp.bg_process_oob(ESP8266_RECV_TIMEOUT, true);
switch (_conn_stat) {
case NSAPI_STATUS_DISCONNECTED:
ret = NSAPI_ERROR_NO_CONNECTION;
break;
case NSAPI_STATUS_CONNECTING:
ret = NSAPI_ERROR_ALREADY;
break;
case NSAPI_STATUS_GLOBAL_UP:
ret = NSAPI_ERROR_IS_CONNECTED;
break;
default:
ret = NSAPI_ERROR_DEVICE_ERROR;
}
return ret;
}
nsapi_error_t ESP8266Interface::set_blocking(bool blocking)
{
_if_blocking = blocking;
return NSAPI_ERROR_OK;
}
#endif #endif

View File

@ -29,6 +29,8 @@
#include "features/netsocket/WiFiAccessPoint.h" #include "features/netsocket/WiFiAccessPoint.h"
#include "features/netsocket/WiFiInterface.h" #include "features/netsocket/WiFiInterface.h"
#include "platform/Callback.h" #include "platform/Callback.h"
#include "rtos/ConditionVariable.h"
#include "rtos/Mutex.h"
#define ESP8266_SOCKET_COUNT 5 #define ESP8266_SOCKET_COUNT 5
@ -316,6 +318,13 @@ protected:
return this; return this;
} }
/** Set blocking status of connect() which by default should be blocking.
*
* @param blocking Use true to make connect() blocking.
* @return NSAPI_ERROR_OK on success, negative error code on failure.
*/
virtual nsapi_error_t set_blocking(bool blocking);
private: private:
// AT layer // AT layer
ESP8266 _esp; ESP8266 _esp;
@ -341,6 +350,12 @@ private:
char ap_pass[ESP8266_PASSPHRASE_MAX_LENGTH + 1]; /* The longest possible passphrase; +1 for the \0 */ char ap_pass[ESP8266_PASSPHRASE_MAX_LENGTH + 1]; /* The longest possible passphrase; +1 for the \0 */
nsapi_security_t _ap_sec; nsapi_security_t _ap_sec;
bool _if_blocking; // NetworkInterface, blocking or not
rtos::ConditionVariable _if_connected;
// connect status reporting
nsapi_error_t _conn_status_to_error();
// Drivers's socket info // Drivers's socket info
struct _sock_info { struct _sock_info {
bool open; bool open;
@ -369,8 +384,12 @@ private:
// Use global EventQueue // Use global EventQueue
events::EventQueue *_global_event_queue; events::EventQueue *_global_event_queue;
int _oob_event_id; int _oob_event_id;
int _connect_event_id;
void proc_oob_evnt(); void proc_oob_evnt();
void _oob2global_event_queue(); void _oob2global_event_queue();
void _connect_async();
rtos::Mutex _cmutex; // Protect asynchronous connection logic
}; };
#endif #endif
#endif #endif