for testing wifi

Dependents:   ESP8266_Test_WIFI

Fork of ESP8266Interface by Steve Kim

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers ESP8266.cpp Source File

ESP8266.cpp

00001 /* Copyright (C) 2012 mbed.org, MIT License
00002  *
00003  * Permission is hereby granted, free of charge, to any person obtaining a copy of this software
00004  * and associated documentation files (the "Software"), to deal in the Software without restriction,
00005  * including without limitation the rights to use, copy, modify, merge, publish, distribute,
00006  * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
00007  * furnished to do so, subject to the following conditions:
00008  *
00009  * The above copyright notice and this permission notice shall be included in all copies or
00010  * substantial portions of the Software.
00011  *
00012  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
00013  * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
00014  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
00015  * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
00016  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
00017  */
00018 
00019 #include "mbed.h"
00020 #include "ESP8266.h"
00021 #include "Endpoint.h"
00022 #include <string>
00023 #include <algorithm>
00024 
00025 //Debug is disabled by default
00026 #if 0
00027 #define DBG(x, ...)  printf("[ESP8266 : DBG]"x" \t[%s,%d]\r\n", ##__VA_ARGS__,__FILE__,__LINE__); 
00028 #define WARN(x, ...) printf("[ESP8266 : WARN]"x" \t[%s,%d]\r\n", ##__VA_ARGS__,__FILE__,__LINE__); 
00029 #define ERR(x, ...)  printf("[ESP8266 : ERR]"x" \t[%s,%d]\r\n", ##__VA_ARGS__,__FILE__,__LINE__); 
00030 #else
00031 #define DBG(x, ...) //wait_us(10);
00032 #define WARN(x, ...) //wait_us(10);
00033 #define ERR(x, ...)
00034 #endif
00035 
00036 #if 0
00037 #define INFO(x, ...) printf("[ESP8266 : INFO]"x" \t[%s,%d]\r\n", ##__VA_ARGS__,__FILE__,__LINE__); 
00038 #else
00039 #define INFO(x, ...)
00040 #endif
00041 
00042 #define ESP_MAX_TRY_JOIN 3
00043 #define ESP_MAXID 4 // the largest possible ID Value (max num of sockets possible)
00044 
00045 ESP8266 * ESP8266::inst;
00046 char* ip = NULL;
00047 
00048 ESP8266::ESP8266(PinName tx, PinName rx, PinName reset, const char *ssid, const char *phrase, uint32_t baud) :
00049     wifi(tx, rx), reset_pin(reset), buf_ESP8266(ESP_MBUFFE_MAX)
00050 {
00051     INFO("Initializing ESP8266 object");
00052     memset(&state, 0, sizeof(state));
00053 
00054 
00055     strcpy(this->ssid, ssid);
00056     strcpy(this->phrase, phrase);
00057     inst = this;
00058     attach_rx(false);
00059 
00060     wifi.baud(baud); // initial baud rate of the ESP8266
00061 
00062     state.associated = false;
00063     state.cmdMode = false;
00064 }
00065 
00066 bool ESP8266::join()
00067 {
00068     sendCommand( "AT+CWMODE=1", "change", NULL, 1000);
00069     string cmd="AT+CWJAP=\""+(string)this->ssid+"\",\""+(string)this->phrase+"\"";
00070     if( sendCommand( cmd.c_str(), "OK", NULL, 10000) ) {
00071         // successfully joined the network
00072         state.associated = true;
00073         INFO("ssid: %s, phrase: %s", this->ssid, this->phrase);
00074         
00075         return true;
00076     }
00077     return false;
00078 }
00079 
00080 bool ESP8266::connect()
00081 {
00082     sendCommand("AT+CWDHCP=1,1","OK",NULL,1000); // DHCP Enabled in Station Mode
00083     return ESP8266::join();
00084 }
00085 
00086 bool ESP8266::is_connected()
00087 {
00088     return true;
00089 }
00090 
00091 bool ESP8266::start(bool type,char* ip, int port, int id)
00092 {
00093     // Error Check
00094     if(id > ESP_MAXID) {
00095         ERR("startUDPMulti: max id is: %d, id given is %d",ESP_MAXID,id);
00096         return false;
00097     }
00098     // Single Connection Mode
00099     if(id < 0) {
00100         DBG("Start Single Connection Mode");
00101         char portstr[5];
00102         char idstr[2];
00103         bool check [3] = {0};
00104         sprintf(idstr,"%d",id);
00105         sprintf(portstr, "%d", port);
00106         switch(type) {
00107             case ESP_UDP_TYPE : //UDP
00108                 check[0] = sendCommand(( "AT+CIPSTART=\"UDP\",\"" + (string) ip + "\"," + (string) portstr ).c_str(), "OK", NULL, 10000);
00109                 break;
00110             case ESP_TCP_TYPE : //TCP
00111                 check[0] = sendCommand(( "AT+CIPSTART=\"TCP\",\"" + (string) ip + "\"," + (string) portstr ).c_str(), "OK", NULL, 10000);
00112                 break;
00113             default:
00114                 ERR("Default hit for starting connection, this shouldnt be possible!!");
00115                 break;
00116         }
00117         check[1] = sendCommand("AT+CIPMODE=1", "OK", NULL, 1000);// go into transparent mode
00118         check[2] = sendCommand("AT+CIPSEND", ">", NULL, 1000);// go into transparent mode
00119         // check that all commands were sucessful
00120         if(check[0] and check[1] and check[2]) {
00121             state.cmdMode = false;
00122             return true;
00123         } else {
00124             ERR("startUDPTransparent Failed for ip:%s, port:%d",ip,port);
00125             return false;
00126         }
00127     }
00128     // Multi Connection Mode
00129     else {
00130         //TODO: impliment Multi Connection Mode
00131         ERR("Not currently Supported!");
00132         return false;
00133         
00134 //        DBG("Start Multi Connection Mode");
00135 //        char portstr[5];
00136 //        char idstr[2];
00137 //        bool check [3] = {0};
00138 //        sprintf(idstr,"%d",id);
00139 //        sprintf(portstr, "%d", port);
00140 //        switch(type) {
00141 //            case ESP_UDP_TYPE : //UDP
00142 //                check[0] = sendCommand(( "AT+CIPSTART=" + (string) idstr + ",\"UDP\",\"" + (string) ip + "\"," + (string) portstr ).c_str(), "OK", NULL, 10000);
00143 //                break;
00144 //            case ESP_TCP_TYPE : //TCP
00145 //                check[0] = sendCommand(( "AT+CIPSTART=" + (string) idstr + ",\"TCP\",\"" + (string) ip + "\"," + (string) portstr ).c_str(), "OK", NULL, 10000);
00146 //                break;
00147 //            default:
00148 //                ERR("Default hit for starting connection, this shouldnt be possible!!");
00149 //                break;
00150 //        }
00151     }
00152 }
00153 
00154 bool ESP8266::startUDP(char* ip, int port, int id, int length)
00155 {
00156     char portstr[5];
00157     char idstr[1];
00158     char lenstr[2];
00159     
00160     sprintf(portstr, "%d", port);
00161     sprintf(idstr, "%d", id);
00162     sprintf(lenstr, "%d", length);
00163     
00164     sendCommand("AT+CIPMUX=1", "OK", NULL, 1000);
00165     sendCommand(( "AT+CIPSTART=" + string(idstr) + ",\"UDP\",\"" + (string) ip + "\"," + (string) portstr + ",1112,0").c_str(), "OK", NULL, 10000);
00166     sendCommand(("AT+CIPSEND=" + (string)idstr + "," +  (string)lenstr).c_str(), ">", NULL, 1000);// go into transparent mode
00167     DBG("Data Mode\r\n");
00168     state.cmdMode = false;
00169 
00170     return true;
00171 }
00172 
00173 bool ESP8266::startTCPServer(int port)
00174 {
00175     bool command_results[3];
00176     command_results[0]=sendCommand("AT+CWMODE=3", "OK", NULL, 1000);
00177     command_results[1]=sendCommand("AT+CIPMUX=1", "OK", NULL, 1000);
00178     if(port == 333){
00179         command_results[2]=sendCommand("AT+CIPSERVER=1", "OK", NULL, 1000);
00180     }
00181     else{
00182         char portstr[5];
00183         sprintf(portstr, "%d", port);
00184         command_results[2]=sendCommand(("AT+CIPSERVER=1," + (string)portstr).c_str(), "OK", NULL, 1000);
00185     }
00186     //sendCommand("AT+CIFSR", "OK", NULL, 1000);
00187     DBG("Data Mode\r\n");
00188     state.cmdMode = false;
00189     if (command_results[0] and command_results[1] and command_results[2]){
00190         return true;
00191     }
00192     else{
00193         return false;
00194     }
00195 }
00196 
00197 bool ESP8266::close()
00198 {
00199     wait(0.1f);
00200     send("+++",3);
00201     wait(1.0f);
00202     state.cmdMode = true;
00203     sendCommand("AT+CIPCLOSE","OK", NULL, 10000);
00204     return true;
00205 }
00206 
00207 bool ESP8266::disconnect()
00208 {
00209     // if already disconnected, return
00210     if (!state.associated)
00211         return true;
00212     // send command to quit AP
00213     sendCommand("AT+CWQAP", "OK", NULL, 10000);
00214     state.associated = false;
00215     return true;
00216 }
00217 
00218 /*
00219     Assuming Returned data looks like this:
00220     +CIFSR:STAIP,"192.168.11.2"
00221     +CIFSR:STAMAC,"18:fe:34:9f:3a:f5"
00222     grabbing IP from first set of quotation marks
00223 */
00224 extern RawSerial pc;
00225 char* ESP8266::getIPAddress()
00226 {
00227     char result[30] = {0};
00228     int check = 0;
00229     check = sendCommand("AT+CIFSR", NULL, result, 1000);
00230     //pc.printf("\r\nReceivedInfo for IP Command is: %s\r\n",result);
00231     ip = ipString;
00232     if(check) {
00233         // Success
00234         string resultString(result);
00235         uint8_t pos1 = 0, pos2 = 0;
00236         //uint8_t pos3 = 0, pos4 = 0;
00237         pos1 = resultString.find("+CIFSR:STAIP");
00238         pos1 = resultString.find('"',pos1);
00239         pos2 = resultString.find('"',pos1+1);
00240         //pos3 = resultString.find('"',pos2+1); //would find mac address
00241         //pos4 = resultString.find('"',pos3+1);
00242 // sekim XXXXX
00243 /*
00244 if ( pos2<=pos1 )
00245 {
00246     pc.printf("\r\n IP String Error : (%d) (%d, %d) \r\n", strlen(result), pos1, pos2);
00247     return NULL;
00248 }
00249 */
00250         strncpy(ipString,resultString.substr(pos1,pos2).c_str(),sizeof(ipString));
00251         ipString[pos2 - pos1 +1] = 0; // null terminate string correctly.
00252         INFO("IP: %s",ipString);
00253         ip = ipString;
00254 
00255     } else {
00256         // Failure
00257         ERR("getIPAddress() failed");
00258         ip = NULL;
00259     }
00260     return ip;
00261 }
00262 
00263 bool ESP8266::gethostbyname(const char * host, char * ip)
00264 {
00265     string h = host;
00266     int nb_digits = 0;
00267 
00268     // no dns needed
00269     int pos = h.find(".");
00270     if (pos != string::npos) {
00271         string sub = h.substr(0, h.find("."));
00272         nb_digits = atoi(sub.c_str());
00273     }
00274     //printf("substrL %s\r\n", sub.c_str());
00275     if (count(h.begin(), h.end(), '.') == 3 && nb_digits > 0) {
00276         strcpy(ip, host);
00277         return true;
00278     } else {
00279         // dns needed, not currently available
00280         ERR("gethostbyname(): DNS Not currently available, only use IP Addresses!");
00281         return false;
00282     }
00283 }
00284 
00285 void ESP8266::reset()
00286 {
00287     reset_pin = 0;
00288     wait_us(20);
00289     reset_pin = 1;
00290     wait(1);
00291     //reset_pin = !reset_pin
00292     //send("+++",3);
00293     //wait(1);
00294     state.cmdMode = true;
00295     sendCommand("AT", "OK", NULL, 1000);
00296     sendCommand("AT+RST", "ready", NULL, 10000);
00297     state.associated = false;
00298 
00299 }
00300 
00301 bool ESP8266::reboot()
00302 {
00303     reset();
00304     return true;
00305 }
00306 
00307 // sekim XXXX
00308 extern CircBuffer<char> buffer_ESP8266_recv;
00309 
00310 void ESP8266::handler_rx(void)
00311 {
00312     //read characters
00313     char c;
00314     while (wifi.readable()) {
00315         c=wifi.getc();
00316         buf_ESP8266.queue(c);
00317         //if (state.cmdMode) pc.printf("%c",c); //debug echo, needs fast serial console to prevent UART overruns
00318         
00319         // sekim XXXX
00320         buffer_ESP8266_recv.queue(c);
00321     }
00322 }
00323 
00324 void ESP8266::attach_rx(bool callback)
00325 {
00326     if (!callback) {
00327         wifi.attach(NULL);
00328     }
00329     else {
00330         wifi.attach(this, &ESP8266::handler_rx);
00331     }    
00332 }
00333 
00334 int ESP8266::readable()
00335 {
00336     return buf_ESP8266.available();
00337 }
00338 
00339 int ESP8266::writeable()
00340 {
00341     return wifi.writeable();
00342 }
00343 
00344 char ESP8266::getc()
00345 {
00346     char c=0;
00347     while (!buf_ESP8266.available());
00348     buf_ESP8266.dequeue(&c);
00349     return c;
00350 }
00351 
00352 int ESP8266::putc(char c)
00353 {
00354     while (!wifi.writeable() || wifi.readable()); //wait for echoed command characters to be read first
00355     return wifi.putc(c);
00356 }
00357 
00358 void ESP8266::flush()
00359 {
00360     buf_ESP8266.flush();
00361 }
00362 
00363 int ESP8266::send(const char * buf, int len)
00364 {
00365     //TODO: need to add handler for data > 2048B, this is the max packet size of the ESP8266.
00366     if(len >= 2048){
00367         WARN("send buffer >= 2048B, need to chunk this up to be less.");    
00368     }
00369     const char* bufptr=buf;
00370     for(int i=0; i<len; i++) {
00371         //pc.printf("%c", *bufptr);
00372         putc((int)*bufptr++);
00373         
00374     }
00375     return len;
00376 }
00377 
00378 bool ESP8266::sendCommand(const char * cmd, const char * ACK, char * res, int timeout)
00379 {
00380     char read;
00381     size_t found = string::npos;
00382     string checking = "";
00383     Timer tmr;
00384     int result = 0;
00385 
00386     DBG("sendCmd:\t %s",cmd);
00387 
00388     attach_rx(true);
00389 
00390     //We flush the buffer
00391     while (readable())
00392         getc();
00393 
00394     if (!ACK || !strcmp(ACK, "NO")) {
00395         for (int i = 0; i < strlen(cmd); i++) {
00396             result = (putc(cmd[i]) == cmd[i]) ? result + 1 : result;
00397             wait(0.005f); // prevents stuck recieve ready (?) need to let echoed character get read first
00398         }
00399         putc(13); //CR
00400         wait(0.005f); // wait for echo
00401         putc(10); //LF
00402 
00403     } else {
00404         //We flush the buffer
00405         while (readable())
00406             getc();
00407 
00408         tmr.start();
00409         for (int i = 0; i < strlen(cmd); i++) {
00410             result = (putc(cmd[i]) == cmd[i]) ? result + 1 : result;
00411             wait(.005); // wait for echo
00412         }
00413         putc(13); //CR
00414         wait(0.005f); // wait for echo
00415         putc(10); //LF
00416 
00417         while (1) {
00418             if (tmr.read_ms() > timeout) {
00419                 //We flush the buffer
00420                 while (readable())
00421                     getc();
00422 
00423                 DBG("check:\t %s", checking.c_str());
00424 
00425                 attach_rx(true);
00426                 return -1;
00427             } else if (readable()) {
00428                 read = getc();
00429                 //printf("%c",read); //debug echo
00430                 if ( read != '\r' && read != '\n') {
00431                     checking += read;
00432                     found = checking.find(ACK);
00433                     if (found != string::npos) {
00434                         wait(0.01f);
00435 
00436                         //We flush the buffer
00437                         while (readable())
00438                             read = getc();
00439                         //printf("%c",read); //debug echo
00440                         break;
00441                     }
00442                 }
00443             }
00444         }
00445         DBG("check: %s", checking.c_str());
00446 
00447         attach_rx(true);
00448         return result;
00449     }
00450 
00451     //the user wants the result from the command (ACK == NULL, res != NULL)
00452     if (res != NULL) {
00453         int i = 0;
00454         Timer timeout;
00455         timeout.start();
00456         tmr.reset();
00457         while (1) {
00458             if (timeout.read() > 2) {
00459                 if (i == 0) {
00460                     res = NULL;
00461                     break;
00462                 }
00463                 res[i] = '\0';
00464                 DBG("user str 1: %s", res);
00465 
00466                 break;
00467             } else {
00468                 if (tmr.read_ms() > 300) {
00469                     res[i] = '\0';
00470                     DBG("user str: %s", res);
00471 
00472                     break;
00473                 }
00474                 if (readable()) {
00475                     tmr.start();
00476                     read = getc();
00477 
00478                     // we drop \r and \n
00479                     if ( read != '\r' && read != '\n') {
00480                         res[i++] = read;
00481                     }
00482                 }
00483             }
00484         }
00485         DBG("user str: %s", res);
00486     }
00487 
00488     //We flush the buffer
00489     while (readable())
00490         getc();
00491 
00492     attach_rx(true);
00493     DBG("result: %d", result)
00494     return result;
00495 }
00496