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 1:e1c7c1c636af, committed 2016-04-14
- Comitter:
- IanBenzMaxim
- Date:
- Thu Apr 14 19:48:01 2016 +0000
- Parent:
- 0:19b8608fc4ee
- Child:
- 2:e67d29a371db
- Commit message:
- Add initial source files.
Changed in this revision
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/DS7505.cpp Thu Apr 14 19:48:01 2016 +0000
@@ -0,0 +1,277 @@
+/*******************************************************************************
+* 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 "DS7505.hpp"
+#include "mbed.h"
+
+#define I2C_WRITE 0
+#define I2C_READ 1
+
+static const int I2C_WRITE_OK = 0;
+static const uint8_t DS7505_Config_SD_Bit = 0x01; // Enable shutdown mode
+
+DS7505::DS7505(I2C & I2C_interface, uint8_t I2C_address)
+ : m_current_config(Config_9b_Res, true), m_I2C_interface(I2C_interface), m_I2C_address(I2C_address)
+{
+
+}
+
+uint8_t DS7505::get_measure_delay_ms(Config_Resolution resolution)
+{
+ uint8_t measure_delay_ms;
+
+ switch (resolution)
+ {
+ case Config_9b_Res:
+ measure_delay_ms = 25;
+ break;
+ case Config_10b_Res:
+ measure_delay_ms = 50;
+ break;
+ case Config_11b_Res:
+ measure_delay_ms = 100;
+ break;
+ case Config_12b_Res:
+ measure_delay_ms = 200;
+ break;
+ default:
+ measure_delay_ms = 0;
+ break;
+ }
+
+ return measure_delay_ms;
+}
+
+bool DS7505::read_temp_sensor_data(uint16_t & sensor_data) const
+{
+ bool result;
+ uint8_t upperByte, lowerByte;
+ int sub_res;
+
+ sensor_data = 0;
+ m_I2C_interface.start();
+ sub_res = m_I2C_interface.write(m_I2C_address | I2C_READ);
+ if (sub_res == I2C_WRITE_OK)
+ {
+ upperByte = m_I2C_interface.read(I2C::ACK);
+ lowerByte = m_I2C_interface.read(I2C::NoACK);
+ }
+ m_I2C_interface.stop();
+ if (sub_res == I2C_WRITE_OK)
+ {
+ sensor_data = ((((uint16_t)upperByte) << 8) | lowerByte);
+ result = true;
+ }
+ else
+ {
+ // Handle hardware malfunction
+ result = false;
+ }
+
+ return result;
+}
+
+bool DS7505::set_register_pointer(Register pointer_reg) const
+{
+ int res;
+
+ m_I2C_interface.start();
+ res = m_I2C_interface.write(m_I2C_address | I2C_WRITE);
+ if (res == I2C_WRITE_OK)
+ {
+ res = m_I2C_interface.write(pointer_reg);
+ }
+ m_I2C_interface.stop();
+
+ return (res == I2C_WRITE_OK);
+}
+
+bool DS7505::write_register(Register write_reg, uint8_t write_val) const
+{
+ bool res;
+
+ m_I2C_interface.start();
+ res = m_I2C_interface.write(m_I2C_address | I2C_WRITE);
+ if (res == I2C_WRITE_OK)
+ {
+ res = m_I2C_interface.write(write_reg);
+ if (res == I2C_WRITE_OK)
+ res = m_I2C_interface.write(write_val);
+ }
+ m_I2C_interface.stop();
+
+ return (res == I2C_WRITE_OK);
+}
+
+bool DS7505::write_current_config() const
+{
+ uint8_t DS7505_Config_Val = m_current_config.resolution;
+ if (m_current_config.enable_shutdown_mode)
+ DS7505_Config_Val |= DS7505_Config_SD_Bit;
+ return write_register(Configuration_Reg, DS7505_Config_Val);
+}
+
+DS7505::Result DS7505::set_resolution(uint8_t resolution)
+{
+ switch (resolution)
+ {
+ case 1:
+ m_current_config.resolution = Config_9b_Res;
+ break;
+ case 2:
+ m_current_config.resolution = Config_10b_Res;
+ break;
+ case 3:
+ m_current_config.resolution = Config_11b_Res;
+ break;
+ case 4:
+ m_current_config.resolution = Config_12b_Res;
+ break;
+ default:
+ return Out_of_Range;
+ }
+
+ // Write DS7505 configuration
+ if (!write_current_config())
+ {
+ // Handle hardware malfunction
+ return Hardware_Failure;
+ }
+
+ // Set pointer to temperature register
+ if (!set_register_pointer(Temperature_Reg))
+ {
+ // Handle hardware malfunction
+ return Hardware_Failure;
+ }
+
+ return Success;
+}
+
+DS7505::Result DS7505::read_temp_sensor(uint16_t & sensor_data) const
+{
+ bool res;
+
+ if (m_current_config.enable_shutdown_mode)
+ {
+ // Disable shutdown mode
+ m_current_config.enable_shutdown_mode = false;
+ res = write_current_config();
+ if (!res)
+ return Hardware_Failure;
+
+ // DS7505 measures temperature
+
+ // Enable shutdown mode
+ m_current_config.enable_shutdown_mode = true;
+ res = write_current_config();
+ if (!res)
+ return Hardware_Failure;
+
+ // Set pointer to temperature register
+ res = set_register_pointer(Temperature_Reg);
+ if (!res)
+ return Hardware_Failure;
+
+ // Sleep for maximum time needed for sample
+ wait_ms(get_measure_delay_ms(m_current_config.resolution));
+ }
+ // else: shutdown mode disabled
+ // DS7505 is constantly measuring temperature
+
+ // Read temperature from sensor
+ if (!read_temp_sensor_data(sensor_data))
+ {
+ return Hardware_Failure;
+ }
+
+ return Success;
+}
+
+DS7505::Result DS7505::read_current_temp(int16_t & temperature) const
+{
+ uint16_t sensor_data;
+ Result result;
+
+ result = read_temp_sensor(sensor_data);
+ if (result == Success)
+ {
+ // Convert temperature to have an exponent of 10^-2
+ temperature = ((int8_t)(sensor_data >> 8)) * 100;
+ if (sensor_data & 0x0080)
+ temperature += 50; // 0.5
+ if (sensor_data & 0x0040)
+ temperature += 25; // 0.25
+ if (sensor_data & 0x0020)
+ temperature += 13; // 0.125
+ if (sensor_data & 0x0010)
+ temperature += 6; // 0.0625
+ }
+ return result;
+}
+
+DS7505::Result DS7505::read_current_temp(double & temperature) const
+{
+ uint16_t sensor_data;
+ Result result;
+
+ result = read_temp_sensor(sensor_data);
+ if (result == Success)
+ {
+ // Convert sensor data to floating-point temperature
+ temperature = ((int8_t)(sensor_data >> 8));
+ if (sensor_data & 0x0080)
+ temperature += 0.5;
+ if (sensor_data & 0x0040)
+ temperature += 0.25;
+ if (sensor_data & 0x0020)
+ temperature += 0.125;
+ if (sensor_data & 0x0010)
+ temperature += 0.0625;
+ }
+ return result;
+}
+
+DS7505::Result DS7505::read_current_temp(int8_t & temperature) const
+{
+ uint16_t sensor_data;
+ Result result;
+
+ result = read_temp_sensor(sensor_data);
+ if (result == Success)
+ {
+ // Convert sensor data to integer temperature
+ temperature = ((int8_t)(sensor_data >> 8));
+ }
+ return result;
+}
\ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/DS7505.hpp Thu Apr 14 19:48:01 2016 +0000
@@ -0,0 +1,141 @@
+/*******************************************************************************
+* 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 _DS7505_HPP
+#define _DS7505_HPP
+
+#include <cstdint>
+
+namespace mbed
+{
+ class I2C;
+}
+
+/// Interface to the DS7505 temperature sensor.
+class DS7505
+{
+public:
+ enum Result
+ {
+ Success,
+ Hardware_Failure,
+ Out_of_Range
+ };
+
+ /// @param I2C_interface A configured I2C interface to use for communication.
+ /// @param I2C_address Device bus address in mbed format.
+ DS7505(mbed::I2C & I2C_interface, std::uint8_t I2C_address);
+
+ /// Set the resolution for temperature conversions.
+ /// @param resolution Number of decimal bit from 1 to 4.
+ Result set_resolution(std::uint8_t resolution);
+
+ /// Reads the current temperature with an exponent of 10^-2.
+ /// @note Compatible with Bluetooth characteristic: org.bluetooth.characteristic.temperature.
+ Result read_current_temp(std::int16_t & temperature) const;
+
+ /// Reads the current temperature as a floating point value.
+ Result read_current_temp(double & temperature) const;
+
+ /// Reads the current temperature as an integer value.
+ Result read_current_temp(std::int8_t & temperature) const;
+
+private:
+ /// Bit resolution of temperature conversions.
+ enum Config_Resolution
+ {
+ Config_9b_Res = 0x00,
+ Config_10b_Res = 0x20,
+ Config_11b_Res = 0x40,
+ Config_12b_Res = 0x60
+ };
+
+ /// DS7505 Register addresses.
+ enum Register
+ {
+ Temperature_Reg = 0x00,
+ Configuration_Reg = 0x01,
+ Thyst_Reg = 0x02,
+ Tos_Reg = 0x03
+ };
+
+ /// Represents a DS7505 configuration.
+ struct Config
+ {
+ Config_Resolution resolution;
+ bool enable_shutdown_mode;
+
+ Config(Config_Resolution resolution, bool enable_shutdown_mode)
+ : resolution(resolution), enable_shutdown_mode(enable_shutdown_mode) { }
+ };
+
+ /// @note Mark as mutable to allow manipulation by read_temp_sensor().
+ mutable Config m_current_config;
+
+ mbed::I2C & m_I2C_interface;
+ std::uint8_t m_I2C_address;
+
+ /// Returns the maximum time needed in ms for a sample at the specified resolution.
+ static std::uint8_t get_measure_delay_ms(Config_Resolution resolution);
+
+ /// Reads the current temperature via I2C.
+ /// Assumes that the I2C register pointer is already set to the temperature register.
+ /// @param sensor_data Output for raw data from DS7505 with upper and lower bytes combined.
+ /// @returns True on success.
+ bool read_temp_sensor_data(std::uint16_t & sensor_data) const;
+
+ /// Reads the current temperature with support for shutdown mode.
+ /// @param sensor_data Output for raw data from DS7505 with upper and lower bytes combined.
+ /// @returns Success or Hardware_Failure.
+ Result read_temp_sensor(std::uint16_t & sensor_data) const;
+
+ /// Sets the I2C register pointer for the next operation.
+ /// @param pointer_reg Desired register to set.
+ /// @returns True on success.
+ /// @note Allow marking const since not public.
+ bool set_register_pointer(Register pointer_reg) const;
+
+ /// Writes to a device register via I2C.
+ /// @param write_reg Register to write to.
+ /// @param write_val Value to write to the register.
+ /// @returns True on success.
+ /// @note Allow marking const since not public
+ bool write_register(Register write_reg, std::uint8_t write_val) const;
+
+ /// Writes the current configuration via I2C.
+ /// @returns True on success.
+ /// @note Allow marking const since not public
+ bool write_current_config() const;
+};
+
+#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/Display.cpp Thu Apr 14 19:48:01 2016 +0000
@@ -0,0 +1,283 @@
+/*******************************************************************************
+* 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 <sstream>
+#include "Display.hpp"
+#include "mbed.h"
+
+//LCD Commands
+//If the RS bit is set to logic 1, these display bytes are stored in the display RAM at the address specified by the data pointer. The data pointer is
+//automatically updated and the data is directed to the intended ST7036i device. If the RS bit of the last control byte is set to
+//logic 0, these command bytes will be decoded and the setting of the device will be changed according to the received commands.
+enum LCD_Commands
+{
+ ControlByte = 0x00, //Only one control byte will be sent. Only a stream of data bytes is allowed to follow.
+ ControlByte_RS_Set = 0x40, //Only one control byte will be sent with the RS bit set. Only a stream of data bytes is allowed to follow.
+ ControlBytes = 0x80, //Another control byte will follow, unless an I2C Stop condition is received.
+ ControlBytes_RS_Set = 0xC0, //RS Set and another control byte will follow, unless an I2C Stop condition is received.
+};
+
+//LCD Instructions
+enum LCD_Instructions
+{
+ ClearDisplay = 0x01,
+ Display_OFF = 0x08, //Display off
+ Display_ON = 0x0C, //Display on, cursor off, cursor position off
+ ReturnHome = 0x02,
+ SetDdramAddress = 0x80
+};
+
+// LED Driver Port Registers
+// Initial port state 0x80
+enum LED_Driver_Ports
+{
+ P1 = 0x01,
+ P2 = 0x02, // Blue LED
+ P3 = 0x03, // Green LED
+ P4 = 0x04 // Red LED
+};
+
+// Convert a byte color value into the representation used by the MAX7306 PWM registers
+static std::uint8_t convertColorToPwmRegVal(std::uint8_t color)
+{
+ const std::uint8_t staticOffRegVal = 0x80; // LED is static off by setting to input
+ const std::uint8_t staticOnRegVal = 0x00; // LED is static on
+ const std::uint8_t minOnRegVal = 0x01; // LED on for minimum duty cycle
+
+ std::uint8_t regVal;
+ if (color == 0x00) // Use static off for no color
+ {
+ regVal = staticOffRegVal;
+ }
+ else if (color == 0xFF) // Use static on for full color
+ {
+ regVal = staticOnRegVal;
+ }
+ else // Use standard PWN for all other values
+ {
+ // The 3 least significant bits cannot be rendered with the MAX7306
+ regVal = color >> 3;
+ if (regVal == staticOnRegVal)
+ regVal = minOnRegVal;
+ }
+ return regVal;
+}
+
+Display::Display(I2C & I2C_intf, uint8_t LCD_I2C_addr, uint8_t LED_driver_I2C_addr)
+ : m_I2C_intf(I2C_intf), m_LCD_I2C_addr(LCD_I2C_addr), m_LED_driver_I2C_addr(LED_driver_I2C_addr)
+{
+
+}
+
+void Display::initialize(void)
+{
+ initializeLCD();
+ initializeLED_Driver();
+}
+
+void Display::initializeLED_Driver(void)
+{
+ const std::uint8_t Configuration26 = 0x26; //intial port state 0xEC
+ const std::uint8_t Configuration27 = 0x27; //intial port state 0x8F
+
+ //Intial mode
+ //write to Configuration Register 0x26
+ m_I2C_intf.start();
+ m_I2C_intf.write(m_LED_driver_I2C_addr);
+ m_I2C_intf.write(Configuration26);
+ //RST does reset PWM/blink counters, RST resets registers to power-on-reset state
+ m_I2C_intf.write(0x1F);
+ m_I2C_intf.stop();
+
+ //Write to Configuration Register 0x27
+ m_I2C_intf.start();
+ m_I2C_intf.write(m_LED_driver_I2C_addr);
+ m_I2C_intf.write(Configuration27);
+ //Enable bus time out, set P1,P2,P3 to be controlled by their registers (0x01,0x02,0x03)
+ m_I2C_intf.write(0x0E);
+ m_I2C_intf.stop();
+}
+
+void Display::setBackLightColor(const Color & color)
+{
+ // Red
+ m_I2C_intf.start();
+ m_I2C_intf.write(m_LED_driver_I2C_addr);
+ m_I2C_intf.write(P4);
+ m_I2C_intf.write(convertColorToPwmRegVal(color.R));
+ m_I2C_intf.stop();
+
+ // Green
+ m_I2C_intf.start();
+ m_I2C_intf.write(m_LED_driver_I2C_addr);
+ m_I2C_intf.write(P3);
+ m_I2C_intf.write(convertColorToPwmRegVal(color.G));
+ m_I2C_intf.stop();
+
+ // Blue
+ m_I2C_intf.start();
+ m_I2C_intf.write(m_LED_driver_I2C_addr);
+ m_I2C_intf.write(P2);
+ m_I2C_intf.write(convertColorToPwmRegVal(color.B));
+ m_I2C_intf.stop();
+}
+
+void Display::clearLine(Line line)
+{
+ writeCompleteLine("", line);
+ setCursorPosition(line);
+}
+
+void Display::clearDisplay(void)
+{
+ m_I2C_intf.start();
+ m_I2C_intf.write(m_LCD_I2C_addr);
+ m_I2C_intf.write(ControlByte); //No more control bytes will be sent
+ m_I2C_intf.write(ClearDisplay);
+ m_I2C_intf.stop();
+}
+
+void Display::initializeLCD(void)
+{
+ m_I2C_intf.start();
+ m_I2C_intf.write(m_LCD_I2C_addr);
+ m_I2C_intf.write(ControlByte); //No more control bytes will be sent
+ //************************************************************************************
+ m_I2C_intf.write(0x38); //Function Set IS[2:1] = 0,0 (&h38 = Single height font, 0x3C = double height font)
+ m_I2C_intf.write(0x39); //Function Set IS[2:1] = (0,1)
+ //When IS[2:1]=(0,0): normal instruction be selected(refer instruction table 0)
+ //When IS[2:1]=(0,1): extension instruction be selected(refer instruction table 1 )
+ //When IS[2:1]=(1,0): extension instruction be selected(refer instruction table 2 )
+ m_I2C_intf.write(0x14); //BIAS SET
+ m_I2C_intf.write(0x70); //CONTRAST (was 0x78)
+ m_I2C_intf.write(0x5E); //POWER/ICON CONTROL/CONTRAST (upper two bits)
+ m_I2C_intf.write(0x6D); //FOLLOWER CONTROL
+ m_I2C_intf.write(Display_ON); //Display on, cursor on, cursor position on
+ m_I2C_intf.write(ClearDisplay); //Clear Display
+ m_I2C_intf.write(0x06); //ENTRY MODE
+ //************************************************************************************
+ m_I2C_intf.stop();
+}
+
+void Display::writeCharacter(std::uint8_t character)
+{
+ m_I2C_intf.start();
+ m_I2C_intf.write(m_LCD_I2C_addr);
+ m_I2C_intf.write(ControlByte_RS_Set); //No more control bytes will be sent
+ m_I2C_intf.write(character); //Display on, cursor on, cursor position on
+ m_I2C_intf.stop();
+}
+
+void Display::writeText(const std::string & text)
+{
+ const char RETURN_CHAR = 0x16;
+
+ std::size_t length = text.length();
+ if (length > lineLength)
+ length = lineLength;
+
+ //Write to LCD
+ m_I2C_intf.start();
+ m_I2C_intf.write(m_LCD_I2C_addr);
+ m_I2C_intf.write(ControlByte_RS_Set);
+
+ for(std::size_t i = 0; i < length; i++)
+ {
+ if(text[i] != RETURN_CHAR)
+ m_I2C_intf.write(text[i]);
+ }
+
+ m_I2C_intf.stop();
+}
+
+void Display::setCursorPosition(Line line, std::size_t position)
+{
+ if (position > (lineLength - 1)) // Set to last line character for values outside the upper bound
+ position = (lineLength - 1);
+
+ m_I2C_intf.start();
+ m_I2C_intf.write(m_LCD_I2C_addr);
+ m_I2C_intf.write(ControlByte); // No more control bytes will be sent
+ if(line == SecondLine) // Offset for second line
+ position += 0x40;
+ m_I2C_intf.write(SetDdramAddress | position);
+ m_I2C_intf.stop();
+}
+
+void Display::writeLine(const std::string & text, Line line)
+{
+ setCursorPosition(line);
+ writeText(text);
+}
+
+void Display::writeCompleteLine(const std::string & text, Line line)
+{
+ // Add padding to user's string
+ std::string writeText(text);
+ if (writeText.length() < lineLength)
+ writeText.append(lineLength - writeText.length(), ' ');
+
+ writeLine(writeText, line);
+}
+
+void Display::writeMessage(const std::string & message)
+{
+ if (message.length() > lineLength)
+ {
+ // Find split point
+ std::istringstream messageStream(message);
+ std::string word;
+ std::size_t splitIndex = 0;
+ do
+ {
+ if (word.length() > 0)
+ splitIndex += (word.length() + 1);
+ std::getline(messageStream, word, ' ');
+ } while ((splitIndex + word.length()) <= lineLength);
+ if (splitIndex == 0) // First word is too long
+ {
+ writeCompleteLine(message.substr(0, lineLength), FirstLine);
+ writeCompleteLine(message.substr(lineLength), SecondLine);
+ }
+ else
+ {
+ writeCompleteLine(message.substr(0, splitIndex - 1), FirstLine);
+ writeCompleteLine(message.substr(splitIndex), SecondLine);
+ }
+ }
+ else
+ {
+ writeCompleteLine(message, FirstLine);
+ writeCompleteLine("", SecondLine);
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/Display.hpp Thu Apr 14 19:48:01 2016 +0000
@@ -0,0 +1,108 @@
+/*******************************************************************************
+* 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 _DISPLAY_HPP
+#define _DISPLAY_HPP
+
+#include <cstdint>
+#include <string>
+
+namespace mbed { class I2C; }
+
+/// Interface to the Newhaven Display NHD-C0220BiZ-FS(RGB)-FBW-3VM LCD module
+/// and MAX7306 PWM LED driver for backlight color selection.
+class Display
+{
+public:
+ /// Display line referenced from top
+ enum Line
+ {
+ FirstLine = 0,
+ SecondLine
+ };
+
+ /// 24-bit RGB color for the backlight.
+ struct Color
+ {
+ std::uint8_t R, G, B;
+ Color(std::uint8_t R, std::uint8_t G, std::uint8_t B)
+ : R(R), G(G), B(B) { }
+ };
+
+ /// Length in character os a display line.
+ static const std::size_t lineLength = 20;
+
+ /// @param I2C_interface A configured I2C interface to use for communication.
+ /// @param LCD_I2C_address LCD module bus address in mbed format.
+ /// @param LED_driver_I2C_addr PWM LED driver (MAX7306) bus address in mbed format.
+ Display(mbed::I2C & I2C_intf, std::uint8_t LCD_I2C_addr, std::uint8_t LED_driver_I2C_addr);
+
+ /// Initialize display components.
+ void initialize(void);
+
+ /// Clear all display lines.
+ void clearDisplay(void);
+
+ /// Clear a specific display line.
+ void clearLine(Line line);
+
+ /// Write a single character to the display at the current cursor position.
+ void writeCharacter(std::uint8_t character);
+
+ /// Write text to the display at the current cursor position.
+ void writeText(const std::string & text);
+
+ /// Set cursor to a certain line and zero-index position within the line.
+ void setCursorPosition(Line line, std::size_t position = 0);
+
+ /// Writes text to the display starting at the beginning of the line.
+ void writeLine(const std::string & text, Line line);
+
+ /// Writes text to the display starting at the beginning of the line and clears the remainder of the line.
+ void writeCompleteLine(const std::string & text, Line line);
+
+ // Writes a message to the display with text wrapping allowed at spaces.
+ void writeMessage(const std::string & text);
+
+ // Set the display backlight to a certain color.
+ void setBackLightColor(const Color & color);
+
+private:
+ mbed::I2C & m_I2C_intf;
+ std::uint8_t m_LCD_I2C_addr, m_LED_driver_I2C_addr;
+
+ void initializeLCD(void);
+ void initializeLED_Driver(void);
+};
+
+#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/ESP8266.cpp Thu Apr 14 19:48:01 2016 +0000
@@ -0,0 +1,486 @@
+/*******************************************************************************
+* 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 "ESP8266.hpp"
+
+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, 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;
+
+ 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 = 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
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/ESP8266.hpp Thu Apr 14 19:48:01 2016 +0000
@@ -0,0 +1,216 @@
+/*******************************************************************************
+* 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 "mbed.h"
+#include "CircularBuffer.h"
+
+/// 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, 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.
+
+ Serial AT_intf;
+ DigitalOut resetPin;
+ mutable DigitalOut powerDownPin; ///< @note Mark as mutable for use in powered().
+ CircularBuffer<char, 1024> recvIpDataBuffer; ///< Received IP data buffer.
+ 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
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/Factory.cpp Thu Apr 14 19:48:01 2016 +0000
@@ -0,0 +1,191 @@
+/*******************************************************************************
+* 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 "Factory.hpp"
+#include "SensorNode.hpp"
+#include "common.hpp"
+#include "OneWire_Masters/DS2465/DS2465.hpp"
+#include "OneWire_Memory/Authenticators/DS28E15_22_25/DS28E15_22_25.hpp"
+#include "mbed.h"
+
+const std::uint8_t Factory::masterSecret[] = { 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x21,
+ 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, 0x31, 0x32 };
+const std::uint8_t Factory::invalidMasterSecret[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
+
+bool Factory::provision(DS2465 & ds2465)
+{
+ bool result = (ds2465.setMasterSecret(masterSecret) == ISha256MacCoprocessor::Success);
+ if (result)
+ {
+ SensorNode::AuthData authData;
+ DS28E15_22_25::Page pageData;
+ std::memset(pageData, SensorNode::defaultPaddingByte, pageData.length);
+ std::memcpy(pageData, authData.segment, authData.segment.length);
+ result = (ds2465.writeScratchpad(pageData, pageData.length) == OneWireMaster::Success);
+ }
+ if (result)
+ {
+ result = (ds2465.copyScratchpadToPage(0) == OneWireMaster::Success);
+ if (result)
+ wait_ms(DS2465::eepromPageWriteDelayMs);
+ }
+
+ return result;
+}
+
+bool Factory::provision(SensorNode & sensorNode, bool validSecret)
+{
+ const int blockNum = sensorNode.authData.pageNum / 2;
+ const DS28E15_22_25::BlockProtection desiredProtection(false, false, false, true, blockNum); // Authentication Protection only
+
+ // Reset to starting defaults
+ sensorNode.authData.reset();
+
+ // Read current protection status
+ DS28E15_22_25::BlockProtection protectionStatus;
+ bool result;
+ // Select device through Skip ROM
+ result = (sensorNode.ds2465.OWSkipROM() == OneWireMaster::Success);
+ if (result)
+ result = (sensorNode.ds28e15_22_25.readBlockProtection(blockNum, protectionStatus) == OneWireSlave::Success);
+ // Check if invalid protections are set
+ if (result)
+ result = ((protectionStatus.statusByte() & ~(desiredProtection.statusByte())) == 0x00);
+ // Select device through Skip ROM
+ if (result)
+ result = (sensorNode.ds2465.OWSkipROM() == OneWireMaster::Success);
+ // Load secret into scratchpad
+ if (result)
+ result = (sensorNode.ds28e15_22_25.writeScratchpad(validSecret ? masterSecret : invalidMasterSecret) == OneWireSlave::Success);
+ // Select device through Skip ROM
+ if (result)
+ result = (sensorNode.ds2465.OWSkipROM() == OneWireMaster::Success);
+ // Load master secret from scratchpad without locking
+ if (result)
+ result = (sensorNode.ds28e15_22_25.loadSecret(false) == OneWireSlave::Success);
+
+ // Setup is complete if not using a valid secret
+ if (!validSecret)
+ return result;
+
+ // Create constant partial secret
+ DS28E15_22_25::Scratchpad partialSecret;
+ DS28E15_22_25::Page pageData;
+ std::memset(partialSecret, SensorNode::defaultPaddingByte, partialSecret.length);
+
+ // Select device through Skip ROM
+ if (result)
+ result = (sensorNode.ds2465.OWSkipROM() == OneWireMaster::Success);
+ // Read page data
+ if (result)
+ result = (sensorNode.ds28e15_22_25.readPage(sensorNode.authData.pageNum, pageData, false) == OneWireSlave::Success);
+ // Select device through Skip ROM
+ if (result)
+ result = (sensorNode.ds2465.OWSkipROM() == OneWireMaster::Success);
+ // Load partial secret into scratchpad
+ if (result)
+ result = (sensorNode.ds28e15_22_25.writeScratchpad(partialSecret) == OneWireSlave::Success);
+ // Select device through Skip ROM
+ if (result)
+ result = (sensorNode.ds2465.OWSkipROM() == OneWireMaster::Success);
+ // Compute secret
+ if (result)
+ result = (sensorNode.ds28e15_22_25.computeSecret(sensorNode.authData.pageNum, false) == OneWireSlave::Success);
+ // Configure slave secret on DS2465
+ if (result)
+ result = (DS28E15_22_25::computeNextSecret(sensorNode.ds2465, pageData, sensorNode.authData.pageNum, partialSecret, sensorNode.ds28e15_22_25.romId, sensorNode.ds28e15_22_25.manId) == ISha256MacCoprocessor::Success);
+ // Select device through Skip ROM
+ if (result)
+ result = (sensorNode.ds2465.OWSkipROM() == OneWireMaster::Success);
+ // Enable authentication protection if not set
+ if (result && (protectionStatus != desiredProtection))
+ result = (sensorNode.ds28e15_22_25.writeAuthBlockProtection(sensorNode.ds2465, desiredProtection, protectionStatus) == OneWireSlave::Success);
+ // Select device through Skip ROM
+ if (result)
+ result = (sensorNode.ds2465.OWSkipROM() == OneWireMaster::Success);
+ // Write initial filter life and set all other segments to default value
+ if (result)
+ {
+ DS28E15_22_25::Segment blankSegment;
+ std::memset(blankSegment, SensorNode::defaultPaddingByte, blankSegment.length);
+ for (std::size_t i = 0; i < (DS28E15_22_25::Page::length / DS28E15_22_25::Segment::length); i++)
+ {
+ result = (sensorNode.ds2465.OWSkipROM() == OneWireMaster::Success);
+ if (result)
+ result = (sensorNode.ds28e15_22_25.writeAuthSegment(sensorNode.ds2465, sensorNode.authData.pageNum, i,
+ ((i == sensorNode.authData.segmentNum) ? sensorNode.authData.segment : blankSegment),
+ reinterpret_cast<const DS28E15_22_25::Segment::Buffer &>(static_cast<const DS28E15_22_25::Page::Buffer &>(pageData)[i * sizeof(DS28E15_22_25::Segment::Buffer)]), false) == OneWireSlave::Success);
+
+ if (!result)
+ break;
+ }
+ }
+
+ // Reload secret with known page values
+ // Select device through Skip ROM
+ if (result)
+ result = (sensorNode.ds2465.OWSkipROM() == OneWireMaster::Success);
+ // Load master secret into scratchpad
+ if (result)
+ result = (sensorNode.ds28e15_22_25.writeScratchpad(masterSecret) == OneWireSlave::Success);
+ // Select device through Skip ROM
+ if (result)
+ result = (sensorNode.ds2465.OWSkipROM() == OneWireMaster::Success);
+ // Load master secret
+ if (result)
+ result = (sensorNode.ds28e15_22_25.loadSecret(false) == OneWireSlave::Success);
+ // Select device through Skip ROM
+ if (result)
+ result = (sensorNode.ds2465.OWSkipROM() == OneWireMaster::Success);
+ // Read page data
+ if (result)
+ result = (sensorNode.ds28e15_22_25.readPage(sensorNode.authData.pageNum, pageData, false) == OneWireSlave::Success);
+ // Select device through Skip ROM
+ if (result)
+ result = (sensorNode.ds2465.OWSkipROM() == OneWireMaster::Success);
+ // Write partial secret to scratchpad
+ if (result)
+ result = (sensorNode.ds28e15_22_25.writeScratchpad(partialSecret) == OneWireSlave::Success);
+ // Select device through Skip ROM
+ if (result)
+ result = (sensorNode.ds2465.OWSkipROM() == OneWireMaster::Success);
+ // Compute secret
+ if (result)
+ result = (sensorNode.ds28e15_22_25.computeSecret(sensorNode.authData.pageNum, false) == OneWireSlave::Success);
+ // Configure slave secret on DS2465
+ if (result)
+ result = (DS28E15_22_25::computeNextSecret(sensorNode.ds2465, pageData, sensorNode.authData.pageNum, partialSecret, sensorNode.ds28e15_22_25.romId, sensorNode.ds28e15_22_25.manId) == ISha256MacCoprocessor::Success);
+
+ return result;
+}
\ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/Factory.hpp Thu Apr 14 19:48:01 2016 +0000
@@ -0,0 +1,61 @@
+/*******************************************************************************
+* 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 _FACTORY_HPP
+#define _FACTORY_HPP
+
+#include <cstdint>
+
+class DS2465;
+class SensorNode;
+
+/// Represents the secure factory that will perform the initial provisioning of
+/// Controllers (DS2465) and Sensor Nodes (DS28E15) for later authentication.
+class Factory
+{
+public:
+ /// Provision the DS2465 on a Controller.
+ /// @returns True on success.
+ bool provision(DS2465 & ds2465);
+
+ /// Provision the DS28E15 on a Sensor Node.
+ /// @param validSecret True to provision using the valid system secret or false to imitate an invalid Controller.
+ /// @returns True on success.
+ bool provision(SensorNode & sensorNode, bool validSecret);
+
+private:
+ static const std::uint8_t masterSecret[]; ///< The valid master secret for the system.
+ static const std::uint8_t invalidMasterSecret[]; ///< An invalid master secret for example purposes.
+};
+
+#endif
\ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/MAX44009.cpp Thu Apr 14 19:48:01 2016 +0000
@@ -0,0 +1,86 @@
+/*******************************************************************************
+* 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 "MAX44009.hpp"
+#include "mbed.h"
+
+static const int I2C_OK = 0;
+
+MAX44009::MAX44009(I2C & I2C_interface, uint8_t I2C_address)
+ : m_I2C_interface(I2C_interface), m_I2C_address(I2C_address)
+{
+
+}
+
+MAX44009::Result MAX44009::read_current_lux(double & lux) const
+{
+ char I2C_data;
+ uint8_t mantissa, exponent;
+
+ I2C_data = Lux_High_Byte_Reg;
+ if (m_I2C_interface.write(m_I2C_address, &I2C_data, 1, true) != I2C_OK)
+ {
+ m_I2C_interface.stop();
+ return Hardware_Failure;
+ }
+ if (m_I2C_interface.read(m_I2C_address, &I2C_data, 1, true) != I2C_OK)
+ {
+ m_I2C_interface.stop();
+ return Hardware_Failure;
+ }
+ mantissa = (I2C_data << 4);
+ exponent = (I2C_data >> 4);
+
+ I2C_data = Lux_Low_Byte_Reg;
+ if (m_I2C_interface.write(m_I2C_address, &I2C_data, 1, true) != I2C_OK)
+ {
+ m_I2C_interface.stop();
+ return Hardware_Failure;
+ }
+ if (m_I2C_interface.read(m_I2C_address, &I2C_data, 1, false) != I2C_OK)
+ {
+ m_I2C_interface.stop();
+ return Hardware_Failure;
+ }
+ mantissa |= (I2C_data & 0x0F);
+
+ unsigned long calc_result = 1;
+ if (exponent > 0)
+ {
+ calc_result <<= exponent;
+ }
+ calc_result *= mantissa;
+ lux = calc_result * 0.045;
+
+ return Success;
+}
\ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/MAX44009.hpp Thu Apr 14 19:48:01 2016 +0000
@@ -0,0 +1,71 @@
+/*******************************************************************************
+* 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 _MAX44009_HPP
+#define _MAX44009_HPP
+
+#include <cstdint>
+
+namespace mbed { class I2C; }
+
+/// Interface to the MAX44009 optical light sensor.
+class MAX44009
+{
+public:
+ enum Result
+ {
+ Success,
+ Hardware_Failure
+ };
+
+ /// @param I2C_interface A configured I2C interface to use for communication.
+ /// @param I2C_address Device bus address in mbed format.
+ MAX44009(mbed::I2C & I2C_interface, std::uint8_t I2C_address);
+
+ /// Read the current lux from the MAX44009.
+ /// @returns Success or Hardware_Failure.
+ Result read_current_lux(double & lux) const;
+
+private:
+ /// MAX44009 Register addresses.
+ enum Register
+ {
+ Lux_High_Byte_Reg = 0x03,
+ Lux_Low_Byte_Reg = 0x04
+ };
+
+ mbed::I2C & m_I2C_interface;
+ std::uint8_t m_I2C_address;
+};
+
+#endif
--- a/OneWire.lib Wed Apr 13 18:54:30 2016 +0000 +++ b/OneWire.lib Thu Apr 14 19:48:01 2016 +0000 @@ -1,1 +1,1 @@ -https://developer.mbed.org/teams/Maxim-Integrated/code/OneWire/#071ae5d090d1 +https://developer.mbed.org/teams/Maxim-Integrated/code/OneWire/#268612a10614
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/SensorNode.cpp Thu Apr 14 19:48:01 2016 +0000
@@ -0,0 +1,260 @@
+/*******************************************************************************
+* 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 "SensorNode.hpp"
+#include "common.hpp"
+#include "OneWire_Masters/DS2465/DS2465.hpp"
+#include "mbed.h"
+
+#ifdef TARGET_MAX32600
+#include "max32600.h"
+#include "clkman_regs.h"
+#include "tpu_regs.h"
+#else
+#include <cstdlib>
+#endif
+
+bool SensorNode::rngInitialized = false;
+
+void SensorNode::initializeRng()
+{
+#ifdef TARGET_MAX32600
+ MXC_CLKMAN->clk_config |= (MXC_F_CLKMAN_CLK_CONFIG_CRYPTO_ENABLE | MXC_F_CLKMAN_CLK_CONFIG_CRYPTO_RESET_N); // Enable crypto oscillator
+ while ((MXC_CLKMAN->intfl & MXC_F_CLKMAN_INTFL_CRYPTO_STABLE) != MXC_F_CLKMAN_INTFL_CRYPTO_STABLE) ; // Wait for crypto oscillator stability
+ MXC_CLKMAN->clk_ctrl |= MXC_F_CLKMAN_CLK_CTRL_CRYPTO_GATE_N; // Disable crypto clock gating
+ MXC_CLKMAN->crypt_clk_ctrl_2_prng = MXC_CLKMAN->clk_ctrl_10_prng = 1; // Set PRNG clock to crypto clock
+ MXC_CLKMAN->clk_gate_ctrl2 |= (1 << MXC_F_CLKMAN_CLK_GATE_CTRL2_TPU_CLK_GATER_POS); // Use dynamic clock gating
+#endif
+}
+
+SensorNode::SensorNode(I2C & i2c, std::uint8_t ds7505_i2c_addr, std::uint8_t max44009_i2c_addr, DS2465 & ds2465)
+ : m_initialLux(1), ds28e15_22_25(ds2465), ds7505(i2c, ds7505_i2c_addr), max44009(i2c, max44009_i2c_addr), ds2465(ds2465)
+{
+ if (!rngInitialized)
+ {
+ initializeRng();
+ rngInitialized = true;
+ }
+}
+
+bool SensorNode::initializeSensors()
+{
+ return (max44009.read_current_lux(m_initialLux) == MAX44009::Success);
+}
+
+bool SensorNode::setSecret()
+{
+ DS28E15_22_25::Scratchpad scratchpad;
+ DS28E15_22_25::Page pageData;
+
+ // Create constant partial secret
+ std::memset(scratchpad, defaultPaddingByte, scratchpad.length);
+ // Read page data
+ bool result = (ds2465.readMemory(DS2465::ADDR_USER_MEM_PAGE_0, pageData, pageData.length, false) == OneWireMaster::Success);
+ // Calculate secret
+ if (result)
+ {
+ result = (DS28E15_22_25::computeNextSecret(ds2465, pageData, authData.pageNum, scratchpad, ds28e15_22_25.romId, ds28e15_22_25.manId) == ISha256MacCoprocessor::Success);
+ }
+ return result;
+}
+
+bool SensorNode::checkProvisioned(bool & provisioned)
+{
+ DS28E15_22_25::BlockProtection protectionStatus;
+ bool result;
+
+ // Select device through Skip ROM
+ result = (ds2465.OWSkipROM() == OneWireMaster::Success);
+ if (result)
+ result = (ds28e15_22_25.readBlockProtection(0, protectionStatus) == OneWireSlave::Success);
+ if (result)
+ {
+ if (!protectionStatus.noProtection())
+ {
+ // Select device through Skip ROM
+ result = (ds2465.OWSkipROM() == OneWireMaster::Success);
+ if (result)
+ result = (ds28e15_22_25.readSegment(authData.pageNum, authData.segmentNum, authData.segment) == OneWireSlave::Success);
+ if (result)
+ provisioned = true;
+ }
+ else
+ {
+ provisioned = false;
+ }
+ }
+ return result;
+}
+
+bool SensorNode::checkAuthentic(unsigned int userEntropy)
+{
+ DS28E15_22_25::Scratchpad challenge;
+ DS28E15_22_25::Page pageData;
+
+ // Select device through Skip ROM
+ if (ds2465.OWSkipROM() != OneWireMaster::Success)
+ return false;
+ // Read page data
+ if (ds28e15_22_25.readPage(authData.pageNum, pageData, false) != OneWireSlave::Success)
+ return false;
+
+ // Create random challenge
+ // Use hardare RNG on MAX32600
+#ifdef TARGET_MAX32600
+ MXC_TPU->prng_user_entropy = userEntropy;
+#else
+ std::srand(userEntropy);
+#endif
+ for (std::size_t i = 0; i < challenge.length; i++)
+ {
+#ifdef TARGET_MAX32600
+ challenge[i] = MXC_TPU->prng_rnd_num;
+#else
+ challenge[i] = std::rand();
+#endif
+ }
+
+ // Select device through Skip ROM
+ if (ds2465.OWSkipROM() != OneWireMaster::Success)
+ return false;
+ // Write challenge to scratchpad
+ if (ds28e15_22_25.writeScratchpad(challenge) != OneWireSlave::Success)
+ return false;
+ // Select device through Skip ROM
+ if (ds2465.OWSkipROM() != OneWireMaster::Success)
+ return false;
+ // Have device compute MAC
+ DS28E15_22_25::Mac nodeMac;
+ if (ds28e15_22_25.computeReadPageMac(0, false, nodeMac) != OneWireSlave::Success)
+ return false;
+ // Compute expected MAC
+ DS28E15_22_25::Mac controllerMac;
+ if (DS28E15_22_25::computeAuthMac(ds2465, pageData, authData.pageNum, challenge, ds28e15_22_25.romId, ds28e15_22_25.manId, controllerMac) != ISha256MacCoprocessor::Success)
+ return false;
+ // Check if authentic
+ return (nodeMac == controllerMac);
+}
+
+bool SensorNode::readSensorData(SensorData & sensorData)
+{
+ bool result;
+ std::int8_t temp;
+
+ // Read temperature sensor
+ result = (ds7505.read_current_temp(temp) == DS7505::Success);
+
+ if (result)
+ {
+ sensorData.temp = temp;
+
+ // Read light sensor
+ double currentLux;
+ result = (max44009.read_current_lux(currentLux) == MAX44009::Success);
+ if (result)
+ {
+ // Convert lux to remaining filter life
+ sensorData.filterLife = (unsigned int)((currentLux / m_initialLux) * 100);
+ }
+ }
+
+ return result;
+}
+
+bool SensorNode::checkAndWriteAuthData(SensorData & sensorData)
+{
+ bool result = true;
+
+ if (sensorData.filterLife > authData.filterLife)
+ {
+ sensorData.filterLife = authData.filterLife;
+ }
+ else if (sensorData.filterLife < authData.filterLife)
+ {
+ AuthData oldAuthData(authData);
+ authData.filterLife = sensorData.filterLife;
+ // Select device through Skip ROM
+ result = (ds2465.OWSkipROM() == OneWireMaster::Success);
+ // Write new filter life to DS28E15
+ if (result)
+ result = (ds28e15_22_25.writeAuthSegment(ds2465, authData.pageNum, authData.segmentNum, authData.segment, oldAuthData.segment, false) == OneWireSlave::Success);
+ }
+
+ return result;
+}
+
+SensorNode::State SensorNode::detect(unsigned int userEntropy)
+{
+ bool provisioned;
+
+ ds2465.OWSetSpeed(DS2465::SPEED_OVERDRIVE);
+
+ if (ds2465.OWReadROM(ds28e15_22_25.romId) != OneWireMaster::Success)
+ return UnableToCommunicate;
+
+ if (!checkProvisioned(provisioned))
+ return UnableToCommunicate;
+
+ if (!provisioned)
+ return NotProvisioned;
+
+ if (!setSecret())
+ return UnableToCommunicate;
+
+ if (!checkAuthentic(userEntropy))
+ return NotAuthentic;
+
+ if (!initializeSensors())
+ return UnableToCommunicate;
+
+ return Authentic;
+}
+
+SensorNode::State SensorNode::authenticatedReadSensorData(unsigned int userEntropy, SensorData & sensorData)
+{
+ ds2465.OWSetSpeed(DS2465::SPEED_OVERDRIVE);
+
+ if (!setSecret())
+ return UnableToCommunicate;
+
+ if (!checkAuthentic(userEntropy))
+ return NotAuthentic;
+
+ if (!readSensorData(sensorData))
+ return UnableToCommunicate;
+
+ if (!checkAndWriteAuthData(sensorData))
+ return NotAuthentic;
+
+ return Authentic;
+}
\ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/SensorNode.hpp Thu Apr 14 19:48:01 2016 +0000
@@ -0,0 +1,156 @@
+/*******************************************************************************
+* 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 _SENSORNODE_HPP
+#define _SENSORNODE_HPP
+
+#include <cstdint>
+#include <cstring>
+
+#include "DS7505.hpp"
+#include "MAX44009.hpp"
+#include "OneWire_Memory/Authenticators/DS28E15_22_25/DS28E15_22_25.hpp"
+
+class DS2465;
+class RomId;
+class SensorData;
+namespace mbed { class I2C; }
+
+/// Interface to the Authenticated Sensor Node peripheral board.
+class SensorNode
+{
+public:
+ enum State
+ {
+ UnableToCommunicate, ///< I2C or 1-Wire communication failure.
+ NotProvisioned, ///< DS28E15 has not been provisioned.
+ NotAuthentic, ///< DS28E15 is not authentic.
+ Authentic ///< DS218E15 is authentic.
+ };
+
+ /// @param i2c Configured I2C communication interface.
+ /// @param ds7505_i2c_addr I2C bus address of the DS7505 in mbed format.
+ /// @param max44009_i2c_addr I2C bus address of the MAX44009 in mbed format.
+ /// @param ds2465 Interface to DS2465 on the Controller.
+ SensorNode(mbed::I2C & i2c, std::uint8_t ds7505_i2c_addr, std::uint8_t max44009_i2c_addr, DS2465 & ds2465);
+
+ /// Detect if an authentic Sensor Node is connected.
+ /// @param userEntropy Additional entropy to supply to the RNG.
+ /// @returns Authentic on success.
+ State detect(unsigned int userEntropy);
+
+ /// Read the current temperature and filter life measurements with authentication.
+ /// @param userEntropy Additional entropy to supply to the RNG.
+ /// @param sensorData Measurements output location.
+ /// @returns Authentic on success.
+ State authenticatedReadSensorData(unsigned int userEntropy, SensorData & sensorData);
+
+ /// Reads the current temperature and filter life measurements.
+ /// @param sensorData Measurements output location.
+ /// @returns True on success or false if unable to communicate with a sensor.
+ bool readSensorData(SensorData & sensorData);
+
+ /// Get the ROM ID for this sensor node.
+ const RomId & romId() const { return ds28e15_22_25.romId; }
+
+ /// Get the initial lux measurement for this sensor node.
+ double initialLux() const { return m_initialLux; }
+
+ // Grant access to hardware interfaces for provisioning.
+ friend class Factory;
+
+private:
+ /// Authenticated data stored in DS28E15.
+ struct AuthData
+ {
+ static const std::uint8_t initialFilterLife = 100;
+ DS28E15_22_25::Segment segment;
+ std::uint8_t & filterLife;
+ unsigned int pageNum, segmentNum;
+
+ AuthData() : filterLife(segment[0]), pageNum(0), segmentNum(0) { reset(); }
+
+ void reset()
+ {
+ std::memset(segment, 0, segment.length);
+ filterLife = initialFilterLife;
+ }
+ };
+
+ /// Padding value used in creation of the Slave Secret.
+ static const std::uint8_t defaultPaddingByte = 0x00;
+
+ /// Indicates hardware RNG is initialized.
+ static bool rngInitialized;
+ // Initialize the hardware RNG.
+ static void initializeRng();
+
+ /// Initial lux measurement taken on initialization.
+ /// Assumed to be the maximum intensity that will be observed.
+ double m_initialLux;
+
+ /// Authenticated data stored on the DS28E15.
+ AuthData authData;
+
+ // Hardware interfaces
+ DS28E15_22_25 ds28e15_22_25; ///< DS28E15 for authentication.
+ DS7505 ds7505; ///< DS7505 temperature sensor.
+ MAX44009 max44009; ///< MAX44009 optical light sensor.
+ DS2465 & ds2465; ///< Interface to DS2465 on Controller.
+
+ /// Initialize sensors for measurement.
+ /// @returns True on success.
+ bool initializeSensors();
+
+ /// Select the Slave Secret for this Sensor Node in the Controller.
+ /// @returns True on success.
+ bool setSecret();
+
+ /// Check if the Sensor Board is provisioned.
+ /// @param provisioned True if the sensor board is provisioned.
+ /// @returns True if provisioning check was successful.
+ bool checkProvisioned(bool & provisioned);
+
+ /// Check if the Sensor Board is authentic.
+ /// @param userEntropy Additional entropy to supply to the RNG.
+ /// @returns True if the Sensor Board passed the authentication check.
+ bool checkAuthentic(unsigned int userEntropy);
+
+ /// Checks if the authenticated data stored in the DS28E15 needs to be updated.
+ /// Updates the authenticated data if necessary.
+ /// @param sensorData Current sensor data to check.
+ /// @returns True on success.
+ bool checkAndWriteAuthData(SensorData & sensorData);
+};
+
+#endif
\ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/WebServerInterface.cpp Thu Apr 14 19:48:01 2016 +0000
@@ -0,0 +1,331 @@
+/*******************************************************************************
+* 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 <vector>
+
+#include "WebServerInterface.hpp"
+#include "ESP8266.hpp"
+#include "OneWire_Masters/ISha256MacCoprocessor.hpp"
+#include "common.hpp"
+#include "mbed.h"
+
+const char WebServerInterface::wifiSsid[] = "WifiSsid";
+const char WebServerInterface::wifiPassword[] = "WifiPassword";
+const char WebServerInterface::serverAddress[] = "website.com";
+const char WebServerInterface::serverPostPath[] = "/post.php";
+const char WebServerInterface::serverChallengePath[] = "/challenge.php";
+
+// HTTP formatting constants
+static const char keyValSeparator = '=';
+static const char fieldSeparator = '&';
+static const std::string newline = "\r\n";
+static const char sessionIdKey[] = "SessionId";
+
+// Authentication MAC constants
+static const std::size_t challengeLen = 32;
+static const std::uint8_t defaultPaddingByte = 0x00;
+
+/// Select the Transport Secret for the web server in the Controller.
+/// @returns True on success.
+static bool setHttpPostSecret(ISha256MacCoprocessor & MacCoproc)
+{
+ ISha256MacCoprocessor::DevicePage fillData;
+ std::memset(fillData, defaultPaddingByte, fillData.length);
+ return (MacCoproc.computeSlaveSecret(fillData, fillData, reinterpret_cast<ISha256MacCoprocessor::SlaveSecretData &>(fillData)) == ISha256MacCoprocessor::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)
+ {
+ return false;
+ }
+ result = (esp8266.setCurrentWifiMode(ESP8266::softAP_station_mode) == ESP8266::AT_OK);
+ if (!result)
+ {
+ return false;
+ }
+ result = (esp8266.setMaxRFTXPower(10) == ESP8266::AT_OK);
+ if (!result)
+ {
+ return false;
+ }
+ result = (esp8266.joinCurrentAccessPoint(wifiSsid, wifiPassword) == ESP8266::AT_OK);
+ if (!result)
+ {
+ return false;
+ }
+ return true;
+}
+
+/// Format an HTTP GET request as a string for transmission.
+/// @param host Web server address.
+/// @param path Web server location to retrieve.
+/// @param sessionId Session ID used to identify this controller.
+/// @returns GET request string.
+static std::string formatHttpGet(const std::string & host, const std::string & path, const std::string & sessionId)
+{
+ std::ostringstream httpGetStream;
+ httpGetStream << "GET " << path;
+ if (sessionId.length() > 0)
+ httpGetStream << '?' << sessionIdKey << keyValSeparator << sessionId;
+ httpGetStream << " HTTP/1.1" << newline;
+ httpGetStream << "Host: " << host << newline;
+ httpGetStream << newline;
+ return httpGetStream.str();
+}
+
+/// Computes a MAC using the Transport Secret to sign HTTP POST requests.
+/// @param macCoproc Coprocessor such as the DS2465 used to calculate the authentication MAC.
+/// @param input Message array used for MAC calculation.
+/// @param ilen Length of array input.
+/// @param output Calculated MAC output.
+static void calculateHttpPostMac(const ISha256MacCoprocessor & macCoproc, const std::uint8_t * input, std::size_t ilen, ISha256MacCoprocessor::Mac & output)
+{
+ ISha256MacCoprocessor::DeviceScratchpad block;
+ std::size_t index = 0;
+ ISha256MacCoprocessor::AuthMacData padding;
+ std::memset(padding, defaultPaddingByte, padding.length);
+ std::memset(output, defaultPaddingByte, output.length); // Set initial hash value
+ while (index < ilen)
+ {
+ if ((index + block.length) <= ilen) // Full block
+ {
+ std::memcpy(block, &input[index], block.length);
+ index += block.length;
+ }
+ else // Partial block with padding
+ {
+ std::memcpy(block, &input[index], ilen - index);
+ std::memset(&block[ilen - index], defaultPaddingByte, block.length - (ilen - index));
+ index = ilen;
+ }
+ // Write data to coprocessor and hash block
+ macCoproc.computeAuthMac(output, block, padding, output);
+ }
+}
+
+/// Format an HTTP POST request as a string for transmission.
+/// @param host Web server address.
+/// @param path Web server location to receive POST.
+/// @param sessionId Session ID used to identify this Controller.
+/// @param macCoproc Coprocessor such as the DS2465 used to calculate the authentication MAC.
+/// @param event Event message type.
+/// @param initialPostBody Message body as determined by the event message type.
+/// @param challenge Challenge previously received from web server for use in authentication MAC.
+/// @returns POST request string.
+static std::string formatHttpPost(const std::string & host, const std::string & path, const std::string & sessionId,
+ const ISha256MacCoprocessor & macCoproc, PostEvent event, const std::string & initialPostBody,
+ const std::uint8_t (&challenge)[challengeLen])
+{
+ const std::size_t headerReserve = 115, bodyReserve = 200;
+
+ std::string httpPost;
+ httpPost.reserve(initialPostBody.length() + headerReserve + bodyReserve);
+
+ // Add session ID to post body
+ if (sessionId.length() > 0)
+ {
+ httpPost += sessionIdKey;
+ httpPost += keyValSeparator;
+ httpPost += sessionId;
+ }
+
+ // Add event to post body
+ std::string eventString;
+ switch (event)
+ {
+ case SensorDataEvent:
+ eventString = "SensorData";
+ break;
+
+ case InvalidSensorEvent:
+ eventString = "InvalidSensor";
+ break;
+ }
+ if (eventString.length() > 0)
+ {
+ if (httpPost.length() > 0)
+ httpPost += fieldSeparator;
+ httpPost += "Event";
+ httpPost += keyValSeparator;
+ httpPost += eventString;
+ }
+
+ // Add initial post body
+ if (initialPostBody.length() > 0)
+ {
+ if (httpPost.length() > 0)
+ httpPost += fieldSeparator;
+ httpPost += initialPostBody;
+ }
+
+ // Combine initial post body with initial secret and hash
+ std::vector<std::uint8_t> hashInput;
+ hashInput.reserve(challengeLen + httpPost.length());
+ hashInput.insert(hashInput.end(), challenge, challenge + challengeLen);
+ hashInput.insert(hashInput.end(), httpPost.begin(), httpPost.end());
+ ISha256MacCoprocessor::Mac mac;
+ calculateHttpPostMac(macCoproc, &hashInput[0], hashInput.size(), mac);
+
+ char contentLen[5];
+ std::snprintf(contentLen, sizeof(contentLen) / sizeof(char), "%u", (hashInput.size() - challengeLen) + (mac.length * charsPerByte) + 5 /* &MAC= */);
+
+ // Construct full post request
+ httpPost = "";
+ httpPost += "POST ";
+ httpPost += path;
+ httpPost += " HTTP/1.1";
+ httpPost += newline;
+ httpPost += "Host: ";
+ httpPost += host;
+ httpPost += newline;
+ httpPost += "Accept: */*";
+ httpPost += newline;
+ httpPost += "Content-Length: ";
+ httpPost += contentLen;
+ httpPost += newline;
+ httpPost += "Content-Type: application/x-www-form-urlencoded";
+ httpPost += newline;
+ httpPost += newline;
+ // Add post body
+ httpPost.append(reinterpret_cast<char *>(&hashInput[challengeLen]), hashInput.size() - challengeLen);
+ // Convert hash to hex string and add to post body
+ httpPost += fieldSeparator;
+ httpPost += "MAC";
+ httpPost += keyValSeparator;
+ byteArrayToHexString(mac, mac.length, httpPost);
+ httpPost += newline;
+
+ return httpPost;
+}
+
+bool WebServerInterface::authPostHttpEvent(ISha256MacCoprocessor & macCoproc, PostEvent event, const std::string & postData, bool setSecret)
+{
+ const std::string challengeSearch(newline + newline);
+ bool result;
+ std::uint8_t challenge[challengeLen];
+ std::string response;
+
+ std::memset(challenge, defaultPaddingByte, challengeLen);
+ response.reserve(300);
+
+ if (setSecret)
+ {
+ result = setHttpPostSecret(macCoproc);
+ if (!result)
+ return result;
+ }
+
+ // Open connection
+ esp8266.clearRecvData(); // Clear received data buffer
+ result = (esp8266.openConnection(ESP8266::TCP, serverAddress, 80) == ESP8266::AT_OK);
+ if (result)
+ {
+ // Request challenge
+ result = (esp8266.sendData(formatHttpGet(serverAddress, serverChallengePath, sessionId)) == ESP8266::AT_OK);
+ if (result)
+ {
+ // Receive server response
+ for (int i = 0; i < 10; i++)
+ {
+ while (esp8266.recvIpDataReadable())
+ {
+ char read = esp8266.getcRecvIpData();
+ if (pc != NULL)
+ pc->putc(read);
+ if (response.length() < response.capacity())
+ {
+ response += read;
+ }
+ else
+ {
+ wait_ms(ESP8266::sendDataRecoveryTimeMs); // Wait for ESP8266 specified recovery time
+ goto close_get_connection;
+ }
+ }
+ wait_ms(100);
+ }
+ // Close connection
+ close_get_connection:
+ esp8266.closeConnection();
+
+ // Parse challenge from response
+ std::size_t challengePos = response.find(challengeSearch);
+ if ((challengePos != std::string::npos) && ((challengePos + challengeSearch.length() + (challengeLen * charsPerByte)) <= response.length()))
+ {
+ challengePos += challengeSearch.length();
+ for (std::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, 80) == ESP8266::AT_OK);
+ if (result)
+ {
+ result = (esp8266.sendData(formatHttpPost(serverAddress, serverPostPath, sessionId, macCoproc, event, postData, challenge)) == ESP8266::AT_OK);
+ wait_ms(ESP8266::sendDataRecoveryTimeMs); // Wait for ESP8266 specified recovery time
+ }
+ }
+
+ // Close connection
+ esp8266.closeConnection();
+ }
+
+ return result;
+}
+
+std::string WebServerInterface::formatSensorDataPostBody(const SensorData & sensorData)
+{
+ // Create initial post body string from input data
+ std::ostringstream postBodyStream;
+ postBodyStream << "Temp" << keyValSeparator << static_cast<int>(sensorData.temp);
+ postBodyStream << fieldSeparator;
+ postBodyStream << "FilterLife" << keyValSeparator << static_cast<unsigned>(sensorData.filterLife);
+ postBodyStream << fieldSeparator;
+ postBodyStream << "TempAlarm" << keyValSeparator << (sensorData.tempAlarm() ? "true" : "false");
+ postBodyStream << fieldSeparator;
+ postBodyStream << "FilterLifeAlarm" << keyValSeparator << (sensorData.filterLifeAlarm() ? "true" : "false");
+ return postBodyStream.str();
+}
\ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/WebServerInterface.hpp Thu Apr 14 19:48:01 2016 +0000
@@ -0,0 +1,94 @@
+/*******************************************************************************
+* 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 _WEBSERVERINTERFACE_HPP
+#define _WEBSERVERINTERFACE_HPP
+
+#include <string>
+
+/// The message type descibed by the POST.
+enum PostEvent
+{
+ SensorDataEvent, ///< Adding sensor data to the log.
+ InvalidSensorEvent ///< Reporting an invalid sensor node.
+};
+
+namespace mbed { class Serial; }
+class ESP8266;
+class ISha256MacCoprocessor;
+struct SensorData;
+
+/// Network interface to the web server supporting authenticated posting of event
+/// through an HTTP challenge-respones scheme with SHA-256 data signing.
+class WebServerInterface
+{
+public:
+ /// Session ID used by the web server to distinguish between multiple Controllers.
+ std::string sessionId;
+
+ /// @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();
+
+ /// Send an authenticated event message to the web server.
+ /// @param macCoProc Coprocessor such as the DS2465 used to calculate the authentication MAC.
+ /// @param event Event message type.
+ /// @postData Message body as determined by the event message type.
+ /// @setSecret True if the Transport Secret needs to be selected in the coprocessor.
+ /// @returns True on success.
+ bool authPostHttpEvent(ISha256MacCoprocessor & macCoproc, PostEvent event, const std::string & postData, bool setSecret);
+
+ /// Format sensor data as text suitable for use in a POST body.
+ /// @param sensorData Sensor data to format.
+ /// @returns Data formatted for web server.
+ static std::string formatSensorDataPostBody(const SensorData & sensorData);
+
+private:
+ /// @{
+ /// Configuration strings.
+ static const char wifiSsid[];
+ static const char wifiPassword[];
+ static const char serverAddress[];
+ static const char serverPostPath[];
+ static const char serverChallengePath[];
+ /// @}
+
+ ESP8266 & esp8266;
+ mbed::Serial * pc;
+};
+
+#endif
\ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/common.cpp Thu Apr 14 19:48:01 2016 +0000
@@ -0,0 +1,54 @@
+/*******************************************************************************
+* 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 "common.hpp"
+
+const std::size_t charsPerByte = 2;
+
+std::string byteArrayToHexString(const std::uint8_t * byteArray, std::size_t byteArraySize)
+{
+ std::string hexString;
+ hexString.reserve(byteArraySize * charsPerByte);
+ byteArrayToHexString(byteArray, byteArraySize, hexString);
+ return hexString;
+}
+
+void byteArrayToHexString(const std::uint8_t * byteArray, std::size_t byteArraySize, std::string & hexString)
+{
+ char hexBuf[charsPerByte + 1];
+ for (std::size_t i = 0; i < byteArraySize; i++)
+ {
+ std::snprintf(hexBuf, (sizeof(hexBuf) / sizeof(hexBuf[0])), "%2.2X", byteArray[i]);
+ hexString.append(hexBuf, charsPerByte);
+ }
+}
\ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/common.hpp Thu Apr 14 19:48:01 2016 +0000
@@ -0,0 +1,62 @@
+/*******************************************************************************
+* 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 _COMMON_HPP
+#define _COMMON_HPP
+
+#include <string>
+#include <cstdint>
+
+/// Contains a set of sensor measurements.
+struct SensorData
+{
+ static const std::int8_t tempAlarmLevel = 26;
+ static const std::uint8_t filterLifeAlarmLevel = 20;
+
+ std::int8_t temp;
+ std::uint8_t filterLife;
+
+ bool tempAlarm() const { return (temp >= tempAlarmLevel); }
+ bool filterLifeAlarm() const { return (filterLife <= filterLifeAlarmLevel); }
+};
+
+/// Characters per byte for hex data.
+extern const std::size_t charsPerByte;
+
+/// Creates a new hex string from a byte array.
+std::string byteArrayToHexString(const std::uint8_t * byteArray, std::size_t byteArraySize);
+
+/// Appends a hex string created from a byte array to an existing string.
+void byteArrayToHexString(const std::uint8_t * byteArray, std::size_t byteArraySize, std::string & hexString);
+
+#endif
\ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/main.cpp Thu Apr 14 19:48:01 2016 +0000
@@ -0,0 +1,475 @@
+/*******************************************************************************
+* 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 <sstream>
+
+#include "common.hpp"
+#include "WebServerInterface.hpp"
+#include "Factory.hpp"
+#include "SensorNode.hpp"
+#include "OneWire_Masters/DS2465/DS2465.hpp"
+#include "Display.hpp"
+#include "RomId.hpp"
+#include "ESP8266.hpp"
+#include "mbed.h"
+
+/// Main status for the program.
+enum Status
+{
+ InitializingController, ///< Configure DS2465 and connect to network.
+ DisplaySessionId, ///< Display ID for use with website.
+ SensorNodeNeedsDetection, ///< Prompt user to insert Sensor Node.
+ DetectingSensorNode, ///< Check if Sensor Node present.
+ SensorNodeNeedsProvision, ///< Sensor Node needs to be provisioned.
+ ProvisioningSensorNode, ///< Provisioning Sensor Node to factory defaults.
+ NormalOperation, ///< The normal demo operation state.
+ SensorNodeNotAuthentic, ///< Sensor Node failed authentication check.
+ ControllerInitializationError, ///< Failed to initialize Controller.
+ ControllerHardwareError, ///< Controller hardware failed unexpectedly.
+ SensorNodeHardwareError ///< Sensor Node hardware failed unexpectedly.
+};
+
+/// @{
+/// Configuration options.
+static const unsigned int webPostIntervalMs = 10000;
+static const unsigned int webPostRetryIntervalMs = 1000;
+static const std::uint8_t maxConsecutiveWebPostErrors = 3;
+/// @}
+
+/// @{
+/// LCD display colors.
+static const Display::Color Teal(0x00, 0xB2, 0xA9);
+static const Display::Color Red(0xFF, 0x00, 0x00);
+static const Display::Color Green(0x00, 0xFF, 0x00);
+/// @}
+
+/// @{
+/// Peripheral and pin definitions
+static Serial pc(USBTX, USBRX);
+static DigitalIn provisionButton(P2_0);
+static DigitalIn invalidateButton(P1_5);
+static DigitalOut tempAlarmLed(P2_1, 1);
+static DigitalOut filterLifeAlarmLed(P2_3, 1);
+static I2C i2c(P2_6, P2_7);
+static Display lcd(i2c, 0x78, 0x98);
+static DS2465 ds2465(i2c, 0x30);
+static SensorNode sensorNode(i2c, 0x90, 0x94, ds2465);
+static Factory factory;
+static ESP8266 esp8266(P1_1, P1_0, P1_2, P1_3, 38400);
+static WebServerInterface webIntf(esp8266, &pc);
+/// @}
+
+static bool useInvalidSecret = false; ///< Imitate an invalid controller when posting to web server.
+static unsigned int randomSeed = 0; ///< Create extra entropy for challenge.
+static Status currentStatus = InitializingController;
+static bool result = false;
+static std::uint8_t consecutiveWebPostErrors = 0; ///< Account for a few network errors in case of flaky connection.
+static Timer webPostTimer; ///< Software timer to track web posting interval.
+
+static void blinkLeds(unsigned int time_ms); ///< Invert LEDs for a given amount of time.
+static bool buttonPressed(DigitalIn & button); ///< Checks if button is pressed (returns true) and waits for release.
+static void displayStatus(Status status); ///< Display status message on LCD.
+static void displaySensorData(const SensorData & sensorData); ///< Display sensor data on the LCD.
+static bool readWebSessionId(std::string & sessionId); ///< Read device's web session ID from it's nonvolatile storage.
+
+#ifdef ASSEMBLY_TEST
+#include "AssemblyTest.cpp"
+#endif
+
+int main()
+{
+ blinkLeds(500);
+
+#ifdef ASSEMBLY_TEST
+ assemblyTest();
+#endif
+
+ while (true)
+ {
+ Status nextStatus = currentStatus;
+ switch (currentStatus)
+ {
+ case InitializingController:
+ pc.baud(115200);
+ i2c.frequency(100000);
+ webPostTimer.start();
+
+ // Set initial LCD state
+ lcd.initialize();
+ displayStatus(currentStatus);
+
+ // Connect to Wifi network
+ result = webIntf.initialize();
+
+ // Read session ID
+ if (result)
+ {
+ result = readWebSessionId(webIntf.sessionId);
+ }
+
+ // Provision DS2465 with master secret and page data
+ if (result)
+ {
+ result = factory.provision(ds2465);
+ }
+
+ if (result)
+ {
+ nextStatus = DisplaySessionId;
+ }
+ else
+ {
+ nextStatus = ControllerInitializationError;
+ }
+ break;
+
+ case DisplaySessionId:
+ // Wait for user to press Provision button
+ if (buttonPressed(provisionButton))
+ {
+ nextStatus = SensorNodeNeedsDetection;
+ }
+ break;
+
+ case SensorNodeNeedsDetection:
+ // Wait for user to press Provision button
+ if (buttonPressed(provisionButton))
+ {
+ nextStatus = DetectingSensorNode;
+ }
+ break;
+
+ case DetectingSensorNode:
+ // Perform Sensor Node detection sequence
+ switch (sensorNode.detect(randomSeed))
+ {
+ case SensorNode::UnableToCommunicate:
+ default:
+ nextStatus = SensorNodeHardwareError;
+ break;
+
+ case SensorNode::NotProvisioned:
+ nextStatus = SensorNodeNeedsProvision;
+ break;
+
+ case SensorNode::NotAuthentic:
+ nextStatus = SensorNodeNotAuthentic;
+ break;
+
+ case SensorNode::Authentic:
+ nextStatus = NormalOperation;
+ break;
+ }
+ break;
+
+ case SensorNodeNeedsProvision:
+ // Wait for user to press Provision button
+ if (buttonPressed(provisionButton))
+ {
+ nextStatus = ProvisioningSensorNode;
+ }
+ break;
+
+ case ProvisioningSensorNode:
+ if (!buttonPressed(invalidateButton)) // Provision normally
+ {
+ if (factory.provision(sensorNode, true))
+ {
+ nextStatus = NormalOperation;
+ }
+ else
+ {
+ nextStatus = SensorNodeNotAuthentic;
+ }
+ }
+ else // Invalidate button also pressed; Load invalid secret
+ {
+ // Provision with invalid secret
+ if (factory.provision(sensorNode, false))
+ {
+ nextStatus = NormalOperation;
+ }
+ else
+ {
+ nextStatus = SensorNodeHardwareError;
+ }
+ }
+ break;
+
+ case NormalOperation:
+ // Check if user pressed Provision button
+ if (buttonPressed(provisionButton))
+ {
+ // Re-provision Sensor Node
+ nextStatus = ProvisioningSensorNode;
+ }
+ // Check if user pressed Invalidate button
+ else if (buttonPressed(invalidateButton))
+ {
+ // Toggle between using valid and invalid secret
+ // 1 blink = invalid; 2 blinks = valid
+ useInvalidSecret = !useInvalidSecret;
+ blinkLeds(100);
+ if (!useInvalidSecret)
+ {
+ wait_ms(100);
+ blinkLeds(100);
+ }
+ }
+ // Check node and display measurements
+ else
+ {
+ SensorData sensorData;
+ // Read sensor data with authentication
+ switch (sensorNode.authenticatedReadSensorData(randomSeed, sensorData))
+ {
+ case SensorNode::Authentic:
+ // Update measurements on LCD
+ displaySensorData(sensorData);
+
+ // Update alarm LEDs
+ tempAlarmLed = !sensorData.tempAlarm(); // Active Low
+ filterLifeAlarmLed = !sensorData.filterLifeAlarm(); // Active Low
+
+ // Send measurements to web if time interval reached
+ if (webPostTimer.read_ms() >= webPostIntervalMs)
+ {
+ // Format, sign, and transmit data to web server
+ result = webIntf.authPostHttpEvent(ds2465, SensorDataEvent, WebServerInterface::formatSensorDataPostBody(sensorData), !useInvalidSecret);
+ if (result)
+ {
+ // Reset timer count after logging sample complete
+ webPostTimer.reset();
+ consecutiveWebPostErrors = 0;
+ }
+ // There was likely an error establishing a web connection
+ else if (++consecutiveWebPostErrors < maxConsecutiveWebPostErrors)
+ {
+ // Wait and try again
+ wait_ms(webPostRetryIntervalMs);
+ }
+ // Too many retry attempts
+ else
+ {
+ // Assume we have lost network connection
+ nextStatus = ControllerHardwareError;
+ }
+ }
+ break;
+
+ case SensorNode::NotAuthentic:
+ nextStatus = SensorNodeNotAuthentic;
+ break;
+
+ case SensorNode::UnableToCommunicate:
+ default:
+ nextStatus = SensorNodeHardwareError;
+ break;
+ }
+ }
+ break;
+
+ case SensorNodeNotAuthentic:
+ // Wait for user to press Provision button
+ if (buttonPressed(provisionButton))
+ {
+ nextStatus = ProvisioningSensorNode;
+ }
+ // Try to authenticate and return to normal operation
+ else if (webPostTimer.read_ms() >= webPostIntervalMs)
+ {
+ // Send event message to server
+ result = webIntf.authPostHttpEvent(ds2465, InvalidSensorEvent, "", !useInvalidSecret);
+ if (result)
+ {
+ // Reset timer count after logging complete
+ webPostTimer.reset();
+ consecutiveWebPostErrors = 0;
+ }
+ else if (++consecutiveWebPostErrors < maxConsecutiveWebPostErrors)
+ {
+ // There was likely an error establishing a web connection
+ // Wait and try again
+ wait_ms(webPostRetryIntervalMs);
+ }
+ else
+ {
+ nextStatus = ControllerHardwareError;
+ }
+
+ // Try to authenticate again
+ nextStatus = SensorNodeNeedsDetection;
+ }
+ break;
+
+ case ControllerInitializationError:
+ case ControllerHardwareError:
+ case SensorNodeHardwareError:
+ default:
+ // Do nothing until user resets
+ break;
+ }
+ // Check if status changed
+ if (currentStatus != nextStatus)
+ {
+ currentStatus = nextStatus;
+ displayStatus(currentStatus); // Display status message on LCD
+ }
+
+ // Change seed value on every loop pass
+ randomSeed++;
+ }
+}
+
+/// Blink all LEDs for a certain amount of time.
+/// @param time_ms Time in ms to blink for.
+static void blinkLeds(unsigned int time_ms)
+{
+ tempAlarmLed = !tempAlarmLed;
+ filterLifeAlarmLed = !filterLifeAlarmLed;
+ wait_ms(time_ms);
+ tempAlarmLed = !tempAlarmLed;
+ filterLifeAlarmLed = !filterLifeAlarmLed;
+}
+
+/// Check if a button is pressed and wait for it to be release.
+/// @param button Active low button to check.
+/// @returns True if pressed.
+static bool buttonPressed(DigitalIn & button)
+{
+ const int buttonPressed = 0; // Active low
+ if (button == buttonPressed)
+ {
+ while (button == buttonPressed) ;
+ return true;
+ }
+ // else
+ return false;
+}
+
+/// Display the current status of the Controller on the LCD display.
+static void displayStatus(Status status)
+{
+ switch (status)
+ {
+ case InitializingController:
+ lcd.writeMessage("Initializing Controller...");
+ lcd.setBackLightColor(Teal);
+ break;
+
+ case DisplaySessionId:
+ lcd.writeLine("ID: " + webIntf.sessionId, Display::FirstLine);
+ lcd.writeLine("Provision to begin", Display::SecondLine);
+ lcd.setBackLightColor(Teal);
+ break;
+
+ case SensorNodeNeedsDetection:
+ lcd.writeMessage("Insert Sensor Node and press Provision");
+ lcd.setBackLightColor(Teal);
+ break;
+
+ case DetectingSensorNode:
+ lcd.writeMessage("Detecting Sensor Node...");
+ lcd.setBackLightColor(Teal);
+ break;
+
+ case SensorNodeNeedsProvision:
+ lcd.writeMessage("Sensor Node Needs Provision");
+ lcd.setBackLightColor(Teal);
+ break;
+
+ case ProvisioningSensorNode:
+ lcd.writeMessage("Provisioning Sensor Node");
+ lcd.setBackLightColor(Teal);
+ break;
+
+ case NormalOperation:
+ // Everything handled in displaySensorData()
+ break;
+
+ case SensorNodeNotAuthentic:
+ lcd.writeMessage("Sensor Node Not Authentic");
+ lcd.setBackLightColor(Red);
+ break;
+
+ case ControllerInitializationError:
+ lcd.writeMessage("Initialization Error Check Wi-Fi");
+ lcd.setBackLightColor(Red);
+ break;
+
+ case ControllerHardwareError:
+ lcd.writeMessage("Controller Hardware Error");
+ lcd.setBackLightColor(Red);
+ break;
+
+ case SensorNodeHardwareError:
+ lcd.writeMessage("Sensor Node Hardware Error");
+ lcd.setBackLightColor(Red);
+ break;
+ }
+}
+
+/// Display sensor data on the LCD display during normal operation.
+static void displaySensorData(const SensorData & sensorData)
+{
+ std::ostringstream stream;
+ stream << "Chiller Temp: " << (int)sensorData.temp << "C";
+ lcd.writeCompleteLine(stream.str(), Display::FirstLine);
+ stream.str(""); // Clear stream
+ stream << "Filter Life: " << (unsigned int)sensorData.filterLife << "%";
+ lcd.writeCompleteLine(stream.str(), Display::SecondLine);
+ lcd.setBackLightColor((sensorData.tempAlarm() || sensorData.filterLifeAlarm()) ? Red : Green);
+}
+
+/// Read the Session ID to use with the web server from ROM.
+/// @note Session ID is taken from the ROM ID of the MAX66242.
+/// @param[out] Session ID string.
+/// @returns True on success.
+static bool readWebSessionId(std::string & sessionId)
+{
+ const uint8_t I2C_address = 0x32;
+ const uint8_t ROM_address = 0x68;
+ RomId romId;
+
+ // Set register pointer
+ if (i2c.write(I2C_address, (const char *)&ROM_address, 1) != 0)
+ return false;
+ // Read ROM ID
+ if (i2c.read(I2C_address, (char *)(&(static_cast<RomId::ByteBuffer &>(romId))), RomId::byteLen) != 0)
+ return false;
+ // Check if CRC valid
+ if (!romId.crc8Valid())
+ return false;
+ sessionId = byteArrayToHexString(romId, RomId::byteLen);
+ return true;
+}
\ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mbed.bld Thu Apr 14 19:48:01 2016 +0000 @@ -0,0 +1,1 @@ +http://mbed.org/users/mbed_official/code/mbed/builds/082adc85693f \ No newline at end of file
MAXREFDES143#: DeepCover Embedded Security in IoT Authenticated Sensing & Notification