Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Dependents: TYBLE16_simple_data_logger TYBLE16_MP3_Air
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
Generated on Tue Jul 12 2022 13:54:18 by
