ESP8266 Socket Library. AT Thinker firmware.
Dependents: ESP8266_MQTT_HelloWorld ESP8266_IFTTT_Test ECE_4180_Lab_4 websocketmbed ... more
Fork of ESP8266Interface by
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 return true; 00075 } 00076 return false; 00077 } 00078 00079 bool ESP8266::connect() 00080 { 00081 sendCommand("AT+CWDHCP=1,1","OK",NULL,1000); // DHCP Enabled in Station Mode 00082 return ESP8266::join(); 00083 } 00084 00085 bool ESP8266::is_connected() 00086 { 00087 return true; 00088 } 00089 00090 bool ESP8266::start(bool type,char* ip, int port, int id) 00091 { 00092 // Error Check 00093 if(id > ESP_MAXID) { 00094 ERR("startUDPMulti: max id is: %d, id given is %d",ESP_MAXID,id); 00095 return false; 00096 } 00097 // Single Connection Mode 00098 if(id < 0) { 00099 DBG("Start Single Connection Mode"); 00100 char portstr[5]; 00101 char idstr[2]; 00102 bool check [3] = {0}; 00103 sprintf(idstr,"%d",id); 00104 sprintf(portstr, "%d", port); 00105 switch(type) { 00106 case ESP_UDP_TYPE : //UDP 00107 check[0] = sendCommand(( "AT+CIPSTART=\"UDP\",\"" + (string) ip + "\"," + (string) portstr ).c_str(), "OK", NULL, 10000); 00108 break; 00109 case ESP_TCP_TYPE : //TCP 00110 check[0] = sendCommand(( "AT+CIPSTART=\"TCP\",\"" + (string) ip + "\"," + (string) portstr ).c_str(), "OK", NULL, 10000); 00111 break; 00112 default: 00113 ERR("Default hit for starting connection, this shouldnt be possible!!"); 00114 break; 00115 } 00116 check[1] = sendCommand("AT+CIPMODE=1", "OK", NULL, 1000);// go into transparent mode 00117 check[2] = sendCommand("AT+CIPSEND", ">", NULL, 1000);// go into transparent mode 00118 // check that all commands were sucessful 00119 if(check[0] and check[1] and check[2]) { 00120 state.cmdMode = false; 00121 return true; 00122 } else { 00123 ERR("startUDPTransparent Failed for ip:%s, port:%d",ip,port); 00124 return false; 00125 } 00126 } 00127 // Multi Connection Mode 00128 else { 00129 //TODO: impliment Multi Connection Mode 00130 ERR("Not currently Supported!"); 00131 return false; 00132 00133 // DBG("Start Multi Connection Mode"); 00134 // char portstr[5]; 00135 // char idstr[2]; 00136 // bool check [3] = {0}; 00137 // sprintf(idstr,"%d",id); 00138 // sprintf(portstr, "%d", port); 00139 // switch(type) { 00140 // case ESP_UDP_TYPE : //UDP 00141 // check[0] = sendCommand(( "AT+CIPSTART=" + (string) idstr + ",\"UDP\",\"" + (string) ip + "\"," + (string) portstr ).c_str(), "OK", NULL, 10000); 00142 // break; 00143 // case ESP_TCP_TYPE : //TCP 00144 // check[0] = sendCommand(( "AT+CIPSTART=" + (string) idstr + ",\"TCP\",\"" + (string) ip + "\"," + (string) portstr ).c_str(), "OK", NULL, 10000); 00145 // break; 00146 // default: 00147 // ERR("Default hit for starting connection, this shouldnt be possible!!"); 00148 // break; 00149 // } 00150 } 00151 } 00152 00153 bool ESP8266::startUDP(char* ip, int port, int id, int length) 00154 { 00155 char portstr[5]; 00156 char idstr[1]; 00157 char lenstr[2]; 00158 00159 sprintf(portstr, "%d", port); 00160 sprintf(idstr, "%d", id); 00161 sprintf(lenstr, "%d", length); 00162 00163 sendCommand("AT+CIPMUX=1", "OK", NULL, 1000); 00164 sendCommand(( "AT+CIPSTART=" + string(idstr) + ",\"UDP\",\"" + (string) ip + "\"," + (string) portstr + ",1112,0").c_str(), "OK", NULL, 10000); 00165 sendCommand(("AT+CIPSEND=" + (string)idstr + "," + (string)lenstr).c_str(), ">", NULL, 1000);// go into transparent mode 00166 DBG("Data Mode\r\n"); 00167 state.cmdMode = false; 00168 00169 return true; 00170 } 00171 00172 bool ESP8266::startTCPServer(int port) 00173 { 00174 bool command_results[3]; 00175 command_results[0]=sendCommand("AT+CWMODE=3", "OK", NULL, 1000); 00176 command_results[1]=sendCommand("AT+CIPMUX=1", "OK", NULL, 1000); 00177 if(port == 333){ 00178 command_results[2]=sendCommand("AT+CIPSERVER=1", "OK", NULL, 1000); 00179 } 00180 else{ 00181 char portstr[5]; 00182 sprintf(portstr, "%d", port); 00183 command_results[2]=sendCommand(("AT+CIPSERVER=1," + (string)portstr).c_str(), "OK", NULL, 1000); 00184 } 00185 //sendCommand("AT+CIFSR", "OK", NULL, 1000); 00186 DBG("Data Mode\r\n"); 00187 state.cmdMode = false; 00188 if (command_results[0] and command_results[1] and command_results[2]){ 00189 return true; 00190 } 00191 else{ 00192 return false; 00193 } 00194 } 00195 00196 bool ESP8266::close() 00197 { 00198 wait(0.1f); 00199 send("+++",3); 00200 wait(1.0f); 00201 state.cmdMode = true; 00202 sendCommand("AT+CIPCLOSE","OK", NULL, 10000); 00203 return true; 00204 } 00205 00206 bool ESP8266::disconnect() 00207 { 00208 // if already disconnected, return 00209 if (!state.associated) 00210 return true; 00211 // send command to quit AP 00212 sendCommand("AT+CWQAP", "OK", NULL, 10000); 00213 state.associated = false; 00214 return true; 00215 } 00216 00217 /* 00218 Assuming Returned data looks like this: 00219 +CIFSR:STAIP,"192.168.11.2" 00220 +CIFSR:STAMAC,"18:fe:34:9f:3a:f5" 00221 grabbing IP from first set of quotation marks 00222 */ 00223 char* ESP8266::getIPAddress() 00224 { 00225 char result[30] = {0}; 00226 int check = 0; 00227 check = sendCommand("AT+CIFSR", NULL, result, 1000); 00228 //pc.printf("\r\nReceivedInfo for IP Command is: %s\r\n",result); 00229 ip = ipString; 00230 if(check) { 00231 // Success 00232 string resultString(result); 00233 uint8_t pos1 = 0, pos2 = 0; 00234 //uint8_t pos3 = 0, pos4 = 0; 00235 pos1 = resultString.find("+CIFSR:STAIP"); 00236 pos1 = resultString.find('"',pos1); 00237 pos2 = resultString.find('"',pos1+1); 00238 //pos3 = resultString.find('"',pos2+1); //would find mac address 00239 //pos4 = resultString.find('"',pos3+1); 00240 strncpy(ipString,resultString.substr(pos1,pos2).c_str(),sizeof(ipString)); 00241 ipString[pos2 - pos1 +1] = 0; // null terminate string correctly. 00242 INFO("IP: %s",ipString); 00243 ip = ipString; 00244 00245 } else { 00246 // Failure 00247 ERR("getIPAddress() failed"); 00248 ip = NULL; 00249 } 00250 return ip; 00251 } 00252 00253 bool ESP8266::gethostbyname(const char * host, char * ip) 00254 { 00255 string h = host; 00256 int nb_digits = 0; 00257 00258 // no dns needed 00259 int pos = h.find("."); 00260 if (pos != string::npos) { 00261 string sub = h.substr(0, h.find(".")); 00262 nb_digits = atoi(sub.c_str()); 00263 } 00264 //printf("substrL %s\r\n", sub.c_str()); 00265 if (count(h.begin(), h.end(), '.') == 3 && nb_digits > 0) { 00266 strcpy(ip, host); 00267 return true; 00268 } else { 00269 // dns needed, not currently available 00270 ERR("gethostbyname(): DNS Not currently available, only use IP Addresses!"); 00271 return false; 00272 } 00273 } 00274 00275 void ESP8266::reset() 00276 { 00277 reset_pin = 0; 00278 wait_us(20); 00279 reset_pin = 1; 00280 //wait(1); 00281 //reset_pin = !reset_pin 00282 //send("+++",3); 00283 wait(1); 00284 state.cmdMode = true; 00285 sendCommand("AT", "OK", NULL, 1000); 00286 sendCommand("AT+RST", "ready", NULL, 10000); 00287 state.associated = false; 00288 00289 } 00290 00291 bool ESP8266::reboot() 00292 { 00293 reset(); 00294 return true; 00295 } 00296 00297 void ESP8266::handler_rx(void) 00298 { 00299 //read characters 00300 char c; 00301 while (wifi.readable()) { 00302 c=wifi.getc(); 00303 buf_ESP8266.queue(c); 00304 //if (state.cmdMode) pc.printf("%c",c); //debug echo, needs fast serial console to prevent UART overruns 00305 } 00306 } 00307 00308 void ESP8266::attach_rx(bool callback) 00309 { 00310 if (!callback) { 00311 wifi.attach(NULL); 00312 } 00313 else { 00314 wifi.attach(this, &ESP8266::handler_rx); 00315 } 00316 } 00317 00318 int ESP8266::readable() 00319 { 00320 return buf_ESP8266.available(); 00321 } 00322 00323 int ESP8266::writeable() 00324 { 00325 return wifi.writeable(); 00326 } 00327 00328 char ESP8266::getc() 00329 { 00330 char c=0; 00331 while (!buf_ESP8266.available()); 00332 buf_ESP8266.dequeue(&c); 00333 return c; 00334 } 00335 00336 int ESP8266::putc(char c) 00337 { 00338 while (!wifi.writeable() || wifi.readable()); //wait for echoed command characters to be read first 00339 return wifi.putc(c); 00340 } 00341 00342 void ESP8266::flush() 00343 { 00344 buf_ESP8266.flush(); 00345 } 00346 00347 int ESP8266::send(const char * buf, int len) 00348 { 00349 //TODO: need to add handler for data > 2048B, this is the max packet size of the ESP8266. 00350 if(len >= 2048){ 00351 WARN("send buffer >= 2048B, need to chunk this up to be less."); 00352 } 00353 const char* bufptr=buf; 00354 for(int i=0; i<len; i++) { 00355 putc((int)*bufptr++); 00356 } 00357 return len; 00358 } 00359 00360 bool ESP8266::sendCommand(const char * cmd, const char * ACK, char * res, int timeout) 00361 { 00362 char read; 00363 size_t found = string::npos; 00364 string checking = ""; 00365 Timer tmr; 00366 int result = 0; 00367 00368 DBG("sendCmd:\t %s",cmd); 00369 00370 attach_rx(true); 00371 00372 //We flush the buffer 00373 while (readable()) 00374 getc(); 00375 00376 if (!ACK || !strcmp(ACK, "NO")) { 00377 for (int i = 0; i < strlen(cmd); i++) { 00378 result = (putc(cmd[i]) == cmd[i]) ? result + 1 : result; 00379 wait(0.005f); // prevents stuck recieve ready (?) need to let echoed character get read first 00380 } 00381 putc(13); //CR 00382 wait(0.005f); // wait for echo 00383 putc(10); //LF 00384 00385 } else { 00386 //We flush the buffer 00387 while (readable()) 00388 getc(); 00389 00390 tmr.start(); 00391 for (int i = 0; i < strlen(cmd); i++) { 00392 result = (putc(cmd[i]) == cmd[i]) ? result + 1 : result; 00393 wait(.005); // wait for echo 00394 } 00395 putc(13); //CR 00396 wait(0.005f); // wait for echo 00397 putc(10); //LF 00398 00399 while (1) { 00400 if (tmr.read_ms() > timeout) { 00401 //We flush the buffer 00402 while (readable()) 00403 getc(); 00404 00405 DBG("check:\t %s", checking.c_str()); 00406 00407 attach_rx(true); 00408 return -1; 00409 } else if (readable()) { 00410 read = getc(); 00411 //printf("%c",read); //debug echo 00412 if ( read != '\r' && read != '\n') { 00413 checking += read; 00414 found = checking.find(ACK); 00415 if (found != string::npos) { 00416 wait(0.01f); 00417 00418 //We flush the buffer 00419 while (readable()) 00420 read = getc(); 00421 //printf("%c",read); //debug echo 00422 break; 00423 } 00424 } 00425 } 00426 } 00427 DBG("check: %s", checking.c_str()); 00428 00429 attach_rx(true); 00430 return result; 00431 } 00432 00433 //the user wants the result from the command (ACK == NULL, res != NULL) 00434 if (res != NULL) { 00435 int i = 0; 00436 Timer timeout; 00437 timeout.start(); 00438 tmr.reset(); 00439 while (1) { 00440 if (timeout.read() > 2) { 00441 if (i == 0) { 00442 res = NULL; 00443 break; 00444 } 00445 res[i] = '\0'; 00446 DBG("user str 1: %s", res); 00447 00448 break; 00449 } else { 00450 if (tmr.read_ms() > 300) { 00451 res[i] = '\0'; 00452 DBG("user str: %s", res); 00453 00454 break; 00455 } 00456 if (readable()) { 00457 tmr.start(); 00458 read = getc(); 00459 00460 // we drop \r and \n 00461 if ( read != '\r' && read != '\n') { 00462 res[i++] = read; 00463 } 00464 } 00465 } 00466 } 00467 DBG("user str: %s", res); 00468 } 00469 00470 //We flush the buffer 00471 while (readable()) 00472 getc(); 00473 00474 attach_rx(true); 00475 DBG("result: %d", result) 00476 return result; 00477 }
Generated on Tue Jul 12 2022 22:54:02 by 1.7.2