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.

Committer:
IanBenzMaxim
Date:
Thu Jul 21 11:06:13 2016 -0500
Revision:
17:41be4896ed6d
Parent:
16:6bce01c1dd90
Child:
19:b8b0cd35f7b4
Fixed issue with LCD controller initialization on some boards due to power instability. Updated following downstream restructuring in OneWire library.

Who changed what in which revision?

UserRevisionLine numberNew contents of line
IanBenzMaxim 1:e1c7c1c636af 1 /*******************************************************************************
IanBenzMaxim 1:e1c7c1c636af 2 * Copyright (C) 2016 Maxim Integrated Products, Inc., All Rights Reserved.
IanBenzMaxim 1:e1c7c1c636af 3 *
IanBenzMaxim 1:e1c7c1c636af 4 * Permission is hereby granted, free of charge, to any person obtaining a
IanBenzMaxim 1:e1c7c1c636af 5 * copy of this software and associated documentation files (the "Software"),
IanBenzMaxim 1:e1c7c1c636af 6 * to deal in the Software without restriction, including without limitation
IanBenzMaxim 1:e1c7c1c636af 7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
IanBenzMaxim 1:e1c7c1c636af 8 * and/or sell copies of the Software, and to permit persons to whom the
IanBenzMaxim 1:e1c7c1c636af 9 * Software is furnished to do so, subject to the following conditions:
IanBenzMaxim 1:e1c7c1c636af 10 *
IanBenzMaxim 1:e1c7c1c636af 11 * The above copyright notice and this permission notice shall be included
IanBenzMaxim 1:e1c7c1c636af 12 * in all copies or substantial portions of the Software.
IanBenzMaxim 1:e1c7c1c636af 13 *
IanBenzMaxim 1:e1c7c1c636af 14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
IanBenzMaxim 1:e1c7c1c636af 15 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
IanBenzMaxim 1:e1c7c1c636af 16 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IanBenzMaxim 1:e1c7c1c636af 17 * IN NO EVENT SHALL MAXIM INTEGRATED BE LIABLE FOR ANY CLAIM, DAMAGES
IanBenzMaxim 1:e1c7c1c636af 18 * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
IanBenzMaxim 1:e1c7c1c636af 19 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
IanBenzMaxim 1:e1c7c1c636af 20 * OTHER DEALINGS IN THE SOFTWARE.
IanBenzMaxim 1:e1c7c1c636af 21 *
IanBenzMaxim 1:e1c7c1c636af 22 * Except as contained in this notice, the name of Maxim Integrated
IanBenzMaxim 1:e1c7c1c636af 23 * Products, Inc. shall not be used except as stated in the Maxim Integrated
IanBenzMaxim 1:e1c7c1c636af 24 * Products, Inc. Branding Policy.
IanBenzMaxim 1:e1c7c1c636af 25 *
IanBenzMaxim 1:e1c7c1c636af 26 * The mere transfer of this software does not imply any licenses
IanBenzMaxim 1:e1c7c1c636af 27 * of trade secrets, proprietary technology, copyrights, patents,
IanBenzMaxim 1:e1c7c1c636af 28 * trademarks, maskwork rights, or any other form of intellectual
IanBenzMaxim 1:e1c7c1c636af 29 * property whatsoever. Maxim Integrated Products, Inc. retains all
IanBenzMaxim 1:e1c7c1c636af 30 * ownership rights.
IanBenzMaxim 1:e1c7c1c636af 31 *******************************************************************************
IanBenzMaxim 1:e1c7c1c636af 32 */
IanBenzMaxim 1:e1c7c1c636af 33
IanBenzMaxim 1:e1c7c1c636af 34 #include <sstream>
IanBenzMaxim 1:e1c7c1c636af 35
IanBenzMaxim 1:e1c7c1c636af 36 #include "common.hpp"
IanBenzMaxim 1:e1c7c1c636af 37 #include "WebServerInterface.hpp"
IanBenzMaxim 1:e1c7c1c636af 38 #include "Factory.hpp"
IanBenzMaxim 1:e1c7c1c636af 39 #include "SensorNode.hpp"
IanBenzMaxim 6:b6bafd0a7013 40 #include "Masters/DS2465/DS2465.h"
IanBenzMaxim 1:e1c7c1c636af 41 #include "Display.hpp"
IanBenzMaxim 17:41be4896ed6d 42 #include "RomId/RomId.h"
IanBenzMaxim 1:e1c7c1c636af 43 #include "ESP8266.hpp"
IanBenzMaxim 1:e1c7c1c636af 44 #include "mbed.h"
IanBenzMaxim 1:e1c7c1c636af 45
IanBenzMaxim 6:b6bafd0a7013 46 using OneWire::RomId;
IanBenzMaxim 8:594529956266 47 using OneWire::DS2465;
IanBenzMaxim 6:b6bafd0a7013 48
IanBenzMaxim 1:e1c7c1c636af 49 /// Main status for the program.
IanBenzMaxim 1:e1c7c1c636af 50 enum Status
IanBenzMaxim 1:e1c7c1c636af 51 {
IanBenzMaxim 1:e1c7c1c636af 52 InitializingController, ///< Configure DS2465 and connect to network.
IanBenzMaxim 1:e1c7c1c636af 53 DisplaySessionId, ///< Display ID for use with website.
IanBenzMaxim 1:e1c7c1c636af 54 SensorNodeNeedsDetection, ///< Prompt user to insert Sensor Node.
IanBenzMaxim 1:e1c7c1c636af 55 DetectingSensorNode, ///< Check if Sensor Node present.
IanBenzMaxim 1:e1c7c1c636af 56 SensorNodeNeedsProvision, ///< Sensor Node needs to be provisioned.
IanBenzMaxim 1:e1c7c1c636af 57 ProvisioningSensorNode, ///< Provisioning Sensor Node to factory defaults.
IanBenzMaxim 1:e1c7c1c636af 58 NormalOperation, ///< The normal demo operation state.
IanBenzMaxim 1:e1c7c1c636af 59 SensorNodeNotAuthentic, ///< Sensor Node failed authentication check.
IanBenzMaxim 1:e1c7c1c636af 60 ControllerInitializationError, ///< Failed to initialize Controller.
IanBenzMaxim 1:e1c7c1c636af 61 ControllerHardwareError, ///< Controller hardware failed unexpectedly.
IanBenzMaxim 1:e1c7c1c636af 62 SensorNodeHardwareError ///< Sensor Node hardware failed unexpectedly.
IanBenzMaxim 1:e1c7c1c636af 63 };
IanBenzMaxim 1:e1c7c1c636af 64
IanBenzMaxim 1:e1c7c1c636af 65 /// @{
IanBenzMaxim 1:e1c7c1c636af 66 /// Configuration options.
IanBenzMaxim 1:e1c7c1c636af 67 static const unsigned int webPostIntervalMs = 10000;
IanBenzMaxim 1:e1c7c1c636af 68 static const unsigned int webPostRetryIntervalMs = 1000;
IanBenzMaxim 6:b6bafd0a7013 69 static const uint8_t maxConsecutiveWebPostErrors = 3;
IanBenzMaxim 1:e1c7c1c636af 70 /// @}
IanBenzMaxim 1:e1c7c1c636af 71
IanBenzMaxim 1:e1c7c1c636af 72 /// @{
IanBenzMaxim 1:e1c7c1c636af 73 /// LCD display colors.
IanBenzMaxim 1:e1c7c1c636af 74 static const Display::Color Teal(0x00, 0xB2, 0xA9);
IanBenzMaxim 1:e1c7c1c636af 75 static const Display::Color Red(0xFF, 0x00, 0x00);
IanBenzMaxim 1:e1c7c1c636af 76 static const Display::Color Green(0x00, 0xFF, 0x00);
IanBenzMaxim 1:e1c7c1c636af 77 /// @}
IanBenzMaxim 1:e1c7c1c636af 78
IanBenzMaxim 1:e1c7c1c636af 79 /// @{
IanBenzMaxim 1:e1c7c1c636af 80 /// Peripheral and pin definitions
IanBenzMaxim 1:e1c7c1c636af 81 static Serial pc(USBTX, USBRX);
IanBenzMaxim 1:e1c7c1c636af 82 static DigitalIn provisionButton(P2_0);
IanBenzMaxim 1:e1c7c1c636af 83 static DigitalIn invalidateButton(P1_5);
IanBenzMaxim 1:e1c7c1c636af 84 static DigitalOut tempAlarmLed(P2_1, 1);
IanBenzMaxim 1:e1c7c1c636af 85 static DigitalOut filterLifeAlarmLed(P2_3, 1);
IanBenzMaxim 1:e1c7c1c636af 86 static I2C i2c(P2_6, P2_7);
IanBenzMaxim 1:e1c7c1c636af 87 static Display lcd(i2c, 0x78, 0x98);
IanBenzMaxim 1:e1c7c1c636af 88 static DS2465 ds2465(i2c, 0x30);
IanBenzMaxim 1:e1c7c1c636af 89 static SensorNode sensorNode(i2c, 0x90, 0x94, ds2465);
IanBenzMaxim 1:e1c7c1c636af 90 static Factory factory;
IanBenzMaxim 1:e1c7c1c636af 91 static ESP8266 esp8266(P1_1, P1_0, P1_2, P1_3, 38400);
IanBenzMaxim 1:e1c7c1c636af 92 static WebServerInterface webIntf(esp8266, &pc);
IanBenzMaxim 1:e1c7c1c636af 93 /// @}
IanBenzMaxim 1:e1c7c1c636af 94
IanBenzMaxim 1:e1c7c1c636af 95 static bool useInvalidSecret = false; ///< Imitate an invalid controller when posting to web server.
IanBenzMaxim 1:e1c7c1c636af 96 static unsigned int randomSeed = 0; ///< Create extra entropy for challenge.
IanBenzMaxim 1:e1c7c1c636af 97 static Status currentStatus = InitializingController;
IanBenzMaxim 1:e1c7c1c636af 98 static bool result = false;
IanBenzMaxim 6:b6bafd0a7013 99 static uint8_t consecutiveWebPostErrors = 0; ///< Account for a few network errors in case of flaky connection.
IanBenzMaxim 1:e1c7c1c636af 100 static Timer webPostTimer; ///< Software timer to track web posting interval.
IanBenzMaxim 5:63232ef22abe 101 static Timer retryTimer; ///< Software timer to track authentication retries.
IanBenzMaxim 1:e1c7c1c636af 102
IanBenzMaxim 1:e1c7c1c636af 103 static void blinkLeds(unsigned int time_ms); ///< Invert LEDs for a given amount of time.
IanBenzMaxim 1:e1c7c1c636af 104 static bool buttonPressed(DigitalIn & button); ///< Checks if button is pressed (returns true) and waits for release.
IanBenzMaxim 1:e1c7c1c636af 105 static void displayStatus(Status status); ///< Display status message on LCD.
IanBenzMaxim 1:e1c7c1c636af 106 static void displaySensorData(const SensorData & sensorData); ///< Display sensor data on the LCD.
IanBenzMaxim 1:e1c7c1c636af 107 static bool readWebSessionId(std::string & sessionId); ///< Read device's web session ID from it's nonvolatile storage.
IanBenzMaxim 1:e1c7c1c636af 108
IanBenzMaxim 1:e1c7c1c636af 109 #ifdef ASSEMBLY_TEST
IanBenzMaxim 1:e1c7c1c636af 110 #include "AssemblyTest.cpp"
IanBenzMaxim 1:e1c7c1c636af 111 #endif
IanBenzMaxim 1:e1c7c1c636af 112
IanBenzMaxim 1:e1c7c1c636af 113 int main()
IanBenzMaxim 1:e1c7c1c636af 114 {
IanBenzMaxim 1:e1c7c1c636af 115 blinkLeds(500);
IanBenzMaxim 1:e1c7c1c636af 116
IanBenzMaxim 1:e1c7c1c636af 117 #ifdef ASSEMBLY_TEST
IanBenzMaxim 1:e1c7c1c636af 118 assemblyTest();
IanBenzMaxim 1:e1c7c1c636af 119 #endif
IanBenzMaxim 1:e1c7c1c636af 120
IanBenzMaxim 1:e1c7c1c636af 121 while (true)
IanBenzMaxim 1:e1c7c1c636af 122 {
IanBenzMaxim 1:e1c7c1c636af 123 Status nextStatus = currentStatus;
IanBenzMaxim 1:e1c7c1c636af 124 switch (currentStatus)
IanBenzMaxim 1:e1c7c1c636af 125 {
IanBenzMaxim 1:e1c7c1c636af 126 case InitializingController:
IanBenzMaxim 1:e1c7c1c636af 127 pc.baud(115200);
IanBenzMaxim 1:e1c7c1c636af 128 i2c.frequency(100000);
IanBenzMaxim 1:e1c7c1c636af 129 webPostTimer.start();
IanBenzMaxim 1:e1c7c1c636af 130
IanBenzMaxim 1:e1c7c1c636af 131 // Set initial LCD state
IanBenzMaxim 1:e1c7c1c636af 132 lcd.initialize();
IanBenzMaxim 1:e1c7c1c636af 133 displayStatus(currentStatus);
IanBenzMaxim 1:e1c7c1c636af 134
IanBenzMaxim 1:e1c7c1c636af 135 // Connect to Wifi network
IanBenzMaxim 1:e1c7c1c636af 136 result = webIntf.initialize();
IanBenzMaxim 1:e1c7c1c636af 137
IanBenzMaxim 1:e1c7c1c636af 138 // Read session ID
IanBenzMaxim 1:e1c7c1c636af 139 if (result)
IanBenzMaxim 1:e1c7c1c636af 140 {
IanBenzMaxim 1:e1c7c1c636af 141 result = readWebSessionId(webIntf.sessionId);
IanBenzMaxim 1:e1c7c1c636af 142 }
IanBenzMaxim 1:e1c7c1c636af 143
IanBenzMaxim 1:e1c7c1c636af 144 // Provision DS2465 with master secret and page data
IanBenzMaxim 1:e1c7c1c636af 145 if (result)
IanBenzMaxim 1:e1c7c1c636af 146 {
IanBenzMaxim 1:e1c7c1c636af 147 result = factory.provision(ds2465);
IanBenzMaxim 1:e1c7c1c636af 148 }
IanBenzMaxim 1:e1c7c1c636af 149
IanBenzMaxim 1:e1c7c1c636af 150 if (result)
IanBenzMaxim 1:e1c7c1c636af 151 {
IanBenzMaxim 1:e1c7c1c636af 152 nextStatus = DisplaySessionId;
IanBenzMaxim 1:e1c7c1c636af 153 }
IanBenzMaxim 1:e1c7c1c636af 154 else
IanBenzMaxim 1:e1c7c1c636af 155 {
IanBenzMaxim 1:e1c7c1c636af 156 nextStatus = ControllerInitializationError;
IanBenzMaxim 1:e1c7c1c636af 157 }
IanBenzMaxim 1:e1c7c1c636af 158 break;
IanBenzMaxim 1:e1c7c1c636af 159
IanBenzMaxim 1:e1c7c1c636af 160 case DisplaySessionId:
IanBenzMaxim 1:e1c7c1c636af 161 // Wait for user to press Provision button
IanBenzMaxim 1:e1c7c1c636af 162 if (buttonPressed(provisionButton))
IanBenzMaxim 1:e1c7c1c636af 163 {
IanBenzMaxim 1:e1c7c1c636af 164 nextStatus = SensorNodeNeedsDetection;
IanBenzMaxim 1:e1c7c1c636af 165 }
IanBenzMaxim 1:e1c7c1c636af 166 break;
IanBenzMaxim 1:e1c7c1c636af 167
IanBenzMaxim 1:e1c7c1c636af 168 case SensorNodeNeedsDetection:
IanBenzMaxim 1:e1c7c1c636af 169 // Wait for user to press Provision button
IanBenzMaxim 1:e1c7c1c636af 170 if (buttonPressed(provisionButton))
IanBenzMaxim 1:e1c7c1c636af 171 {
IanBenzMaxim 1:e1c7c1c636af 172 nextStatus = DetectingSensorNode;
IanBenzMaxim 1:e1c7c1c636af 173 }
IanBenzMaxim 1:e1c7c1c636af 174 break;
IanBenzMaxim 1:e1c7c1c636af 175
IanBenzMaxim 1:e1c7c1c636af 176 case DetectingSensorNode:
IanBenzMaxim 1:e1c7c1c636af 177 // Perform Sensor Node detection sequence
IanBenzMaxim 1:e1c7c1c636af 178 switch (sensorNode.detect(randomSeed))
IanBenzMaxim 1:e1c7c1c636af 179 {
IanBenzMaxim 1:e1c7c1c636af 180 case SensorNode::UnableToCommunicate:
IanBenzMaxim 1:e1c7c1c636af 181 default:
IanBenzMaxim 1:e1c7c1c636af 182 nextStatus = SensorNodeHardwareError;
IanBenzMaxim 1:e1c7c1c636af 183 break;
IanBenzMaxim 1:e1c7c1c636af 184
IanBenzMaxim 1:e1c7c1c636af 185 case SensorNode::NotProvisioned:
IanBenzMaxim 1:e1c7c1c636af 186 nextStatus = SensorNodeNeedsProvision;
IanBenzMaxim 1:e1c7c1c636af 187 break;
IanBenzMaxim 1:e1c7c1c636af 188
IanBenzMaxim 1:e1c7c1c636af 189 case SensorNode::NotAuthentic:
IanBenzMaxim 1:e1c7c1c636af 190 nextStatus = SensorNodeNotAuthentic;
IanBenzMaxim 1:e1c7c1c636af 191 break;
IanBenzMaxim 1:e1c7c1c636af 192
IanBenzMaxim 1:e1c7c1c636af 193 case SensorNode::Authentic:
IanBenzMaxim 1:e1c7c1c636af 194 nextStatus = NormalOperation;
IanBenzMaxim 1:e1c7c1c636af 195 break;
IanBenzMaxim 1:e1c7c1c636af 196 }
IanBenzMaxim 1:e1c7c1c636af 197 break;
IanBenzMaxim 1:e1c7c1c636af 198
IanBenzMaxim 1:e1c7c1c636af 199 case SensorNodeNeedsProvision:
IanBenzMaxim 1:e1c7c1c636af 200 // Wait for user to press Provision button
IanBenzMaxim 1:e1c7c1c636af 201 if (buttonPressed(provisionButton))
IanBenzMaxim 1:e1c7c1c636af 202 {
IanBenzMaxim 1:e1c7c1c636af 203 nextStatus = ProvisioningSensorNode;
IanBenzMaxim 1:e1c7c1c636af 204 }
IanBenzMaxim 1:e1c7c1c636af 205 break;
IanBenzMaxim 1:e1c7c1c636af 206
IanBenzMaxim 1:e1c7c1c636af 207 case ProvisioningSensorNode:
IanBenzMaxim 1:e1c7c1c636af 208 if (!buttonPressed(invalidateButton)) // Provision normally
IanBenzMaxim 1:e1c7c1c636af 209 {
IanBenzMaxim 1:e1c7c1c636af 210 if (factory.provision(sensorNode, true))
IanBenzMaxim 1:e1c7c1c636af 211 {
IanBenzMaxim 1:e1c7c1c636af 212 nextStatus = NormalOperation;
IanBenzMaxim 1:e1c7c1c636af 213 }
IanBenzMaxim 1:e1c7c1c636af 214 else
IanBenzMaxim 1:e1c7c1c636af 215 {
IanBenzMaxim 1:e1c7c1c636af 216 nextStatus = SensorNodeNotAuthentic;
IanBenzMaxim 1:e1c7c1c636af 217 }
IanBenzMaxim 1:e1c7c1c636af 218 }
IanBenzMaxim 1:e1c7c1c636af 219 else // Invalidate button also pressed; Load invalid secret
IanBenzMaxim 1:e1c7c1c636af 220 {
IanBenzMaxim 1:e1c7c1c636af 221 // Provision with invalid secret
IanBenzMaxim 1:e1c7c1c636af 222 if (factory.provision(sensorNode, false))
IanBenzMaxim 1:e1c7c1c636af 223 {
IanBenzMaxim 1:e1c7c1c636af 224 nextStatus = NormalOperation;
IanBenzMaxim 1:e1c7c1c636af 225 }
IanBenzMaxim 1:e1c7c1c636af 226 else
IanBenzMaxim 1:e1c7c1c636af 227 {
IanBenzMaxim 1:e1c7c1c636af 228 nextStatus = SensorNodeHardwareError;
IanBenzMaxim 1:e1c7c1c636af 229 }
IanBenzMaxim 1:e1c7c1c636af 230 }
IanBenzMaxim 1:e1c7c1c636af 231 break;
IanBenzMaxim 1:e1c7c1c636af 232
IanBenzMaxim 1:e1c7c1c636af 233 case NormalOperation:
IanBenzMaxim 1:e1c7c1c636af 234 // Check if user pressed Provision button
IanBenzMaxim 1:e1c7c1c636af 235 if (buttonPressed(provisionButton))
IanBenzMaxim 1:e1c7c1c636af 236 {
IanBenzMaxim 1:e1c7c1c636af 237 // Re-provision Sensor Node
IanBenzMaxim 1:e1c7c1c636af 238 nextStatus = ProvisioningSensorNode;
IanBenzMaxim 1:e1c7c1c636af 239 }
IanBenzMaxim 1:e1c7c1c636af 240 // Check if user pressed Invalidate button
IanBenzMaxim 1:e1c7c1c636af 241 else if (buttonPressed(invalidateButton))
IanBenzMaxim 1:e1c7c1c636af 242 {
IanBenzMaxim 1:e1c7c1c636af 243 // Toggle between using valid and invalid secret
IanBenzMaxim 1:e1c7c1c636af 244 // 1 blink = invalid; 2 blinks = valid
IanBenzMaxim 1:e1c7c1c636af 245 useInvalidSecret = !useInvalidSecret;
IanBenzMaxim 1:e1c7c1c636af 246 blinkLeds(100);
IanBenzMaxim 1:e1c7c1c636af 247 if (!useInvalidSecret)
IanBenzMaxim 1:e1c7c1c636af 248 {
IanBenzMaxim 1:e1c7c1c636af 249 wait_ms(100);
IanBenzMaxim 1:e1c7c1c636af 250 blinkLeds(100);
IanBenzMaxim 1:e1c7c1c636af 251 }
IanBenzMaxim 1:e1c7c1c636af 252 }
IanBenzMaxim 1:e1c7c1c636af 253 // Check node and display measurements
IanBenzMaxim 1:e1c7c1c636af 254 else
IanBenzMaxim 1:e1c7c1c636af 255 {
IanBenzMaxim 1:e1c7c1c636af 256 SensorData sensorData;
IanBenzMaxim 1:e1c7c1c636af 257 // Read sensor data with authentication
IanBenzMaxim 1:e1c7c1c636af 258 switch (sensorNode.authenticatedReadSensorData(randomSeed, sensorData))
IanBenzMaxim 1:e1c7c1c636af 259 {
IanBenzMaxim 1:e1c7c1c636af 260 case SensorNode::Authentic:
IanBenzMaxim 1:e1c7c1c636af 261 // Update measurements on LCD
IanBenzMaxim 1:e1c7c1c636af 262 displaySensorData(sensorData);
IanBenzMaxim 1:e1c7c1c636af 263
IanBenzMaxim 1:e1c7c1c636af 264 // Update alarm LEDs
IanBenzMaxim 1:e1c7c1c636af 265 tempAlarmLed = !sensorData.tempAlarm(); // Active Low
IanBenzMaxim 1:e1c7c1c636af 266 filterLifeAlarmLed = !sensorData.filterLifeAlarm(); // Active Low
IanBenzMaxim 1:e1c7c1c636af 267
IanBenzMaxim 1:e1c7c1c636af 268 // Send measurements to web if time interval reached
IanBenzMaxim 1:e1c7c1c636af 269 if (webPostTimer.read_ms() >= webPostIntervalMs)
IanBenzMaxim 1:e1c7c1c636af 270 {
IanBenzMaxim 1:e1c7c1c636af 271 // Format, sign, and transmit data to web server
IanBenzMaxim 1:e1c7c1c636af 272 result = webIntf.authPostHttpEvent(ds2465, SensorDataEvent, WebServerInterface::formatSensorDataPostBody(sensorData), !useInvalidSecret);
IanBenzMaxim 1:e1c7c1c636af 273 if (result)
IanBenzMaxim 1:e1c7c1c636af 274 {
IanBenzMaxim 1:e1c7c1c636af 275 // Reset timer count after logging sample complete
IanBenzMaxim 1:e1c7c1c636af 276 webPostTimer.reset();
IanBenzMaxim 1:e1c7c1c636af 277 consecutiveWebPostErrors = 0;
IanBenzMaxim 1:e1c7c1c636af 278 }
IanBenzMaxim 1:e1c7c1c636af 279 // There was likely an error establishing a web connection
IanBenzMaxim 1:e1c7c1c636af 280 else if (++consecutiveWebPostErrors < maxConsecutiveWebPostErrors)
IanBenzMaxim 1:e1c7c1c636af 281 {
IanBenzMaxim 1:e1c7c1c636af 282 // Wait and try again
IanBenzMaxim 1:e1c7c1c636af 283 wait_ms(webPostRetryIntervalMs);
IanBenzMaxim 1:e1c7c1c636af 284 }
IanBenzMaxim 1:e1c7c1c636af 285 // Too many retry attempts
IanBenzMaxim 1:e1c7c1c636af 286 else
IanBenzMaxim 1:e1c7c1c636af 287 {
IanBenzMaxim 1:e1c7c1c636af 288 // Assume we have lost network connection
IanBenzMaxim 1:e1c7c1c636af 289 nextStatus = ControllerHardwareError;
IanBenzMaxim 1:e1c7c1c636af 290 }
IanBenzMaxim 1:e1c7c1c636af 291 }
IanBenzMaxim 1:e1c7c1c636af 292 break;
IanBenzMaxim 1:e1c7c1c636af 293
IanBenzMaxim 1:e1c7c1c636af 294 case SensorNode::NotAuthentic:
IanBenzMaxim 1:e1c7c1c636af 295 nextStatus = SensorNodeNotAuthentic;
IanBenzMaxim 1:e1c7c1c636af 296 break;
IanBenzMaxim 1:e1c7c1c636af 297
IanBenzMaxim 1:e1c7c1c636af 298 case SensorNode::UnableToCommunicate:
IanBenzMaxim 1:e1c7c1c636af 299 default:
IanBenzMaxim 1:e1c7c1c636af 300 nextStatus = SensorNodeHardwareError;
IanBenzMaxim 1:e1c7c1c636af 301 break;
IanBenzMaxim 1:e1c7c1c636af 302 }
IanBenzMaxim 1:e1c7c1c636af 303 }
IanBenzMaxim 1:e1c7c1c636af 304 break;
IanBenzMaxim 1:e1c7c1c636af 305
IanBenzMaxim 1:e1c7c1c636af 306 case SensorNodeNotAuthentic:
IanBenzMaxim 5:63232ef22abe 307 // Wait for some time before retrying authentication
IanBenzMaxim 5:63232ef22abe 308 retryTimer.reset();
IanBenzMaxim 5:63232ef22abe 309 retryTimer.start();
IanBenzMaxim 5:63232ef22abe 310 do
IanBenzMaxim 1:e1c7c1c636af 311 {
IanBenzMaxim 5:63232ef22abe 312 // Wait for user to press Provision button
IanBenzMaxim 5:63232ef22abe 313 if (buttonPressed(provisionButton))
IanBenzMaxim 5:63232ef22abe 314 {
IanBenzMaxim 5:63232ef22abe 315 nextStatus = ProvisioningSensorNode;
IanBenzMaxim 5:63232ef22abe 316 break;
IanBenzMaxim 5:63232ef22abe 317 }
IanBenzMaxim 5:63232ef22abe 318 // Try to authenticate and return to normal operation
IanBenzMaxim 5:63232ef22abe 319 else if (webPostTimer.read_ms() >= webPostIntervalMs)
IanBenzMaxim 1:e1c7c1c636af 320 {
IanBenzMaxim 5:63232ef22abe 321 // Send event message to server
IanBenzMaxim 5:63232ef22abe 322 result = webIntf.authPostHttpEvent(ds2465, InvalidSensorEvent, "", !useInvalidSecret);
IanBenzMaxim 5:63232ef22abe 323 if (result)
IanBenzMaxim 5:63232ef22abe 324 {
IanBenzMaxim 5:63232ef22abe 325 // Reset timer count after logging complete
IanBenzMaxim 5:63232ef22abe 326 webPostTimer.reset();
IanBenzMaxim 5:63232ef22abe 327 consecutiveWebPostErrors = 0;
IanBenzMaxim 5:63232ef22abe 328
IanBenzMaxim 5:63232ef22abe 329 // Try to authenticate again
IanBenzMaxim 5:63232ef22abe 330 nextStatus = SensorNodeNeedsDetection;
IanBenzMaxim 5:63232ef22abe 331 }
IanBenzMaxim 5:63232ef22abe 332 else if (++consecutiveWebPostErrors < maxConsecutiveWebPostErrors)
IanBenzMaxim 5:63232ef22abe 333 {
IanBenzMaxim 5:63232ef22abe 334 // There was likely an error establishing a web connection
IanBenzMaxim 5:63232ef22abe 335 // Wait and try again
IanBenzMaxim 5:63232ef22abe 336 wait_ms(webPostRetryIntervalMs);
IanBenzMaxim 5:63232ef22abe 337 }
IanBenzMaxim 15:8cc4cdea59da 338 // Too many retry attempts
IanBenzMaxim 5:63232ef22abe 339 else
IanBenzMaxim 5:63232ef22abe 340 {
IanBenzMaxim 15:8cc4cdea59da 341 // Assume we have lost network connection
IanBenzMaxim 5:63232ef22abe 342 nextStatus = ControllerHardwareError;
IanBenzMaxim 5:63232ef22abe 343 break;
IanBenzMaxim 5:63232ef22abe 344 }
IanBenzMaxim 1:e1c7c1c636af 345 }
IanBenzMaxim 5:63232ef22abe 346 } while (retryTimer.read_ms() < webPostIntervalMs);
IanBenzMaxim 5:63232ef22abe 347 retryTimer.stop();
IanBenzMaxim 1:e1c7c1c636af 348 break;
IanBenzMaxim 1:e1c7c1c636af 349
IanBenzMaxim 1:e1c7c1c636af 350 case ControllerInitializationError:
IanBenzMaxim 1:e1c7c1c636af 351 case ControllerHardwareError:
IanBenzMaxim 1:e1c7c1c636af 352 case SensorNodeHardwareError:
IanBenzMaxim 1:e1c7c1c636af 353 default:
IanBenzMaxim 1:e1c7c1c636af 354 // Do nothing until user resets
IanBenzMaxim 1:e1c7c1c636af 355 break;
IanBenzMaxim 1:e1c7c1c636af 356 }
IanBenzMaxim 1:e1c7c1c636af 357 // Check if status changed
IanBenzMaxim 1:e1c7c1c636af 358 if (currentStatus != nextStatus)
IanBenzMaxim 1:e1c7c1c636af 359 {
IanBenzMaxim 1:e1c7c1c636af 360 currentStatus = nextStatus;
IanBenzMaxim 1:e1c7c1c636af 361 displayStatus(currentStatus); // Display status message on LCD
IanBenzMaxim 1:e1c7c1c636af 362 }
IanBenzMaxim 1:e1c7c1c636af 363
IanBenzMaxim 1:e1c7c1c636af 364 // Change seed value on every loop pass
IanBenzMaxim 1:e1c7c1c636af 365 randomSeed++;
IanBenzMaxim 1:e1c7c1c636af 366 }
IanBenzMaxim 1:e1c7c1c636af 367 }
IanBenzMaxim 1:e1c7c1c636af 368
IanBenzMaxim 1:e1c7c1c636af 369 /// Blink all LEDs for a certain amount of time.
IanBenzMaxim 1:e1c7c1c636af 370 /// @param time_ms Time in ms to blink for.
IanBenzMaxim 1:e1c7c1c636af 371 static void blinkLeds(unsigned int time_ms)
IanBenzMaxim 1:e1c7c1c636af 372 {
IanBenzMaxim 1:e1c7c1c636af 373 tempAlarmLed = !tempAlarmLed;
IanBenzMaxim 1:e1c7c1c636af 374 filterLifeAlarmLed = !filterLifeAlarmLed;
IanBenzMaxim 1:e1c7c1c636af 375 wait_ms(time_ms);
IanBenzMaxim 1:e1c7c1c636af 376 tempAlarmLed = !tempAlarmLed;
IanBenzMaxim 1:e1c7c1c636af 377 filterLifeAlarmLed = !filterLifeAlarmLed;
IanBenzMaxim 1:e1c7c1c636af 378 }
IanBenzMaxim 1:e1c7c1c636af 379
IanBenzMaxim 1:e1c7c1c636af 380 /// Check if a button is pressed and wait for it to be release.
IanBenzMaxim 1:e1c7c1c636af 381 /// @param button Active low button to check.
IanBenzMaxim 1:e1c7c1c636af 382 /// @returns True if pressed.
IanBenzMaxim 1:e1c7c1c636af 383 static bool buttonPressed(DigitalIn & button)
IanBenzMaxim 1:e1c7c1c636af 384 {
IanBenzMaxim 1:e1c7c1c636af 385 const int buttonPressed = 0; // Active low
IanBenzMaxim 1:e1c7c1c636af 386 if (button == buttonPressed)
IanBenzMaxim 1:e1c7c1c636af 387 {
IanBenzMaxim 1:e1c7c1c636af 388 while (button == buttonPressed) ;
IanBenzMaxim 1:e1c7c1c636af 389 return true;
IanBenzMaxim 1:e1c7c1c636af 390 }
IanBenzMaxim 1:e1c7c1c636af 391 // else
IanBenzMaxim 1:e1c7c1c636af 392 return false;
IanBenzMaxim 1:e1c7c1c636af 393 }
IanBenzMaxim 1:e1c7c1c636af 394
IanBenzMaxim 1:e1c7c1c636af 395 /// Display the current status of the Controller on the LCD display.
IanBenzMaxim 1:e1c7c1c636af 396 static void displayStatus(Status status)
IanBenzMaxim 1:e1c7c1c636af 397 {
IanBenzMaxim 1:e1c7c1c636af 398 switch (status)
IanBenzMaxim 1:e1c7c1c636af 399 {
IanBenzMaxim 1:e1c7c1c636af 400 case InitializingController:
IanBenzMaxim 1:e1c7c1c636af 401 lcd.writeMessage("Initializing Controller...");
IanBenzMaxim 1:e1c7c1c636af 402 lcd.setBackLightColor(Teal);
IanBenzMaxim 1:e1c7c1c636af 403 break;
IanBenzMaxim 1:e1c7c1c636af 404
IanBenzMaxim 1:e1c7c1c636af 405 case DisplaySessionId:
IanBenzMaxim 1:e1c7c1c636af 406 lcd.writeLine("ID: " + webIntf.sessionId, Display::FirstLine);
IanBenzMaxim 1:e1c7c1c636af 407 lcd.writeLine("Provision to begin", Display::SecondLine);
IanBenzMaxim 1:e1c7c1c636af 408 lcd.setBackLightColor(Teal);
IanBenzMaxim 1:e1c7c1c636af 409 break;
IanBenzMaxim 1:e1c7c1c636af 410
IanBenzMaxim 1:e1c7c1c636af 411 case SensorNodeNeedsDetection:
IanBenzMaxim 1:e1c7c1c636af 412 lcd.writeMessage("Insert Sensor Node and press Provision");
IanBenzMaxim 1:e1c7c1c636af 413 lcd.setBackLightColor(Teal);
IanBenzMaxim 1:e1c7c1c636af 414 break;
IanBenzMaxim 1:e1c7c1c636af 415
IanBenzMaxim 1:e1c7c1c636af 416 case DetectingSensorNode:
IanBenzMaxim 1:e1c7c1c636af 417 lcd.writeMessage("Detecting Sensor Node...");
IanBenzMaxim 1:e1c7c1c636af 418 lcd.setBackLightColor(Teal);
IanBenzMaxim 1:e1c7c1c636af 419 break;
IanBenzMaxim 1:e1c7c1c636af 420
IanBenzMaxim 1:e1c7c1c636af 421 case SensorNodeNeedsProvision:
IanBenzMaxim 1:e1c7c1c636af 422 lcd.writeMessage("Sensor Node Needs Provision");
IanBenzMaxim 1:e1c7c1c636af 423 lcd.setBackLightColor(Teal);
IanBenzMaxim 1:e1c7c1c636af 424 break;
IanBenzMaxim 1:e1c7c1c636af 425
IanBenzMaxim 1:e1c7c1c636af 426 case ProvisioningSensorNode:
IanBenzMaxim 1:e1c7c1c636af 427 lcd.writeMessage("Provisioning Sensor Node");
IanBenzMaxim 1:e1c7c1c636af 428 lcd.setBackLightColor(Teal);
IanBenzMaxim 1:e1c7c1c636af 429 break;
IanBenzMaxim 1:e1c7c1c636af 430
IanBenzMaxim 1:e1c7c1c636af 431 case NormalOperation:
IanBenzMaxim 1:e1c7c1c636af 432 // Everything handled in displaySensorData()
IanBenzMaxim 1:e1c7c1c636af 433 break;
IanBenzMaxim 1:e1c7c1c636af 434
IanBenzMaxim 1:e1c7c1c636af 435 case SensorNodeNotAuthentic:
IanBenzMaxim 1:e1c7c1c636af 436 lcd.writeMessage("Sensor Node Not Authentic");
IanBenzMaxim 1:e1c7c1c636af 437 lcd.setBackLightColor(Red);
IanBenzMaxim 1:e1c7c1c636af 438 break;
IanBenzMaxim 1:e1c7c1c636af 439
IanBenzMaxim 1:e1c7c1c636af 440 case ControllerInitializationError:
IanBenzMaxim 1:e1c7c1c636af 441 lcd.writeMessage("Initialization Error Check Wi-Fi");
IanBenzMaxim 1:e1c7c1c636af 442 lcd.setBackLightColor(Red);
IanBenzMaxim 1:e1c7c1c636af 443 break;
IanBenzMaxim 1:e1c7c1c636af 444
IanBenzMaxim 1:e1c7c1c636af 445 case ControllerHardwareError:
IanBenzMaxim 15:8cc4cdea59da 446 lcd.writeMessage("Controller Hardware Error: Check Wi-Fi");
IanBenzMaxim 1:e1c7c1c636af 447 lcd.setBackLightColor(Red);
IanBenzMaxim 1:e1c7c1c636af 448 break;
IanBenzMaxim 1:e1c7c1c636af 449
IanBenzMaxim 1:e1c7c1c636af 450 case SensorNodeHardwareError:
IanBenzMaxim 1:e1c7c1c636af 451 lcd.writeMessage("Sensor Node Hardware Error");
IanBenzMaxim 1:e1c7c1c636af 452 lcd.setBackLightColor(Red);
IanBenzMaxim 1:e1c7c1c636af 453 break;
IanBenzMaxim 1:e1c7c1c636af 454 }
IanBenzMaxim 1:e1c7c1c636af 455 }
IanBenzMaxim 1:e1c7c1c636af 456
IanBenzMaxim 1:e1c7c1c636af 457 /// Display sensor data on the LCD display during normal operation.
IanBenzMaxim 1:e1c7c1c636af 458 static void displaySensorData(const SensorData & sensorData)
IanBenzMaxim 1:e1c7c1c636af 459 {
IanBenzMaxim 1:e1c7c1c636af 460 std::ostringstream stream;
IanBenzMaxim 1:e1c7c1c636af 461 stream << "Chiller Temp: " << (int)sensorData.temp << "C";
IanBenzMaxim 1:e1c7c1c636af 462 lcd.writeCompleteLine(stream.str(), Display::FirstLine);
IanBenzMaxim 1:e1c7c1c636af 463 stream.str(""); // Clear stream
IanBenzMaxim 1:e1c7c1c636af 464 stream << "Filter Life: " << (unsigned int)sensorData.filterLife << "%";
IanBenzMaxim 1:e1c7c1c636af 465 lcd.writeCompleteLine(stream.str(), Display::SecondLine);
IanBenzMaxim 1:e1c7c1c636af 466 lcd.setBackLightColor((sensorData.tempAlarm() || sensorData.filterLifeAlarm()) ? Red : Green);
IanBenzMaxim 1:e1c7c1c636af 467 }
IanBenzMaxim 1:e1c7c1c636af 468
IanBenzMaxim 1:e1c7c1c636af 469 /// Read the Session ID to use with the web server from ROM.
IanBenzMaxim 1:e1c7c1c636af 470 /// @note Session ID is taken from the ROM ID of the MAX66242.
IanBenzMaxim 1:e1c7c1c636af 471 /// @param[out] Session ID string.
IanBenzMaxim 1:e1c7c1c636af 472 /// @returns True on success.
IanBenzMaxim 1:e1c7c1c636af 473 static bool readWebSessionId(std::string & sessionId)
IanBenzMaxim 1:e1c7c1c636af 474 {
IanBenzMaxim 1:e1c7c1c636af 475 const uint8_t I2C_address = 0x32;
IanBenzMaxim 1:e1c7c1c636af 476 const uint8_t ROM_address = 0x68;
IanBenzMaxim 1:e1c7c1c636af 477 RomId romId;
IanBenzMaxim 1:e1c7c1c636af 478
IanBenzMaxim 1:e1c7c1c636af 479 // Set register pointer
IanBenzMaxim 4:71d578d3af22 480 if (i2c.write(I2C_address, reinterpret_cast<const char *>(&ROM_address), 1) != 0)
IanBenzMaxim 1:e1c7c1c636af 481 return false;
IanBenzMaxim 1:e1c7c1c636af 482 // Read ROM ID
IanBenzMaxim 4:71d578d3af22 483 if (i2c.read(I2C_address, reinterpret_cast<char *>(&(static_cast<RomId::ByteBuffer &>(romId))), RomId::byteLen) != 0)
IanBenzMaxim 1:e1c7c1c636af 484 return false;
IanBenzMaxim 1:e1c7c1c636af 485 // Check if CRC valid
IanBenzMaxim 1:e1c7c1c636af 486 if (!romId.crc8Valid())
IanBenzMaxim 1:e1c7c1c636af 487 return false;
IanBenzMaxim 1:e1c7c1c636af 488 sessionId = byteArrayToHexString(romId, RomId::byteLen);
IanBenzMaxim 1:e1c7c1c636af 489 return true;
IanBenzMaxim 1:e1c7c1c636af 490 }