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.
Dependencies: X_NUCLEO_IKS01A2 mbed-http
ESP8266.cpp
00001 /* ESP8266 Example 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 #include "ESP8266.h" 00018 #include "mbed_debug.h" 00019 #include "nsapi_types.h" 00020 00021 #include <cstring> 00022 00023 #define ESP8266_DEFAULT_BAUD_RATE 115200 00024 #define ESP8266_ALL_SOCKET_IDS -1 00025 00026 ESP8266::ESP8266(PinName tx, PinName rx, bool debug) 00027 : _serial(tx, rx, ESP8266_DEFAULT_BAUD_RATE), 00028 _parser(&_serial), 00029 _packets(0), 00030 _packets_end(&_packets), 00031 _connect_error(0), 00032 _fail(false), 00033 _closed(false), 00034 _socket_open(), 00035 _connection_status(NSAPI_STATUS_DISCONNECTED) 00036 { 00037 _serial.set_baud( ESP8266_DEFAULT_BAUD_RATE ); 00038 _parser.debug_on(debug); 00039 _parser.set_delimiter("\r\n"); 00040 _parser.oob("+IPD", callback(this, &ESP8266::_packet_handler)); 00041 //Note: espressif at command document says that this should be +CWJAP_CUR:<error code> 00042 //but seems that at least current version is not sending it 00043 //https://www.espressif.com/sites/default/files/documentation/4a-esp8266_at_instruction_set_en.pdf 00044 //Also seems that ERROR is not sent, but FAIL instead 00045 _parser.oob("+CWJAP:", callback(this, &ESP8266::_connect_error_handler)); 00046 _parser.oob("0,CLOSED", callback(this, &ESP8266::_oob_socket0_closed_handler)); 00047 _parser.oob("1,CLOSED", callback(this, &ESP8266::_oob_socket1_closed_handler)); 00048 _parser.oob("2,CLOSED", callback(this, &ESP8266::_oob_socket2_closed_handler)); 00049 _parser.oob("3,CLOSED", callback(this, &ESP8266::_oob_socket3_closed_handler)); 00050 _parser.oob("4,CLOSED", callback(this, &ESP8266::_oob_socket4_closed_handler)); 00051 _parser.oob("WIFI ", callback(this, &ESP8266::_connection_status_handler)); 00052 _parser.oob("UNLINK", callback(this, &ESP8266::_oob_socket_close_error)); 00053 } 00054 00055 int ESP8266::get_firmware_version() 00056 { 00057 int version; 00058 00059 _smutex.lock(); 00060 bool done = _parser.send("AT+GMR") 00061 && _parser.recv("SDK version:%d", &version) 00062 && _parser.recv("OK\n"); 00063 _smutex.unlock(); 00064 00065 if(done) { 00066 return version; 00067 } else { 00068 // Older firmware versions do not prefix the version with "SDK version: " 00069 return -1; 00070 } 00071 } 00072 00073 bool ESP8266::startup(int mode) 00074 { 00075 if (!(mode == WIFIMODE_STATION || mode == WIFIMODE_SOFTAP 00076 || mode == WIFIMODE_STATION_SOFTAP)) { 00077 return false; 00078 } 00079 00080 _smutex.lock(); 00081 setTimeout(ESP8266_CONNECT_TIMEOUT); 00082 bool done = _parser.send("AT+CWMODE_CUR=%d", mode) 00083 && _parser.recv("OK\n") 00084 &&_parser.send("AT+CIPMUX=1") 00085 && _parser.recv("OK\n"); 00086 setTimeout(); //Restore default 00087 _smutex.unlock(); 00088 00089 return done; 00090 } 00091 00092 bool ESP8266::reset(void) 00093 { 00094 _smutex.lock(); 00095 setTimeout(ESP8266_CONNECT_TIMEOUT); 00096 00097 for (int i = 0; i < 2; i++) { 00098 if (_parser.send("AT+RST") 00099 && _parser.recv("OK\n") 00100 && _parser.recv("ready")) { 00101 _clear_socket_packets(ESP8266_ALL_SOCKET_IDS); 00102 _smutex.unlock(); 00103 return true; 00104 } 00105 } 00106 setTimeout(); 00107 _smutex.unlock(); 00108 00109 return false; 00110 } 00111 00112 bool ESP8266::dhcp(bool enabled, int mode) 00113 { 00114 //only 3 valid modes 00115 if (mode < 0 || mode > 2) { 00116 return false; 00117 } 00118 00119 _smutex.lock(); 00120 bool done = _parser.send("AT+CWDHCP_CUR=%d,%d", mode, enabled?1:0) 00121 && _parser.recv("OK\n"); 00122 _smutex.unlock(); 00123 00124 return done; 00125 } 00126 00127 nsapi_error_t ESP8266::connect(const char *ap, const char *passPhrase) 00128 { 00129 _smutex.lock(); 00130 setTimeout(ESP8266_CONNECT_TIMEOUT); 00131 _connection_status = NSAPI_STATUS_CONNECTING; 00132 if(_connection_status_cb) 00133 _connection_status_cb(NSAPI_EVENT_CONNECTION_STATUS_CHANGE, _connection_status); 00134 00135 _parser.send("AT+CWJAP_CUR=\"%s\",\"%s\"", ap, passPhrase); 00136 if (!_parser.recv("OK\n")) { 00137 if (_fail) { 00138 _smutex.unlock(); 00139 nsapi_error_t ret; 00140 if (_connect_error == 1) 00141 ret = NSAPI_ERROR_CONNECTION_TIMEOUT; 00142 else if (_connect_error == 2) 00143 ret = NSAPI_ERROR_AUTH_FAILURE; 00144 else if (_connect_error == 3) 00145 ret = NSAPI_ERROR_NO_SSID; 00146 else 00147 ret = NSAPI_ERROR_NO_CONNECTION; 00148 00149 _fail = false; 00150 _connect_error = 0; 00151 return ret; 00152 } 00153 } 00154 setTimeout(); 00155 _smutex.unlock(); 00156 00157 return NSAPI_ERROR_OK; 00158 } 00159 00160 bool ESP8266::disconnect(void) 00161 { 00162 _smutex.lock(); 00163 bool done = _parser.send("AT+CWQAP") && _parser.recv("OK\n"); 00164 _smutex.unlock(); 00165 00166 return done; 00167 } 00168 00169 const char *ESP8266::getIPAddress(void) 00170 { 00171 _smutex.lock(); 00172 setTimeout(ESP8266_CONNECT_TIMEOUT); 00173 if (!(_parser.send("AT+CIFSR") 00174 && _parser.recv("+CIFSR:STAIP,\"%15[^\"]\"", _ip_buffer) 00175 && _parser.recv("OK\n"))) { 00176 _smutex.unlock(); 00177 return 0; 00178 } 00179 setTimeout(); 00180 _smutex.unlock(); 00181 00182 return _ip_buffer; 00183 } 00184 00185 const char *ESP8266::getMACAddress(void) 00186 { 00187 _smutex.lock(); 00188 if (!(_parser.send("AT+CIFSR") 00189 && _parser.recv("+CIFSR:STAMAC,\"%17[^\"]\"", _mac_buffer) 00190 && _parser.recv("OK\n"))) { 00191 _smutex.unlock(); 00192 return 0; 00193 } 00194 _smutex.unlock(); 00195 00196 return _mac_buffer; 00197 } 00198 00199 const char *ESP8266::getGateway() 00200 { 00201 _smutex.lock(); 00202 if (!(_parser.send("AT+CIPSTA_CUR?") 00203 && _parser.recv("+CIPSTA_CUR:gateway:\"%15[^\"]\"", _gateway_buffer) 00204 && _parser.recv("OK\n"))) { 00205 _smutex.unlock(); 00206 return 0; 00207 } 00208 _smutex.unlock(); 00209 00210 return _gateway_buffer; 00211 } 00212 00213 const char *ESP8266::getNetmask() 00214 { 00215 _smutex.lock(); 00216 if (!(_parser.send("AT+CIPSTA_CUR?") 00217 && _parser.recv("+CIPSTA_CUR:netmask:\"%15[^\"]\"", _netmask_buffer) 00218 && _parser.recv("OK\n"))) { 00219 _smutex.unlock(); 00220 return 0; 00221 } 00222 _smutex.unlock(); 00223 00224 return _netmask_buffer; 00225 } 00226 00227 int8_t ESP8266::getRSSI() 00228 { 00229 int8_t rssi; 00230 char bssid[18]; 00231 00232 _smutex.lock(); 00233 setTimeout(ESP8266_CONNECT_TIMEOUT); 00234 if (!(_parser.send("AT+CWJAP_CUR?") 00235 && _parser.recv("+CWJAP_CUR:\"%*[^\"]\",\"%17[^\"]\"", bssid) 00236 && _parser.recv("OK\n"))) { 00237 _smutex.unlock(); 00238 return 0; 00239 } 00240 setTimeout(); 00241 _smutex.unlock(); 00242 00243 _smutex.lock(); 00244 setTimeout(ESP8266_CONNECT_TIMEOUT); 00245 if (!(_parser.send("AT+CWLAP=\"\",\"%s\",", bssid) 00246 && _parser.recv("+CWLAP:(%*d,\"%*[^\"]\",%hhd,", &rssi) 00247 && _parser.recv("OK\n"))) { 00248 _smutex.unlock(); 00249 return 0; 00250 } 00251 setTimeout(); 00252 _smutex.unlock(); 00253 00254 return rssi; 00255 } 00256 00257 int ESP8266::scan(WiFiAccessPoint *res, unsigned limit) 00258 { 00259 unsigned cnt = 0; 00260 nsapi_wifi_ap_t ap; 00261 00262 _smutex.lock(); 00263 setTimeout(ESP8266_CONNECT_TIMEOUT); 00264 00265 if (!_parser.send("AT+CWLAP")) { 00266 _smutex.unlock(); 00267 return NSAPI_ERROR_DEVICE_ERROR; 00268 } 00269 00270 while (recv_ap(&ap)) { 00271 if (cnt < limit) { 00272 res[cnt] = WiFiAccessPoint(ap); 00273 } 00274 00275 cnt++; 00276 if (limit != 0 && cnt >= limit) { 00277 break; 00278 } 00279 } 00280 setTimeout(); 00281 _smutex.unlock(); 00282 00283 return cnt; 00284 } 00285 00286 nsapi_error_t ESP8266::open_udp(int id, const char* addr, int port, int local_port) 00287 { 00288 static const char *type = "UDP"; 00289 bool done = false; 00290 00291 if (id >= SOCKET_COUNT) { 00292 return NSAPI_ERROR_PARAMETER; 00293 } else if (_socket_open[id]) { 00294 return NSAPI_ERROR_IS_CONNECTED; 00295 } 00296 00297 _smutex.lock(); 00298 if(local_port) { 00299 done = _parser.send("AT+CIPSTART=%d,\"%s\",\"%s\",%d,%d", id, type, addr, port, local_port) 00300 && _parser.recv("OK\n"); 00301 } else { 00302 done = _parser.send("AT+CIPSTART=%d,\"%s\",\"%s\",%d", id, type, addr, port) 00303 && _parser.recv("OK\n"); 00304 } 00305 00306 if (done) { 00307 _socket_open[id] = 1; 00308 } 00309 00310 _clear_socket_packets(id); 00311 00312 _smutex.unlock(); 00313 00314 return done ? NSAPI_ERROR_OK : NSAPI_ERROR_DEVICE_ERROR; 00315 } 00316 00317 bool ESP8266::open_tcp(int id, const char* addr, int port, int keepalive) 00318 { 00319 static const char *type = "TCP"; 00320 bool done = false; 00321 00322 if (id >= SOCKET_COUNT || _socket_open[id]) { 00323 return false; 00324 } 00325 00326 _smutex.lock(); 00327 if(keepalive) { 00328 done = _parser.send("AT+CIPSTART=%d,\"%s\",\"%s\",%d,%d", id, type, addr, port, keepalive) 00329 && _parser.recv("OK\n"); 00330 } else { 00331 done = _parser.send("AT+CIPSTART=%d,\"%s\",\"%s\",%d", id, type, addr, port) 00332 && _parser.recv("OK\n"); 00333 } 00334 00335 if (done) { 00336 _socket_open[id] = 1; 00337 } 00338 00339 _clear_socket_packets(id); 00340 00341 _smutex.unlock(); 00342 00343 return done; 00344 } 00345 00346 bool ESP8266::dns_lookup(const char* name, char* ip) 00347 { 00348 _smutex.lock(); 00349 bool done = _parser.send("AT+CIPDOMAIN=\"%s\"", name) && _parser.recv("+CIPDOMAIN:%s%*[\r]%*[\n]", ip); 00350 _smutex.unlock(); 00351 00352 return done; 00353 } 00354 00355 nsapi_error_t ESP8266::send(int id, const void *data, uint32_t amount) 00356 { 00357 //May take a second try if device is busy 00358 for (unsigned i = 0; i < 2; i++) { 00359 _smutex.lock(); 00360 setTimeout(ESP8266_SEND_TIMEOUT); 00361 if (_parser.send("AT+CIPSEND=%d,%lu", id, amount) 00362 && _parser.recv(">") 00363 && _parser.write((char*)data, (int)amount) >= 0) { 00364 while (_parser.process_oob()); // multiple sends in a row require this 00365 _smutex.unlock(); 00366 return NSAPI_ERROR_OK; 00367 } 00368 setTimeout(); 00369 _smutex.unlock(); 00370 } 00371 00372 return NSAPI_ERROR_DEVICE_ERROR; 00373 } 00374 00375 void ESP8266::_packet_handler() 00376 { 00377 int id; 00378 int amount; 00379 00380 // parse out the packet 00381 if (!_parser.recv(",%d,%d:", &id, &amount)) { 00382 return; 00383 } 00384 00385 struct packet *packet = (struct packet*)malloc( 00386 sizeof(struct packet) + amount); 00387 if (!packet) { 00388 debug("ESP8266: could not allocate memory for RX data\n"); 00389 return; 00390 } 00391 00392 packet->id = id; 00393 packet->len = amount; 00394 packet->next = 0; 00395 00396 if (_parser.read((char*)(packet + 1), amount) < amount) { 00397 free(packet); 00398 return; 00399 } 00400 00401 // append to packet list 00402 *_packets_end = packet; 00403 _packets_end = &packet->next; 00404 } 00405 00406 int32_t ESP8266::recv_tcp(int id, void *data, uint32_t amount, uint32_t timeout) 00407 { 00408 _smutex.lock(); 00409 setTimeout(timeout); 00410 00411 // Poll for inbound packets 00412 while (_parser.process_oob()) { 00413 } 00414 00415 setTimeout(); 00416 00417 // check if any packets are ready for us 00418 for (struct packet **p = &_packets; *p; p = &(*p)->next) { 00419 if ((*p)->id == id) { 00420 struct packet *q = *p; 00421 00422 if (q->len <= amount) { // Return and remove full packet 00423 memcpy(data, q+1, q->len); 00424 00425 if (_packets_end == &(*p)->next) { 00426 _packets_end = p; 00427 } 00428 *p = (*p)->next; 00429 _smutex.unlock(); 00430 00431 uint32_t len = q->len; 00432 free(q); 00433 return len; 00434 } else { // return only partial packet 00435 memcpy(data, q+1, amount); 00436 00437 q->len -= amount; 00438 memmove(q+1, (uint8_t*)(q+1) + amount, q->len); 00439 00440 _smutex.unlock(); 00441 return amount; 00442 } 00443 } 00444 } 00445 if(!_socket_open[id]) { 00446 _smutex.unlock(); 00447 return 0; 00448 } 00449 _smutex.unlock(); 00450 00451 return NSAPI_ERROR_WOULD_BLOCK; 00452 } 00453 00454 int32_t ESP8266::recv_udp(int id, void *data, uint32_t amount, uint32_t timeout) 00455 { 00456 _smutex.lock(); 00457 setTimeout(timeout); 00458 00459 // Poll for inbound packets 00460 while (_parser.process_oob()) { 00461 } 00462 00463 setTimeout(); 00464 00465 // check if any packets are ready for us 00466 for (struct packet **p = &_packets; *p; p = &(*p)->next) { 00467 if ((*p)->id == id) { 00468 struct packet *q = *p; 00469 00470 // Return and remove packet (truncated if necessary) 00471 uint32_t len = q->len < amount ? q->len : amount; 00472 memcpy(data, q+1, len); 00473 00474 if (_packets_end == &(*p)->next) { 00475 _packets_end = p; 00476 } 00477 *p = (*p)->next; 00478 _smutex.unlock(); 00479 00480 free(q); 00481 return len; 00482 } 00483 } 00484 _smutex.unlock(); 00485 00486 return NSAPI_ERROR_WOULD_BLOCK; 00487 } 00488 00489 void ESP8266::_clear_socket_packets(int id) 00490 { 00491 struct packet **p = &_packets; 00492 00493 while (*p) { 00494 if ((*p)->id == id || id == ESP8266_ALL_SOCKET_IDS) { 00495 struct packet *q = *p; 00496 00497 if (_packets_end == &(*p)->next) { 00498 _packets_end = p; // Set last packet next field/_packets 00499 } 00500 *p = (*p)->next; 00501 00502 free(q); 00503 } else { 00504 // Point to last packet next field 00505 p = &(*p)->next; 00506 } 00507 } 00508 } 00509 00510 bool ESP8266::close(int id) 00511 { 00512 //May take a second try if device is busy 00513 for (unsigned i = 0; i < 2; i++) { 00514 _smutex.lock(); 00515 if (_parser.send("AT+CIPCLOSE=%d", id)) { 00516 if (!_parser.recv("OK\n")) { 00517 if (_closed) { // UNLINK ERROR 00518 _closed = false; 00519 _socket_open[id] = 0; 00520 _clear_socket_packets(id); 00521 _smutex.unlock(); 00522 // ESP8266 has a habit that it might close a socket on its own. 00523 //debug("ESP8266: socket %d already closed when calling close\n", id); 00524 return true; 00525 } 00526 } else { 00527 _clear_socket_packets(id); 00528 _smutex.unlock(); 00529 return true; 00530 } 00531 } 00532 _smutex.unlock(); 00533 } 00534 00535 return false; 00536 } 00537 00538 void ESP8266::setTimeout(uint32_t timeout_ms) 00539 { 00540 _parser.set_timeout(timeout_ms); 00541 } 00542 00543 bool ESP8266::readable() 00544 { 00545 return _serial.FileHandle::readable(); 00546 } 00547 00548 bool ESP8266::writeable() 00549 { 00550 return _serial.FileHandle::writable(); 00551 } 00552 00553 void ESP8266::sigio(Callback<void()> func) 00554 { 00555 _serial.sigio(func); 00556 } 00557 00558 void ESP8266::attach(mbed::Callback<void(nsapi_event_t, intptr_t)> status_cb) 00559 { 00560 _connection_status_cb = status_cb; 00561 } 00562 00563 bool ESP8266::recv_ap(nsapi_wifi_ap_t *ap) 00564 { 00565 int sec; 00566 int dummy; 00567 bool ret = _parser.recv("+CWLAP:(%d,\"%32[^\"]\",%hhd,\"%hhx:%hhx:%hhx:%hhx:%hhx:%hhx\",%hhu,%d,%d)\n", 00568 &sec, 00569 ap->ssid, 00570 &ap->rssi, 00571 &ap->bssid[0], &ap->bssid[1], &ap->bssid[2], &ap->bssid[3], &ap->bssid[4], &ap->bssid[5], 00572 &ap->channel, 00573 &dummy, 00574 &dummy); 00575 00576 ap->security = sec < 5 ? (nsapi_security_t)sec : NSAPI_SECURITY_UNKNOWN; 00577 00578 return ret; 00579 } 00580 00581 void ESP8266::_connect_error_handler() 00582 { 00583 _fail = false; 00584 _connect_error = 0; 00585 00586 if (_parser.recv("%d", &_connect_error) && _parser.recv("FAIL")) { 00587 _fail = true; 00588 _parser.abort(); 00589 } 00590 } 00591 00592 void ESP8266::_oob_socket_close_error() 00593 { 00594 if (_parser.recv("ERROR\n")) { 00595 _closed = true; // Not possible to pinpoint to a certain socket 00596 _parser.abort(); 00597 } 00598 } 00599 00600 void ESP8266::_oob_socket0_closed_handler() 00601 { 00602 _socket_open[0] = 0; 00603 } 00604 00605 void ESP8266::_oob_socket1_closed_handler() 00606 { 00607 _socket_open[1] = 0; 00608 } 00609 00610 void ESP8266::_oob_socket2_closed_handler() 00611 { 00612 _socket_open[2] = 0; 00613 } 00614 00615 void ESP8266::_oob_socket3_closed_handler() 00616 { 00617 _socket_open[3] = 0; 00618 } 00619 00620 void ESP8266::_oob_socket4_closed_handler() 00621 { 00622 _socket_open[4] = 0; 00623 } 00624 00625 void ESP8266::_connection_status_handler() 00626 { 00627 char status[13]; 00628 if (_parser.recv("%12[^\"]\n", status)) { 00629 if (strcmp(status, "GOT IP\n") == 0) 00630 _connection_status = NSAPI_STATUS_GLOBAL_UP; 00631 else if (strcmp(status, "DISCONNECT\n") == 0) 00632 _connection_status = NSAPI_STATUS_DISCONNECTED; 00633 else 00634 return; 00635 00636 if(_connection_status_cb) 00637 _connection_status_cb(NSAPI_EVENT_CONNECTION_STATUS_CHANGE, _connection_status); 00638 } 00639 } 00640 00641 int8_t ESP8266::get_default_wifi_mode() 00642 { 00643 int8_t mode; 00644 00645 _smutex.lock(); 00646 if (_parser.send("AT+CWMODE_DEF?") 00647 && _parser.recv("+CWMODE_DEF:%hhd", &mode) 00648 && _parser.recv("OK\n")) { 00649 _smutex.unlock(); 00650 return mode; 00651 } 00652 _smutex.unlock(); 00653 00654 return 0; 00655 } 00656 00657 bool ESP8266::set_default_wifi_mode(const int8_t mode) 00658 { 00659 _smutex.lock(); 00660 bool done = _parser.send("AT+CWMODE_DEF=%hhd", mode) 00661 && _parser.recv("OK\n"); 00662 _smutex.unlock(); 00663 00664 return done; 00665 } 00666 00667 nsapi_connection_status_t ESP8266::get_connection_status() const 00668 { 00669 return _connection_status; 00670 }
Generated on Tue Jul 12 2022 17:09:09 by
1.7.2