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.
Revision 28:e5cdaf13d299, committed 2017-01-26
- Comitter:
- IanBenzMaxim
- Date:
- Thu Jan 26 14:18:21 2017 -0600
- Parent:
- 27:81a87d29bedd
- Child:
- 29:590a7561318b
- Commit message:
- Migrated the web interface to the mbed 5 networking stack to improve system compatibility.
Changed in this revision
--- a/ESP8266.cpp Fri Dec 16 20:14:05 2016 +0000
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,489 +0,0 @@
-/*******************************************************************************
-* 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(100);
- 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 size_t 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;
-}
\ No newline at end of file
--- a/ESP8266.hpp Fri Dec 16 20:14:05 2016 +0000
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,220 +0,0 @@
-/*******************************************************************************
-* 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.
-*******************************************************************************
-*/
-
-#ifndef ESP8266_HPP
-#define ESP8266_HPP
-
-#include <string>
-#include <sstream>
-
-#include "PinNames.h"
-#include "Serial.h"
-#include "DigitalOut.h"
-#include "CircularBuffer.h"
-
-namespace mbed { class Serial; }
-
-/// Interface to the ESP8266 Wi-Fi module.
-class ESP8266
-{
-public:
- /// Result of sending an AT command.
- enum CmdResult
- {
- AT_OK = 1,
- AT_FAIL = 0,
- AT_ERROR = -1,
- HardwareError = -2,
- TimeoutError = -3
- };
-
- /// ESP8266 Wi-Fi mode.
- enum WifiMode
- {
- station_mode = 1,
- softAP_mode = 2,
- softAP_station_mode = 3
- };
-
- /// Connection type.
- enum ConnType
- {
- TCP,
- UDP
- };
-
- /// Recovery time between Send Data operation as specified by datasheet.
- static const unsigned int sendDataRecoveryTimeMs = 1000;
-
- /// Builds command strings for the ESP8266 with proper formatting.
- class CmdBuilder
- {
- public:
- /// @param cmd Command of the format "AT+[cmd]".
- CmdBuilder(const std::string & cmd = "");
-
- /// Clear all arguments.
- /// @param cmd Command of the format "AT+[cmd]".
- void clear(const std::string & cmd);
-
- /// Append an argument using the default string conversion for that type.
- /// @param arg Argument to append to the command.
- template <typename T> void addRawArgument(const T & arg)
- {
- cmdStream << ((numArgs == 0) ? "=" : ",") << arg;
- numArgs++;
- }
-
- /// Append a string argument with proper quoting.
- /// @param arg Argument to append to the command.
- void addStringArgument(const std::string & arg);
-
- /// Create a string suitable for use with sendCommand().
- /// @returns The formatted command string.
- std::string str() const;
-
- private:
- int numArgs;
- std::ostringstream cmdStream;
- };
-
- /// @{
- /// Default instance support for use with mbed Sockets.
- static void setDefaultInstance(ESP8266 * const instance);
- static ESP8266** getDefaultInstance();
- /// @}
-
- /// @param tx Transmit pin from mbed to ESP8266.
- /// @param rx Receive pin from ESP8266 to mbed.
- /// @param rst Reset pin on ESP8266.
- /// @param CH_PD Power-down pin on ESP8266.
- /// @param baud Baud rate that the ESP8266 is using.
- /// @param debugMsgIntf Optional serial interface for debugging messages.
- ESP8266(const PinName tx, const PinName rx, const PinName rst, const PinName CH_PD, const int baud, mbed::Serial * debugMsgIntf = NULL);
- ~ESP8266();
-
- /// Reset the ESP8266 via the hardware reset pin.
- void reset();
-
- // Update the baud rate for the ESP8266.
- void setBaud(int baud) { AT_intf.baud(baud); }
-
- /// @{
- /// Control if the ESP8266 is powered via the hardware power-down pin.
- bool powered() const;
- void setPowered(bool powered);
- /// @}
-
- /// Perform a self-test on the ESP8266.
- CmdResult performSelfTest();
-
- /// Set the current Wi-Fi mode.
- CmdResult setCurrentWifiMode(const WifiMode mode);
-
- /// Join a Wi-Fi access point.
- /// @param ssid Network SSID to connect to.
- /// @param pwd Network password.
- /// @param bssid Optional network BSSID.
- CmdResult joinCurrentAccessPoint(const std::string & ssid, const std::string & pwd, const std::string & bssid = "");
-
- /// Quit the current access point.
- CmdResult quitAccessPoint();
-
- /// Set the maximum WiFi tranmission power.
- /// @param power_dBm Power in dBm valid from 0 to 20.5 in 0.25 dBm increments.
- CmdResult setMaxRFTXPower(const float power_dBm);
-
- /// Ping a host via the current access point.
- /// @param IP IP address or resolvable hostname.
- CmdResult ping(const std::string & IP);
-
- /// Open a connection to a host via the current access point.
- /// @param type TCP or UPD connection.
- /// @param remoteIP IP address or resolvable hostname to connect to.
- /// @param remotePort Port on the host to connect to.
- CmdResult openConnection(const ConnType type, const std::string & remoteIP, const unsigned int remotePort);
-
- /// Close the connection to the current host.
- CmdResult closeConnection();
-
- /// Send data to the currently connected host.
- /// @param data May be in text or binary form.
- CmdResult sendData(const std::string & data);
-
- /// Send an AT command to the ESP8266.
- /// @param cmd Formatted command to send.
- CmdResult sendCommand(const CmdBuilder & cmd);
-
- /// Check if received IP data is available in the buffer.
- /// @note Allow some processing delay to happen between calls to this function.
- /// @returns True if data is available.
- bool recvIpDataReadable();
- /// Get the next character of received IP data from the buffer.
- char getcRecvIpData();
- /// Clear all received data from the buffer.
- void clearRecvData();
-
-private:
- static ESP8266 * defaultInstance; ///< Default instance support for use with mbed Sockets.
-
- mbed::Serial AT_intf;
- mbed::DigitalOut resetPin;
- mutable mbed::DigitalOut powerDownPin; ///< @note Mark as mutable for use in powered().
- mbed::CircularBuffer<char, 1024> recvIpDataBuffer; ///< Received IP data buffer.
- mbed::Serial * debugMsg;
- volatile bool parseRecvReset; ///< Indicates when AT interface received data parsers should be reset.
-
- /// Send raw AT data to the ESP8266.
- /// @param cmdString Data to send.
- /// @param expectEcho True if the ESP8266 will echo sent data back.
- CmdResult send_AT_data(const std::string & cmdString, const bool expectEcho);
-
- /// Attempts to read an entire line terminated with \r\n from the AT interface.
- /// \r will be preserved in the final string and \n will be stripped.
- /// @param line Buffer to store received characters in.
- /// @returns True if an entire line was read.
- bool read_line(std::string & line);
-
- /// Callback for when data is received on the AT interface.
- void recv_AT_data_cb();
- /// Parse the next character received on the AT interface checking for valid IP data.
- void parseRecvIpData(const char received);
- /// Parse the next character receive on the AT interface for the connection closed message.
- void parseRecvConnClosedMsg(const char received);
-
- /// Print a message on the debugging interface if setup.
- /// @param message Null terminated string.
- void printDbgMsg(const char * message);
-};
-
-#endif
\ No newline at end of file
--- a/WebServerInterface.cpp Fri Dec 16 20:14:05 2016 +0000
+++ b/WebServerInterface.cpp Thu Jan 26 14:18:21 2017 -0600
@@ -31,9 +31,11 @@
*******************************************************************************
*/
+#include <sstream>
#include <vector>
#include "WebServerInterface.hpp"
-#include "ESP8266.hpp"
+#include "NetworkStack.h"
+#include "TCPSocket.h"
#include "Slaves/Authenticators/ISha256MacCoproc.h"
#include "SensorData.hpp"
#include "HexConversions.hpp"
@@ -42,8 +44,6 @@
using OneWire::ISha256MacCoproc;
-const char WebServerInterface::wifiSsid[] = "WifiSsid";
-const char WebServerInterface::wifiPassword[] = "WifiPassword";
const char WebServerInterface::serverAddress[] = "www.mxim-security.us";
const unsigned int WebServerInterface::serverPort = 80;
const char WebServerInterface::serverPostPath[] = "/post.php";
@@ -71,32 +71,6 @@
return (MacCoproc.computeSlaveSecret(fillData, fillData, secretData) == ISha256MacCoproc::Success);
}
-WebServerInterface::WebServerInterface(ESP8266 & esp8266, mbed::Serial * pc)
- : esp8266(esp8266), pc(pc)
-{
-
-}
-
-bool WebServerInterface::initialize()
-{
- esp8266.setPowered(true);
- esp8266.reset();
- bool result = (esp8266.performSelfTest() == ESP8266::AT_OK);
- if (result)
- {
- result = (esp8266.setCurrentWifiMode(ESP8266::softAP_station_mode) == ESP8266::AT_OK);
- }
- if (result)
- {
- result = (esp8266.setMaxRFTXPower(10) == ESP8266::AT_OK);
- }
- if (result)
- {
- result = (esp8266.joinCurrentAccessPoint(wifiSsid, wifiPassword) == ESP8266::AT_OK);
- }
- return result;
-}
-
/// Format an HTTP GET request as a string for transmission.
/// @param host Web server address.
/// @param path Web server location to retrieve.
@@ -241,13 +215,7 @@
bool WebServerInterface::authPostHttpEvent(ISha256MacCoproc & macCoproc, PostEvent event, const std::string & postData, bool setSecret)
{
- const std::string challengeSearch(newline + newline);
bool result;
- uint8_t challenge[challengeLen];
- std::string response;
-
- std::memset(challenge, defaultPaddingByte, challengeLen);
- response.reserve(300);
if (setSecret)
{
@@ -257,60 +225,47 @@
}
// Open connection
- esp8266.clearRecvData(); // Clear received data buffer
- result = (esp8266.openConnection(ESP8266::TCP, serverAddress, 80) == ESP8266::AT_OK);
+ TCPSocket socket(&networkStack);
+ result = (socket.connect(serverAddress, 80) == 0);
if (result)
{
// Request challenge
- result = (esp8266.sendData(formatHttpGet(serverAddress, serverChallengePath, m_sessionIdString)) == ESP8266::AT_OK);
+ std::string httpData = formatHttpGet(serverAddress, serverChallengePath, m_sessionIdString);
+ result = (socket.send(httpData.data(), httpData.size()) == httpData.size());
if (result)
{
// Receive server response
- for (int i = 0; i < 10; i++)
- {
- while (esp8266.recvIpDataReadable())
+ int recvResult = socket.recv(recvBuf, sizeof(recvBuf) / sizeof(recvBuf[0]));
+ result = recvResult > 0;
+
+ if (result)
+ {
+ // Parse challenge from response
+ const std::string challengeSearch(newline + newline);
+ httpData.assign(recvBuf, recvResult);
+ size_t challengePos = httpData.find(challengeSearch);
+ if ((challengePos != std::string::npos) && ((challengePos + challengeSearch.length() + (challengeLen * charsPerByte)) <= httpData.length()))
{
- char read = esp8266.getcRecvIpData();
- if (pc != NULL)
- pc->putc(read);
- if (response.length() < response.capacity())
+ uint8_t challenge[challengeLen];
+ challengePos += challengeSearch.length();
+ for (size_t i = 0; i < challengeLen; i++)
{
- response += read;
+ std::sscanf(httpData.substr(challengePos + (i * charsPerByte), charsPerByte).c_str(), "%2hhx", &challenge[i]);
}
- else
+
+ // Post sensor data
+ httpData = formatHttpPost(serverAddress, serverPostPath, m_sessionIdString, macCoproc, event, postData, challenge);
+ result = (socket.send(httpData.data(), httpData.size()) == httpData.size());
+ if (result)
{
- wait_ms(ESP8266::sendDataRecoveryTimeMs); // Wait for ESP8266 specified recovery time
- goto close_get_connection;
+ result = (socket.recv(recvBuf, sizeof(recvBuf) / sizeof(recvBuf[0])) >= 0);
}
}
- wait_ms(100);
- }
- // Close connection
- close_get_connection:
- esp8266.closeConnection();
-
- // Parse challenge from response
- size_t challengePos = response.find(challengeSearch);
- if ((challengePos != std::string::npos) && ((challengePos + challengeSearch.length() + (challengeLen * charsPerByte)) <= response.length()))
- {
- challengePos += challengeSearch.length();
- for (size_t i = 0; i < challengeLen; i++)
- {
- std::sscanf(response.substr(challengePos + (i * charsPerByte), charsPerByte).c_str(), "%2hhx", &challenge[i]);
- }
- }
-
- // Post sensor data
- result = (esp8266.openConnection(ESP8266::TCP, serverAddress, serverPort) == ESP8266::AT_OK);
- if (result)
- {
- result = (esp8266.sendData(formatHttpPost(serverAddress, serverPostPath, m_sessionIdString, macCoproc, event, postData, challenge)) == ESP8266::AT_OK);
- wait_ms(ESP8266::sendDataRecoveryTimeMs); // Wait for ESP8266 specified recovery time
}
}
// Close connection
- esp8266.closeConnection();
+ socket.close();
}
return result;
--- a/WebServerInterface.hpp Fri Dec 16 20:14:05 2016 +0000
+++ b/WebServerInterface.hpp Thu Jan 26 14:18:21 2017 -0600
@@ -46,7 +46,7 @@
namespace mbed { class Serial; }
namespace OneWire { class ISha256MacCoproc; }
-class ESP8266;
+class NetworkStack;
struct SensorData;
/// Network interface to the web server supporting authenticated posting of event
@@ -56,11 +56,7 @@
public:
/// @param esp8266 Interface to ESP8266 for Wi-Fi access.
/// @param pc Optional serial interface for received web traffic.
- WebServerInterface(ESP8266 & esp8266, mbed::Serial * pc = NULL);
-
- /// Initialize network interface and connect to access point.
- /// @returns True on success.
- bool initialize();
+ WebServerInterface(NetworkStack & networkStack) : networkStack(networkStack) { }
/// Send an authenticated event message to the web server.
/// @param macCoProc Coprocessor such as the DS2465 used to calculate the authentication MAC.
@@ -85,8 +81,6 @@
private:
/// @{
/// Configuration strings.
- static const char wifiSsid[];
- static const char wifiPassword[];
static const char serverAddress[];
static const unsigned int serverPort;
static const char serverPostPath[];
@@ -96,8 +90,9 @@
OneWire::RomId m_sessionId;
std::string m_sessionIdString;
- ESP8266 & esp8266;
- mbed::Serial * pc;
+ NetworkStack & networkStack;
+
+ char recvBuf[1024];
};
#endif
\ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/esp8266-driver/ESP8266/ATParser.lib Thu Jan 26 14:18:21 2017 -0600 @@ -0,0 +1,1 @@ +https://github.com/ARMmbed/ATParser/#269f14532b98442669c50383782cbce1c67aced5
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/esp8266-driver/ESP8266/ESP8266.cpp Thu Jan 26 14:18:21 2017 -0600
@@ -0,0 +1,302 @@
+/* ESP8266 Example
+ * Copyright (c) 2015 ARM Limited
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "ESP8266.h"
+
+ESP8266::ESP8266(PinName tx, PinName rx, bool debug)
+ : _serial(tx, rx, 1024), _parser(_serial)
+ , _packets(0), _packets_end(&_packets)
+{
+ _serial.baud(38400);
+ _parser.debugOn(debug);
+}
+
+bool ESP8266::startup(int mode)
+{
+ //only 3 valid modes
+ if(mode < 1 || mode > 3) {
+ return false;
+ }
+
+ bool success = reset()
+ && _parser.send("AT+RFPOWER=10")
+ && _parser.recv("OK")
+ && _parser.send("AT+CWMODE_CUR=%d", mode)
+ && _parser.recv("OK")
+ && _parser.send("AT+CIPMUX=1")
+ && _parser.recv("OK");
+
+ _parser.oob("+IPD", this, &ESP8266::_packet_handler);
+
+ return success;
+}
+
+bool ESP8266::reset(void)
+{
+ return _parser.send("AT+RST")
+ && _parser.recv("ready");
+}
+
+bool ESP8266::dhcp(bool enabled, int mode)
+{
+ //only 3 valid modes
+ if(mode < 0 || mode > 2) {
+ return false;
+ }
+
+ return _parser.send("AT+CWDHCP_CUR=%d,%d", enabled?1:0, mode)
+ && _parser.recv("OK");
+}
+
+bool ESP8266::connect(const char *ap, const char *passPhrase)
+{
+ return _parser.send("AT+CWJAP_CUR=\"%s\",\"%s\"", ap, passPhrase)
+ && _parser.recv("OK");
+}
+
+bool ESP8266::disconnect(void)
+{
+ return _parser.send("AT+CWQAP") && _parser.recv("OK");
+}
+
+const char *ESP8266::getIPAddress(void)
+{
+ if (!(_parser.send("AT+CIFSR")
+ && _parser.recv("+CIFSR:STAIP,\"%15[^\"]\"", _ip_buffer)
+ && _parser.recv("OK"))) {
+ return 0;
+ }
+
+ return _ip_buffer;
+}
+
+const char *ESP8266::getMACAddress(void)
+{
+ if (!(_parser.send("AT+CIFSR")
+ && _parser.recv("+CIFSR:STAMAC,\"%17[^\"]\"", _mac_buffer)
+ && _parser.recv("OK"))) {
+ return 0;
+ }
+
+ return _mac_buffer;
+}
+
+const char *ESP8266::getGateway()
+{
+ if (!(_parser.send("AT+CIPSTA?")
+ && _parser.recv("+CIPSTA:gateway:\"%15[^\"]\"", _gateway_buffer)
+ && _parser.recv("OK"))) {
+ return 0;
+ }
+
+ return _gateway_buffer;
+}
+
+const char *ESP8266::getNetmask()
+{
+ if (!(_parser.send("AT+CIPSTA?")
+ && _parser.recv("+CIPSTA:netmask:\"%15[^\"]\"", _netmask_buffer)
+ && _parser.recv("OK"))) {
+ return 0;
+ }
+
+ return _netmask_buffer;
+}
+
+int8_t ESP8266::getRSSI()
+{
+ int8_t rssi;
+ char bssid[18];
+
+ if (!(_parser.send("AT+CWJAP?")
+ && _parser.recv("+CWJAP:\"%*[^\"]\",\"%17[^\"]\"", bssid)
+ && _parser.recv("OK"))) {
+ return 0;
+ }
+
+ if (!(_parser.send("AT+CWLAP=\"\",\"%s\",", bssid)
+ && _parser.recv("+CWLAP:(%*d,\"%*[^\"]\",%hhd,", &rssi)
+ && _parser.recv("OK"))) {
+ return 0;
+ }
+
+ return rssi;
+}
+
+bool ESP8266::isConnected(void)
+{
+ return getIPAddress() != 0;
+}
+
+int ESP8266::scan(WiFiAccessPoint *res, unsigned limit)
+{
+ unsigned cnt = 0;
+ nsapi_wifi_ap_t ap;
+
+ if (!_parser.send("AT+CWLAP")) {
+ return NSAPI_ERROR_DEVICE_ERROR;
+ }
+
+ while (recv_ap(&ap)) {
+ if (cnt < limit) {
+ res[cnt] = WiFiAccessPoint(ap);
+ }
+
+ cnt++;
+ if (limit != 0 && cnt >= limit) {
+ break;
+ }
+ }
+
+ return cnt;
+}
+
+bool ESP8266::open(const char *type, int id, const char* addr, int port)
+{
+ //IDs only 0-4
+ if(id > 4) {
+ return false;
+ }
+
+ return _parser.send("AT+CIPSTART=%d,\"%s\",\"%s\",%d", id, type, addr, port)
+ && _parser.recv("OK");
+}
+
+bool ESP8266::send(int id, const void *data, uint32_t amount)
+{
+ //May take a second try if device is busy
+ for (unsigned i = 0; i < 2; i++) {
+ if (_parser.send("AT+CIPSEND=%d,%d", id, amount)
+ && _parser.recv(">")
+ && _parser.write((char*)data, (int)amount) >= 0) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+void ESP8266::_packet_handler()
+{
+ int id;
+ uint32_t amount;
+
+ // parse out the packet
+ if (!_parser.recv(",%d,%d:", &id, &amount)) {
+ return;
+ }
+
+ struct packet *packet = (struct packet*)malloc(
+ sizeof(struct packet) + amount);
+ if (!packet) {
+ return;
+ }
+
+ packet->id = id;
+ packet->len = amount;
+ packet->next = 0;
+
+ if (!(_parser.read((char*)(packet + 1), amount))) {
+ free(packet);
+ return;
+ }
+
+ // append to packet list
+ *_packets_end = packet;
+ _packets_end = &packet->next;
+}
+
+int32_t ESP8266::recv(int id, void *data, uint32_t amount)
+{
+ while (true) {
+ // check if any packets are ready for us
+ for (struct packet **p = &_packets; *p; p = &(*p)->next) {
+ if ((*p)->id == id) {
+ struct packet *q = *p;
+
+ if (q->len <= amount) { // Return and remove full packet
+ memcpy(data, q+1, q->len);
+
+ if (_packets_end == &(*p)->next) {
+ _packets_end = p;
+ }
+ *p = (*p)->next;
+
+ uint32_t len = q->len;
+ free(q);
+ return len;
+ } else { // return only partial packet
+ memcpy(data, q+1, amount);
+
+ q->len -= amount;
+ memmove(q+1, (uint8_t*)(q+1) + amount, q->len);
+
+ return amount;
+ }
+ }
+ }
+
+ // Wait for inbound packet
+ if (!_parser.recv("OK")) {
+ return -1;
+ }
+ }
+}
+
+bool ESP8266::close(int id)
+{
+ //May take a second try if device is busy
+ for (unsigned i = 0; i < 2; i++) {
+ if (_parser.send("AT+CIPCLOSE=%d", id)
+ && _parser.recv("OK")) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+void ESP8266::setTimeout(uint32_t timeout_ms)
+{
+ _parser.setTimeout(timeout_ms);
+}
+
+bool ESP8266::readable()
+{
+ return _serial.readable();
+}
+
+bool ESP8266::writeable()
+{
+ return _serial.writeable();
+}
+
+void ESP8266::attach(Callback<void()> func)
+{
+ _serial.attach(func);
+}
+
+bool ESP8266::recv_ap(nsapi_wifi_ap_t *ap)
+{
+ int sec;
+ bool ret = _parser.recv("+CWLAP:(%d,\"%32[^\"]\",%hhd,\"%hhx:%hhx:%hhx:%hhx:%hhx:%hhx\",%d", &sec, ap->ssid,
+ &ap->rssi, &ap->bssid[0], &ap->bssid[1], &ap->bssid[2], &ap->bssid[3], &ap->bssid[4],
+ &ap->bssid[5], &ap->channel);
+
+ ap->security = sec < 5 ? (nsapi_security_t)sec : NSAPI_SECURITY_UNKNOWN;
+
+ return ret;
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/esp8266-driver/ESP8266/ESP8266.h Thu Jan 26 14:18:21 2017 -0600
@@ -0,0 +1,213 @@
+/* ESP8266Interface Example
+ * Copyright (c) 2015 ARM Limited
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ESP8266_H
+#define ESP8266_H
+
+#include "ATParser.h"
+
+/** ESP8266Interface class.
+ This is an interface to a ESP8266 radio.
+ */
+class ESP8266
+{
+public:
+ ESP8266(PinName tx, PinName rx, bool debug=false);
+
+ /**
+ * Startup the ESP8266
+ *
+ * @param mode mode of WIFI 1-client, 2-host, 3-both
+ * @return true only if ESP8266 was setup correctly
+ */
+ bool startup(int mode);
+
+ /**
+ * Reset ESP8266
+ *
+ * @return true only if ESP8266 resets successfully
+ */
+ bool reset(void);
+
+ /**
+ * 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);
+
+ /**
+ * Connect ESP8266 to AP
+ *
+ * @param ap the name of the AP
+ * @param passPhrase the password of AP
+ * @return true only if ESP8266 is connected successfully
+ */
+ bool connect(const char *ap, const char *passPhrase);
+
+ /**
+ * Disconnect ESP8266 from AP
+ *
+ * @return true only if ESP8266 is disconnected successfully
+ */
+ bool disconnect(void);
+
+ /**
+ * Get the IP address of ESP8266
+ *
+ * @return null-teriminated IP address or null if no IP address is assigned
+ */
+ const char *getIPAddress(void);
+
+ /**
+ * Get the MAC address of ESP8266
+ *
+ * @return null-terminated MAC address or null if no MAC address is assigned
+ */
+ const char *getMACAddress(void);
+
+ /** Get the local gateway
+ *
+ * @return Null-terminated representation of the local gateway
+ * or null if no network mask has been recieved
+ */
+ const char *getGateway();
+
+ /** Get the local network mask
+ *
+ * @return Null-terminated representation of the local network mask
+ * or null if no network mask has been recieved
+ */
+ const char *getNetmask();
+
+ /* Return RSSI for active connection
+ *
+ * @return Measured RSSI
+ */
+ int8_t getRSSI();
+
+ /**
+ * Check if ESP8266 is conenected
+ *
+ * @return true only if the chip has an IP address
+ */
+ bool isConnected(void);
+
+ /** Scan for available networks
+ *
+ * @param ap Pointer to allocated array to store discovered AP
+ * @param limit Size of allocated @a res array, or 0 to only count available AP
+ * @return Number of entries in @a res, or if @a count was 0 number of available networks, negative on error
+ * see @a nsapi_error
+ */
+ int scan(WiFiAccessPoint *res, unsigned limit);
+
+ /**
+ * Open a socketed connection
+ *
+ * @param type the type of socket to open "UDP" or "TCP"
+ * @param id id to give the new socket, valid 0-4
+ * @param port port to open connection with
+ * @param addr the IP address of the destination
+ * @return true only if socket opened successfully
+ */
+ bool open(const char *type, int id, const char* addr, int port);
+
+ /**
+ * Sends data to an open socket
+ *
+ * @param id id of socket to send to
+ * @param data data to be sent
+ * @param amount amount of data to be sent - max 1024
+ * @return true only if data sent successfully
+ */
+ bool send(int id, const void *data, uint32_t amount);
+
+ /**
+ * Receives data from an open socket
+ *
+ * @param id id to receive from
+ * @param data placeholder for returned information
+ * @param amount number of bytes to be received
+ * @return the number of bytes received
+ */
+ int32_t recv(int id, void *data, uint32_t amount);
+
+ /**
+ * Closes a socket
+ *
+ * @param id id of socket to close, valid only 0-4
+ * @return true only if socket is closed successfully
+ */
+ bool close(int id);
+
+ /**
+ * Allows timeout to be changed between commands
+ *
+ * @param timeout_ms timeout of the connection
+ */
+ void setTimeout(uint32_t timeout_ms);
+
+ /**
+ * Checks if data is available
+ */
+ bool readable();
+
+ /**
+ * Checks if data can be written
+ */
+ bool writeable();
+
+ /**
+ * Attach a function to call whenever network state has changed
+ *
+ * @param func A pointer to a void function, or 0 to set as none
+ */
+ void attach(Callback<void()> func);
+
+ /**
+ * Attach a function to call whenever network state has changed
+ *
+ * @param obj pointer to the object to call the member function on
+ * @param method pointer to the member function to call
+ */
+ template <typename T, typename M>
+ void attach(T *obj, M method) {
+ attach(Callback<void()>(obj, method));
+ }
+
+private:
+ BufferedSerial _serial;
+ ATParser _parser;
+
+ struct packet {
+ struct packet *next;
+ int id;
+ uint32_t len;
+ // data follows
+ } *_packets, **_packets_end;
+ void _packet_handler();
+ bool recv_ap(nsapi_wifi_ap_t *ap);
+
+ char _ip_buffer[16];
+ char _gateway_buffer[16];
+ char _netmask_buffer[16];
+ char _mac_buffer[18];
+};
+
+#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/esp8266-driver/ESP8266Interface.cpp Thu Jan 26 14:18:21 2017 -0600
@@ -0,0 +1,282 @@
+/* ESP8266 implementation of NetworkInterfaceAPI
+ * Copyright (c) 2015 ARM Limited
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <string.h>
+#include "ESP8266Interface.h"
+
+// Various timeouts for different ESP8266 operations
+#define ESP8266_CONNECT_TIMEOUT 15000
+#define ESP8266_SEND_TIMEOUT 500
+#define ESP8266_RECV_TIMEOUT 0
+#define ESP8266_MISC_TIMEOUT 500
+
+// ESP8266Interface implementation
+ESP8266Interface::ESP8266Interface(PinName tx, PinName rx, bool debug)
+ : _esp(tx, rx, debug)
+{
+ memset(_ids, 0, sizeof(_ids));
+ memset(_cbs, 0, sizeof(_cbs));
+
+ _esp.attach(this, &ESP8266Interface::event);
+}
+
+int ESP8266Interface::connect(const char *ssid, const char *pass, nsapi_security_t security,
+ uint8_t channel)
+{
+ if (channel != 0) {
+ return NSAPI_ERROR_UNSUPPORTED;
+ }
+
+ set_credentials(ssid, pass, security);
+ return connect();
+}
+
+int ESP8266Interface::connect()
+{
+ _esp.setTimeout(ESP8266_CONNECT_TIMEOUT);
+
+ if (!_esp.startup(3)) {
+ return NSAPI_ERROR_DEVICE_ERROR;
+ }
+
+ if (!_esp.dhcp(true, 1)) {
+ return NSAPI_ERROR_DHCP_FAILURE;
+ }
+
+ if (!_esp.connect(ap_ssid, ap_pass)) {
+ return NSAPI_ERROR_NO_CONNECTION;
+ }
+
+ if (!_esp.getIPAddress()) {
+ return NSAPI_ERROR_DHCP_FAILURE;
+ }
+
+ return NSAPI_ERROR_OK;
+}
+
+int ESP8266Interface::set_credentials(const char *ssid, const char *pass, nsapi_security_t security)
+{
+ memset(ap_ssid, 0, sizeof(ap_ssid));
+ strncpy(ap_ssid, ssid, sizeof(ap_ssid));
+
+ memset(ap_pass, 0, sizeof(ap_pass));
+ strncpy(ap_pass, pass, sizeof(ap_pass));
+
+ ap_sec = security;
+
+ return 0;
+}
+
+int ESP8266Interface::set_channel(uint8_t channel)
+{
+ return NSAPI_ERROR_UNSUPPORTED;
+}
+
+
+int ESP8266Interface::disconnect()
+{
+ _esp.setTimeout(ESP8266_MISC_TIMEOUT);
+
+ if (!_esp.disconnect()) {
+ return NSAPI_ERROR_DEVICE_ERROR;
+ }
+
+ return NSAPI_ERROR_OK;
+}
+
+const char *ESP8266Interface::get_ip_address()
+{
+ return _esp.getIPAddress();
+}
+
+const char *ESP8266Interface::get_mac_address()
+{
+ return _esp.getMACAddress();
+}
+
+const char *ESP8266Interface::get_gateway()
+{
+ return _esp.getGateway();
+}
+
+const char *ESP8266Interface::get_netmask()
+{
+ return _esp.getNetmask();
+}
+
+int8_t ESP8266Interface::get_rssi()
+{
+ return _esp.getRSSI();
+}
+
+int ESP8266Interface::scan(WiFiAccessPoint *res, unsigned count)
+{
+ return _esp.scan(res, count);
+}
+
+struct esp8266_socket {
+ int id;
+ nsapi_protocol_t proto;
+ bool connected;
+ SocketAddress addr;
+};
+
+int ESP8266Interface::socket_open(void **handle, nsapi_protocol_t proto)
+{
+ // Look for an unused socket
+ int id = -1;
+
+ for (int i = 0; i < ESP8266_SOCKET_COUNT; i++) {
+ if (!_ids[i]) {
+ id = i;
+ _ids[i] = true;
+ break;
+ }
+ }
+
+ if (id == -1) {
+ return NSAPI_ERROR_NO_SOCKET;
+ }
+
+ struct esp8266_socket *socket = new struct esp8266_socket;
+ if (!socket) {
+ return NSAPI_ERROR_NO_SOCKET;
+ }
+
+ socket->id = id;
+ socket->proto = proto;
+ socket->connected = false;
+ *handle = socket;
+ return 0;
+}
+
+int ESP8266Interface::socket_close(void *handle)
+{
+ struct esp8266_socket *socket = (struct esp8266_socket *)handle;
+ int err = 0;
+ _esp.setTimeout(ESP8266_MISC_TIMEOUT);
+
+ if (!_esp.close(socket->id)) {
+ err = NSAPI_ERROR_DEVICE_ERROR;
+ }
+
+ _ids[socket->id] = false;
+ delete socket;
+ return err;
+}
+
+int ESP8266Interface::socket_bind(void *handle, const SocketAddress &address)
+{
+ return NSAPI_ERROR_UNSUPPORTED;
+}
+
+int ESP8266Interface::socket_listen(void *handle, int backlog)
+{
+ return NSAPI_ERROR_UNSUPPORTED;
+}
+
+int ESP8266Interface::socket_connect(void *handle, const SocketAddress &addr)
+{
+ struct esp8266_socket *socket = (struct esp8266_socket *)handle;
+ _esp.setTimeout(ESP8266_MISC_TIMEOUT);
+
+ const char *proto = (socket->proto == NSAPI_UDP) ? "UDP" : "TCP";
+ if (!_esp.open(proto, socket->id, addr.get_ip_address(), addr.get_port())) {
+ return NSAPI_ERROR_DEVICE_ERROR;
+ }
+
+ socket->connected = true;
+ return 0;
+}
+
+int ESP8266Interface::socket_accept(void *server, void **socket, SocketAddress *addr)
+{
+ return NSAPI_ERROR_UNSUPPORTED;
+}
+
+int ESP8266Interface::socket_send(void *handle, const void *data, unsigned size)
+{
+ struct esp8266_socket *socket = (struct esp8266_socket *)handle;
+ _esp.setTimeout(ESP8266_SEND_TIMEOUT);
+
+ if (!_esp.send(socket->id, data, size)) {
+ return NSAPI_ERROR_DEVICE_ERROR;
+ }
+
+ return size;
+}
+
+int ESP8266Interface::socket_recv(void *handle, void *data, unsigned size)
+{
+ struct esp8266_socket *socket = (struct esp8266_socket *)handle;
+ _esp.setTimeout(ESP8266_RECV_TIMEOUT);
+
+ int32_t recv = _esp.recv(socket->id, data, size);
+ if (recv < 0) {
+ return NSAPI_ERROR_WOULD_BLOCK;
+ }
+
+ return recv;
+}
+
+int ESP8266Interface::socket_sendto(void *handle, const SocketAddress &addr, const void *data, unsigned size)
+{
+ struct esp8266_socket *socket = (struct esp8266_socket *)handle;
+
+ if (socket->connected && socket->addr != addr) {
+ _esp.setTimeout(ESP8266_MISC_TIMEOUT);
+ if (!_esp.close(socket->id)) {
+ return NSAPI_ERROR_DEVICE_ERROR;
+ }
+ socket->connected = false;
+ }
+
+ if (!socket->connected) {
+ int err = socket_connect(socket, addr);
+ if (err < 0) {
+ return err;
+ }
+ socket->addr = addr;
+ }
+
+ return socket_send(socket, data, size);
+}
+
+int ESP8266Interface::socket_recvfrom(void *handle, SocketAddress *addr, void *data, unsigned size)
+{
+ struct esp8266_socket *socket = (struct esp8266_socket *)handle;
+ int ret = socket_recv(socket, data, size);
+ if (ret >= 0 && addr) {
+ *addr = socket->addr;
+ }
+
+ return ret;
+}
+
+void ESP8266Interface::socket_attach(void *handle, void (*callback)(void *), void *data)
+{
+ struct esp8266_socket *socket = (struct esp8266_socket *)handle;
+ _cbs[socket->id].callback = callback;
+ _cbs[socket->id].data = data;
+}
+
+void ESP8266Interface::event() {
+ for (int i = 0; i < ESP8266_SOCKET_COUNT; i++) {
+ if (_cbs[i].callback) {
+ _cbs[i].callback(_cbs[i].data);
+ }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/esp8266-driver/ESP8266Interface.h Thu Jan 26 14:18:21 2017 -0600
@@ -0,0 +1,275 @@
+/* ESP8266 implementation of NetworkInterfaceAPI
+ * Copyright (c) 2015 ARM Limited
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ESP8266_INTERFACE_H
+#define ESP8266_INTERFACE_H
+
+#include "mbed.h"
+#include "ESP8266.h"
+
+
+#define ESP8266_SOCKET_COUNT 5
+
+/** ESP8266Interface class
+ * Implementation of the NetworkStack for the ESP8266
+ */
+class ESP8266Interface : public NetworkStack, public WiFiInterface
+{
+public:
+ /** ESP8266Interface lifetime
+ * @param tx TX pin
+ * @param rx RX pin
+ * @param debug Enable debugging
+ */
+ ESP8266Interface(PinName tx, PinName rx, bool debug = false);
+
+ /** Start the interface
+ *
+ * Attempts to connect to a WiFi network. Requires ssid and passphrase to be set.
+ * If passphrase is invalid, NSAPI_ERROR_AUTH_ERROR is returned.
+ *
+ * @return 0 on success, negative error code on failure
+ */
+ virtual int connect();
+
+ /** Start the interface
+ *
+ * Attempts to connect to a WiFi network.
+ *
+ * @param ssid Name of the network to connect to
+ * @param pass Security passphrase to connect to the network
+ * @param security Type of encryption for connection (Default: NSAPI_SECURITY_NONE)
+ * @param channel This parameter is not supported, setting it to anything else than 0 will result in NSAPI_ERROR_UNSUPPORTED
+ * @return 0 on success, or error code on failure
+ */
+ virtual int connect(const char *ssid, const char *pass, nsapi_security_t security = NSAPI_SECURITY_NONE,
+ uint8_t channel = 0);
+
+ /** Set the WiFi network credentials
+ *
+ * @param ssid Name of the network to connect to
+ * @param pass Security passphrase to connect to the network
+ * @param security Type of encryption for connection
+ * (defaults to NSAPI_SECURITY_NONE)
+ * @return 0 on success, or error code on failure
+ */
+ virtual int set_credentials(const char *ssid, const char *pass, nsapi_security_t security = NSAPI_SECURITY_NONE);
+
+ /** Set the WiFi network channel - NOT SUPPORTED
+ *
+ * This function is not supported and will return NSAPI_ERROR_UNSUPPORTED
+ *
+ * @param channel Channel on which the connection is to be made, or 0 for any (Default: 0)
+ * @return Not supported, returns NSAPI_ERROR_UNSUPPORTED
+ */
+ virtual int set_channel(uint8_t channel);
+
+ /** Stop the interface
+ * @return 0 on success, negative on failure
+ */
+ virtual int disconnect();
+
+ /** Get the internally stored IP address
+ * @return IP address of the interface or null if not yet connected
+ */
+ virtual const char *get_ip_address();
+
+ /** Get the internally stored MAC address
+ * @return MAC address of the interface
+ */
+ virtual const char *get_mac_address();
+
+ /** Get the local gateway
+ *
+ * @return Null-terminated representation of the local gateway
+ * or null if no network mask has been recieved
+ */
+ virtual const char *get_gateway();
+
+ /** Get the local network mask
+ *
+ * @return Null-terminated representation of the local network mask
+ * or null if no network mask has been recieved
+ */
+ virtual const char *get_netmask();
+
+ /** Gets the current radio signal strength for active connection
+ *
+ * @return Connection strength in dBm (negative value)
+ */
+ virtual int8_t get_rssi();
+
+ /** Scan for available networks
+ *
+ * This function will block.
+ *
+ * @param ap Pointer to allocated array to store discovered AP
+ * @param count Size of allocated @a res array, or 0 to only count available AP
+ * @param timeout Timeout in milliseconds; 0 for no timeout (Default: 0)
+ * @return Number of entries in @a, or if @a count was 0 number of available networks, negative on error
+ * see @a nsapi_error
+ */
+ virtual int scan(WiFiAccessPoint *res, unsigned count);
+
+ /** Translates a hostname to an IP address with specific version
+ *
+ * The hostname may be either a domain name or an IP address. If the
+ * hostname is an IP address, no network transactions will be performed.
+ *
+ * If no stack-specific DNS resolution is provided, the hostname
+ * will be resolve using a UDP socket on the stack.
+ *
+ * @param address Destination for the host SocketAddress
+ * @param host Hostname to resolve
+ * @param version IP version of address to resolve, NSAPI_UNSPEC indicates
+ * version is chosen by the stack (defaults to NSAPI_UNSPEC)
+ * @return 0 on success, negative error code on failure
+ */
+ using NetworkInterface::gethostbyname;
+
+ /** Add a domain name server to list of servers to query
+ *
+ * @param addr Destination for the host address
+ * @return 0 on success, negative error code on failure
+ */
+ using NetworkInterface::add_dns_server;
+
+protected:
+ /** Open a socket
+ * @param handle Handle in which to store new socket
+ * @param proto Type of socket to open, NSAPI_TCP or NSAPI_UDP
+ * @return 0 on success, negative on failure
+ */
+ virtual int socket_open(void **handle, nsapi_protocol_t proto);
+
+ /** Close the socket
+ * @param handle Socket handle
+ * @return 0 on success, negative on failure
+ * @note On failure, any memory associated with the socket must still
+ * be cleaned up
+ */
+ virtual int socket_close(void *handle);
+
+ /** Bind a server socket to a specific port
+ * @param handle Socket handle
+ * @param address Local address to listen for incoming connections on
+ * @return 0 on success, negative on failure.
+ */
+ virtual int socket_bind(void *handle, const SocketAddress &address);
+
+ /** Start listening for incoming connections
+ * @param handle Socket handle
+ * @param backlog Number of pending connections that can be queued up at any
+ * one time [Default: 1]
+ * @return 0 on success, negative on failure
+ */
+ virtual int socket_listen(void *handle, int backlog);
+
+ /** Connects this TCP socket to the server
+ * @param handle Socket handle
+ * @param address SocketAddress to connect to
+ * @return 0 on success, negative on failure
+ */
+ virtual int socket_connect(void *handle, const SocketAddress &address);
+
+ /** Accept a new connection.
+ * @param handle Handle in which to store new socket
+ * @param server Socket handle to server to accept from
+ * @return 0 on success, negative on failure
+ * @note This call is not-blocking, if this call would block, must
+ * immediately return NSAPI_ERROR_WOULD_WAIT
+ */
+ virtual int socket_accept(void *handle, void **socket, SocketAddress *address);
+
+ /** Send data to the remote host
+ * @param handle Socket handle
+ * @param data The buffer to send to the host
+ * @param size The length of the buffer to send
+ * @return Number of written bytes on success, negative on failure
+ * @note This call is not-blocking, if this call would block, must
+ * immediately return NSAPI_ERROR_WOULD_WAIT
+ */
+ virtual int socket_send(void *handle, const void *data, unsigned size);
+
+ /** Receive data from the remote host
+ * @param handle Socket handle
+ * @param data The buffer in which to store the data received from the host
+ * @param size The maximum length of the buffer
+ * @return Number of received bytes on success, negative on failure
+ * @note This call is not-blocking, if this call would block, must
+ * immediately return NSAPI_ERROR_WOULD_WAIT
+ */
+ virtual int socket_recv(void *handle, void *data, unsigned size);
+
+ /** Send a packet to a remote endpoint
+ * @param handle Socket handle
+ * @param address The remote SocketAddress
+ * @param data The packet to be sent
+ * @param size The length of the packet to be sent
+ * @return The number of written bytes on success, negative on failure
+ * @note This call is not-blocking, if this call would block, must
+ * immediately return NSAPI_ERROR_WOULD_WAIT
+ */
+ virtual int socket_sendto(void *handle, const SocketAddress &address, const void *data, unsigned size);
+
+ /** Receive a packet from a remote endpoint
+ * @param handle Socket handle
+ * @param address Destination for the remote SocketAddress or null
+ * @param buffer The buffer for storing the incoming packet data
+ * If a packet is too long to fit in the supplied buffer,
+ * excess bytes are discarded
+ * @param size The length of the buffer
+ * @return The number of received bytes on success, negative on failure
+ * @note This call is not-blocking, if this call would block, must
+ * immediately return NSAPI_ERROR_WOULD_WAIT
+ */
+ virtual int socket_recvfrom(void *handle, SocketAddress *address, void *buffer, unsigned size);
+
+ /** Register a callback on state change of the socket
+ * @param handle Socket handle
+ * @param callback Function to call on state change
+ * @param data Argument to pass to callback
+ * @note Callback may be called in an interrupt context.
+ */
+ virtual void socket_attach(void *handle, void (*callback)(void *), void *data);
+
+ /** Provide access to the NetworkStack object
+ *
+ * @return The underlying NetworkStack object
+ */
+ virtual NetworkStack *get_stack()
+ {
+ return this;
+ }
+
+private:
+ ESP8266 _esp;
+ bool _ids[ESP8266_SOCKET_COUNT];
+
+ char ap_ssid[33]; /* 32 is what 802.11 defines as longest possible name; +1 for the \0 */
+ nsapi_security_t ap_sec;
+ uint8_t ap_ch;
+ char ap_pass[64]; /* The longest allowed passphrase */
+
+ void event();
+
+ struct {
+ void (*callback)(void *);
+ void *data;
+ } _cbs[ESP8266_SOCKET_COUNT];
+};
+
+#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/esp8266-driver/README.md Thu Jan 26 14:18:21 2017 -0600 @@ -0,0 +1,5 @@ +# esp8266 mbed-os driver +The driver for the ESP8266 WiFi module + +## Firmware version +esp8266 modules come in different shapes and forms, but most important difference is which firmware version it is programmed with. To make sure that your module has mbed-os compatible firmware follow update guide: https://developer.mbed.org/teams/ESP8266/wiki/Firmware-Update
--- a/main.cpp Fri Dec 16 20:14:05 2016 +0000
+++ b/main.cpp Thu Jan 26 14:18:21 2017 -0600
@@ -40,7 +40,7 @@
#include "Masters/DS2465/DS2465.h"
#include "Display.hpp"
#include "RomId/RomId.h"
-#include "ESP8266.hpp"
+#include "ESP8266Interface.h"
#include "mbed.h"
using OneWire::RomId;
@@ -77,6 +77,9 @@
static const Display::Color Purple = { 0x6E, 0x25, 0x85 };
/// @}
+static const char wifiSsid[] = "TWS iPhone";
+static const char wifiPassword[] = "maxim1234";
+
/// @{
/// Peripheral and pin definitions
static Serial pc(USBTX, USBRX);
@@ -88,8 +91,10 @@
static Display lcd(i2c, 0x78, 0x98);
static DS2465 ds2465(i2c, 0x30);
static SensorNode sensorNode(i2c, 0x90, 0x94, ds2465);
-static ESP8266 esp8266(D1, D0, D2, D3, 38400);
-static WebServerInterface webIntf(esp8266, &pc);
+static ESP8266Interface esp8266(D1, D0, true);
+static DigitalOut esp8266_RST(D2, 0);
+static DigitalOut esp8266_CH_PD(D3, 1);
+static WebServerInterface webIntf(esp8266);
/// @}
static bool useInvalidSecret = false; ///< Imitate an invalid controller when posting to web server.
@@ -133,7 +138,8 @@
displayStatus(currentStatus);
// Connect to Wifi network
- result = webIntf.initialize();
+ esp8266_RST = 1;
+ result = (esp8266.connect(wifiSsid, wifiPassword, NSAPI_SECURITY_WPA2) == 0);
// Read session ID
if (result)
--- a/mbed-os-mutex.lib Fri Dec 16 20:14:05 2016 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1 +0,0 @@ -https://developer.mbed.org/users/IanBenzMaxim/code/mbed-os-mutex/#ff111f3941b4
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mbed-os.lib Thu Jan 26 14:18:21 2017 -0600 @@ -0,0 +1,1 @@ +https://github.com/ARMmbed/mbed-os/#34c1facf42a174f47fdf9002cd8c6bf10ac41744 \ No newline at end of file
MAXREFDES143#: DeepCover Embedded Security in IoT Authenticated Sensing & Notification