Mbed Cloud example program for workshop in W27 2018.

Dependencies:   MMA7660 LM75B

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers ESP8266.cpp Source File

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 }