MAXREFDES143#: DeepCover Embedded Security in IoT Authenticated Sensing & Notification
Dependencies: MaximInterface mbed
ESP8266.cpp
00001 /******************************************************************************* 00002 * Copyright (C) 2016 Maxim Integrated Products, Inc., All Rights Reserved. 00003 * 00004 * Permission is hereby granted, free of charge, to any person obtaining a 00005 * copy of this software and associated documentation files (the "Software"), 00006 * to deal in the Software without restriction, including without limitation 00007 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 00008 * and/or sell copies of the Software, and to permit persons to whom the 00009 * Software is furnished to do so, subject to the following conditions: 00010 * 00011 * The above copyright notice and this permission notice shall be included 00012 * in all copies or substantial portions of the Software. 00013 * 00014 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 00015 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 00016 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 00017 * IN NO EVENT SHALL MAXIM INTEGRATED BE LIABLE FOR ANY CLAIM, DAMAGES 00018 * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 00019 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 00020 * OTHER DEALINGS IN THE SOFTWARE. 00021 * 00022 * Except as contained in this notice, the name of Maxim Integrated 00023 * Products, Inc. shall not be used except as stated in the Maxim Integrated 00024 * Products, Inc. Branding Policy. 00025 * 00026 * The mere transfer of this software does not imply any licenses 00027 * of trade secrets, proprietary technology, copyrights, patents, 00028 * trademarks, maskwork rights, or any other form of intellectual 00029 * property whatsoever. Maxim Integrated Products, Inc. retains all 00030 * ownership rights. 00031 *******************************************************************************/ 00032 00033 #include <cstdlib> 00034 #include <Timer.h> 00035 #include <wait_api.h> 00036 #include "ESP8266.hpp" 00037 00038 static inline void disableRecvData() { __disable_irq(); } 00039 00040 static inline void enableRecvData() { __enable_irq(); } 00041 00042 ESP8266::ESP8266 (const PinName tx, const PinName rx, const PinName rst, 00043 const PinName CH_PD, const int baud, 00044 mbed::Serial * debugMsgIntf) 00045 : AT_intf(tx, rx), resetPin(rst), powerDownPin(CH_PD), 00046 debugMsg(debugMsgIntf), parseRecvReset(false) { 00047 AT_intf.baud(baud); 00048 AT_intf.attach(this, &ESP8266::recv_AT_data_cb); 00049 00050 // Ensure that device is not held in reset 00051 if (resetPin.is_connected()) 00052 resetPin = 1; 00053 // Power down device at startup due to high current demand 00054 setPowered(false); 00055 } 00056 00057 void ESP8266::reset() { 00058 if (resetPin.is_connected()) { 00059 resetPin = 0; 00060 wait_ms(100); 00061 resetPin = 1; 00062 wait_ms(1000); 00063 } 00064 } 00065 00066 bool ESP8266::powered () const { 00067 bool isPowered; 00068 if (powerDownPin.is_connected()) { 00069 isPowered = powerDownPin.read(); 00070 } else { 00071 isPowered = false; 00072 } 00073 return isPowered; 00074 } 00075 00076 void ESP8266::setPowered(bool powered) { 00077 if (powerDownPin.is_connected()) 00078 powerDownPin = powered; 00079 } 00080 00081 ESP8266::CmdResult ESP8266::performSelfTest() { 00082 return sendCommand(CmdBuilder("")); 00083 } 00084 00085 ESP8266::CmdResult ESP8266::setCurrentWifiMode(const ESP8266::WifiMode mode) { 00086 CmdBuilder builder("CWMODE_CUR"); 00087 builder.addRawArgument(mode); 00088 return sendCommand(builder); 00089 } 00090 00091 ESP8266::CmdResult ESP8266::joinCurrentAccessPoint(const std::string & ssid, 00092 const std::string & pwd, 00093 const std::string & bssid) { 00094 CmdBuilder builder("CWJAP_CUR"); 00095 builder.addStringArgument(ssid); 00096 builder.addStringArgument(pwd); 00097 if (bssid != "") 00098 builder.addStringArgument(bssid); 00099 return sendCommand(builder); 00100 } 00101 00102 ESP8266::CmdResult ESP8266::quitAccessPoint() { 00103 return sendCommand(CmdBuilder("CWQAP")); 00104 } 00105 00106 ESP8266::CmdResult ESP8266::setMaxRFTXPower(const float power_dBm) { 00107 int power_arg = (int)(power_dBm * 4); 00108 if (power_arg > 82) 00109 power_arg = 82; 00110 else if (power_arg < 0) 00111 power_arg = 0; 00112 00113 CmdBuilder builder("RFPOWER"); 00114 builder.addRawArgument(power_arg); 00115 return sendCommand(builder); 00116 } 00117 00118 ESP8266::CmdResult ESP8266::ping(const std::string & IP) { 00119 CmdBuilder builder("PING"); 00120 builder.addStringArgument(IP); 00121 return sendCommand(builder); 00122 } 00123 00124 ESP8266::CmdResult ESP8266::openConnection(const ESP8266::ConnType type, 00125 const std::string & remoteIP, 00126 const unsigned int remotePort) { 00127 CmdBuilder builder("CIPSTART"); 00128 builder.addStringArgument((type == TCP) ? "TCP" : "UDP"); 00129 builder.addStringArgument(remoteIP); 00130 builder.addRawArgument(remotePort); 00131 return sendCommand(builder); 00132 } 00133 00134 ESP8266::CmdResult ESP8266::closeConnection() { 00135 return sendCommand(CmdBuilder("CIPCLOSE")); 00136 } 00137 00138 ESP8266::CmdResult ESP8266::sendData(const std::string & data) { 00139 CmdBuilder builder("CIPSEND"); 00140 builder.addRawArgument(data.length()); 00141 ESP8266::CmdResult result = sendCommand(builder); 00142 if (result == ESP8266::AT_OK) 00143 result = send_AT_data(data, false); 00144 return result; 00145 } 00146 00147 ESP8266::CmdResult ESP8266::sendCommand(const CmdBuilder & cmd) { 00148 return send_AT_data(cmd.str(), true); 00149 } 00150 00151 bool ESP8266::recvIpDataReadable() { 00152 bool result; 00153 00154 disableRecvData(); // Lock queue access 00155 00156 result = !recvIpDataBuffer.empty(); 00157 00158 enableRecvData(); // Unlock queue access 00159 00160 return result; 00161 } 00162 00163 char ESP8266::getcRecvIpData() { 00164 char received; 00165 00166 disableRecvData(); // Lock queue access 00167 00168 // Pop next char or set to NTC if not data in buffer 00169 if (!recvIpDataBuffer.pop(received)) 00170 received = '\0'; 00171 00172 enableRecvData(); // Unlock queue access 00173 00174 return received; 00175 } 00176 00177 void ESP8266::clearRecvData() { 00178 disableRecvData(); // Lock queue access 00179 00180 recvIpDataBuffer.reset(); 00181 parseRecvReset = true; 00182 00183 enableRecvData(); // Unlock queue access 00184 } 00185 00186 ESP8266::CmdResult ESP8266::send_AT_data(const std::string & cmdString, 00187 const bool expectEcho) { 00188 const int timeout_ms = 10000; 00189 00190 mbed::Timer timer; 00191 ESP8266::CmdResult result = ESP8266::HardwareError; 00192 std::string response; 00193 00194 disableRecvData(); // Lock for manual data handling in this procedure 00195 00196 // Flush receive buffer 00197 while (AT_intf.readable()) 00198 AT_intf.getc(); 00199 00200 // Begin counting for timeout 00201 timer.start(); 00202 00203 for (size_t i = 0; i < cmdString.length(); i++) { 00204 // Write next character 00205 while (!AT_intf.writeable()) { 00206 if (timer.read_ms() > timeout_ms) { 00207 result = TimeoutError; 00208 goto exit; 00209 } 00210 } 00211 AT_intf.putc(cmdString[i]); 00212 // Wait for echo 00213 if (expectEcho && (cmdString[i] != '\r') && (cmdString[i] != '\n')) { 00214 while (!AT_intf.readable()) { 00215 if (timer.read_ms() > timeout_ms) { 00216 result = TimeoutError; 00217 goto exit; 00218 } 00219 } 00220 // Compare to written character 00221 if (AT_intf.getc() != cmdString[i]) { 00222 // Handle error 00223 result = ESP8266::HardwareError; 00224 goto exit; 00225 } 00226 } 00227 } 00228 00229 while (result == ESP8266::HardwareError) { 00230 // Wait to receive something 00231 response.clear(); 00232 while (!read_line(response)) 00233 ; 00234 00235 // Check if valid response 00236 if (response == "OK") 00237 result = ESP8266::AT_OK; 00238 else if (response == "FAIL") 00239 result = ESP8266::AT_FAIL; 00240 else if (response == "ERROR") 00241 result = ESP8266::AT_ERROR; 00242 else if (response == "SEND OK") // Used by AT+CIPSEND 00243 result = ESP8266::AT_OK; 00244 else if (response == "ALREADY CONNECT") // Used by AT+CIPSTART 00245 result = ESP8266::AT_OK; 00246 00247 if (timer.read_ms() > timeout_ms) { 00248 result = TimeoutError; 00249 break; 00250 } 00251 } 00252 00253 exit: 00254 enableRecvData(); // Enable interrupt processing 00255 return result; 00256 } 00257 00258 bool ESP8266::read_line(std::string & line) { 00259 char received; 00260 00261 while (AT_intf.readable()) { 00262 received = AT_intf.getc(); 00263 if (received == '\n') { 00264 return true; 00265 } else if (received != '\r') { 00266 line.push_back(received); 00267 } 00268 } 00269 return false; 00270 } 00271 00272 void ESP8266::recv_AT_data_cb() { 00273 while (AT_intf.readable()) { 00274 char received = AT_intf.getc(); 00275 parseRecvIpData(received); 00276 parseRecvConnClosedMsg(received); 00277 parseRecvReset = false; 00278 } 00279 } 00280 00281 void ESP8266::parseRecvIpData(const char received) { 00282 enum DataRecvState { Header, Length, Data, Reset }; 00283 00284 static const char findChars[] = "+IPD,"; 00285 static const size_t maxSizeDigits = 4; 00286 00287 static size_t dataFinishedSize = 0; 00288 static size_t index = 0; 00289 static char sizeDigits[] = {'\0', '\0', '\0', '\0', '\0'}; 00290 static DataRecvState state = Header; 00291 00292 if (parseRecvReset) 00293 state = Reset; 00294 00295 switch (state) { 00296 case Reset: 00297 default: 00298 index = 0; 00299 dataFinishedSize = 0; 00300 state = Header; 00301 // Continue processing switch 00302 00303 case Header: 00304 if (received == findChars[index]) { 00305 if (findChars[++index] == '\0') { 00306 index = 0; 00307 state = Length; 00308 } 00309 } else { 00310 state = Reset; 00311 } 00312 break; 00313 00314 case Length: 00315 if ((received <= '9') && (received >= '0')) { 00316 if (index < maxSizeDigits) { 00317 sizeDigits[index++] = received; 00318 } else { 00319 state = Reset; 00320 } 00321 } else if (received == ':') { 00322 dataFinishedSize = std::atoi(sizeDigits); 00323 if (dataFinishedSize == 0) { 00324 state = Reset; 00325 } else { 00326 index = 0; 00327 state = Data; 00328 } 00329 } else { 00330 state = Reset; 00331 } 00332 break; 00333 00334 case Data: 00335 if (index < dataFinishedSize) { 00336 recvIpDataBuffer.push(received); 00337 index++; 00338 } else { 00339 state = Reset; 00340 } 00341 break; 00342 }; 00343 } 00344 00345 void ESP8266::parseRecvConnClosedMsg(const char received) { 00346 static const char findChars[] = "CLOSED"; 00347 00348 static int index = 0; 00349 00350 bool shouldReset = parseRecvReset; 00351 00352 if (received == findChars[index]) { 00353 if (findChars[++index] == '\0') { 00354 printDbgMsg(findChars); 00355 shouldReset = true; 00356 } 00357 } else { 00358 shouldReset = true; 00359 } 00360 00361 if (shouldReset) { 00362 index = 0; 00363 } 00364 } 00365 00366 void ESP8266::printDbgMsg(const char * message) { 00367 if (debugMsg != NULL) 00368 debugMsg->printf("%s", message); 00369 } 00370 00371 ESP8266::CmdBuilder::CmdBuilder (const std::string & cmd) { clear(cmd); } 00372 00373 void ESP8266::CmdBuilder::clear(const std::string & cmd) { 00374 numArgs = 0; 00375 cmdStream.str(""); 00376 00377 cmdStream << "AT"; 00378 if (cmd != "") 00379 cmdStream << "+" << cmd; 00380 } 00381 00382 void ESP8266::CmdBuilder::addStringArgument(const std::string & arg) { 00383 std::ostringstream argStream; 00384 argStream << "\"" << arg << "\""; 00385 addRawArgument<std::string>(argStream.str()); 00386 } 00387 00388 std::string ESP8266::CmdBuilder::str() const { 00389 std::string cmdString = cmdStream.str(); 00390 cmdString.append("\r\n"); 00391 return cmdString; 00392 }
Generated on Wed Jul 13 2022 21:31:02 by 1.7.2