Skip to content

ESP8266: implements possibility to decide between non-blocking/blocking connect. #9421

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Jan 24, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
109 changes: 103 additions & 6 deletions components/wifi/esp8266-driver/ESP8266Interface.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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),
_rst_pin(MBED_CONF_ESP8266_RST), // Notice that Pin7 CH_EN cannot be left floating if used as reset
_ap_sec(NSAPI_SECURITY_UNKNOWN),
_if_blocking(true),
_if_connected(_cmutex),
_initialized(false),
_conn_stat(NSAPI_STATUS_DISCONNECTED),
_conn_stat_cb(NULL),
_global_event_queue(NULL),
_oob_event_id(0)
_oob_event_id(0),
_connect_event_id(0)
{
memset(_cbs, 0, sizeof(_cbs));
memset(ap_ssid, 0, sizeof(ap_ssid));
Expand All @@ -83,11 +86,14 @@ ESP8266Interface::ESP8266Interface(PinName tx, PinName rx, bool debug, PinName r
: _esp(tx, rx, debug, rts, cts),
_rst_pin(rst),
_ap_sec(NSAPI_SECURITY_UNKNOWN),
_if_blocking(true),
_if_connected(_cmutex),
_initialized(false),
_conn_stat(NSAPI_STATUS_DISCONNECTED),
_conn_stat_cb(NULL),
_global_event_queue(NULL),
_oob_event_id(0)
_oob_event_id(0),
_connect_event_id(0)
{
memset(_cbs, 0, sizeof(_cbs));
memset(ap_ssid, 0, sizeof(ap_ssid));
Expand All @@ -111,6 +117,12 @@ ESP8266Interface::~ESP8266Interface()
_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
_rst_pin.rst_assert();
}
Expand Down Expand Up @@ -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()
{
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) {
return NSAPI_ERROR_NO_SSID;
Expand All @@ -194,11 +233,32 @@ int ESP8266Interface::connect()
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)
{
nsapi_error_t status = _conn_status_to_error();
if (status != NSAPI_ERROR_NO_CONNECTION) {
return status;
}

_ap_sec = security;

if (!ssid) {
Expand Down Expand Up @@ -244,10 +304,16 @@ int ESP8266Interface::set_channel(uint8_t channel)

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;

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;
}

Expand Down Expand Up @@ -716,4 +782,35 @@ void ESP8266Interface::proc_oob_evnt()
_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
19 changes: 19 additions & 0 deletions components/wifi/esp8266-driver/ESP8266Interface.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@
#include "features/netsocket/WiFiAccessPoint.h"
#include "features/netsocket/WiFiInterface.h"
#include "platform/Callback.h"
#include "rtos/ConditionVariable.h"
#include "rtos/Mutex.h"

#define ESP8266_SOCKET_COUNT 5

Expand Down Expand Up @@ -316,6 +318,13 @@ class ESP8266Interface : public NetworkStack, public WiFiInterface {
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:
// AT layer
ESP8266 _esp;
Expand All @@ -341,6 +350,12 @@ class ESP8266Interface : public NetworkStack, public WiFiInterface {
char ap_pass[ESP8266_PASSPHRASE_MAX_LENGTH + 1]; /* The longest possible passphrase; +1 for the \0 */
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
struct _sock_info {
bool open;
Expand Down Expand Up @@ -369,8 +384,12 @@ class ESP8266Interface : public NetworkStack, public WiFiInterface {
// Use global EventQueue
events::EventQueue *_global_event_queue;
int _oob_event_id;
int _connect_event_id;
void proc_oob_evnt();
void _oob2global_event_queue();
void _connect_async();
rtos::Mutex _cmutex; // Protect asynchronous connection logic

};
#endif
#endif