MAXREFDES143#: DeepCover Embedded Security in IoT Authenticated Sensing & Notification
Dependencies: MaximInterface mbed
The MAXREFDES143# is an Internet of Things (IoT) embedded security reference design, built to protect an industrial sensing node by means of authentication and notification to a web server. The hardware includes a peripheral module representing a protected sensor node monitoring operating temperature and remaining life of a filter (simulated through ambient light sensing) and an mbed shield representing a controller node responsible for monitoring one or more sensor nodes. The design is hierarchical with each controller node communicating data from connected sensor nodes to a web server that maintains a centralized log and dispatches notifications as necessary. The mbed shield contains a Wi-Fi module, a DS2465 coprocessor with 1-Wire® master function, an LCD, LEDs, and pushbuttons. The protected sensor node contains a DS28E15 authenticator, a DS7505 temperature sensor, and a MAX44009 light sensor. The mbed shield communicates to a web server by the onboard Wi-Fi module and to the protected sensor node with I2C and 1-Wire. The MAXREFDES143# is equipped with a standard shield connector for immediate testing using an mbed board such as the MAX32600MBED#. The simplicity of this design enables rapid integration into any star-topology IoT network requiring the heightened security with low overhead provided by the SHA-256 symmetric-key algorithm.
More information about the MAXREFDES143# is available on the Maxim Integrated website.
ESP8266.cpp
- Committer:
- IanBenzMaxim
- Date:
- 2016-05-12
- Revision:
- 6:b6bafd0a7013
- Parent:
- 1:e1c7c1c636af
- Child:
- 9:bc3d211d75ce
File content as of revision 6:b6bafd0a7013:
/******************************************************************************* * Copyright (C) 2016 Maxim Integrated Products, Inc., All Rights Reserved. * * 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 MAXIM INTEGRATED 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. * * Except as contained in this notice, the name of Maxim Integrated * Products, Inc. shall not be used except as stated in the Maxim Integrated * Products, Inc. Branding Policy. * * The mere transfer of this software does not imply any licenses * of trade secrets, proprietary technology, copyrights, patents, * trademarks, maskwork rights, or any other form of intellectual * property whatsoever. Maxim Integrated Products, Inc. retains all * ownership rights. ******************************************************************************* */ #include <cstdlib> #include "ESP8266.hpp" #include "Timer.h" #include "wait_api.h" ESP8266* ESP8266::defaultInstance = NULL; static inline void disableRecvData() { __disable_irq(); } static inline void enableRecvData() { __enable_irq(); } void ESP8266::setDefaultInstance(ESP8266 * const instance) { if (instance != NULL) defaultInstance = instance; } ESP8266** ESP8266::getDefaultInstance() { return &defaultInstance; } ESP8266::ESP8266(const PinName tx, const PinName rx, const PinName rst, const PinName CH_PD, const int baud, mbed::Serial * debugMsgIntf) : AT_intf(tx, rx), resetPin(rst), powerDownPin(CH_PD), debugMsg(debugMsgIntf), parseRecvReset(false) { AT_intf.baud(baud); AT_intf.attach(this, &ESP8266::recv_AT_data_cb); // Ensure that device is not held in reset if (resetPin.is_connected()) resetPin = 1; // Power down device at startup due to high current demand setPowered(false); if (defaultInstance == NULL) defaultInstance = this; } ESP8266::~ESP8266() { if (defaultInstance == this) defaultInstance = NULL; } void ESP8266::reset() { if (resetPin.is_connected()) { resetPin = 0; wait_ms(10); resetPin = 1; wait_ms(1000); } } bool ESP8266::powered() const { bool isPowered; if (powerDownPin.is_connected()) { isPowered = powerDownPin.read(); } else { isPowered = false; } return isPowered; } void ESP8266::setPowered(bool powered) { if (powerDownPin.is_connected()) powerDownPin = powered; } ESP8266::CmdResult ESP8266::performSelfTest() { return sendCommand(CmdBuilder("")); } ESP8266::CmdResult ESP8266::setCurrentWifiMode(const ESP8266::WifiMode mode) { CmdBuilder builder("CWMODE_CUR"); builder.addRawArgument(mode); return sendCommand(builder); } ESP8266::CmdResult ESP8266::joinCurrentAccessPoint(const std::string & ssid, const std::string & pwd, const std::string & bssid) { CmdBuilder builder("CWJAP_CUR"); builder.addStringArgument(ssid); builder.addStringArgument(pwd); if (bssid != "") builder.addStringArgument(bssid); return sendCommand(builder); } ESP8266::CmdResult ESP8266::quitAccessPoint() { return sendCommand(CmdBuilder("CWQAP")); } ESP8266::CmdResult ESP8266::setMaxRFTXPower(const float power_dBm) { int power_arg = (int)(power_dBm * 4); if (power_arg > 82) power_arg = 82; else if (power_arg < 0) power_arg = 0; CmdBuilder builder("RFPOWER"); builder.addRawArgument(power_arg); return sendCommand(builder); } ESP8266::CmdResult ESP8266::ping(const std::string & IP) { CmdBuilder builder("PING"); builder.addStringArgument(IP); return sendCommand(builder); } ESP8266::CmdResult ESP8266::openConnection(const ESP8266::ConnType type, const std::string & remoteIP, const unsigned int remotePort) { CmdBuilder builder("CIPSTART"); builder.addStringArgument((type == TCP) ? "TCP" : "UDP"); builder.addStringArgument(remoteIP); builder.addRawArgument(remotePort); return sendCommand(builder); } ESP8266::CmdResult ESP8266::closeConnection() { return sendCommand(CmdBuilder("CIPCLOSE")); } ESP8266::CmdResult ESP8266::sendData(const std::string & data) { CmdBuilder builder("CIPSEND"); builder.addRawArgument(data.length()); ESP8266::CmdResult result = sendCommand(builder); if (result == ESP8266::AT_OK) result = send_AT_data(data, false); return result; } ESP8266::CmdResult ESP8266::sendCommand(const CmdBuilder & cmd) { return send_AT_data(cmd.str(), true); } bool ESP8266::recvIpDataReadable() { bool result; disableRecvData(); // Lock queue access result = !recvIpDataBuffer.empty(); enableRecvData(); // Unlock queue access return result; } char ESP8266::getcRecvIpData() { char received; disableRecvData(); // Lock queue access // Pop next char or set to NTC if not data in buffer if (!recvIpDataBuffer.pop(received)) received = '\0'; enableRecvData(); // Unlock queue access return received; } void ESP8266::clearRecvData() { disableRecvData(); // Lock queue access recvIpDataBuffer.reset(); parseRecvReset = true; enableRecvData(); // Unlock queue access } ESP8266::CmdResult ESP8266::send_AT_data(const std::string & cmdString, const bool expectEcho) { const int timeout_ms = 10000; mbed::Timer timer; ESP8266::CmdResult result = ESP8266::HardwareError; std::string response; disableRecvData(); // Lock for manual data handling in this procedure // Flush receive buffer while (AT_intf.readable()) AT_intf.getc(); // Begin counting for timeout timer.start(); for (size_t i = 0; i < cmdString.length(); i++) { // Write next character while (!AT_intf.writeable()) { if (timer.read_ms() > timeout_ms) { result = TimeoutError; goto exit; } } AT_intf.putc(cmdString[i]); // Wait for echo if (expectEcho && (cmdString[i] != '\r') && (cmdString[i] != '\n')) { while (!AT_intf.readable()) { if (timer.read_ms() > timeout_ms) { result = TimeoutError; goto exit; } } // Compare to written character if (AT_intf.getc() != cmdString[i]) { // Handle error result = ESP8266::HardwareError; goto exit; } } } while (result == ESP8266::HardwareError) { // Wait to receive something response.clear(); while (!read_line(response)) ; // Check if valid response if (response == "OK") result = ESP8266::AT_OK; else if (response == "FAIL") result = ESP8266::AT_FAIL; else if (response == "ERROR") result = ESP8266::AT_ERROR; else if (response == "SEND OK") // Used by AT+CIPSEND result = ESP8266::AT_OK; else if (response == "ALREADY CONNECT") // Used by AT+CIPSTART result = ESP8266::AT_OK; if (timer.read_ms() > timeout_ms) { result = TimeoutError; break; } } exit: enableRecvData(); // Enable interrupt processing return result; } bool ESP8266::read_line(std::string & line) { char received; while (AT_intf.readable()) { received = AT_intf.getc(); if (received == '\n') { return true; } else if (received != '\r') { line.push_back(received); } } return false; } void ESP8266::recv_AT_data_cb() { while (AT_intf.readable()) { char received = AT_intf.getc(); parseRecvIpData(received); parseRecvConnClosedMsg(received); parseRecvReset = false; } } void ESP8266::parseRecvIpData(const char received) { enum DataRecvState { Header, Length, Data, Reset }; static const char findChars[] = "+IPD,"; static const size_t maxSizeDigits = 4; static size_t dataFinishedSize = 0; static int index = 0; static char sizeDigits[] = { '\0', '\0', '\0', '\0', '\0' }; static DataRecvState state = Header; if (parseRecvReset) state = Reset; switch (state) { case Reset: default: index = 0; dataFinishedSize = 0; state = Header; // Continue processing switch case Header: if (received == findChars[index]) { if (findChars[++index] == '\0') { index = 0; state = Length; } } else { state = Reset; } break; case Length: if ((received <= '9') && (received >= '0')) { if (index < maxSizeDigits) { sizeDigits[index++] = received; } else { state = Reset; } } else if (received == ':') { dataFinishedSize = std::atoi(sizeDigits); if (dataFinishedSize == 0) { state = Reset; } else { index = 0; state = Data; } } else { state = Reset; } break; case Data: if (index < dataFinishedSize) { recvIpDataBuffer.push(received); index++; } else { state = Reset; } break; }; } void ESP8266::parseRecvConnClosedMsg(const char received) { static const char findChars[] = "CLOSED"; static int index = 0; bool shouldReset = parseRecvReset; if (received == findChars[index]) { if (findChars[++index] == '\0') { printDbgMsg(findChars); shouldReset = true; } } else { shouldReset = true; } if (shouldReset) { index = 0; } } void ESP8266::printDbgMsg(const char * message) { if (debugMsg != NULL) debugMsg->printf("%s", message); } ESP8266::CmdBuilder::CmdBuilder(const std::string & cmd) { clear(cmd); } void ESP8266::CmdBuilder::clear(const std::string & cmd) { numArgs = 0; cmdStream.str(""); cmdStream << "AT"; if (cmd != "") cmdStream << "+" << cmd; } void ESP8266::CmdBuilder::addStringArgument(const std::string & arg) { std::ostringstream argStream; argStream << "\"" << arg << "\""; addRawArgument<std::string>(argStream.str()); } std::string ESP8266::CmdBuilder::str() const { std::string cmdString = cmdStream.str(); cmdString.append("\r\n"); return cmdString; }