Kenji Arai / mbed-os_TYBLE16

Dependents:   TYBLE16_simple_data_logger TYBLE16_MP3_Air

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers ESP8266Interface.cpp Source File

ESP8266Interface.cpp

00001 /* ESP8266 implementation of NetworkInterfaceAPI
00002  * Copyright (c) 2015 ARM Limited
00003  *
00004  * Licensed under the Apache License, Version 2.0 (the "License");
00005  * you may not use this file except in compliance with the License.
00006  * You may obtain a copy of the License at
00007  *
00008  *     http://www.apache.org/licenses/LICENSE-2.0
00009  *
00010  * Unless required by applicable law or agreed to in writing, software
00011  * distributed under the License is distributed on an "AS IS" BASIS,
00012  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00013  * See the License for the specific language governing permissions and
00014  * limitations under the License.
00015  */
00016 
00017 #if DEVICE_SERIAL && DEVICE_INTERRUPTIN && defined(MBED_CONF_EVENTS_PRESENT) && defined(MBED_CONF_NSAPI_PRESENT) && defined(MBED_CONF_RTOS_API_PRESENT)
00018 
00019 #include <string.h>
00020 #include <stdint.h>
00021 
00022 #include "ESP8266.h"
00023 #include "ESP8266Interface.h"
00024 #include "events/EventQueue.h"
00025 #include "events/mbed_shared_queues.h"
00026 #include "features/netsocket/nsapi_types.h"
00027 #include "mbed_trace.h"
00028 #include "platform/Callback.h"
00029 #include "platform/mbed_atomic.h"
00030 #include "platform/mbed_debug.h"
00031 #include "rtos/ThisThread.h"
00032 
00033 #ifndef MBED_CONF_ESP8266_DEBUG
00034 #define MBED_CONF_ESP8266_DEBUG false
00035 #endif
00036 
00037 #ifndef MBED_CONF_ESP8266_RTS
00038 #define MBED_CONF_ESP8266_RTS NC
00039 #endif
00040 
00041 #ifndef MBED_CONF_ESP8266_CTS
00042 #define MBED_CONF_ESP8266_CTS NC
00043 #endif
00044 
00045 #ifndef MBED_CONF_ESP8266_RST
00046 #define MBED_CONF_ESP8266_RST NC
00047 #endif
00048 
00049 #ifndef MBED_CONF_ESP8266_PWR
00050 #define MBED_CONF_ESP8266_PWR NC
00051 #endif
00052 
00053 #define TRACE_GROUP  "ESPI" // ESP8266 Interface
00054 
00055 #define ESP8266_WIFI_IF_NAME "es0"
00056 
00057 using namespace mbed;
00058 using namespace rtos;
00059 
00060 #if defined MBED_CONF_ESP8266_TX && defined MBED_CONF_ESP8266_RX
00061 ESP8266Interface::ESP8266Interface()
00062     : _esp(MBED_CONF_ESP8266_TX, MBED_CONF_ESP8266_RX, MBED_CONF_ESP8266_DEBUG, MBED_CONF_ESP8266_RTS, MBED_CONF_ESP8266_CTS),
00063       _rst_pin(MBED_CONF_ESP8266_RST), // Notice that Pin7 CH_EN cannot be left floating if used as reset
00064       _pwr_pin(MBED_CONF_ESP8266_PWR),
00065       _ap_sec(NSAPI_SECURITY_UNKNOWN ),
00066       _if_blocking(true),
00067 #if MBED_CONF_RTOS_PRESENT
00068       _if_connected(_cmutex),
00069 #endif
00070       _initialized(false),
00071       _connect_retval(NSAPI_ERROR_OK ),
00072       _disconnect_retval(NSAPI_ERROR_OK ),
00073       _conn_stat(NSAPI_STATUS_DISCONNECTED ),
00074       _conn_stat_cb(NULL),
00075       _global_event_queue(mbed_event_queue()), // Needs to be set before attaching event() to SIGIO
00076       _oob_event_id(0),
00077       _connect_event_id(0),
00078       _disconnect_event_id(0),
00079       _software_conn_stat(IFACE_STATUS_DISCONNECTED)
00080 {
00081     memset(_cbs, 0, sizeof(_cbs));
00082     memset(ap_ssid, 0, sizeof(ap_ssid));
00083     memset(ap_pass, 0, sizeof(ap_pass));
00084 
00085     _ch_info.track_ap = true;
00086     strncpy(_ch_info.country_code, MBED_CONF_ESP8266_COUNTRY_CODE, sizeof(_ch_info.country_code));
00087     _ch_info.channel_start = MBED_CONF_ESP8266_CHANNEL_START;
00088     _ch_info.channels = MBED_CONF_ESP8266_CHANNELS;
00089 
00090     _esp.sigio(this, &ESP8266Interface::event);
00091     _esp.set_timeout();
00092     _esp.attach(this, &ESP8266Interface::refresh_conn_state_cb);
00093 
00094     for (int i = 0; i < ESP8266_SOCKET_COUNT; i++) {
00095         _sock_i[i].open = false;
00096         _sock_i[i].sport = 0;
00097     }
00098     _esp.uart_enable_input(false);
00099 }
00100 #endif
00101 
00102 // ESP8266Interface implementation
00103 ESP8266Interface::ESP8266Interface(PinName tx, PinName rx, bool debug, PinName rts, PinName cts, PinName rst, PinName pwr)
00104     : _esp(tx, rx, debug, rts, cts),
00105       _rst_pin(rst),
00106       _pwr_pin(pwr),
00107       _ap_sec(NSAPI_SECURITY_UNKNOWN ),
00108       _if_blocking(true),
00109 #if MBED_CONF_RTOS_PRESENT
00110       _if_connected(_cmutex),
00111 #endif
00112       _initialized(false),
00113       _connect_retval(NSAPI_ERROR_OK ),
00114       _disconnect_retval(NSAPI_ERROR_OK ),
00115       _conn_stat(NSAPI_STATUS_DISCONNECTED ),
00116       _conn_stat_cb(NULL),
00117       _global_event_queue(mbed_event_queue()), // Needs to be set before attaching event() to SIGIO
00118       _oob_event_id(0),
00119       _connect_event_id(0),
00120       _disconnect_event_id(0),
00121       _software_conn_stat(IFACE_STATUS_DISCONNECTED)
00122 {
00123     memset(_cbs, 0, sizeof(_cbs));
00124     memset(ap_ssid, 0, sizeof(ap_ssid));
00125     memset(ap_pass, 0, sizeof(ap_pass));
00126 
00127     _ch_info.track_ap = true;
00128     strncpy(_ch_info.country_code, MBED_CONF_ESP8266_COUNTRY_CODE, sizeof(_ch_info.country_code));
00129     _ch_info.channel_start = MBED_CONF_ESP8266_CHANNEL_START;
00130     _ch_info.channels = MBED_CONF_ESP8266_CHANNELS;
00131 
00132     _esp.sigio(this, &ESP8266Interface::event);
00133     _esp.set_timeout();
00134     _esp.attach(this, &ESP8266Interface::refresh_conn_state_cb);
00135 
00136     for (int i = 0; i < ESP8266_SOCKET_COUNT; i++) {
00137         _sock_i[i].open = false;
00138         _sock_i[i].sport = 0;
00139     }
00140     _esp.uart_enable_input(false);
00141 }
00142 
00143 ESP8266Interface::~ESP8266Interface()
00144 {
00145     if (_oob_event_id) {
00146         _global_event_queue->cancel(_oob_event_id);
00147     }
00148 
00149     _cmutex.lock();
00150     if (_connect_event_id) {
00151         _global_event_queue->cancel(_connect_event_id);
00152     }
00153     _cmutex.unlock();
00154 
00155     // Power down the modem
00156     _rst_pin.rst_assert();
00157     // Power off the modem
00158     _pwr_pin.power_off();
00159 }
00160 
00161 ESP8266Interface::ResetPin::ResetPin(PinName rst_pin) : _rst_pin(mbed::DigitalOut(rst_pin, 1))
00162 {
00163 }
00164 
00165 void ESP8266Interface::ResetPin::rst_assert()
00166 {
00167     if (_rst_pin.is_connected()) {
00168         _rst_pin = 0;
00169         tr_debug("rst_assert(): HW reset asserted.");
00170     }
00171 }
00172 
00173 void ESP8266Interface::ResetPin::rst_deassert()
00174 {
00175     if (_rst_pin.is_connected()) {
00176         // Notice that Pin7 CH_EN cannot be left floating if used as reset
00177         _rst_pin = 1;
00178         tr_debug("rst_deassert(): HW reset deasserted.");
00179     }
00180 }
00181 
00182 bool ESP8266Interface::ResetPin::is_connected()
00183 {
00184     return _rst_pin.is_connected();
00185 }
00186 
00187 ESP8266Interface::PowerPin::PowerPin(PinName pwr_pin) : _pwr_pin(mbed::DigitalOut(pwr_pin, !MBED_CONF_ESP8266_POWER_ON_POLARITY))
00188 {
00189 }
00190 
00191 void ESP8266Interface::PowerPin::power_on()
00192 {
00193     if (_pwr_pin.is_connected()) {
00194         _pwr_pin = MBED_CONF_ESP8266_POWER_ON_POLARITY;
00195         tr_debug("power_on(): HW power-on.");
00196         ThisThread::sleep_for(MBED_CONF_ESP8266_POWER_ON_TIME_MS);
00197     }
00198 }
00199 
00200 void ESP8266Interface::PowerPin::power_off()
00201 {
00202     if (_pwr_pin.is_connected()) {
00203         _pwr_pin = !MBED_CONF_ESP8266_POWER_ON_POLARITY;
00204         tr_debug("power_off(): HW power-off.");
00205         ThisThread::sleep_for(MBED_CONF_ESP8266_POWER_OFF_TIME_MS);
00206     }
00207 }
00208 
00209 void ESP8266Interface::_power_off()
00210 {
00211     _rst_pin.rst_assert();
00212     _pwr_pin.power_off();
00213 }
00214 
00215 bool ESP8266Interface::PowerPin::is_connected()
00216 {
00217     return _pwr_pin.is_connected();
00218 }
00219 
00220 int ESP8266Interface::connect(const char *ssid, const char *pass, nsapi_security_t security,
00221                               uint8_t channel)
00222 {
00223     if (channel != 0) {
00224         return NSAPI_ERROR_UNSUPPORTED ;
00225     }
00226 
00227     int err = set_credentials(ssid, pass, security);
00228     if (err) {
00229         return err;
00230     }
00231 
00232     return connect();
00233 }
00234 
00235 void ESP8266Interface::_connect_async()
00236 {
00237     nsapi_error_t status = _init();
00238     if (status != NSAPI_ERROR_OK ) {
00239         _connect_retval = status;
00240         _esp.uart_enable_input(false);
00241         _software_conn_stat = IFACE_STATUS_DISCONNECTED;
00242         //_conn_stat_cb will be called from refresh_conn_state_cb
00243         return;
00244     }
00245 
00246     if (!_esp.dhcp(true, 1)) {
00247         _connect_retval = NSAPI_ERROR_DHCP_FAILURE ;
00248         _esp.uart_enable_input(false);
00249         _software_conn_stat = IFACE_STATUS_DISCONNECTED;
00250         //_conn_stat_cb will be called from refresh_conn_state_cb
00251         return;
00252     }
00253     _cmutex.lock();
00254     if (!_connect_event_id) {
00255         tr_debug("_connect_async(): Cancelled.");
00256         _cmutex.unlock();
00257         return;
00258     }
00259     _connect_retval = _esp.connect(ap_ssid, ap_pass);
00260     int timeleft_ms = ESP8266_INTERFACE_CONNECT_TIMEOUT_MS - _conn_timer.read_ms();
00261     if (_connect_retval == NSAPI_ERROR_OK 
00262             || _connect_retval == NSAPI_ERROR_AUTH_FAILURE 
00263             || _connect_retval == NSAPI_ERROR_NO_SSID 
00264             || ((_if_blocking == true) && (timeleft_ms <= 0))) {
00265         _connect_event_id = 0;
00266         _conn_timer.stop();
00267         if (timeleft_ms <= 0 && _connect_retval != NSAPI_ERROR_OK ) {
00268             _connect_retval = NSAPI_ERROR_CONNECTION_TIMEOUT ;
00269         }
00270         if (_connect_retval != NSAPI_ERROR_OK ) {
00271             _esp.uart_enable_input(false);
00272             _software_conn_stat = IFACE_STATUS_DISCONNECTED;
00273         }
00274 #if MBED_CONF_RTOS_PRESENT
00275         _if_connected.notify_all();
00276 #endif
00277     } else {
00278         // Postpone to give other stuff time to run
00279         _connect_event_id = _global_event_queue->call_in(ESP8266_INTERFACE_CONNECT_INTERVAL_MS,
00280                                                          callback(this, &ESP8266Interface::_connect_async));
00281         if (!_connect_event_id) {
00282             MBED_ERROR(MBED_MAKE_ERROR(MBED_MODULE_DRIVER, MBED_ERROR_CODE_ENOMEM), \
00283                        "ESP8266Interface::_connect_async(): unable to add event to queue. Increase \"events.shared-eventsize\"\n");
00284         }
00285     }
00286     _cmutex.unlock();
00287 
00288     if (_connect_event_id == 0) {
00289         if (_conn_stat_cb) {
00290             _conn_stat_cb(NSAPI_EVENT_CONNECTION_STATUS_CHANGE , _conn_stat);
00291         }
00292         if (_conn_stat == NSAPI_STATUS_GLOBAL_UP  || _conn_stat == NSAPI_STATUS_LOCAL_UP ) {
00293             _software_conn_stat = IFACE_STATUS_CONNECTED;
00294         }
00295     }
00296 }
00297 
00298 int ESP8266Interface::connect()
00299 {
00300     if (_software_conn_stat == IFACE_STATUS_CONNECTING) {
00301         return NSAPI_ERROR_BUSY ;
00302     }
00303     if (_software_conn_stat == IFACE_STATUS_CONNECTED) {
00304         return NSAPI_ERROR_IS_CONNECTED ;
00305     }
00306 
00307     if (strlen(ap_ssid) == 0) {
00308         return NSAPI_ERROR_NO_SSID ;
00309     }
00310 
00311     if (_ap_sec != NSAPI_SECURITY_NONE ) {
00312         if (strlen(ap_pass) < ESP8266_PASSPHRASE_MIN_LENGTH) {
00313             return NSAPI_ERROR_PARAMETER ;
00314         }
00315     }
00316     if (!_if_blocking) {
00317         bool ret = _cmutex.trylock();
00318         if (ret == false) {
00319             return NSAPI_ERROR_BUSY ;
00320         }
00321     } else {
00322         _cmutex.lock();
00323     }
00324     _software_conn_stat = IFACE_STATUS_CONNECTING;
00325     _esp.uart_enable_input(true);
00326     _connect_retval = NSAPI_ERROR_NO_CONNECTION ;
00327     MBED_ASSERT(!_connect_event_id);
00328     _conn_timer.stop();
00329     _conn_timer.reset();
00330     _conn_timer.start();
00331     _connect_event_id = _global_event_queue->call(callback(this, &ESP8266Interface::_connect_async));
00332 
00333     if (!_connect_event_id) {
00334         MBED_ERROR(MBED_MAKE_ERROR(MBED_MODULE_DRIVER, MBED_ERROR_CODE_ENOMEM), \
00335                    "connect(): unable to add event to queue. Increase \"events.shared-eventsize\"\n");
00336     }
00337 
00338 #if MBED_CONF_RTOS_PRESENT
00339     while (_if_blocking && (_conn_status_to_error() != NSAPI_ERROR_IS_CONNECTED )
00340             && (_connect_retval == NSAPI_ERROR_NO_CONNECTION )) {
00341         _if_connected.wait();
00342     }
00343 #endif
00344 
00345     _cmutex.unlock();
00346 
00347     if (!_if_blocking) {
00348         return NSAPI_ERROR_OK ;
00349     } else {
00350         return _connect_retval;
00351     }
00352 }
00353 
00354 int ESP8266Interface::set_credentials(const char *ssid, const char *pass, nsapi_security_t security)
00355 {
00356     nsapi_error_t status = _conn_status_to_error();
00357     if (_software_conn_stat == IFACE_STATUS_CONNECTING) {
00358         return NSAPI_ERROR_BUSY ;
00359     }
00360     if (status != NSAPI_ERROR_NO_CONNECTION ) {
00361         return status;
00362     }
00363 
00364     _ap_sec = security;
00365 
00366     if (!ssid) {
00367         return NSAPI_ERROR_PARAMETER ;
00368     }
00369 
00370     int ssid_length = strlen(ssid);
00371 
00372     if (ssid_length > 0
00373             && ssid_length <= ESP8266_SSID_MAX_LENGTH) {
00374         memset(ap_ssid, 0, sizeof(ap_ssid));
00375         strncpy(ap_ssid, ssid, ESP8266_SSID_MAX_LENGTH);
00376     } else {
00377         return NSAPI_ERROR_PARAMETER ;
00378     }
00379 
00380     if (_ap_sec != NSAPI_SECURITY_NONE ) {
00381 
00382         if (!pass) {
00383             return NSAPI_ERROR_PARAMETER ;
00384         }
00385 
00386         int pass_length = strlen(pass);
00387         if (pass_length >= ESP8266_PASSPHRASE_MIN_LENGTH
00388                 && pass_length <= ESP8266_PASSPHRASE_MAX_LENGTH) {
00389             memset(ap_pass, 0, sizeof(ap_pass));
00390             strncpy(ap_pass, pass, ESP8266_PASSPHRASE_MAX_LENGTH);
00391         } else {
00392             return NSAPI_ERROR_PARAMETER ;
00393         }
00394     } else {
00395         memset(ap_pass, 0, sizeof(ap_pass));
00396     }
00397 
00398     return NSAPI_ERROR_OK ;
00399 }
00400 
00401 int ESP8266Interface::set_channel(uint8_t channel)
00402 {
00403     return NSAPI_ERROR_UNSUPPORTED ;
00404 }
00405 
00406 
00407 void ESP8266Interface::_disconnect_async()
00408 {
00409     _cmutex.lock();
00410     _disconnect_retval = _esp.disconnect() ? NSAPI_ERROR_OK  : NSAPI_ERROR_DEVICE_ERROR ;
00411     int timeleft_ms = ESP8266_INTERFACE_CONNECT_TIMEOUT_MS - _conn_timer.read_ms();
00412 
00413     if (_disconnect_retval == NSAPI_ERROR_OK  || ((_if_blocking == true) && (timeleft_ms <= 0))) {
00414 
00415         if (timeleft_ms <= 0 && _connect_retval != NSAPI_ERROR_OK ) {
00416             _disconnect_retval = NSAPI_ERROR_CONNECTION_TIMEOUT ;
00417         } else {
00418             if (_conn_stat != NSAPI_STATUS_DISCONNECTED ) {
00419                 _conn_stat = NSAPI_STATUS_DISCONNECTED ;
00420             }
00421             // In case the status update arrives later inform upper layers manually
00422             _disconnect_event_id = 0;
00423             _conn_timer.stop();
00424             _connect_retval = NSAPI_ERROR_NO_CONNECTION ;
00425         }
00426 
00427         _power_off();
00428         _software_conn_stat = IFACE_STATUS_DISCONNECTED;
00429 #if MBED_CONF_RTOS_PRESENT
00430         _if_connected.notify_all();
00431 #endif
00432 
00433     } else {
00434         // Postpone to give other stuff time to run
00435         _disconnect_event_id = _global_event_queue->call_in(
00436                                    ESP8266_INTERFACE_CONNECT_INTERVAL_MS,
00437                                    callback(this, &ESP8266Interface::_disconnect_async));
00438         if (!_disconnect_event_id) {
00439             MBED_ERROR(
00440                 MBED_MAKE_ERROR(MBED_MODULE_DRIVER, MBED_ERROR_CODE_ENOMEM), \
00441                 "ESP8266Interface::_disconnect_async(): unable to add event to queue. Increase \"events.shared-eventsize\"\n");
00442         }
00443     }
00444     _cmutex.unlock();
00445 
00446     _esp.uart_enable_input(false);
00447     if (_disconnect_event_id == 0) {
00448         if (_conn_stat_cb) {
00449             _conn_stat_cb(NSAPI_EVENT_CONNECTION_STATUS_CHANGE , _conn_stat);
00450         }
00451     }
00452 }
00453 
00454 int ESP8266Interface::disconnect()
00455 {
00456     if (_software_conn_stat == IFACE_STATUS_DISCONNECTING) {
00457         return NSAPI_ERROR_BUSY ;
00458     }
00459     if (_software_conn_stat == IFACE_STATUS_DISCONNECTED) {
00460         return NSAPI_ERROR_NO_CONNECTION ;
00461     }
00462     if (!_if_blocking) {
00463         bool ret = _cmutex.trylock();
00464         if (ret == false) {
00465             return NSAPI_ERROR_BUSY ;
00466         }
00467     } else {
00468         _cmutex.lock();
00469     }
00470     if (_connect_event_id) {
00471         _global_event_queue->cancel(_connect_event_id);
00472         _connect_event_id = 0; // cancel asynchronous connection attempt if one is ongoing
00473     }
00474     _software_conn_stat = IFACE_STATUS_DISCONNECTING;
00475 
00476     _disconnect_retval = NSAPI_ERROR_IS_CONNECTED ;
00477     _disconnect_event_id = 0;
00478 
00479     _initialized = false;
00480     _conn_timer.stop();
00481     _conn_timer.reset();
00482     _conn_timer.start();
00483 
00484     _disconnect_event_id = _global_event_queue->call(
00485                                callback(this, &ESP8266Interface::_disconnect_async));
00486 
00487     if (!_disconnect_event_id) {
00488         MBED_ERROR(MBED_MAKE_ERROR(MBED_MODULE_DRIVER, MBED_ERROR_CODE_ENOMEM),
00489                    "disconnect(): unable to add event to queue. Increase \"events.shared-eventsize\"\n");
00490     }
00491 
00492 #if MBED_CONF_RTOS_PRESENT
00493     while (_if_blocking
00494             && (_conn_status_to_error() != NSAPI_ERROR_NO_CONNECTION )
00495             && (_disconnect_retval != NSAPI_ERROR_OK )) {
00496         _if_connected.wait();
00497     }
00498 #endif
00499 
00500     _cmutex.unlock();
00501     if (!_if_blocking) {
00502         return NSAPI_ERROR_OK ;
00503     } else {
00504         return _disconnect_retval;
00505     }
00506 }
00507 
00508 const char *ESP8266Interface::get_ip_address()
00509 {
00510     if (_software_conn_stat == IFACE_STATUS_DISCONNECTED) {
00511         _esp.uart_enable_input(true);
00512     }
00513 
00514     const char *ip_buff = _esp.ip_addr();
00515     if (!ip_buff || strcmp(ip_buff, "0.0.0.0") == 0) {
00516         ip_buff = NULL;
00517     }
00518     if (_software_conn_stat == IFACE_STATUS_DISCONNECTED) {
00519         _esp.uart_enable_input(false);
00520     }
00521     return ip_buff;
00522 }
00523 
00524 nsapi_error_t ESP8266Interface::get_ip_address(SocketAddress *address)
00525 {
00526     if (_software_conn_stat == IFACE_STATUS_DISCONNECTED) {
00527         _esp.uart_enable_input(true);
00528     }
00529 
00530     const char *ip_buff = _esp.ip_addr();
00531     if (!ip_buff || strcmp(ip_buff, "0.0.0.0") == 0) {
00532         ip_buff = NULL;
00533     }
00534     if (_software_conn_stat == IFACE_STATUS_DISCONNECTED) {
00535         _esp.uart_enable_input(false);
00536     }
00537     if (ip_buff) {
00538         address->set_ip_address(ip_buff);
00539         return NSAPI_ERROR_OK ;
00540     }
00541     return NSAPI_ERROR_NO_ADDRESS ;
00542 }
00543 
00544 const char *ESP8266Interface::get_mac_address()
00545 {
00546     if (_software_conn_stat == IFACE_STATUS_DISCONNECTED) {
00547         _esp.uart_enable_input(true);
00548     }
00549     const char *ret = _esp.mac_addr();
00550 
00551     if (_software_conn_stat == IFACE_STATUS_DISCONNECTED) {
00552         _esp.uart_enable_input(false);
00553     }
00554     return ret;
00555 }
00556 
00557 nsapi_error_t ESP8266Interface::get_gateway(SocketAddress *address)
00558 {
00559     if (address == nullptr) {
00560         return NSAPI_ERROR_PARAMETER ;
00561     }
00562     if (_conn_stat == NSAPI_STATUS_DISCONNECTED ) {
00563         return NSAPI_ERROR_NO_CONNECTION ;
00564     }
00565 
00566     if (!address->set_ip_address(_esp.gateway())) {
00567         return NSAPI_ERROR_NO_ADDRESS ;
00568     }
00569 
00570     return NSAPI_ERROR_OK ;
00571 }
00572 
00573 const char *ESP8266Interface::get_gateway()
00574 {
00575     return _conn_stat != NSAPI_STATUS_DISCONNECTED  ? _esp.gateway() : NULL;
00576 }
00577 
00578 nsapi_error_t ESP8266Interface::get_netmask(SocketAddress *address)
00579 {
00580     if (address == nullptr) {
00581         return NSAPI_ERROR_PARAMETER ;
00582     }
00583     if (_conn_stat == NSAPI_STATUS_DISCONNECTED ) {
00584         return NSAPI_ERROR_NO_CONNECTION ;
00585     }
00586 
00587     if (!address->set_ip_address(_esp.gateway())) {
00588         return NSAPI_ERROR_NO_ADDRESS ;
00589     }
00590 
00591     return NSAPI_ERROR_OK ;
00592 }
00593 
00594 const char *ESP8266Interface::get_netmask()
00595 {
00596     return _conn_stat != NSAPI_STATUS_DISCONNECTED  ? _esp.netmask() : NULL;
00597 }
00598 
00599 char *ESP8266Interface::get_interface_name(char *interface_name)
00600 {
00601     memcpy(interface_name, ESP8266_WIFI_IF_NAME, sizeof(ESP8266_WIFI_IF_NAME));
00602     return interface_name;
00603 }
00604 
00605 int8_t ESP8266Interface::get_rssi()
00606 {
00607     if (_software_conn_stat == IFACE_STATUS_DISCONNECTED) {
00608         _esp.uart_enable_input(true);
00609     }
00610 
00611     int8_t ret = _esp.rssi();
00612 
00613     if (_software_conn_stat == IFACE_STATUS_DISCONNECTED) {
00614         _esp.uart_enable_input(false);
00615     }
00616 
00617     return ret;
00618 }
00619 
00620 int ESP8266Interface::scan(WiFiAccessPoint *res, unsigned count)
00621 {
00622     return scan(res, count, SCANMODE_ACTIVE , 0, 0);
00623 }
00624 
00625 int ESP8266Interface::scan(WiFiAccessPoint *res, unsigned count, scan_mode mode, unsigned t_max, unsigned t_min)
00626 {
00627     if (t_max > ESP8266_SCAN_TIME_MAX) {
00628         return NSAPI_ERROR_PARAMETER ;
00629     }
00630     if (mode == SCANMODE_ACTIVE  && t_min > t_max) {
00631         return NSAPI_ERROR_PARAMETER ;
00632     }
00633 
00634     if (_software_conn_stat == IFACE_STATUS_DISCONNECTED) {
00635         _esp.uart_enable_input(true);
00636     }
00637 
00638     nsapi_error_t status = _init();
00639     if (status != NSAPI_ERROR_OK ) {
00640         if (_software_conn_stat == IFACE_STATUS_DISCONNECTED) {
00641             _esp.uart_enable_input(false);
00642         }
00643         return status;
00644     }
00645 
00646     int ret = _esp.scan(res, count, (mode == SCANMODE_ACTIVE  ? ESP8266::SCANMODE_ACTIVE  : ESP8266::SCANMODE_PASSIVE ),
00647                         t_max, t_min);
00648 
00649     if (_software_conn_stat == IFACE_STATUS_DISCONNECTED) {
00650         _esp.uart_enable_input(false);
00651     }
00652     return ret;
00653 }
00654 
00655 bool ESP8266Interface::_get_firmware_ok()
00656 {
00657     ESP8266::fw_at_version at_v = _esp.at_version();
00658     if (at_v.major < ESP8266_AT_VERSION_MAJOR) {
00659         debug("ESP8266: ERROR: AT Firmware v%d incompatible with this driver.", at_v.major);
00660         debug("Update at least to v%d - https://developer.mbed.org/teams/ESP8266/wiki/Firmware-Update\n", ESP8266_AT_VERSION_MAJOR);
00661         MBED_ERROR(MBED_MAKE_ERROR(MBED_MODULE_DRIVER, MBED_ERROR_UNSUPPORTED), "Too old AT firmware");
00662     }
00663     ESP8266::fw_sdk_version sdk_v = _esp.sdk_version();
00664     if (sdk_v.major < ESP8266_SDK_VERSION_MAJOR) {
00665         debug("ESP8266: ERROR: Firmware v%d incompatible with this driver.", sdk_v.major);
00666         debug("Update at least to v%d - https://developer.mbed.org/teams/ESP8266/wiki/Firmware-Update\n", ESP8266_SDK_VERSION_MAJOR);
00667         MBED_ERROR(MBED_MAKE_ERROR(MBED_MODULE_DRIVER, MBED_ERROR_UNSUPPORTED), "Too old SDK firmware");
00668     }
00669 
00670     return true;
00671 }
00672 
00673 nsapi_error_t ESP8266Interface::_init(void)
00674 {
00675     if (!_initialized) {
00676         _pwr_pin.power_off();
00677         _pwr_pin.power_on();
00678 
00679         if (_reset() != NSAPI_ERROR_OK ) {
00680             return NSAPI_ERROR_DEVICE_ERROR ;
00681         }
00682         if (!_esp.echo_off()) {
00683             return NSAPI_ERROR_DEVICE_ERROR ;
00684         }
00685         if (!_esp.start_uart_hw_flow_ctrl()) {
00686             return NSAPI_ERROR_DEVICE_ERROR ;
00687         }
00688         if (!_get_firmware_ok()) {
00689             return NSAPI_ERROR_DEVICE_ERROR ;
00690         }
00691         if (!_esp.set_default_wifi_mode(ESP8266::WIFIMODE_STATION)) {
00692             return NSAPI_ERROR_DEVICE_ERROR ;
00693         }
00694         if (!_esp.set_country_code_policy (true, _ch_info.country_code, _ch_info.channel_start, _ch_info.channels)) {
00695             return NSAPI_ERROR_DEVICE_ERROR ;
00696         }
00697         if (!_esp.cond_enable_tcp_passive_mode()) {
00698             return NSAPI_ERROR_DEVICE_ERROR ;
00699         }
00700         if (!_esp.startup(ESP8266::WIFIMODE_STATION)) {
00701             return NSAPI_ERROR_DEVICE_ERROR ;
00702         }
00703 
00704         _initialized = true;
00705     }
00706     return NSAPI_ERROR_OK ;
00707 }
00708 
00709 nsapi_error_t ESP8266Interface::_reset()
00710 {
00711     if (_rst_pin.is_connected()) {
00712         _rst_pin.rst_assert();
00713         // If you happen to use Pin7 CH_EN as reset pin, not needed otherwise
00714         // https://www.espressif.com/sites/default/files/documentation/esp8266_hardware_design_guidelines_en.pdf
00715         ThisThread::sleep_for(2); // Documentation says 200 us; need 2 ticks to get minimum 1 ms.
00716         _esp.flush();
00717         _rst_pin.rst_deassert();
00718     } else {
00719         _esp.flush();
00720         if (!_esp.at_available()) {
00721             return NSAPI_ERROR_DEVICE_ERROR ;
00722         }
00723         if (!_esp.reset()) {
00724             return NSAPI_ERROR_DEVICE_ERROR ;
00725         }
00726     }
00727 
00728     return _esp.at_available() ? NSAPI_ERROR_OK  : NSAPI_ERROR_DEVICE_ERROR ;
00729 }
00730 
00731 struct esp8266_socket {
00732     int id;
00733     nsapi_protocol_t proto;
00734     bool connected;
00735     SocketAddress addr;
00736     int keepalive; // TCP
00737 };
00738 
00739 int ESP8266Interface::socket_open(void **handle, nsapi_protocol_t proto)
00740 {
00741     // Look for an unused socket
00742     int id = -1;
00743 
00744     for (int i = 0; i < ESP8266_SOCKET_COUNT; i++) {
00745         if (!_sock_i[i].open) {
00746             id = i;
00747             _sock_i[i].open = true;
00748             break;
00749         }
00750     }
00751 
00752     if (id == -1) {
00753         return NSAPI_ERROR_NO_SOCKET ;
00754     }
00755 
00756     struct esp8266_socket *socket = new struct esp8266_socket;
00757     if (!socket) {
00758         return NSAPI_ERROR_NO_SOCKET ;
00759     }
00760 
00761     socket->id = id;
00762     socket->proto = proto;
00763     socket->connected = false;
00764     socket->keepalive = 0;
00765     *handle = socket;
00766     return 0;
00767 }
00768 
00769 int ESP8266Interface::socket_close(void *handle)
00770 {
00771     struct esp8266_socket *socket = (struct esp8266_socket *)handle;
00772     int err = 0;
00773 
00774     if (!socket) {
00775         return NSAPI_ERROR_NO_SOCKET ;
00776     }
00777 
00778     if (socket->connected && !_esp.close(socket->id)) {
00779         err = NSAPI_ERROR_DEVICE_ERROR ;
00780     }
00781 
00782     _cbs[socket->id].callback = NULL;
00783     _cbs[socket->id].data = NULL;
00784     core_util_atomic_store_u8(&_cbs[socket->id].deferred, false);
00785 
00786     socket->connected = false;
00787     _sock_i[socket->id].open = false;
00788     _sock_i[socket->id].sport = 0;
00789     delete socket;
00790     return err;
00791 }
00792 
00793 int ESP8266Interface::socket_bind(void *handle, const SocketAddress &address)
00794 {
00795     struct esp8266_socket *socket = (struct esp8266_socket *)handle;
00796 
00797     if (!socket) {
00798         return NSAPI_ERROR_NO_SOCKET ;
00799     }
00800 
00801     if (socket->proto == NSAPI_UDP ) {
00802         if (address.get_addr().version != NSAPI_UNSPEC ) {
00803             return NSAPI_ERROR_UNSUPPORTED ;
00804         }
00805 
00806         for (int id = 0; id < ESP8266_SOCKET_COUNT; id++) {
00807             if (_sock_i[id].sport == address.get_port() && id != socket->id) { // Port already reserved by another socket
00808                 return NSAPI_ERROR_PARAMETER ;
00809             } else if (id == socket->id && socket->connected) {
00810                 return NSAPI_ERROR_PARAMETER ;
00811             }
00812         }
00813         _sock_i[socket->id].sport = address.get_port();
00814         return 0;
00815     }
00816 
00817     return NSAPI_ERROR_UNSUPPORTED ;
00818 }
00819 
00820 int ESP8266Interface::socket_listen(void *handle, int backlog)
00821 {
00822     return NSAPI_ERROR_UNSUPPORTED ;
00823 }
00824 
00825 int ESP8266Interface::socket_connect(void *handle, const SocketAddress &addr)
00826 {
00827     struct esp8266_socket *socket = (struct esp8266_socket *)handle;
00828     nsapi_error_t ret;
00829 
00830     if (!socket) {
00831         return NSAPI_ERROR_NO_SOCKET ;
00832     }
00833 
00834     if (socket->proto == NSAPI_UDP ) {
00835         ret = _esp.open_udp(socket->id, addr.get_ip_address(), addr.get_port(), _sock_i[socket->id].sport);
00836     } else {
00837         ret = _esp.open_tcp(socket->id, addr.get_ip_address(), addr.get_port(), socket->keepalive);
00838     }
00839 
00840     socket->connected = (ret == NSAPI_ERROR_OK ) ? true : false;
00841 
00842     return ret;
00843 }
00844 
00845 int ESP8266Interface::socket_accept(void *server, void **socket, SocketAddress *addr)
00846 {
00847     return NSAPI_ERROR_UNSUPPORTED ;
00848 }
00849 
00850 int ESP8266Interface::socket_send(void *handle, const void *data, unsigned size)
00851 {
00852     nsapi_error_t status;
00853     struct esp8266_socket *socket = (struct esp8266_socket *)handle;
00854     uint8_t expect_false = false;
00855 
00856     if (!socket) {
00857         return NSAPI_ERROR_NO_SOCKET ;
00858     }
00859 
00860     if (!_sock_i[socket->id].open) {
00861         return NSAPI_ERROR_CONNECTION_LOST ;
00862     }
00863 
00864     if (!size) {
00865         // Firmware limitation
00866         return socket->proto == NSAPI_TCP  ? 0 : NSAPI_ERROR_UNSUPPORTED ;
00867     }
00868 
00869     status = _esp.send(socket->id, data, size);
00870 
00871     if (status == NSAPI_ERROR_WOULD_BLOCK 
00872             && socket->proto == NSAPI_TCP 
00873             && core_util_atomic_cas_u8(&_cbs[socket->id].deferred, &expect_false, true)) {
00874         tr_debug("socket_send(...): Postponing SIGIO from the device.");
00875         if (!_global_event_queue->call_in(50, callback(this, &ESP8266Interface::event_deferred))) {
00876             MBED_ERROR(MBED_MAKE_ERROR(MBED_MODULE_DRIVER, MBED_ERROR_CODE_ENOMEM), \
00877                        "socket_send(): unable to add event to queue. Increase \"events.shared-eventsize\"\n");
00878         }
00879 
00880     } else if (status == NSAPI_ERROR_WOULD_BLOCK  && socket->proto == NSAPI_UDP ) {
00881         status = NSAPI_ERROR_DEVICE_ERROR ;
00882     }
00883 
00884     return status != NSAPI_ERROR_OK  ? status : size;
00885 }
00886 
00887 int ESP8266Interface::socket_recv(void *handle, void *data, unsigned size)
00888 {
00889     struct esp8266_socket *socket = (struct esp8266_socket *)handle;
00890 
00891     if (!socket) {
00892         return NSAPI_ERROR_NO_SOCKET ;
00893     }
00894 
00895     if (!_sock_i[socket->id].open) {
00896         return NSAPI_ERROR_CONNECTION_LOST ;
00897     }
00898 
00899     int32_t recv;
00900     if (socket->proto == NSAPI_TCP ) {
00901         recv = _esp.recv_tcp(socket->id, data, size);
00902         if (recv <= 0 && recv != NSAPI_ERROR_WOULD_BLOCK ) {
00903             socket->connected = false;
00904         }
00905     } else {
00906         recv = _esp.recv_udp(socket->id, data, size);
00907     }
00908 
00909     return recv;
00910 }
00911 
00912 int ESP8266Interface::socket_sendto(void *handle, const SocketAddress &addr, const void *data, unsigned size)
00913 {
00914     struct esp8266_socket *socket = (struct esp8266_socket *)handle;
00915 
00916     if (!socket) {
00917         return NSAPI_ERROR_NO_SOCKET ;
00918     }
00919 
00920     if ((strcmp(addr.get_ip_address(), "0.0.0.0") == 0) || !addr.get_port())  {
00921         return NSAPI_ERROR_DNS_FAILURE ;
00922     }
00923 
00924     if (socket->connected && socket->addr != addr) {
00925         if (!_esp.close(socket->id)) {
00926             return NSAPI_ERROR_DEVICE_ERROR ;
00927         }
00928         socket->connected = false;
00929     }
00930 
00931     if (!socket->connected) {
00932         int err = socket_connect(socket, addr);
00933         if (err < 0) {
00934             return err;
00935         }
00936         socket->addr = addr;
00937     }
00938 
00939     return socket_send(socket, data, size);
00940 }
00941 
00942 int ESP8266Interface::socket_recvfrom(void *handle, SocketAddress *addr, void *data, unsigned size)
00943 {
00944     struct esp8266_socket *socket = (struct esp8266_socket *)handle;
00945 
00946     if (!socket) {
00947         return NSAPI_ERROR_NO_SOCKET ;
00948     }
00949 
00950     int ret = socket_recv(socket, data, size);
00951     if (ret >= 0 && addr) {
00952         *addr = socket->addr;
00953     }
00954 
00955     return ret;
00956 }
00957 
00958 void ESP8266Interface::socket_attach(void *handle, void (*callback)(void *), void *data)
00959 {
00960     struct esp8266_socket *socket = (struct esp8266_socket *)handle;
00961     _cbs[socket->id].callback = callback;
00962     _cbs[socket->id].data = data;
00963 }
00964 
00965 nsapi_error_t ESP8266Interface::setsockopt (nsapi_socket_t handle, int level,
00966                                            int optname, const void *optval, unsigned optlen)
00967 {
00968     struct esp8266_socket *socket = (struct esp8266_socket *)handle;
00969 
00970     if (!optlen) {
00971         return NSAPI_ERROR_PARAMETER ;
00972     } else if (!socket) {
00973         return NSAPI_ERROR_NO_SOCKET ;
00974     }
00975 
00976     if (level == NSAPI_SOCKET  && socket->proto == NSAPI_TCP ) {
00977         switch (optname) {
00978             case NSAPI_KEEPALIVE : {
00979                 if (socket->connected) { // ESP8266 limitation, keepalive needs to be given before connecting
00980                     return NSAPI_ERROR_UNSUPPORTED ;
00981                 }
00982 
00983                 if (optlen == sizeof(int)) {
00984                     int secs = *(int *)optval;
00985                     if (secs  >= 0 && secs <= 7200) {
00986                         socket->keepalive = secs;
00987                         return NSAPI_ERROR_OK ;
00988                     }
00989                 }
00990                 return NSAPI_ERROR_PARAMETER ;
00991             }
00992         }
00993     }
00994 
00995     return NSAPI_ERROR_UNSUPPORTED ;
00996 }
00997 
00998 nsapi_error_t ESP8266Interface::getsockopt (nsapi_socket_t handle, int level, int optname, void *optval, unsigned *optlen)
00999 {
01000     struct esp8266_socket *socket = (struct esp8266_socket *)handle;
01001 
01002     if (!optval || !optlen) {
01003         return NSAPI_ERROR_PARAMETER ;
01004     } else if (!socket) {
01005         return NSAPI_ERROR_NO_SOCKET ;
01006     }
01007 
01008     if (level == NSAPI_SOCKET  && socket->proto == NSAPI_TCP ) {
01009         switch (optname) {
01010             case NSAPI_KEEPALIVE : {
01011                 if (*optlen > sizeof(int)) {
01012                     *optlen = sizeof(int);
01013                 }
01014                 memcpy(optval, &(socket->keepalive), *optlen);
01015                 return NSAPI_ERROR_OK ;
01016             }
01017         }
01018     }
01019 
01020     return NSAPI_ERROR_UNSUPPORTED ;
01021 }
01022 
01023 
01024 void ESP8266Interface::event()
01025 {
01026     if (!_oob_event_id) {
01027         // Throttles event creation by using arbitrary small delay
01028         _oob_event_id = _global_event_queue->call_in(50, callback(this, &ESP8266Interface::proc_oob_evnt));
01029         if (!_oob_event_id) {
01030             MBED_ERROR(MBED_MAKE_ERROR(MBED_MODULE_DRIVER, MBED_ERROR_CODE_ENOMEM), \
01031                        "ESP8266Interface::event(): unable to add event to queue. Increase \"events.shared-eventsize\"\n");
01032         }
01033     }
01034 
01035     for (int i = 0; i < ESP8266_SOCKET_COUNT; i++) {
01036         if (_cbs[i].callback) {
01037             _cbs[i].callback(_cbs[i].data);
01038         }
01039     }
01040 }
01041 
01042 void ESP8266Interface::event_deferred()
01043 {
01044     for (int i = 0; i < ESP8266_SOCKET_COUNT; i++) {
01045         uint8_t expect_true = true;
01046         if (core_util_atomic_cas_u8(&_cbs[i].deferred, &expect_true, false) && _cbs[i].callback) {
01047             _cbs[i].callback(_cbs[i].data);
01048         }
01049     }
01050 }
01051 
01052 void ESP8266Interface::attach(Callback<void(nsapi_event_t, intptr_t)> status_cb)
01053 {
01054     _conn_stat_cb = status_cb;
01055 }
01056 
01057 nsapi_connection_status_t ESP8266Interface::get_connection_status() const
01058 {
01059     return _conn_stat;
01060 }
01061 
01062 #if MBED_CONF_ESP8266_PROVIDE_DEFAULT
01063 
01064 WiFiInterface *WiFiInterface::get_default_instance()
01065 {
01066     static ESP8266Interface esp;
01067     return &esp;
01068 }
01069 
01070 #endif
01071 
01072 void ESP8266Interface::refresh_conn_state_cb()
01073 {
01074     nsapi_connection_status_t prev_stat = _conn_stat;
01075     _conn_stat = _esp.connection_status();
01076 
01077     switch (_conn_stat) {
01078         // Doesn't require changes
01079         case NSAPI_STATUS_CONNECTING :
01080         case NSAPI_STATUS_GLOBAL_UP :
01081             if (_software_conn_stat == IFACE_STATUS_DISCONNECTED) {
01082                 _software_conn_stat = IFACE_STATUS_CONNECTED;
01083             }
01084             break;
01085         // Start from scratch if connection drops/is dropped
01086         case NSAPI_STATUS_DISCONNECTED :
01087             if (_software_conn_stat == IFACE_STATUS_CONNECTED) {
01088                 _software_conn_stat = IFACE_STATUS_DISCONNECTED;
01089             }
01090             break;
01091         // Handled on AT layer
01092         case NSAPI_STATUS_LOCAL_UP :
01093         case NSAPI_STATUS_ERROR_UNSUPPORTED:
01094         default:
01095             _initialized = false;
01096             _conn_stat = NSAPI_STATUS_DISCONNECTED ;
01097             for (int i = 0; i < ESP8266_SOCKET_COUNT; i++) {
01098                 _sock_i[i].open = false;
01099                 _sock_i[i].sport = 0;
01100             }
01101     }
01102 
01103     if (prev_stat == _conn_stat) {
01104         return;
01105     }
01106 
01107     tr_debug("refresh_conn_state_cb(): Changed to %d.", _conn_stat);
01108 
01109     if (_conn_stat_cb) {
01110         // _conn_stat_cb will be called in _connect_async or disconnect_assync to avoid race condition
01111         if ((_software_conn_stat == IFACE_STATUS_CONNECTING
01112                 || _software_conn_stat == IFACE_STATUS_DISCONNECTING)
01113                 && (_conn_stat != NSAPI_STATUS_CONNECTING )) {
01114             return;
01115         }
01116 
01117         _conn_stat_cb(NSAPI_EVENT_CONNECTION_STATUS_CHANGE , _conn_stat);
01118     }
01119 }
01120 
01121 void ESP8266Interface::proc_oob_evnt()
01122 {
01123     _oob_event_id = 0; // Allows creation of a new event
01124     _esp.bg_process_oob(ESP8266_RECV_TIMEOUT, true);
01125 }
01126 
01127 nsapi_error_t ESP8266Interface::_conn_status_to_error()
01128 {
01129     nsapi_error_t ret;
01130 
01131     switch (_conn_stat) {
01132         case NSAPI_STATUS_DISCONNECTED :
01133             ret = NSAPI_ERROR_NO_CONNECTION ;
01134             break;
01135         case NSAPI_STATUS_CONNECTING :
01136             ret = NSAPI_ERROR_ALREADY ;
01137             break;
01138         case NSAPI_STATUS_GLOBAL_UP :
01139             ret = NSAPI_ERROR_IS_CONNECTED ;
01140             break;
01141         default:
01142             ret = NSAPI_ERROR_DEVICE_ERROR ;
01143     }
01144 
01145     return ret;
01146 }
01147 
01148 nsapi_error_t ESP8266Interface::set_blocking(bool blocking)
01149 {
01150     _if_blocking = blocking;
01151 
01152     return NSAPI_ERROR_OK ;
01153 }
01154 
01155 nsapi_error_t ESP8266Interface::set_country_code(bool track_ap, const char *country_code, int len, int channel_start, int channels)
01156 {
01157     for (int i = 0; i < len; i++) {
01158         // Validation done by firmware
01159         if (!country_code[i]) {
01160             tr_warning("set_country_code(): Invalid country code.");
01161             return NSAPI_ERROR_PARAMETER ;
01162         }
01163     }
01164 
01165     _ch_info.track_ap = track_ap;
01166 
01167     // Firmware takes only first three characters
01168     strncpy(_ch_info.country_code, country_code, sizeof(_ch_info.country_code));
01169     _ch_info.country_code[sizeof(_ch_info.country_code) - 1] = '\0';
01170 
01171     _ch_info.channel_start = channel_start;
01172     _ch_info.channels = channels;
01173 
01174     return NSAPI_ERROR_OK ;
01175 }
01176 
01177 #endif