Class library for using the ESP8266 wifi module.
Revision 0:30dd9c0f7559, committed 2018-06-11
- Comitter:
- grantphillips
- Date:
- Mon Jun 11 17:56:55 2018 +0000
- Commit message:
- V1.0
Changed in this revision
ESP8266.cpp | Show annotated file Show diff for this revision Revisions of this file |
ESP8266.h | Show annotated file Show diff for this revision Revisions of this file |
diff -r 000000000000 -r 30dd9c0f7559 ESP8266.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ESP8266.cpp Mon Jun 11 17:56:55 2018 +0000 @@ -0,0 +1,443 @@ +#include "ESP8266.h" +#include "mbed.h" + +/***************************** Public functions ******************************/ +ESP8266::ESP8266(PinName Tx, PinName Rx, PinName Rst) : esp(Tx, Rx), _rst(Rst) { + esp.baud(115200); + mDEBUG = false; +} + +bool ESP8266::startup(uint8_t mode) { + + if(mode < 1 || mode > 3) //only 3 valid modes + return false; + _rst=0; + wait(1.0); + _rst=1; + wait(1.0); + if(!kick()) //check if connected + return(false); + if(!reset()) //reset ESP8266 + return(false); + if(!setWiFiMode(mode)) //set the WiFi mode + return(false); + if(!setMux(true)) //set to multiple connections + return false; + + rxtemp_idx=0; + //rxmsg_idx= 0; + new_rxmsg = false; + rxpass1=false, rxpass2=false, rxpass3=false; + + return true; +} + +void ESP8266::getVersion(char* version) { + string ver; + + eATGMR(ver); + strcpy(version, ver.c_str()); +} + +void ESP8266::getAPList(char* list) { + string lst; + + eATCWLAP(lst); + strcpy(list, lst.c_str()); +} + +bool ESP8266::setSoftAPParam(string ssid, string pwd, uint8_t chl, uint8_t ecn) { + return sATCWSAP(ssid, pwd, chl, ecn); +} + +bool ESP8266::DHCP(bool enabled, int mode) { + return sATCWDHCP(enabled, mode); +} + +bool ESP8266::joinAP(string ssid, string pwd) { + return sATCWJAP(ssid, pwd); +} + +void ESP8266::getLocalIP(char* LocalIP) { + string lst; + + eATCIFSR(lst); + strcpy(LocalIP, lst.c_str()); +} + +bool ESP8266::setLocalIP(string LocalIP) { + return sATCIPSTA(LocalIP); +} + +bool ESP8266::setSoftAPIP(string LocalIP) { + return sATCIPAP(LocalIP); +} + +bool ESP8266::TCPServerStart(uint32_t port) { + if (sATCIPSERVER(1, port)) { + esp.attach(this,&ESP8266::RxInterrupt); + return true; + } + return false; +} + +bool ESP8266::TCPPacketReceived(void) { + return new_rxmsg; +} + +void ESP8266::TCPPacketRead(uint8_t *ID, uint32_t *LEN, char DATA[]) { + *ID = packetID; + *LEN = packetLen; + strcpy(DATA, packetData); + new_rxmsg=false; +} + +bool ESP8266::TCPPacketSend(uint8_t ID, uint32_t LEN, char DATA[]) { + bool ret; + + esp.attach(NULL); + ret=sATCIPSENDMultiple(ID, DATA, LEN); + esp.attach(this,&ESP8266::RxInterrupt); + return ret; +} + +/***************************** Private functions *****************************/ +bool ESP8266::kick(void) { + return eAT(); +} + +bool ESP8266::reset(void) { + unsigned long start; + if (eATRST()) { + wait_ms(2000); + t.start(); + start = t.read_ms(); + while (t.read_ms() - start < 3000) { + if (eAT()) { + wait_ms(1500); /* Waiting for stable */ + return true; + } + wait_ms(100); + } + } + return false; +} + +bool ESP8266::setWiFiMode(uint8_t mode) { + switch(mode) { + case 1: { + if (sATCWMODE(1)) + return true; + else + return false; + } + case 2: { + if (sATCWMODE(2)) + return true; + else + return false; + } + case 3: { + if (sATCWMODE(3)) + return true; + else + return false; + } + default: return false; + } +} + +bool ESP8266::setMux(bool onoff) { + if(onoff) + return sATCIPMUX(1); + else + return sATCIPMUX(0); +} + +bool ESP8266::recvFind(string target, uint32_t timeout) { + string data_tmp; + data_tmp = recvString(target, timeout); + if (data_tmp.find(target) != std::string::npos) { + return true; + } + return false; +} + +string ESP8266::recvString(string target, uint32_t timeout) { + string data; + char a; + t.start(); + unsigned long start = t.read_ms(); + while (t.read_ms() - start < timeout) { + while(esp.readable() > 0) { + a = esp.getc(); + data += a; + } + if (data.find(target) != std::string::npos) { + break; + } + } + t.stop(); + + return data; +} + +string ESP8266::recvString(string target1, string target2, uint32_t timeout) { + string data; + char a; + t.start(); + unsigned long start = t.read_ms(); + while (t.read_ms() - start < timeout) { + while(esp.readable() > 0) { + a = esp.getc(); + data += a; + } + if (data.find(target1) != std::string::npos) { + break; + } else if (data.find(target2) != std::string::npos) { + break; + } + } + t.stop(); + + return data; +} + +string ESP8266::recvString(string target1, string target2, string target3, uint32_t timeout) { + string data; + char a; + t.start(); + unsigned long start = t.read_ms(); + while (t.read_ms() - start < timeout) { + while(esp.readable() > 0) { + a = esp.getc(); + data += a; + } + if (data.find(target1) != std::string::npos) { + break; + } else if (data.find(target2) != std::string::npos) { + break; + } else if (data.find(target3) != std::string::npos) { + break; + } + } + t.stop(); + + return data; +} + +bool ESP8266::recvFindAndFilter(string target, string begin, string end, string &data, uint32_t timeout) { + string data_tmp; + data_tmp = recvString(target, timeout); + if (data_tmp.find(target) != std::string::npos) { + int32_t index1 = data_tmp.find(begin); + int32_t index2 = data_tmp.find(end); + if (index1 != std::string::npos && index2 != std::string::npos) { + index1 += begin.length(); + data = data_tmp.substr(index1, index2-index1); + return true; + } + } + data = ""; + return false; +} + + + + +/************************ Private AT Command Functions ***********************/ +bool ESP8266::eAT(void) { + esp.printf("AT\r\n"); + return recvFind("OK", 2000); +} + +bool ESP8266::eATRST(void) { + esp.printf("AT+RST\r\n"); + return recvFind("OK", 2000); +} + +bool ESP8266::eATGMR(string &version) { + esp.printf("AT+GMR\r\n"); + return recvFindAndFilter("OK", "\r\r\n", "\r\nSDK", version); +} + +bool ESP8266::sATCWMODE(uint8_t mode) { + string data; + esp.printf("AT+CWMODE=%d\r\n", mode); + + data = recvString("OK", "no change"); + if (data.find("OK") != std::string::npos || data.find("no change") != std::string::npos) { + return true; + } + return false; +} + +bool ESP8266::sATCIPMUX(uint8_t mode) +{ + string data; + esp.printf("AT+CIPMUX=%d\r\n",mode); + + data = recvString("OK", "Link is builded"); + if (data.find("OK") != std::string::npos) { + return true; + } + return false; +} + +bool ESP8266::eATCWLAP(string &list) { + string data; + esp.printf("AT+CWLAP\r\n"); + return recvFindAndFilter("OK", "\r\r\n", "\r\n\r\nOK", list, 10000); +} + +bool ESP8266::sATCWJAP(string ssid, string pwd) { + string data; + esp.printf("AT+CWJAP=\"%s\",\"%s\"\r\n", ssid.c_str(), pwd.c_str()); + + data = recvString("OK", "FAIL", 15000); + if (data.find("OK") != std::string::npos) { + return true; + } + return false; +} + +bool ESP8266::eATCIFSR(string &list) { + esp.printf("AT+CIFSR\r\n"); + return recvFindAndFilter("OK", "\r\r\n", "\r\n\r\nOK", list); +} + +bool ESP8266::sATCIPSERVER(uint8_t mode, uint32_t port) { + string data; + if (mode) { + esp.printf("AT+CIPSERVER=1,%d\r\n", port); + + data = recvString("OK", "no change"); + if (data.find("OK") != std::string::npos || data.find("no change") != std::string::npos) { + return true; + } + return false; + } else { + esp.printf("AT+CIPSERVER=0\r\n"); + return recvFind("\r\r\n"); + } +} + +bool ESP8266::sATCIPSENDMultiple(uint8_t mux_id, char buffer[], uint32_t len) { + //esp.flush(); + esp.printf("AT+CIPSEND=%d,%d\r\n", mux_id, len); + if (recvFind(">", 5000)) { + //esp.flush(); + for (uint32_t i = 0; i < len; i++) { + esp.printf("%c",buffer[i]); + } + return recvFind("SEND OK", 10000); + } + return false; +} + +bool ESP8266::sATCWSAP(string ssid, string pwd, uint8_t chl, uint8_t ecn) +{ + string data; + esp.printf("AT+CWSAP=\"%s\",\"%s\",%d,%d\r\n", ssid.c_str(), pwd.c_str(), chl, ecn); + + data = recvString("OK", "ERROR", 5000); + if (data.find("OK") != std::string::npos) { + return true; + } + return false; +} + +bool ESP8266::sATCWDHCP(bool enabled, int mode) { + if(mode < 0 || mode > 2) { + return false; + } + esp.printf("AT+CWDHCP=%d,%d\r\n", enabled?1:0, mode); + return recvFind("OK", 2000); +} + +bool ESP8266::sATCIPSTA(string ip) { + esp.printf("AT+CIPSTA=\"%s\"\r\n", ip.c_str()); + return recvFind("OK", 2000); +} + +bool ESP8266::sATCIPAP(string ip) { + esp.printf("AT+CIPAP=\"%s\"\r\n", ip.c_str()); + return recvFind("OK", 2000); +} + +/************************* Private Callback Functions *************************/ +void ESP8266::RxInterrupt(void) +{ + char c; + + c = esp.getc(); //read the incoming character + if(c == '\n') { + //rxmsg_idx = 0; + rxpass1=false; + rxpass2=false; + rxpass3=false; + rxtemp_idx=0; + //new_rxmsg=false; + } + + if(rxpass1 && rxpass2 && rxpass3) { + if(rxtemp_idx < packetLen-1) { + rxtemp[rxtemp_idx] = c; + rxtemp_idx++; + } + else { + rxtemp[rxtemp_idx] = c; + rxtemp[rxtemp_idx+1] = '\0'; + strcpy(packetData, rxtemp); + //rxmsg_idx = 0; + rxpass1=false; + rxpass2=false; + rxpass3=false; + rxtemp_idx=0; + new_rxmsg=true; + } + } + else if(rxpass1 && rxpass2) { + if(c != ':') { + rxtemp[rxtemp_idx] = c; + rxtemp_idx++; + } + else { + rxtemp[rxtemp_idx] = '\0'; + packetLen= atoi(rxtemp); + rxtemp_idx=0; + rxpass3=true; + } + } + else if(rxpass1) { + if(c != ',') { + rxtemp[rxtemp_idx] = c; + rxtemp_idx++; + } + else { + rxtemp[rxtemp_idx] = '\0'; + packetID = atoi(rxtemp); + rxtemp_idx=0; + rxpass2=true; + } + } + else { + rxtemp[rxtemp_idx] = c; + rxtemp_idx++; + + if(rxtemp_idx == 6) { + if(rxtemp[1] == '+' && rxtemp[2] == 'I' && rxtemp[3] == 'P' && rxtemp[4] == 'D' && rxtemp[5] == ',') { + rxpass1 = true; + } + } + /* + rxmsg[rxmsg_idx] = c; + rxmsg_idx++; + + if(rxmsg_idx == 6) { + if(rxmsg[1] == '+' && rxmsg[2] == 'I' && rxmsg[3] == 'P' && rxmsg[4] == 'D' && rxmsg[5] == ',') { + rxpass1 = true; + } + }*/ + } +} \ No newline at end of file
diff -r 000000000000 -r 30dd9c0f7559 ESP8266.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ESP8266.h Mon Jun 11 17:56:55 2018 +0000 @@ -0,0 +1,251 @@ +/* ESP8266 Library v1.0 + * Copyright (c) 2017 Grant Phillips + * grant.phillips@nmmu.ac.za + * + * This library was adapted from the WeeESP8266 version by ITEAD STUDIO. + * (https://os.mbed.com/users/itead/code/WeeESP8266/) + * + * 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. + */ + +#ifndef ESP8266_H +#define ESP8266_H + +#include "mbed.h" +#include <string> + +/** Class library for using the ESP8266 wifi module. + */ + +class ESP8266 { + public: + /** Create a ESP8266 object connected to the specified pins. + * @param Tx Pin used to connect to ESP8266's Tx pin + * @param Rx Pin used to connect to ESP8266's Rx pin + */ + ESP8266(PinName Tx, PinName Rx, PinName Rst); + + /** Starts the ESP8266 in a specified mode. + * @param mode The WiFi mode the ESP8266 must be set to (1=Station, 2=SoftAP, 3=Station+SoftAP) + * + * @retval true - succesfull + * @retval false - not succesfull + */ + bool startup(uint8_t mode); + + /** Get the version of AT Command Set from the ESP8266. + * + * @param version String variable where version will be stored. + */ + void getVersion(char* version); + + /** Search available AP list and return it. + * + * @param list String variable where AP list will be stored. + * @note This method will occupy a lot of memeory(hundreds of Bytes to a couple of KBytes). + * Do not call this method unless you must and ensure that your board has enough memory left. + */ + void getAPList(char* list); + + /** Set SoftAP parameters. + * + * @param ssid SSID of SoftAP. + * @param pwd PASSWORD of SoftAP. + * @param chl the channel (1 - 13, default: 7). + * @param ecn the way of encrypstion (0 - OPEN, 1 - WEP, + * 2 - WPA_PSK, 3 - WPA2_PSK, 4 - WPA_WPA2_PSK, default: 4). + * @note This method should not be called when station mode. + */ + bool setSoftAPParam(string ssid, string pwd, uint8_t chl = 7, uint8_t ecn = 4); + + /** Enable/Disable DHCP + * + * @param enabled DHCP enabled when true + * @param mode mode of DHCP 0-softAP, 1-station, 2-both + * @return true only if ESP8266 enables/disables DHCP successfully + */ + bool DHCP(bool enabled, int mode); + + /** Join in AP. + * + * @param ssid SSID of AP to join in. + * @param pwd Password of AP to join in. + * @retval true - success. + * @retval false - failure. + * @note This method will take a couple of seconds. + */ + bool joinAP(string ssid, string pwd); + + /** Get the local IP address of ESP8266. + * + * @param version String variable where version will be stored. + */ + void getLocalIP(char* LocalIP); + + /** Sets the IP Address of the ESP8266 Station. + * + * @param LocalIP The IP Address of the ESP8266 Station + * @retval true - success. + * @retval false - failure. + */ + bool setLocalIP(string LocalIP); + + /** Sets the IP Address of the ESP8266 SoftAP. + * + * @param LocalIP The IP Address of the ESP8266 SoftAP + * @retval true - success. + * @retval false - failure. + */ + bool setSoftAPIP(string LocalIP); + + /** Start TCP Server(Only in multiple mode). + * + * After started, only methods TCPPacketSend, TCPPacketRead, and TCPPacketArrived can be used. + * Once TCPServerStop is called, all other methods can be used again. + * + * @param port The port number to listen on (default: 333). + * @retval true - success. + * @retval false - failure. + */ + bool TCPServerStart(uint32_t port = 333); + + /** Indicates whether a new packet has arrived from a connected client. + * + * @retval true - A new packet has arrived. + * @retval false - No new packets have arrived. + */ + bool TCPPacketReceived(void); + + /** Reads the current received TCP packet + * + * @param ID Pointer for the ID of client for the new received packet. + * @param LEN Pointer for the length of the new received packet. + * @param DATA String pointer for the string of the new received packet. + */ + void TCPPacketRead(uint8_t *ID, uint32_t *LEN, char DATA[]); + + /** Send a data packet using TCP to a specified client. + * + * @param ID The identifier of client to send the packet to (available value: 0 - 4). + * @param LEN The length of packet to send. + * @param DATA The buffer of data to send. + * @retval true - success. + * @retval false - failure. + */ + bool TCPPacketSend(uint8_t ID, uint32_t LEN, char DATA[]); + + + private: + Serial esp; //Serial object for connecting to ESP8266 + DigitalOut _rst; + bool mDEBUG; + Timer t; + + char packetData[1000]; + int packetID; + int packetLen; + char rxtemp[1000]; + int rxtemp_idx; + bool new_rxmsg; //flag to indicate if a new complete message was received + bool rxpass1, rxpass2, rxpass3; + void RxInterrupt(void); //Interrupt to receive data when TCP server is set + + bool eAT(void); + bool eATRST(void); + bool eATGMR(string &version); + bool sATCWMODE(uint8_t mode); + bool sATCIPMUX(uint8_t mode); + bool eATCWLAP(string &list); + bool sATCWJAP(string ssid, string pwd); + bool eATCIFSR(string &list); + bool sATCIPSERVER(uint8_t mode, uint32_t port = 333); + bool sATCIPSENDMultiple(uint8_t mux_id, char buffer[], uint32_t len); + bool sATCWSAP(string ssid, string pwd, uint8_t chl, uint8_t ecn); + bool sATCWDHCP(bool enabled, int mode); + bool sATCIPSTA(string ip); + bool sATCIPAP(string ip); +/* + +bool qATCWMODE(uint8_t *mode); + + + +bool eATCWQAP(void); +bool sATCWSAP(string ssid, string pwd, uint8_t chl, uint8_t ecn); +bool eATCWLIF(string &list); + +bool eATCIPSTATUS(string &list); +bool eATCIFSR(string &list); + + */ + + + + + /** Verify whether ESP8266 is connected correctly or not. + * @param None + * + * @retval true - connected. + * @retval false - not connected or found. + */ + bool kick(void); + + /** Restart ESP8266 by "AT+RST". This method will take 3 seconds or more. + * + * @retval true - success. + * @retval false - failure. + */ + bool reset(void); + + /** Sets the ESP8266's WiFi mode. + * @param mode The WiFi mode the ESP8266 must be set to (1=Station, 2=SoftAP, 3=Station+SoftAP) + * + * @retval true - success. + * @retval false - failure. + */ + bool setWiFiMode(uint8_t mode); + + /** Enable of disable multiple connections on the ESP8266 + * @param onoff Value to Enable(=true) or Disable(=false) multiple connections. + * + * @retval true - success. + * @retval false - failure. + */ + bool setMux(bool onoff); + + /* Receive data from uart and search first target. Return true if target found, false for timeout. */ + bool recvFind(string target, uint32_t timeout = 1000); + + /* Receive data from uart. Return all received data if target found or timeout. */ + string recvString(string target, uint32_t timeout = 1000); + + /* Receive data from uart. Return all received data if one of target1 and target2 found or timeout. */ + string recvString(string target1, string target2, uint32_t timeout = 1000); + + /* Receive data from uart. Return all received data if one of target1, target2 and target3 found or timeout. */ + string recvString(string target1, string target2, string target3, uint32_t timeout = 1000); + + /* Receive data from uart and search first target and cut out the substring between begin and end(excluding begin and end self). + * Return true if target found, false for timeout. */ + bool recvFindAndFilter(string target, string begin, string end, string &data, uint32_t timeout = 1000); + + +}; + +#endif \ No newline at end of file