now this shit works
Fork of ESP8266NodeMCUInterface by
Revision 44:16da10e7b3f7, committed 2015-06-03
- Comitter:
- geky
- Date:
- Wed Jun 03 21:44:20 2015 +0000
- Parent:
- 35:22d30e936e4c
- Child:
- 45:3cfb7406d993
- Child:
- 46:4abb80f0a920
- Commit message:
- Reimplemented ESP8266 driver using the Nodemcu firmware
Changed in this revision
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/BufferedSerial.lib Wed Jun 03 21:44:20 2015 +0000 @@ -0,0 +1,1 @@ +http://developer.mbed.org/users/sam_grove/code/BufferedSerial/#9ee15ae3d1a3
--- a/ESP8266/ESP8266.cpp Fri May 01 18:29:38 2015 +0000
+++ b/ESP8266/ESP8266.cpp Wed Jun 03 21:44:20 2015 +0000
@@ -1,454 +1,395 @@
-/* Copyright (C) 2012 mbed.org, MIT License
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy of this software
- * and associated documentation files (the "Software"), to deal in the Software without restriction,
- * including without limitation the rights to use, copy, modify, merge, publish, distribute,
- * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all copies or
- * substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
- * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
- * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- */
-
-#include "mbed.h"
-#include "ESP8266.h"
-#include "Endpoint.h"
-#include <string>
-#include <algorithm>
-
-//Debug is disabled by default
-#ifdef DEBUG
-#define DBG(x, ...) printf("[ESP8266 : DBG]"x"\r\n", ##__VA_ARGS__);
-#define WARN(x, ...) printf("[ESP8266 : WARN]"x"\r\n", ##__VA_ARGS__);
-#define ERR(x, ...) printf("[ESP8266 : ERR]"x"\r\n", ##__VA_ARGS__);
-#else
-#define DBG(x, ...)
-#define WARN(x, ...)
-#define ERR(x, ...)
-#endif
-
-#ifdef DEBUG
-#define INFO(x, ...) printf("[ESP8266 : INFO]"x"\r\n", ##__VA_ARGS__);
-#else
-#define INFO(x, ...)
-#endif
-
-#define ESP_MAX_TRY_JOIN 3
-#define ESP_MAXID 4 // the largest possible ID Value (max num of sockets possible)
-
-extern Serial pc;
-
-ESP8266 * ESP8266::inst;
-char* ip = NULL;
-
-ESP8266::ESP8266( PinName tx, PinName rx, PinName _reset, const char * ssid, const char * phrase, uint32_t baud):
- wifi(tx, rx), reset_pin(_reset), buf_ESP8266(256)
-{
- memset(&state, 0, sizeof(state));
-
- // change all ' ' in '$' in the ssid and the passphrase
- strcpy(this->ssid, ssid);
- for (int i = 0; i < strlen(ssid); i++) {
- if (this->ssid[i] == ' ')
- this->ssid[i] = '$';
- }
- strcpy(this->phrase, phrase);
- for (int i = 0; i < strlen(phrase); i++) {
- if (this->phrase[i] == ' ')
- this->phrase[i] = '$';
- }
-
-
- inst = this;
- attach_rx(false);
-
- wifi.baud(baud); // initial baud rate of the ESP8266
-
- state.associated = false;
- state.cmdMode = false;
-}
-
-bool ESP8266::join()
-{
- sendCommand( "AT+CWMODE=1", "change", NULL, 1000);
- string cmd="AT+CWJAP=\""+(string)this->ssid+"\",\""+(string)this->phrase+"\"";
- if( sendCommand( cmd.c_str(), "OK", NULL, 10000) ) {
- // successfully joined the network
- state.associated = true;
- INFO("\r\nssid: %s\r\nphrase: %s\r\nsecurity: %s\r\n\r\n", this->ssid, this->phrase);
- return true;
- }
- return false;
-}
-
-bool ESP8266::connect()
-{
- sendCommand("AT+CWDHCP=1,1","OK",NULL,1000); // DHCP Enabled in Station Mode
- return ESP8266::join();
-}
-
-bool ESP8266::is_connected()
-{
- return true;
-}
-
-bool ESP8266::start(bool type,char* ip, int port, int id)
-{
- // Error Check
- if(id > ESP_MAXID) {
- ERR("startUDPMulti: max id is: %d, id given is %d",ESP_MAXID,id);
- return false;
- }
- // Single Connection Mode
- if(id < 0) {
- DBG("Start Single Connection Mode");
- char portstr[5];
- char idstr[2];
- bool check [3] = {0};
- sprintf(idstr,"%d",id);
- sprintf(portstr, "%d", port);
- switch(type) {
- case ESP_UDP_TYPE : //UDP
- check[0] = sendCommand(( "AT+CIPSTART=\"UDP\",\"" + (string) ip + "\"," + (string) portstr ).c_str(), "OK", NULL, 10000);
- break;
- case ESP_TCP_TYPE : //TCP
- check[0] = sendCommand(( "AT+CIPSTART=\"TCP\",\"" + (string) ip + "\"," + (string) portstr ).c_str(), "OK", NULL, 10000);
- break;
- default:
- ERR("Default hit for starting connection, this shouldnt be possible!!");
- break;
- }
- check[1] = sendCommand("AT+CIPMODE=1", "OK", NULL, 1000);// go into transparent mode
- check[2] = sendCommand("AT+CIPSEND", ">", NULL, 1000);// go into transparent mode
- // check that all commands were sucessful
- if(check[0] and check[1] and check[2]) {
- DBG("Data Mode\r\n");
- state.cmdMode = false;
- return true;
- } else {
- DBG("\r\nstartUDPTransparent Failed for ip:%s, port:%d\r\n",ip,port);
- return false;
- }
- }
- // Multi Connection Mode
- else {
- //TODO: impliment Multi Connection Mode
- ERR("Not currently Supported!");
- return false;
-
-// DBG("Start Multi Connection Mode");
-// char portstr[5];
-// char idstr[2];
-// bool check [3] = {0};
-// sprintf(idstr,"%d",id);
-// sprintf(portstr, "%d", port);
-// switch(type) {
-// case ESP_UDP_TYPE : //UDP
-// check[0] = sendCommand(( "AT+CIPSTART=" + (string) idstr + ",\"UDP\",\"" + (string) ip + "\"," + (string) portstr ).c_str(), "OK", NULL, 10000);
-// break;
-// case ESP_TCP_TYPE : //TCP
-// check[0] = sendCommand(( "AT+CIPSTART=" + (string) idstr + ",\"TCP\",\"" + (string) ip + "\"," + (string) portstr ).c_str(), "OK", NULL, 10000);
-// break;
-// default:
-// ERR("Default hit for starting connection, this shouldnt be possible!!");
-// break;
-// }
- }
-}
-
-bool ESP8266::startUDP(char* ip, int port)
-{
- char portstr[5];
- sprintf(portstr, "%d", port);
- sendCommand(( "AT+CIPSTART=\"UDP\",\"" + (string) ip + "\"," + (string) portstr ).c_str(), "OK", NULL, 10000);
-
- sendCommand("AT+CIPMODE=1", "OK", NULL, 1000);// go into transparent mode
- sendCommand("AT+CIPSEND", ">", NULL, 1000);// go into transparent mode
- DBG("Data Mode\r\n");
- state.cmdMode = false;
-
- return true;
-}
-
-bool ESP8266::close()
-{
- send("+++",3);
- wait(1);
- state.cmdMode = true;
- sendCommand("AT+CIPCLOSE","OK", NULL, 10000);
- return true;
-}
-
-bool ESP8266::disconnect()
-{
- // if already disconnected, return
- if (!state.associated)
- return true;
- // send command to quit AP
- sendCommand("AT+CWQAP", "OK", NULL, 10000);
- state.associated = false;
- return true;
-}
-
-/*
- Assuming Returned data looks like this:
- +CIFSR:STAIP,"192.168.11.2"
- +CIFSR:STAMAC,"18:fe:34:9f:3a:f5"
- grabbing IP from first set of quotation marks
-*/
-char* ESP8266::getIPAddress()
-{
- char result[30] = {0};
- int check = 0;
- check = sendCommand("AT+CIFSR", NULL, result, 1000);
- //pc.printf("\r\nReceivedInfo for IP Command is: %s\r\n",result);
- ip = ipString;
- if(check) {
- // Success
- string resultString(result);
- uint8_t pos1 = 0, pos2 = 0;
- //uint8_t pos3 = 0, pos4 = 0;
- pos1 = resultString.find("+CIFSR:STAIP");
- pos1 = resultString.find('"',pos1);
- pos2 = resultString.find('"',pos1+1);
- //pos3 = resultString.find('"',pos2+1); //would find mac address
- //pos4 = resultString.find('"',pos3+1);
- strncpy(ipString,resultString.substr(pos1,pos2).c_str(),sizeof(ipString));
- ipString[pos2 - pos1 +1] = 0; // null terminate string correctly.
- DBG("IP: %s\r\n",ipString);
- ip = ipString;
-
- } else {
- // Failure
- DBG("getIPAddress() failed\r\n");
- ip = NULL;
- }
- return ip;
-}
-
-bool ESP8266::gethostbyname(const char * host, char * ip)
-{
- string h = host;
- int nb_digits = 0;
-
- // no dns needed
- int pos = h.find(".");
- if (pos != string::npos) {
- string sub = h.substr(0, h.find("."));
- nb_digits = atoi(sub.c_str());
- }
- //printf("substrL %s\r\n", sub.c_str());
- if (count(h.begin(), h.end(), '.') == 3 && nb_digits > 0) {
- strcpy(ip, host);
- return true;
- } else {
- // dns needed, not currently available
- ERR("gethostbyname(): DNS Not currently available, only use IP Addresses!");
- return false;
- }
-}
-
-void ESP8266::reset()
-{
- reset_pin = 0;
- wait(0.2);
- reset_pin = 1;
- wait(1);
-
- //send("+++",3);
- //wait(1);
- state.cmdMode = true;
- sendCommand("AT", "OK", NULL, 1000);
- sendCommand("AT+RST", "ready", NULL, 10000);
- state.associated = false;
-
-}
-
-bool ESP8266::reboot()
-{
- reset();
- return true;
-}
-
-void ESP8266::handler_rx(void)
-{
- //read characters
- char c;
- while (wifi.readable()) {
- c=wifi.getc();
- buf_ESP8266.queue(c);
- //if (state.cmdMode) pc.printf("%c",c); //debug echo, needs fast serial console to prevent UART overruns
- }
-}
-
-void ESP8266::attach_rx(bool callback)
-{
- if (!callback)
- wifi.attach(NULL);
- else
- wifi.attach(this, &ESP8266::handler_rx);
-}
-
-int ESP8266::readable()
-{
- return buf_ESP8266.available();
-}
-
-int ESP8266::writeable()
-{
- return wifi.writeable();
-}
-
-char ESP8266::getc()
-{
- char c=0;
- while (!buf_ESP8266.available());
- buf_ESP8266.dequeue(&c);
- return c;
-}
-
-int ESP8266::putc(char c)
-{
- while (!wifi.writeable() || wifi.readable()); //wait for echoed command characters to be read first
- return wifi.putc(c);
-}
-
-void ESP8266::flush()
-{
- buf_ESP8266.flush();
-}
-
-int ESP8266::send(const char * buf, int len)
-{
- //TODO: need to add handler for data > 2048B, this is the max packet size of the ESP8266.
- const char* bufptr=buf;
- for(int i=0; i<len; i++) {
- putc((int)*bufptr++);
- }
- return len;
-}
-
-bool ESP8266::sendCommand(const char * cmd, const char * ACK, char * res, int timeout)
-{
- char read;
- size_t found = string::npos;
- string checking;
- Timer tmr;
- int result = 0;
-
- DBG("will send: %s\r\n",cmd);
-
- attach_rx(true);
-
- //We flush the buffer
- while (readable())
- getc();
-
- if (!ACK || !strcmp(ACK, "NO")) {
- for (int i = 0; i < strlen(cmd); i++) {
- result = (putc(cmd[i]) == cmd[i]) ? result + 1 : result;
- wait(.005); // prevents stuck recieve ready (?) need to let echoed character get read first
- }
- putc(13); //CR
- wait(.005); // wait for echo
- putc(10); //LF
-
- } else {
- //We flush the buffer
- while (readable())
- getc();
-
- tmr.start();
- for (int i = 0; i < strlen(cmd); i++) {
- result = (putc(cmd[i]) == cmd[i]) ? result + 1 : result;
- wait(.005); // wait for echo
- }
- putc(13); //CR
- wait(.005); // wait for echo
- putc(10); //LF
-
- while (1) {
- if (tmr.read_ms() > timeout) {
- //We flush the buffer
- while (readable())
- getc();
-
- DBG("check: %s\r\n", checking.c_str());
-
- attach_rx(true);
- return -1;
- } else if (readable()) {
- read = getc();
- printf("%c",read); //debug echo
- if ( read != '\r' && read != '\n') {
- checking += read;
- found = checking.find(ACK);
- if (found != string::npos) {
- wait(0.01);
-
- //We flush the buffer
- while (readable())
- read = getc();
- printf("%c",read); //debug echo
- break;
- }
- }
- }
- }
- DBG("check: %s\r\n", checking.c_str());
-
- attach_rx(true);
- return result;
- }
-
- //the user wants the result from the command (ACK == NULL, res != NULL)
- if ( res != NULL) {
- int i = 0;
- Timer timeout;
- timeout.start();
- tmr.reset();
- while (1) {
- if (timeout.read() > 2) {
- if (i == 0) {
- res = NULL;
- break;
- }
- res[i] = '\0';
- DBG("user str 1: %s\r\n", res);
-
- break;
- } else {
- if (tmr.read_ms() > 300) {
- res[i] = '\0';
- DBG("user str: %s\r\n", res);
-
- break;
- }
- if (readable()) {
- tmr.start();
- read = getc();
-
- // we drop \r and \n
- if ( read != '\r' && read != '\n') {
- res[i++] = read;
- }
- }
- }
- }
- DBG("user str: %s\r\n", res);
- }
-
- //We flush the buffer
- while (readable())
- getc();
-
- attach_rx(true);
- DBG("result: %d\r\n", result)
- return result;
-}
+/* Copyright (C) 2012 mbed.org, MIT License
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this software
+ * and associated documentation files (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge, publish, distribute,
+ * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies or
+ * substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
+ * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include "mbed.h"
+#include "ESP8266.h"
+#include "Endpoint.h"
+#include <string>
+#include <algorithm>
+
+//Debug is disabled by default
+#if 0
+#define DBG(x, ...) printf("[ESP8266 : DBG]"x" \t[%s,%d]\r\n", ##__VA_ARGS__,__FILE__,__LINE__);
+#define WARN(x, ...) printf("[ESP8266 : WARN]"x" \t[%s,%d]\r\n", ##__VA_ARGS__,__FILE__,__LINE__);
+#define ERR(x, ...) printf("[ESP8266 : ERR]"x" \t[%s,%d]\r\n", ##__VA_ARGS__,__FILE__,__LINE__);
+#define INFO(x, ...) printf("[ESP8266 : INFO]"x" \t[%s,%d]\r\n", ##__VA_ARGS__,__FILE__,__LINE__);
+#ifndef ESP8266_ECHO
+#define ESP8266_ECHO 1
+#endif
+#else
+#define DBG(x, ...)
+#define WARN(x, ...)
+#define ERR(x, ...)
+#define INFO(x, ...)
+#endif
+
+
+ESP8266 *ESP8266::_inst;
+
+ESP8266::ESP8266(PinName tx, PinName rx, PinName reset, int baud, int timeout) :
+ _serial(tx, rx), _reset_pin(reset) {
+ INFO("Initializing ESP8266 object");
+
+ _baud = baud;
+ _timeout = timeout;
+
+ _serial.baud(_baud);
+
+ _inst = this;
+}
+
+bool ESP8266::reset() {
+ _reset_pin = 0;
+ wait_us(20);
+ _reset_pin = 1;
+
+ // Send reboot command in case reset is not connected
+ return command("\x03\r\n" "node.restart()") && execute();
+}
+
+bool ESP8266::init() {
+ // Reset device to clear state
+ return reset();
+}
+
+bool ESP8266::connect(const char *ssid, const char *phrase) {
+ // Configure as station with passed ssid and passphrase
+ if (!(command("wifi.setmode(wifi.STATION);") &&
+ command("wifi.sta.config('") &&
+ command(ssid) &&
+ command("','") &&
+ command(phrase) &&
+ command("')") &&
+ execute()))
+ return false;
+
+ // Wait for an IP address
+ // TODO WISHLIST make this a seperate check so it can run asynch?
+ Timer timer;
+ timer.start();
+
+ while (true) {
+ int ip_len = 15;
+
+ if (!(command("ip=wifi.sta.getip();") &&
+ command("print(ip)") &&
+ execute(_ip, &ip_len)))
+ return false;
+
+ _ip[ip_len] = 0;
+
+ if (strcmp(_ip, "nil") != 0)
+ return true;
+
+ if (timer.read_ms() > _timeout)
+ return false;
+ }
+}
+
+bool ESP8266::disconnect() {
+ int ip_len = 15;
+
+ if (!(command("wifi.sta.disconnect();") &&
+ command("ip=wifi.sta.getip();") &&
+ command("print(ip)") &&
+ execute(_ip, &ip_len)))
+ return false;
+
+ _ip[ip_len] = 0;
+
+ return (strcmp(_ip, "nil") == 0);
+}
+
+bool ESP8266::is_connected() {
+ return (strcmp(_ip, "nil") != 0);
+}
+
+bool ESP8266::open(bool type, char* ip, int port, int id) {
+ // Create the actual connection
+ if (!(command("c=net.createConnection(") &&
+ command(type ? "net.TCP" : "net.UDP") &&
+ command(")") &&
+ execute()))
+ return false;
+
+ // Setup handlers for connecting and disconnecting
+ if (!(command("cc=nil;") &&
+ command("c:on('connection',function() cc=true end);") &&
+ command("c:on('disconnection',function() cc=false end)") &&
+ execute()))
+ return false;
+
+ // Setup functions for sending and recieving characters on the esp side
+ if (!(command("cm='';") &&
+ command("function cs(n) c:send(n) end;") &&
+ command("function cr(n) print(cm:sub(1,n)); cm=cm:sub(n+1,-1) end;") &&
+ command("function ca() print(#cm) end;") &&
+ command("c:on('receive',function(c,n) cm=cm..n end)") &&
+ execute()))
+ return false;
+
+ // Convert port to a string
+ char port_buf[16];
+ sprintf(port_buf, "%d", port);
+
+ // Connect to the ip address
+ if (!(command("c:connect(") &&
+ command(port_buf) &&
+ command(",'") &&
+ command(ip) &&
+ command("')") &&
+ execute()))
+ return false;
+
+ // Wait for it to connect
+ // TODO WISHLIST make this a seperate check so it can run asynch?
+ Timer timer;
+ timer.start();
+
+ while (true) {
+ char con_buf[5];
+ int con_len = 5;
+
+ if (!(command("print(cc)") && execute(con_buf, &con_len)))
+ return false;
+
+ if (memcmp(con_buf, "true", con_len) == 0)
+ return true;
+ else if (memcmp(con_buf, "false", con_len) == 0)
+ return false;
+
+ if (timer.read_ms() > _timeout)
+ return false;
+ }
+}
+
+bool ESP8266::close() {
+ return command("c:close();" "c=nil") && execute();
+}
+
+bool ESP8266::send(const char *buffer, int len) {
+ if (!(command("cs('") &&
+ payload(buffer, len) &&
+ command("')") &&
+ execute()))
+ return false;
+
+ return true;
+}
+
+bool ESP8266::recv(char *buffer, int *len) {
+ char len_buf[16];
+ sprintf(len_buf, "%d", *len);
+
+ if (!(command("cr(") &&
+ command(len_buf) &&
+ command(")") &&
+ execute(buffer, len)))
+ return false;
+
+ return true;
+}
+
+int ESP8266::putc(char c) {
+ char buffer[1] = { c };
+
+ return send(buffer, 1) ? 0 : -1;
+}
+
+int ESP8266::getc() {
+ char buffer[1];
+
+ while (true) {
+ int len = 1;
+
+ if (!recv(buffer, &len))
+ return -1;
+
+ if (len > 0)
+ break;
+ }
+
+ return buffer[0];
+}
+
+int ESP8266::writeable() {
+ // Always succeeds since message can be temporarily stored on the esp
+ return 1;
+}
+
+int ESP8266::readable() {
+ char count_buf[16];
+ int count_len = 15;
+
+ if (!(command("ca()") && execute(count_buf, &count_len)))
+ return false;
+
+ count_buf[count_len] = 0;
+ return atoi(count_buf);
+}
+
+const char *ESP8266::getIPAddress() {
+ if (strcmp(_ip, "nil") != 0)
+ return _ip;
+ else
+ return 0;
+}
+
+bool ESP8266::getHostByName(const char *host, char *ip) {
+ if (!(command("dh='") &&
+ command(host) &&
+ command("';") &&
+ command("dn=nil;") &&
+ command("if dh:match('%d+.%d+.%d+.%d+') then ") &&
+ command("dn=dh ") &&
+ command("else ") &&
+ command("dc=net.createConnection(net.TCP);") &&
+ command("dc:dns(dh,function(dc,ip) dn=ip end);") &&
+ command("dc=nil ") &&
+ command("end") &&
+ execute()))
+ return false;
+
+ // Wait for a response
+ Timer timer;
+ timer.start();
+
+ while (true) {
+ int ip_len = 15;
+
+ if (!(command("print(dn)") && execute(ip, &ip_len)))
+ return false;
+
+ ip[ip_len] = 0;
+
+ if (strcmp(ip, "nil") != 0)
+ return true;
+
+ if (timer.read_ms() > _timeout)
+ return false;
+ }
+}
+
+int ESP8266::serialgetc() {
+ Timer timer;
+ timer.start();
+
+ while (true) {
+ if (_serial.readable()) {
+ char c = _serial.getc();
+#ifdef ESP8266_ECHO
+ printf("%c", c);
+#endif
+ return c;
+ }
+
+ if (timer.read_ms() > _timeout)
+ return -1;
+ }
+}
+
+int ESP8266::serialputc(char c) {
+ Timer timer;
+ timer.start();
+
+ while (true) {
+ if (_serial.writeable())
+ return _serial.putc(c);
+
+ if (timer.read_ms() > _timeout)
+ return -1;
+ }
+}
+
+bool ESP8266::discardEcho() {
+ while (true) {
+ int c = serialgetc();
+
+ if (c < 0)
+ return false;
+ else if (c == '>')
+ return true;
+ }
+}
+
+bool ESP8266::command(const char *cmd) {
+ DBG("command sent:\t %s", cmd);
+
+ for (int i = 0; cmd[i]; i++) {
+ if (serialputc(cmd[i]) < 0)
+ return false;
+ }
+
+ return true;
+}
+
+bool ESP8266::payload(const char *data, int len) {
+ for (int i = 0; i < len; i++) {
+ int a = data[i] / 100;
+ int b = (data[i] - a*100) / 10;
+ int c = (data[i] - a*100 - b*10);
+
+ if (serialputc('\\') < 0 ||
+ serialputc(a + '0') < 0 ||
+ serialputc(b + '0') < 0 ||
+ serialputc(c + '0') < 0)
+ return false;
+ }
+
+ return true;
+}
+
+bool ESP8266::execute(char *resp_buf, int *resp_len) {
+ // Finish command with a newline
+ if (serialputc('\r') < 0 || serialputc('\n') < 0)
+ return false;
+
+ // Drop echoed string
+ while (true) {
+ int c = serialgetc();
+
+ if (c < 0)
+ return false;
+ else if (c == '\n')
+ break;
+ }
+
+ // Read in response if any
+ if (resp_buf && resp_len) {
+ int i;
+
+ for (i = 0; i < *resp_len; i++) {
+ int c = serialgetc();
+
+ if (c < 0)
+ return false;
+
+ if (c == '\r') {
+ *resp_len = i;
+ break;
+ }
+
+ resp_buf[i] = c;
+ }
+
+ DBG("command response:\t %.*s", *resp_len, resp_buf);
+ }
+
+ // Flush to next prompt
+ return discardEcho();
+}
--- a/ESP8266/ESP8266.h Fri May 01 18:29:38 2015 +0000
+++ b/ESP8266/ESP8266.h Wed Jun 03 21:44:20 2015 +0000
@@ -1,212 +1,238 @@
-/* Copyright (C) 2012 mbed.org, MIT License
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy of this software
- * and associated documentation files (the "Software"), to deal in the Software without restriction,
- * including without limitation the rights to use, copy, modify, merge, publish, distribute,
- * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all copies or
- * substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
- * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
- * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- *
- * @section DESCRIPTION
- *
- * ESP8266 serial wifi module
- *
- * Datasheet:
- *
- * http://www.electrodragon.com/w/Wi07c
- */
-
-#ifndef ESP8266_H
-#define ESP8266_H
-
-#include "mbed.h"
-#include "CBuffer.h"
-
-#define DEFAULT_WAIT_RESP_TIMEOUT 500
-#define ESP_TCP_TYPE 1
-#define ESP_UDP_TYPE 0
-
-/**
- * The ESP8266 class
- */
-class ESP8266
-{
-
-public:
- /**
- * Constructor
- *
- * @param tx mbed pin to use for tx line of Serial interface
- * @param rx mbed pin to use for rx line of Serial interface
- * @param reset reset pin of the wifi module ()
- * @param ssid ssid of the network
- * @param phrase WEP, WPA or WPA2 key
- * @param baud the baudrate of the serial connection
- */
- ESP8266( PinName tx, PinName rx, PinName reset, const char * ssid, const char * phrase, uint32_t baud );
-
- /**
- * Connect the wifi module to the ssid contained in the constructor.
- *
- * @return true if connected, false otherwise
- */
- bool join();
-
- /**
- * Same as Join: connect to the ssid and get DHCP settings
- * @return true if successful
- */
- bool connect();
-
- /**
- * Check connection to the access point
- * @return true if successful
- */
- bool is_connected();
-
- /**
- * Disconnect the ESP8266 module from the access point
- *
- * @return true if successful
- */
- bool disconnect();
-
- /*
- * Start up a UDP or TCP Connection
- * @param type 0 for UDP, 1 for TCP
- * @param ip A string that contains the IP, no quotes
- * @param port Numerical port number to connect to
- * @param id number between 0-4, if defined it denotes ID to use in multimode (Default to Single connection mode with -1)
- * @return true if sucessful, 0 if fail
- */
- bool start(bool type, char* ip, int port, int id = -1);
-
- /*
- * Legacy Start for UDP only connection in transparent mode
- * @param ip A string that contains the IP, no quotes
- * @param port Numerical port number to connect to
- */
- bool startUDP(char* ip, int port);
-
- /**
- * Close a connection
- *
- * @return true if successful
- */
- bool close();
-
- /**
- * Return the IP address
- * @return IP address as a string
- */
- char* getIPAddress();
-
- /**
- * Return the IP address from host name
- * @return true on success, false on failure
- */
- bool gethostbyname(const char * host, char * ip);
-
- /**
- * Reset the wifi module
- */
- void reset();
-
- /**
- * Reboot the wifi module
- */
- bool reboot();
-
- /**
- * Check if characters are available
- *
- * @return number of available characters
- */
- int readable();
-
- /**
- * Check if characters are available
- *
- * @return number of available characters
- */
- int writeable();
-
- /**
- * Read a character
- *
- * @return the character read
- */
- char getc();
-
- /**
- * Write a character
- *
- * @param the character which will be written
- */
- int putc(char c);
-
- /**
- * Flush the buffer
- */
- void flush();
-
- /**
- * Send a command to the wifi module. Check if the module is in command mode. If not enter in command mode
- *
- * @param str string to be sent
- * @param ACK string which must be acknowledge by the wifi module. If ACK == NULL, no string has to be acknoledged. (default: "NO")
- * @param res this field will contain the response from the wifi module, result of a command sent. This field is available only if ACK = "NO" AND res != NULL (default: NULL)
- *
- * @return true if successful
- */
- bool sendCommand(const char * cmd, const char * ack = NULL, char * res = NULL, int timeout = DEFAULT_WAIT_RESP_TIMEOUT);
-
- /**
- * Send a string to the wifi module by serial port. This function desactivates the user interrupt handler when a character is received to analyze the response from the wifi module.
- * Useful to send a command to the module and wait a response.
- *
- *
- * @param str string to be sent
- * @param len string length
- * @param ACK string which must be acknowledge by the wifi module. If ACK == NULL, no string has to be acknoledged. (default: "NO")
- * @param res this field will contain the response from the wifi module, result of a command sent. This field is available only if ACK = "NO" AND res != NULL (default: NULL)
- *
- * @return true if ACK has been found in the response from the wifi module. False otherwise or if there is no response in 5s.
- */
- int send(const char * buf, int len);
-
- static ESP8266 * getInstance() {
- return inst;
- };
-
-protected:
- RawSerial wifi;
- DigitalOut reset_pin;
- char phrase[30];
- char ssid[30];
- char ipString[20];
- CircBuffer<char> buf_ESP8266;
-
- static ESP8266 * inst;
-
- void attach_rx(bool null);
- void handler_rx(void);
-
-
- typedef struct STATE {
- bool associated;
- bool cmdMode;
- } State;
-
- State state;
-};
-
+/* Copyright (C) 2012 mbed.org, MIT License
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this software
+ * and associated documentation files (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge, publish, distribute,
+ * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies or
+ * substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
+ * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * @section DESCRIPTION
+ *
+ * ESP8266 serial wifi module
+ *
+ * Datasheet:
+ *
+ * http://www.electrodragon.com/w/Wi07c
+ */
+
+#ifndef ESP8266_H
+#define ESP8266_H
+
+#include "mbed.h"
+#include "CBuffer.h"
+#include "BufferedSerial.h"
+
+#define ESP_TCP_TYPE 1
+#define ESP_UDP_TYPE 0
+
+/**
+ * The ESP8266 class
+ */
+class ESP8266
+{
+
+public:
+ /**
+ * Constructor
+ *
+ * @param tx mbed pin to use for tx line of Serial interface
+ * @param rx mbed pin to use for rx line of Serial interface
+ * @param reset reset pin of the wifi module ()
+ * @param baud the baudrate of the serial connection
+ * @param timeout the timeout of the serial connection
+ */
+ ESP8266(PinName tx, PinName rx, PinName reset, int baud = 9600, int timeout = 3000);
+
+ /**
+ * Initialize the wifi hardware
+ *
+ * @return true if successful
+ */
+ bool init();
+
+ /**
+ * Connect the wifi module to the specified ssid.
+ *
+ * @param ssid ssid of the network
+ * @param phrase WEP, WPA or WPA2 key
+ * @return true if successful
+ */
+ bool connect(const char *ssid, const char *phrase);
+
+ /**
+ * Check connection to the access point
+ * @return true if successful
+ */
+ bool is_connected();
+
+ /**
+ * Disconnect the ESP8266 module from the access point
+ *
+ * @return true if successful
+ */
+ bool disconnect();
+
+ /*
+ * Start up a UDP or TCP Connection
+ *
+ * @param type 0 for UDP, 1 for TCP
+ * @param ip A string that contains the IP, no quotes
+ * @param port Numerical port number to connect to
+ * @param id number between 0-4, if defined it denotes ID to use in multimode (Default to Single connection mode with -1)
+ * @return true if sucessful, 0 if fail
+ */
+ bool open(bool type, char* ip, int port, int id = -1);
+
+ /**
+ * Close a connection
+ *
+ * @return true if successful
+ */
+ bool close();
+
+ /**
+ * Read a character or block
+ *
+ * @return the character read or -1 on error
+ */
+ int getc();
+
+ /**
+ * Write a character
+ *
+ * @param the character which will be written
+ * @return -1 on error
+ */
+ int putc(char c);
+
+ /**
+ * Write a string
+ *
+ * @param buffer the buffer that will be written
+ * @param len the length of the buffer
+ * @return true on success
+ */
+ bool send(const char *buffer, int len);
+
+ /**
+ * Read a string without blocking
+ *
+ * @param buffer the buffer that will be written
+ * @param len the length of the buffer, is replaced by read length
+ * @return true on success
+ */
+ bool recv(char *buffer, int *len);
+
+ /**
+ * Check if wifi is writable
+ *
+ * @return 1 if wifi is writable
+ */
+ int writeable();
+
+ /**
+ * Check if wifi is readable
+ *
+ * @return number of characters available
+ */
+ int readable();
+
+ /**
+ * Return the IP address
+ * @return IP address as a string
+ */
+ const char *getIPAddress();
+
+ /**
+ * Return the IP address from host name
+ * @return true on success, false on failure
+ */
+ bool getHostByName(const char *host, char *ip);
+
+ /**
+ * Reset the wifi module
+ */
+ bool reset();
+
+ /**
+ * Obtains the current instance of the ESP8266
+ */
+ static ESP8266 *getInstance() {
+ return _inst;
+ };
+
+private:
+ /**
+ * Read a character with timeout
+ *
+ * @return the character read or -1 on timeout
+ */
+ int serialgetc();
+
+ /**
+ * Write a character
+ *
+ * @param the character which will be written
+ * @return -1 on timeout
+ */
+ int serialputc(char c);
+
+ /**
+ * Discards echoed characters
+ *
+ * @return true if successful
+ */
+ bool discardEcho();
+
+ /**
+ * Send part of a command to the wifi module.
+ *
+ * @param cmd string to be sent
+ * @param len optional length of cmd
+ * @param sanitize flag indicating if cmd is actually payload and needs to be escaped
+ * @return true if successful
+ */
+ bool command(const char *cmd);
+
+ /**
+ * Sanitizes and sends payload to wifi module
+ *
+ * @param data data to send
+ * @param len length of data
+ * @return true if successful
+ */
+ bool payload(const char *data, int len);
+
+ /**
+ * Execute the command sent by command
+ *
+ * @param resp_buf pointer to buffer to store response from the wifi module
+ * @param resp_len len of buffer to store response from the wifi module, is replaced by read length
+ * @return true if successful
+ */
+ bool execute(char *resp_buffer = 0, int *resp_len = 0);
+
+protected:
+ BufferedSerial _serial;
+ DigitalOut _reset_pin;
+
+ static ESP8266 * _inst;
+
+ // TODO WISHLIST: ipv6?
+ // this requires nodemcu support
+ char _ip[16];
+
+ int _baud;
+ int _timeout;
+};
+
#endif
\ No newline at end of file
--- a/ESP8266Interface.cpp Fri May 01 18:29:38 2015 +0000
+++ b/ESP8266Interface.cpp Wed Jun 03 21:44:20 2015 +0000
@@ -1,28 +1,22 @@
#include "ESP8266Interface.h"
-ESP8266Interface::ESP8266Interface( PinName tx, PinName rx, PinName reset,
- const char * ssid, const char * phrase, uint32_t baud ) :
- ESP8266(tx, rx, reset, ssid, phrase, baud )
-{
+ESP8266Interface::ESP8266Interface(PinName tx, PinName rx, PinName reset,
+ int baud, int timeout) :
+ ESP8266(tx, rx, reset, baud, timeout) {
}
-int ESP8266Interface::init()
-{
- ESP8266::reset();
- return 0;
+bool ESP8266Interface::init() {
+ return ESP8266::init();
}
-bool ESP8266Interface::connect()
-{
- return ESP8266::connect();
+bool ESP8266Interface::connect(const char * ssid, const char * phrase) {
+ return ESP8266::connect(ssid, phrase);
}
-int ESP8266Interface::disconnect()
-{
+int ESP8266Interface::disconnect() {
return ESP8266::disconnect();
}
-char * ESP8266Interface::getIPAddress()
-{
+const char *ESP8266Interface::getIPAddress() {
return ESP8266::getIPAddress();
}
\ No newline at end of file
--- a/ESP8266Interface.h Fri May 01 18:29:38 2015 +0000
+++ b/ESP8266Interface.h Wed Jun 03 21:44:20 2015 +0000
@@ -32,40 +32,42 @@
/**
* Constructor
*
- * \param tx mbed pin to use for tx line of Serial interface
- * \param rx mbed pin to use for rx line of Serial interface
- * \param reset reset pin of the wifi module ()
- * \param ssid ssid of the network
- * \param phrase WEP or WPA key
- * \param baud the baudrate of the serial connection (defaults to 115200, diff revs of the firmware use diff baud rates
+ * @param tx mbed pin to use for tx line of Serial interface
+ * @param rx mbed pin to use for rx line of Serial interface
+ * @param reset reset pin of the wifi module ()
+ * @param baud the baudrate of the serial connection
+ * @param timeout the timeout of the serial connection
*/
- ESP8266Interface(PinName tx, PinName rx, PinName reset, const char * ssid, const char * phrase, uint32_t baud = 115200 );
-
- /** Initialize the interface with DHCP.
- * Initialize the interface and configure it to use DHCP (no connection at this point).
- * \return 0 on success, a negative number on failure
- */
- int init(); //With DHCP
+ ESP8266Interface(PinName tx, PinName rx, PinName reset, int baud = 9600, int timeout = 3000);
+
+ /**
+ * Initialize the wifi hardware
+ *
+ * @return true if successful
+ */
+ bool init();
- /** Connect
- * Bring the interface up, start DHCP if needed.
- * \return 0 on success, a negative number on failure
- */
- bool connect();
+ /**
+ * Connect the wifi module to the specified ssid.
+ *
+ * @param ssid ssid of the network
+ * @param phrase WEP, WPA or WPA2 key
+ * @return true if successful
+ */
+ bool connect(const char *ssid, const char *phrase);
- /** Disconnect
- * Bring the interface down
- * \return 0 on success, a negative number on failure
- */
- int disconnect();
+ /**
+ * Disconnect the ESP8266 module from the access point
+ *
+ * @return true if successful
+ */
+ int disconnect();
- /** Get IP address
- *
- * \return ip address
- */
- char* getIPAddress();
-
-private:
+ /** Get IP address
+ *
+ * @return Either a pointer to the internally stored IP address or null if not connected
+ */
+ const char *getIPAddress();
};
#include "UDPSocket.h"
--- a/Socket/Endpoint.cpp Fri May 01 18:29:38 2015 +0000
+++ b/Socket/Endpoint.cpp Wed Jun 03 21:44:20 2015 +0000
@@ -42,7 +42,7 @@
int Endpoint::set_address(const char* host, const int port)
{
//Resolve DNS address or populate hard-coded IP address
- if(ESP8266->gethostbyname(host, _ipAddress)) {
+ if(ESP8266->getHostByName(host, _ipAddress)) {
_port = port;
return 0;
} else {
--- a/Socket/TCPSocketConnection.cpp Fri May 01 18:29:38 2015 +0000
+++ b/Socket/TCPSocketConnection.cpp Wed Jun 03 21:44:20 2015 +0000
@@ -51,7 +51,7 @@
// return -1;
// }
// _is_connected = true;
- _is_connected = ESP8266->start(ESP_TCP_TYPE,_ipAddress,_port);
+ _is_connected = ESP8266->open(ESP_TCP_TYPE,_ipAddress,_port);
if(_is_connected) { //success
return 0;
} else { // fail
@@ -71,16 +71,14 @@
return -1;
}
Timer tmr;
- int idx = 0;
tmr.start();
while ((tmr.read_ms() < _timeout) || _blocking) {
- idx += wifi->send(data, length);
-
- if (idx == length)
- return idx;
+ if (wifi->send(data, length))
+ return length;
}
- return (idx == 0) ? -1 : idx;
+
+ return -1;
//return wifi->send(data,length);
//
@@ -211,7 +209,6 @@
// _is_connected = (n != 0);
//
// return n;
-
}
// -1 if unsuccessful, else number of bytes received
@@ -240,5 +237,8 @@
// }
// }
// return readLen;
- return 0;
+ if (!wifi->recv(data, &length))
+ return -1;
+
+ return length;
}
--- a/Socket/UDPSocket.cpp Fri May 01 18:29:38 2015 +0000
+++ b/Socket/UDPSocket.cpp Wed Jun 03 21:44:20 2015 +0000
@@ -53,7 +53,7 @@
// initialize transparent mode if not already done
if(!endpoint_configured) {
// initialize UDP (default id of -1 means transparent mode)
- if(!wifi->start(ESP_UDP_TYPE, remote._ipAddress, remote._port, remote._id)) {
+ if(!wifi->open(ESP_UDP_TYPE, remote._ipAddress, remote._port, remote._id)) {
return(-1);
}
endpoint_configured = true;
