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