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.
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 Aug 9 2022 00:37:06 by
1.7.2