diff --git a/ESP8266.cpp b/ESP8266.cpp new file mode 100644 index 0000000..38d2c60 --- /dev/null +++ b/ESP8266.cpp @@ -0,0 +1,806 @@ +/** + * @file ESP8266.cpp + * @brief The implementation of class ESP8266. + * @author Wu Pengfei + * @date 2015.02 + * + * @par Copyright: + * Copyright (c) 2015 ITEAD Intelligent Systems Co., Ltd. \n\n + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. \n\n + * 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 "ESP8266.h" + +#define LOG_OUTPUT_DEBUG (1) +#define LOG_OUTPUT_DEBUG_PREFIX (1) + +#define logDebug(arg)\ + do {\ + if (LOG_OUTPUT_DEBUG)\ + {\ + if (LOG_OUTPUT_DEBUG_PREFIX)\ + {\ + Serial.print("[LOG Debug: ");\ + Serial.print((const char*)__FILE__);\ + Serial.print(",");\ + Serial.print((unsigned int)__LINE__);\ + Serial.print(",");\ + Serial.print((const char*)__FUNCTION__);\ + Serial.print("] ");\ + }\ + Serial.print(arg);\ + }\ + } while(0) + +#ifdef ESP8266_USE_SOFTWARE_SERIAL +ESP8266::ESP8266(SoftwareSerial &uart, uint32_t baud): m_puart(&uart) +{ + m_puart->begin(baud); + rx_empty(); +} +ESP8266::ESP8266(uint32_t baud) +{ + SoftwareSerial *s = new SoftwareSerial(7, 6); + m_puart = s; + m_puart->begin(baud); + rx_empty(); +} +#else +ESP8266::ESP8266(HardwareSerial &uart, uint32_t baud): m_puart(&uart) +{ + m_puart->begin(baud); + rx_empty(); +} +#endif + +bool ESP8266::kick(void) +{ + return eAT(); +} + +bool ESP8266::restart(void) +{ + unsigned long start; + if (eATRST()) { + delay(2000); + start = millis(); + while (millis() - start < 3000) { + if (eAT()) { + delay(1500); /* Waiting for stable */ + return true; + } + delay(100); + } + } + return false; +} + +String ESP8266::getVersion(void) +{ + String version; + eATGMR(version); + return version; +} + +bool ESP8266::setOprToStation(void) +{ + uint8_t mode; + if (!qATCWMODE(&mode)) { + return false; + } + if (mode == 1) { + return true; + } else { + if (sATCWMODE(1) && restart()) { + return true; + } else { + return false; + } + } +} + +bool ESP8266::setOprToSoftAP(void) +{ + uint8_t mode; + if (!qATCWMODE(&mode)) { + return false; + } + if (mode == 2) { + return true; + } else { + if (sATCWMODE(2) && restart()) { + return true; + } else { + return false; + } + } +} + +bool ESP8266::setOprToStationSoftAP(void) +{ + uint8_t mode; + if (!qATCWMODE(&mode)) { + return false; + } + if (mode == 3) { + return true; + } else { + if (sATCWMODE(3) && restart()) { + return true; + } else { + return false; + } + } +} + +String ESP8266::getAPList(void) +{ + String list; + eATCWLAP(list); + return list; +} + +bool ESP8266::joinAP(String ssid, String pwd) +{ + return sATCWJAP(ssid, pwd); +} + +bool ESP8266::enableClientDHCP(uint8_t mode, boolean enabled) +{ + return sATCWDHCP(mode, enabled); +} + +bool ESP8266::leaveAP(void) +{ + return eATCWQAP(); +} + +bool ESP8266::setSoftAPParam(String ssid, String pwd, uint8_t chl, uint8_t ecn) +{ + return sATCWSAP(ssid, pwd, chl, ecn); +} + +String ESP8266::getJoinedDeviceIP(void) +{ + String list; + eATCWLIF(list); + return list; +} + +String ESP8266::getIPStatus(void) +{ + String list; + eATCIPSTATUS(list); + return list; +} + +String ESP8266::getLocalIP(void) +{ + String list; + eATCIFSR(list); + return list; +} + +bool ESP8266::enableMUX(void) +{ + return sATCIPMUX(1); +} + +bool ESP8266::disableMUX(void) +{ + return sATCIPMUX(0); +} + +bool ESP8266::createTCP(String addr, uint32_t port) +{ + return sATCIPSTARTSingle("TCP", addr, port); +} + +bool ESP8266::releaseTCP(void) +{ + return eATCIPCLOSESingle(); +} + +bool ESP8266::registerUDP(String addr, uint32_t port) +{ + return sATCIPSTARTSingle("UDP", addr, port); +} + +bool ESP8266::unregisterUDP(void) +{ + return eATCIPCLOSESingle(); +} + +bool ESP8266::createTCP(uint8_t mux_id, String addr, uint32_t port) +{ + return sATCIPSTARTMultiple(mux_id, "TCP", addr, port); +} + +bool ESP8266::releaseTCP(uint8_t mux_id) +{ + return sATCIPCLOSEMulitple(mux_id); +} + +bool ESP8266::registerUDP(uint8_t mux_id, String addr, uint32_t port) +{ + return sATCIPSTARTMultiple(mux_id, "UDP", addr, port); +} + +bool ESP8266::unregisterUDP(uint8_t mux_id) +{ + return sATCIPCLOSEMulitple(mux_id); +} + +bool ESP8266::setTCPServerTimeout(uint32_t timeout) +{ + return sATCIPSTO(timeout); +} + +bool ESP8266::startTCPServer(uint32_t port) +{ + if (sATCIPSERVER(1, port)) { + return true; + } + return false; +} + +bool ESP8266::stopTCPServer(void) +{ + sATCIPSERVER(0); + restart(); + return false; +} + +bool ESP8266::startServer(uint32_t port) +{ + return startTCPServer(port); +} + +bool ESP8266::stopServer(void) +{ + return stopTCPServer(); +} + +bool ESP8266::send(const uint8_t *buffer, uint32_t len) +{ + return sATCIPSENDSingle(buffer, len); +} + +bool ESP8266::send(uint8_t mux_id, const uint8_t *buffer, uint32_t len) +{ + return sATCIPSENDMultiple(mux_id, buffer, len); +} + +uint32_t ESP8266::recv(uint8_t *buffer, uint32_t buffer_size, uint32_t timeout) +{ + return recvPkg(buffer, buffer_size, NULL, timeout, NULL); +} + +uint32_t ESP8266::recv(uint8_t mux_id, uint8_t *buffer, uint32_t buffer_size, uint32_t timeout) +{ + uint8_t id; + uint32_t ret; + ret = recvPkg(buffer, buffer_size, NULL, timeout, &id); + if (ret > 0 && id == mux_id) { + return ret; + } + return 0; +} + +uint32_t ESP8266::recv(uint8_t *coming_mux_id, uint8_t *buffer, uint32_t buffer_size, uint32_t timeout) +{ + return recvPkg(buffer, buffer_size, NULL, timeout, coming_mux_id); +} + +/*----------------------------------------------------------------------------*/ +/* +IPD,,: */ +/* +IPD,: */ + +uint32_t ESP8266::recvPkg(uint8_t *buffer, uint32_t buffer_size, uint32_t *data_len, uint32_t timeout, uint8_t *coming_mux_id) +{ + String data; + char a; + int32_t index_PIPDcomma = -1; + int32_t index_colon = -1; /* : */ + int32_t index_comma = -1; /* , */ + int32_t len = -1; + int8_t id = -1; + bool has_data = false; + uint32_t ret; + unsigned long start; + uint32_t i; + + if (buffer == NULL) { + return 0; + } + + start = millis(); + while (millis() - start < timeout) { + if(m_puart->available() > 0) { + a = m_puart->read(); + data += a; + } + + index_PIPDcomma = data.indexOf("+IPD,"); + if (index_PIPDcomma != -1) { + index_colon = data.indexOf(':', index_PIPDcomma + 5); + if (index_colon != -1) { + index_comma = data.indexOf(',', index_PIPDcomma + 5); + /* +IPD,id,len:data */ + if (index_comma != -1 && index_comma < index_colon) { + id = data.substring(index_PIPDcomma + 5, index_comma).toInt(); + if (id < 0 || id > 4) { + return 0; + } + len = data.substring(index_comma + 1, index_colon).toInt(); + if (len <= 0) { + return 0; + } + } else { /* +IPD,len:data */ + len = data.substring(index_PIPDcomma + 5, index_colon).toInt(); + if (len <= 0) { + return 0; + } + } + has_data = true; + break; + } + } + } + + if (has_data) { + i = 0; + ret = len > buffer_size ? buffer_size : len; + start = millis(); + while (millis() - start < 3000) { + while(m_puart->available() > 0 && i < ret) { + a = m_puart->read(); + buffer[i++] = a; + } + if (i == ret) { + rx_empty(); + if (data_len) { + *data_len = len; + } + if (index_comma != -1 && coming_mux_id) { + *coming_mux_id = id; + } + return ret; + } + } + } + return 0; +} + +void ESP8266::rx_empty(void) +{ + while(m_puart->available() > 0) { + m_puart->read(); + } +} + +String ESP8266::recvString(String target, uint32_t timeout) +{ + String data; + char a; + unsigned long start = millis(); + while (millis() - start < timeout) { + while(m_puart->available() > 0) { + a = m_puart->read(); + if(a == '\0') continue; + data += a; + } + if (data.indexOf(target) != -1) { + break; + } + } + return data; +} + +String ESP8266::recvString(String target1, String target2, uint32_t timeout) +{ + String data; + char a; + unsigned long start = millis(); + while (millis() - start < timeout) { + while(m_puart->available() > 0) { + a = m_puart->read(); + if(a == '\0') continue; + data += a; + } + if (data.indexOf(target1) != -1) { + break; + } else if (data.indexOf(target2) != -1) { + break; + } + } + return data; +} + +String ESP8266::recvString(String target1, String target2, String target3, uint32_t timeout) +{ + String data; + char a; + unsigned long start = millis(); + while (millis() - start < timeout) { + while(m_puart->available() > 0) { + a = m_puart->read(); + if(a == '\0') continue; + data += a; + } + if (data.indexOf(target1) != -1) { + break; + } else if (data.indexOf(target2) != -1) { + break; + } else if (data.indexOf(target3) != -1) { + break; + } + } + return data; +} + +bool ESP8266::recvFind(String target, uint32_t timeout) +{ + String data_tmp; + data_tmp = recvString(target, timeout); + if (data_tmp.indexOf(target) != -1) { + return true; + } + return false; +} + +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.indexOf(target) != -1) { + int32_t index1 = data_tmp.indexOf(begin); + int32_t index2 = data_tmp.indexOf(end); + if (index1 != -1 && index2 != -1) { + index1 += begin.length(); + data = data_tmp.substring(index1, index2); + return true; + } + } + data = ""; + return false; +} + +bool ESP8266::eAT(void) +{ + rx_empty(); + m_puart->println("AT"); + return recvFind("OK"); +} + +bool ESP8266::eATRST(void) +{ + rx_empty(); + m_puart->println("AT+RST"); + return recvFind("OK"); +} + +bool ESP8266::eATGMR(String &version) +{ + rx_empty(); + m_puart->println("AT+GMR"); + return recvFindAndFilter("OK", "\r\r\n", "\r\n\r\nOK", version); +} + +bool ESP8266::qATCWMODE(uint8_t *mode) +{ + String str_mode; + bool ret; + if (!mode) { + return false; + } + rx_empty(); + m_puart->println("AT+CWMODE?"); + ret = recvFindAndFilter("OK", "+CWMODE:", "\r\n\r\nOK", str_mode); + if (ret) { + *mode = (uint8_t)str_mode.toInt(); + return true; + } else { + return false; + } +} + +bool ESP8266::sATCWMODE(uint8_t mode) +{ + String data; + rx_empty(); + m_puart->print("AT+CWMODE="); + m_puart->println(mode); + + data = recvString("OK", "no change"); + if (data.indexOf("OK") != -1 || data.indexOf("no change") != -1) { + return true; + } + return false; +} + +bool ESP8266::sATCWJAP(String ssid, String pwd) +{ + String data; + rx_empty(); + m_puart->print("AT+CWJAP=\""); + m_puart->print(ssid); + m_puart->print("\",\""); + m_puart->print(pwd); + m_puart->println("\""); + + data = recvString("OK", "FAIL", 10000); + if (data.indexOf("OK") != -1) { + return true; + } + return false; +} + +bool ESP8266::sATCWDHCP(uint8_t mode, boolean enabled) +{ + String strEn = "0"; + if (enabled) { + strEn = "1"; + } + + + String data; + rx_empty(); + m_puart->print("AT+CWDHCP="); + m_puart->print(strEn); + m_puart->print(","); + m_puart->println(mode); + + data = recvString("OK", "FAIL", 10000); + if (data.indexOf("OK") != -1) { + return true; + } + return false; +} + +bool ESP8266::eATCWLAP(String &list) +{ + String data; + rx_empty(); + m_puart->println("AT+CWLAP"); + return recvFindAndFilter("OK", "\r\r\n", "\r\n\r\nOK", list, 10000); +} + +bool ESP8266::eATCWQAP(void) +{ + String data; + rx_empty(); + m_puart->println("AT+CWQAP"); + return recvFind("OK"); +} + +bool ESP8266::sATCWSAP(String ssid, String pwd, uint8_t chl, uint8_t ecn) +{ + String data; + rx_empty(); + m_puart->print("AT+CWSAP=\""); + m_puart->print(ssid); + m_puart->print("\",\""); + m_puart->print(pwd); + m_puart->print("\","); + m_puart->print(chl); + m_puart->print(","); + m_puart->println(ecn); + + data = recvString("OK", "ERROR", 5000); + if (data.indexOf("OK") != -1) { + return true; + } + return false; +} + +bool ESP8266::eATCWLIF(String &list) +{ + String data; + rx_empty(); + m_puart->println("AT+CWLIF"); + return recvFindAndFilter("OK", "\r\r\n", "\r\n\r\nOK", list); +} +bool ESP8266::eATCIPSTATUS(String &list) +{ + String data; + delay(100); + rx_empty(); + m_puart->println("AT+CIPSTATUS"); + return recvFindAndFilter("OK", "\r\r\n", "\r\n\r\nOK", list); +} +bool ESP8266::sATCIPSTARTSingle(String type, String addr, uint32_t port) +{ + String data; + rx_empty(); + m_puart->print("AT+CIPSTART=\""); + m_puart->print(type); + m_puart->print("\",\""); + m_puart->print(addr); + m_puart->print("\","); + m_puart->println(port); + + data = recvString("OK", "ERROR", "ALREADY CONNECT", 10000); + if (data.indexOf("OK") != -1 || data.indexOf("ALREADY CONNECT") != -1) { + return true; + } + return false; +} +bool ESP8266::sATCIPSTARTMultiple(uint8_t mux_id, String type, String addr, uint32_t port) +{ + String data; + rx_empty(); + m_puart->print("AT+CIPSTART="); + m_puart->print(mux_id); + m_puart->print(",\""); + m_puart->print(type); + m_puart->print("\",\""); + m_puart->print(addr); + m_puart->print("\","); + m_puart->println(port); + + data = recvString("OK", "ERROR", "ALREADY CONNECT", 10000); + if (data.indexOf("OK") != -1 || data.indexOf("ALREADY CONNECT") != -1) { + return true; + } + return false; +} +bool ESP8266::sATCIPSENDSingle(const uint8_t *buffer, uint32_t len) +{ + rx_empty(); + m_puart->print("AT+CIPSEND="); + m_puart->println(len); + if (recvFind(">", 5000)) { + rx_empty(); + for (uint32_t i = 0; i < len; i++) { + m_puart->write(buffer[i]); + } + return recvFind("SEND OK", 10000); + } + return false; +} +bool ESP8266::sATCIPSENDMultiple(uint8_t mux_id, const uint8_t *buffer, uint32_t len) +{ + rx_empty(); + m_puart->print("AT+CIPSEND="); + m_puart->print(mux_id); + m_puart->print(","); + m_puart->println(len); + if (recvFind(">", 5000)) { + rx_empty(); + for (uint32_t i = 0; i < len; i++) { + m_puart->write(buffer[i]); + } + return recvFind("SEND OK", 10000); + } + return false; +} +bool ESP8266::sATCIPCLOSEMulitple(uint8_t mux_id) +{ + String data; + rx_empty(); + m_puart->print("AT+CIPCLOSE="); + m_puart->println(mux_id); + + data = recvString("OK", "link is not", 5000); + if (data.indexOf("OK") != -1 || data.indexOf("link is not") != -1) { + return true; + } + return false; +} +bool ESP8266::eATCIPCLOSESingle(void) +{ + rx_empty(); + m_puart->println("AT+CIPCLOSE"); + return recvFind("OK", 5000); +} +bool ESP8266::eATCIFSR(String &list) +{ + rx_empty(); + m_puart->println("AT+CIFSR"); + return recvFindAndFilter("OK", "\r\r\n", "\r\n\r\nOK", list); +} +bool ESP8266::sATCIPMUX(uint8_t mode) +{ + String data; + rx_empty(); + m_puart->print("AT+CIPMUX="); + m_puart->println(mode); + + data = recvString("OK", "Link is builded"); + if (data.indexOf("OK") != -1) { + return true; + } + return false; +} +bool ESP8266::sATCIPSERVER(uint8_t mode, uint32_t port) +{ + String data; + if (mode) { + rx_empty(); + m_puart->print("AT+CIPSERVER=1,"); + m_puart->println(port); + + data = recvString("OK", "no change"); + if (data.indexOf("OK") != -1 || data.indexOf("no change") != -1) { + return true; + } + return false; + } else { + rx_empty(); + m_puart->println("AT+CIPSERVER=0"); + return recvFind("\r\r\n"); + } +} +bool ESP8266::sATCIPSTO(uint32_t timeout) +{ + rx_empty(); + m_puart->print("AT+CIPSTO="); + m_puart->println(timeout); + return recvFind("OK"); +} + +/* ESCAPE ROOM CODE STARTS HERE */ +bool ESP8266::getPuzzleStatus(char *puzzle) { + char request[8]; + strcpy(request, puzzle); + strcat(request, " GET"); + request[8] = '\0'; + char resp[8]; + int i=0; + for (; i<3; i++) if (sendRequest(request, resp)) break; + // Return false if we send 3 requests with invalid responses + if (i == 3) return false; + char doneResp[8]; + strcpy(doneResp, puzzle); + strcat(request, " DNE"); + doneResp[7] = '\0'; + if (strcmp(resp, doneResp)) return true; + else return false; +} + +bool ESP8266::markPuzzleDone(char *puzzle) { + char request[8]; + strcpy(request, puzzle); + strcat(request, " DNE"); + request[8] = '\0'; + char resp[8]; + int i=0; + for (; i<3; i++) if (sendRequest(request, resp)) break; + // Return false if we send 3 requests with invalid responses + if (i == 3) return false; + if (strcmp(resp, "INVALID")) return false; + return true; +} + +bool ESP8266::markPuzzleIncomplete(char *puzzle) { + char request[8]; + strcpy(request, puzzle); + strcat(request, " RST"); + request[8] = '\0'; + char resp[8]; + int i=0; + for (; i<3; i++) if (sendRequest(request, resp)) break; + // Return false if we send 3 requests with invalid responses + if (i == 3) return false; + if (strcmp(resp, "INVALID")) return false; + return true; +} + +bool ESP8266::sendRequest(char *request, char *buffer) { + if (!createTCP(HOST_NAME, HOST_PORT)) return false; + send((const uint8_t*)request, strlen(request)); + uint32_t len = recv(buffer, sizeof(buffer), 10000); + if (len > 0) return true; + else return false; +} + diff --git a/ESP8266.h b/ESP8266.h new file mode 100644 index 0000000..4411a6a --- /dev/null +++ b/ESP8266.h @@ -0,0 +1,489 @@ +/** + * @file ESP8266.h + * @brief The definition of class ESP8266. + * @author Wu Pengfei + * @date 2015.02 + * + * @par Copyright: + * Copyright (c) 2015 ITEAD Intelligent Systems Co., Ltd. \n\n + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. \n\n + * 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__ + +#define HOST_NAME "172.27.109.43" +#define HOST_PORT (1337) + +#include "Arduino.h" + + +#define ESP8266_USE_SOFTWARE_SERIAL + + +#ifdef ESP8266_USE_SOFTWARE_SERIAL +#include "SoftwareSerial.h" +#endif + + +/** + * Provide an easy-to-use way to manipulate ESP8266. + */ +class ESP8266 { + public: + +#ifdef ESP8266_USE_SOFTWARE_SERIAL + /* + * Constuctor. + * + * @param uart - an reference of SoftwareSerial object. + * @param baud - the buad rate to communicate with ESP8266(default:9600). + * + * @warning parameter baud depends on the AT firmware. 9600 is an common value. + */ + ESP8266(uint32_t baud = 9600); + ESP8266(SoftwareSerial &uart, uint32_t baud = 9600); +#else /* HardwareSerial */ + /* + * Constuctor. + * + * @param uart - an reference of HardwareSerial object. + * @param baud - the buad rate to communicate with ESP8266(default:9600). + * + * @warning parameter baud depends on the AT firmware. 9600 is an common value. + */ + ESP8266(HardwareSerial &uart, uint32_t baud = 9600); +#endif + + + /** + * Verify ESP8266 whether live or not. + * + * Actually, this method will send command "AT" to ESP8266 and waiting for "OK". + * + * @retval true - alive. + * @retval false - dead. + */ + bool kick(void); + + /** + * Restart ESP8266 by "AT+RST". + * + * This method will take 3 seconds or more. + * + * @retval true - success. + * @retval false - failure. + */ + bool restart(void); + + /** + * Get the version of AT Command Set. + * + * @return the string of version. + */ + String getVersion(void); + + /** + * Set operation mode to staion. + * + * @retval true - success. + * @retval false - failure. + */ + bool setOprToStation(void); + + /** + * Set operation mode to softap. + * + * @retval true - success. + * @retval false - failure. + */ + bool setOprToSoftAP(void); + + /** + * Set operation mode to station + softap. + * + * @retval true - success. + * @retval false - failure. + */ + bool setOprToStationSoftAP(void); + + /** + * Search available AP list and return it. + * + * @return the list of available APs. + * @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 memery left. + */ + String getAPList(void); + + /** + * 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); + + + /** + * Enable DHCP for client mode. + * + * @param mode - server mode (0=soft AP, 1=station, 2=both + * @param enabled - true if dhcp should be enabled, otherwise false + * + * @note This method will enable DHCP but only for client mode! + */ + bool enableClientDHCP(uint8_t mode, boolean enabled); + + /** + * Leave AP joined before. + * + * @retval true - success. + * @retval false - failure. + */ + bool leaveAP(void); + + /** + * 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); + + /** + * Get the IP list of devices connected to SoftAP. + * + * @return the list of IP. + * @note This method should not be called when station mode. + */ + String getJoinedDeviceIP(void); + + /** + * Get the current status of connection(UDP and TCP). + * + * @return the status. + */ + String getIPStatus(void); + + /** + * Get the IP address of ESP8266. + * + * @return the IP list. + */ + String getLocalIP(void); + + /** + * Enable IP MUX(multiple connection mode). + * + * In multiple connection mode, a couple of TCP and UDP communication can be builded. + * They can be distinguished by the identifier of TCP or UDP named mux_id. + * + * @retval true - success. + * @retval false - failure. + */ + bool enableMUX(void); + + /** + * Disable IP MUX(single connection mode). + * + * In single connection mode, only one TCP or UDP communication can be builded. + * + * @retval true - success. + * @retval false - failure. + */ + bool disableMUX(void); + + + /** + * Create TCP connection in single mode. + * + * @param addr - the IP or domain name of the target host. + * @param port - the port number of the target host. + * @retval true - success. + * @retval false - failure. + */ + bool createTCP(String addr, uint32_t port); + + /** + * Release TCP connection in single mode. + * + * @retval true - success. + * @retval false - failure. + */ + bool releaseTCP(void); + + /** + * Register UDP port number in single mode. + * + * @param addr - the IP or domain name of the target host. + * @param port - the port number of the target host. + * @retval true - success. + * @retval false - failure. + */ + bool registerUDP(String addr, uint32_t port); + + /** + * Unregister UDP port number in single mode. + * + * @retval true - success. + * @retval false - failure. + */ + bool unregisterUDP(void); + + /** + * Create TCP connection in multiple mode. + * + * @param mux_id - the identifier of this TCP(available value: 0 - 4). + * @param addr - the IP or domain name of the target host. + * @param port - the port number of the target host. + * @retval true - success. + * @retval false - failure. + */ + bool createTCP(uint8_t mux_id, String addr, uint32_t port); + + /** + * Release TCP connection in multiple mode. + * + * @param mux_id - the identifier of this TCP(available value: 0 - 4). + * @retval true - success. + * @retval false - failure. + */ + bool releaseTCP(uint8_t mux_id); + + /** + * Register UDP port number in multiple mode. + * + * @param mux_id - the identifier of this TCP(available value: 0 - 4). + * @param addr - the IP or domain name of the target host. + * @param port - the port number of the target host. + * @retval true - success. + * @retval false - failure. + */ + bool registerUDP(uint8_t mux_id, String addr, uint32_t port); + + /** + * Unregister UDP port number in multiple mode. + * + * @param mux_id - the identifier of this TCP(available value: 0 - 4). + * @retval true - success. + * @retval false - failure. + */ + bool unregisterUDP(uint8_t mux_id); + + + /** + * Set the timeout of TCP Server. + * + * @param timeout - the duration for timeout by second(0 ~ 28800, default:180). + * @retval true - success. + * @retval false - failure. + */ + bool setTCPServerTimeout(uint32_t timeout = 180); + + /** + * Start TCP Server(Only in multiple mode). + * + * After started, user should call method: getIPStatus to know the status of TCP connections. + * The methods of receiving data can be called for user's any purpose. After communication, + * release the TCP connection is needed by calling method: releaseTCP with mux_id. + * + * @param port - the port number to listen(default: 333). + * @retval true - success. + * @retval false - failure. + * + * @see String getIPStatus(void); + * @see uint32_t recv(uint8_t *coming_mux_id, uint8_t *buffer, uint32_t len, uint32_t timeout); + * @see bool releaseTCP(uint8_t mux_id); + */ + bool startTCPServer(uint32_t port = 333); + + /** + * Stop TCP Server(Only in multiple mode). + * + * @retval true - success. + * @retval false - failure. + */ + bool stopTCPServer(void); + + /** + * Start Server(Only in multiple mode). + * + * @param port - the port number to listen(default: 333). + * @retval true - success. + * @retval false - failure. + * + * @see String getIPStatus(void); + * @see uint32_t recv(uint8_t *coming_mux_id, uint8_t *buffer, uint32_t len, uint32_t timeout); + */ + bool startServer(uint32_t port = 333); + + /** + * Stop Server(Only in multiple mode). + * + * @retval true - success. + * @retval false - failure. + */ + bool stopServer(void); + + /** + * Send data based on TCP or UDP builded already in single mode. + * + * @param buffer - the buffer of data to send. + * @param len - the length of data to send. + * @retval true - success. + * @retval false - failure. + */ + bool send(const uint8_t *buffer, uint32_t len); + + /** + * Send data based on one of TCP or UDP builded already in multiple mode. + * + * @param mux_id - the identifier of this TCP(available value: 0 - 4). + * @param buffer - the buffer of data to send. + * @param len - the length of data to send. + * @retval true - success. + * @retval false - failure. + */ + bool send(uint8_t mux_id, const uint8_t *buffer, uint32_t len); + + /** + * Receive data from TCP or UDP builded already in single mode. + * + * @param buffer - the buffer for storing data. + * @param buffer_size - the length of the buffer. + * @param timeout - the time waiting data. + * @return the length of data received actually. + */ + uint32_t recv(uint8_t *buffer, uint32_t buffer_size, uint32_t timeout = 1000); + + /** + * Receive data from one of TCP or UDP builded already in multiple mode. + * + * @param mux_id - the identifier of this TCP(available value: 0 - 4). + * @param buffer - the buffer for storing data. + * @param buffer_size - the length of the buffer. + * @param timeout - the time waiting data. + * @return the length of data received actually. + */ + uint32_t recv(uint8_t mux_id, uint8_t *buffer, uint32_t buffer_size, uint32_t timeout = 1000); + + /** + * Receive data from all of TCP or UDP builded already in multiple mode. + * + * After return, coming_mux_id store the id of TCP or UDP from which data coming. + * User should read the value of coming_mux_id and decide what next to do. + * + * @param coming_mux_id - the identifier of TCP or UDP. + * @param buffer - the buffer for storing data. + * @param buffer_size - the length of the buffer. + * @param timeout - the time waiting data. + * @return the length of data received actually. + */ + uint32_t recv(uint8_t *coming_mux_id, uint8_t *buffer, uint32_t buffer_size, uint32_t timeout = 1000); + + bool getPuzzleStatus(char *puzzle); + bool markPuzzleDone(char *puzzle); + bool markPuzzleIncomplete(char *puzzle); + + private: + + /* + * Empty the buffer or UART RX. + */ + void rx_empty(void); + + /* + * Recvive data from uart. Return all received data if target found or timeout. + */ + String recvString(String target, uint32_t timeout = 1000); + + /* + * Recvive 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); + + /* + * Recvive 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); + + /* + * Recvive data from uart and search first target. Return true if target found, false for timeout. + */ + bool recvFind(String target, uint32_t timeout = 1000); + + /* + * Recvive 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); + + /* + * Receive a package from uart. + * + * @param buffer - the buffer storing data. + * @param buffer_size - guess what! + * @param data_len - the length of data actually received(maybe more than buffer_size, the remained data will be abandoned). + * @param timeout - the duration waitting data comming. + * @param coming_mux_id - in single connection mode, should be NULL and not NULL in multiple. + */ + uint32_t recvPkg(uint8_t *buffer, uint32_t buffer_size, uint32_t *data_len, uint32_t timeout, uint8_t *coming_mux_id); + + + bool eAT(void); + bool eATRST(void); + bool eATGMR(String &version); + + bool qATCWMODE(uint8_t *mode); + bool sATCWMODE(uint8_t mode); + bool sATCWJAP(String ssid, String pwd); + bool sATCWDHCP(uint8_t mode, boolean enabled); + bool eATCWLAP(String &list); + bool eATCWQAP(void); + bool sATCWSAP(String ssid, String pwd, uint8_t chl, uint8_t ecn); + bool eATCWLIF(String &list); + + bool eATCIPSTATUS(String &list); + bool sATCIPSTARTSingle(String type, String addr, uint32_t port); + bool sATCIPSTARTMultiple(uint8_t mux_id, String type, String addr, uint32_t port); + bool sATCIPSENDSingle(const uint8_t *buffer, uint32_t len); + bool sATCIPSENDMultiple(uint8_t mux_id, const uint8_t *buffer, uint32_t len); + bool sATCIPCLOSEMulitple(uint8_t mux_id); + bool eATCIPCLOSESingle(void); + bool eATCIFSR(String &list); + bool sATCIPMUX(uint8_t mode); + bool sATCIPSERVER(uint8_t mode, uint32_t port = 333); + bool sATCIPSTO(uint32_t timeout); + bool sendRequest(char *request, char *buffer); + + /* + * +IPD,len:data + * +IPD,id,len:data + */ + +#ifdef ESP8266_USE_SOFTWARE_SERIAL + SoftwareSerial *m_puart; /* The UART to communicate with ESP8266 */ +#else + HardwareSerial *m_puart; /* The UART to communicate with ESP8266 */ +#endif +}; + +#endif /* #ifndef __ESP8266_H__ */ + diff --git a/ESP8266EscapeRoom.cpp b/ESP8266EscapeRoom.cpp deleted file mode 100644 index 0cc68b8..0000000 --- a/ESP8266EscapeRoom.cpp +++ /dev/null @@ -1,7 +0,0 @@ -#include "ESP8266EscapeRoom.h" -#include - -/*ESP8266EscapeRoom::ESP8266EscapeRoom(int rx, int tx) { - SoftwareSerial esp(7, 6); - wifi(esp); -}*/ diff --git a/ESP8266EscapeRoom.h b/ESP8266EscapeRoom.h deleted file mode 100644 index 3a9e444..0000000 --- a/ESP8266EscapeRoom.h +++ /dev/null @@ -1,15 +0,0 @@ -#ifndef __ESP8266EscapeRoom_H__ -#define __ESP8266EscapeRoom_H__ - -#include "Arduino.h" -#include "ESP8266.h" -#include - -class ESP8266EscapeRoom { - public: - ESP8266EscapeRoom(int rx, int tx); - - private: - ESP8266 wifi; -}; -#endif diff --git a/ESP8266EscapeRoom.ino b/ESP8266EscapeRoom.ino index 874bc79..0abe848 100644 --- a/ESP8266EscapeRoom.ino +++ b/ESP8266EscapeRoom.ino @@ -18,15 +18,15 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ +//#include "ESP8266EscapeRoom.h" #include "ESP8266.h" #include + #define SSID "wahoo" #define PASSWORD "" -#define HOST_NAME "172.27.108.103" -#define HOST_PORT (1337) -SoftwareSerial esp(7, 6); +SoftwareSerial esp(7,6); ESP8266 wifi(esp); void setup(void) @@ -42,14 +42,15 @@ void setup(void) } else { Serial.print("to station + softap err\r\n"); } - - if (wifi.joinAP(SSID, PASSWORD)) { + Serial.println("Connecting to WiFi"); + while (!wifi.joinAP(SSID, PASSWORD)) Serial.println("Retrying..."); + /*if (wifi.joinAP(SSID, PASSWORD)) { Serial.print("Join AP success\r\n"); Serial.print("IP:"); Serial.println( wifi.getLocalIP().c_str()); } else { Serial.print("Join AP failure\r\n"); - } + }*/ if (wifi.disableMUX()) { Serial.print("single ok\r\n"); @@ -62,32 +63,19 @@ void setup(void) void loop(void) { - uint8_t buffer[7] = {0}; - - if (wifi.createTCP(HOST_NAME, HOST_PORT)) { - Serial.print("create tcp ok\r\n"); - } else { - Serial.print("create tcp err\r\n"); - } - - char *hello = "BKS DNE"; - wifi.send((const uint8_t*)hello, strlen(hello)); - - uint32_t len = wifi.recv(buffer, sizeof(buffer), 10000); - Serial.println(len); - if (len > 0) { - Serial.print("Received:["); - for(uint32_t i = 0; i < len; i++) { - Serial.print((char)buffer[i]); - } - Serial.print("]\r\n"); - } - - if (wifi.releaseTCP()) { - Serial.print("release tcp ok\r\n"); - } else { - Serial.print("release tcp err\r\n"); - } + // Replace BKS with the puzzle you want + // BKS = Books + // MRS = Morse code + // TIM = Time machine + // GRS = Gears + Serial.println("Mark books done:"); + Serial.println(wifi.markPuzzleDone("BKS")); + Serial.println("Books status:"); + Serial.println(wifi.getPuzzleStatus("BKS")); + Serial.println("Mark books incomplete:"); + Serial.println(wifi.markPuzzleIncomplete("BKS")); + Serial.println("Books status:"); + Serial.println(wifi.getPuzzleStatus("BKS")); delay(5000); } diff --git a/escape-room-server.py b/escape-room-server.py index ddeeff2..37f4e8a 100644 --- a/escape-room-server.py +++ b/escape-room-server.py @@ -32,15 +32,12 @@ # Invalid commands are responded to with INVALID import socket -from Adafruit_IO import Client - -aio = Client('gnr7aj', 'cfe1066499504669bd9e2afc759bc199') PUZZLE_FEEDS = { - "MRS": "morse", - "TIM": "time-machine", - "BKS": "books", - "GRS": "gears" + "MRS": "morse_feed", + "TIM": "time_feed", + "BKS": "books_feed", + "GRS": "gears_feed" } @@ -79,7 +76,7 @@ def puzzle_reset(puzzle): # Setup socket s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) -s.bind(("localhost", PORT)) +s.bind(("0.0.0.0", PORT)) while True: s.listen(1)