DeepCover Embedded Security in IoT: Public-key Secured Data Paths

Dependencies:   MaximInterface

The MAXREFDES155# is an internet-of-things (IoT) embedded-security reference design, built to authenticate and control a sensing node using elliptic-curve-based public-key cryptography with control and notification from a web server.

The hardware includes an ARM® mbed™ shield and attached sensor endpoint. The shield contains a DS2476 DeepCover® ECDSA/SHA-2 coprocessor, Wifi communication, LCD push-button controls, and status LEDs. The sensor endpoint is attached to the shield using a 300mm cable and contains a DS28C36 DeepCover ECDSA/SHA-2 authenticator, IR-thermal sensor, and aiming laser for the IR sensor. The MAXREFDES155# is equipped with a standard Arduino® form-factor shield connector for immediate testing using an mbed board such as the MAX32600MBED#. The combination of these two devices represent an IoT device. Communication to the web server is accomplished with the shield Wifi circuitry. Communication from the shield to the attached sensor module is accomplished over I2C . The sensor module represents an IoT endpoint that generates small data with a requirement for message authenticity/integrity and secure on/off operational control.

The design is hierarchical with each mbed platform and shield communicating data from the sensor node to a web server that maintains a centralized log and dispatches notifications as necessary. The simplicity of this design enables rapid integration into any star-topology IoT network to provide security with the low overhead and cost provided by the ECDSA-P256 asymmetric-key and SHA-256 symmetric-key algorithms.

More information about the MAXREFDES155# is available on the Maxim Integrated website.

Committer:
IanBenzMaxim
Date:
Thu Oct 03 11:40:13 2019 -0500
Revision:
16:a004191a79ab
Parent:
NormalOperationWindow.cpp@14:dc839a69379b
Updated MaximInterface to version 2.0. Updated mbed-os to version 5.5.7. Cleaned up code styling.

Who changed what in which revision?

UserRevisionLine numberNew contents of line
IanBenzMaxim 0:33d4e66780c0 1 /*******************************************************************************
IanBenzMaxim 16:a004191a79ab 2 * Copyright (C) Maxim Integrated Products, Inc., All Rights Reserved.
IanBenzMaxim 0:33d4e66780c0 3 *
IanBenzMaxim 0:33d4e66780c0 4 * Permission is hereby granted, free of charge, to any person obtaining a
IanBenzMaxim 0:33d4e66780c0 5 * copy of this software and associated documentation files (the "Software"),
IanBenzMaxim 0:33d4e66780c0 6 * to deal in the Software without restriction, including without limitation
IanBenzMaxim 0:33d4e66780c0 7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
IanBenzMaxim 0:33d4e66780c0 8 * and/or sell copies of the Software, and to permit persons to whom the
IanBenzMaxim 0:33d4e66780c0 9 * Software is furnished to do so, subject to the following conditions:
IanBenzMaxim 0:33d4e66780c0 10 *
IanBenzMaxim 0:33d4e66780c0 11 * The above copyright notice and this permission notice shall be included
IanBenzMaxim 0:33d4e66780c0 12 * in all copies or substantial portions of the Software.
IanBenzMaxim 0:33d4e66780c0 13 *
IanBenzMaxim 0:33d4e66780c0 14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
IanBenzMaxim 0:33d4e66780c0 15 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
IanBenzMaxim 0:33d4e66780c0 16 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IanBenzMaxim 0:33d4e66780c0 17 * IN NO EVENT SHALL MAXIM INTEGRATED BE LIABLE FOR ANY CLAIM, DAMAGES
IanBenzMaxim 0:33d4e66780c0 18 * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
IanBenzMaxim 0:33d4e66780c0 19 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
IanBenzMaxim 0:33d4e66780c0 20 * OTHER DEALINGS IN THE SOFTWARE.
IanBenzMaxim 0:33d4e66780c0 21 *
IanBenzMaxim 0:33d4e66780c0 22 * Except as contained in this notice, the name of Maxim Integrated
IanBenzMaxim 0:33d4e66780c0 23 * Products, Inc. shall not be used except as stated in the Maxim Integrated
IanBenzMaxim 0:33d4e66780c0 24 * Products, Inc. Branding Policy.
IanBenzMaxim 0:33d4e66780c0 25 *
IanBenzMaxim 0:33d4e66780c0 26 * The mere transfer of this software does not imply any licenses
IanBenzMaxim 0:33d4e66780c0 27 * of trade secrets, proprietary technology, copyrights, patents,
IanBenzMaxim 0:33d4e66780c0 28 * trademarks, maskwork rights, or any other form of intellectual
IanBenzMaxim 0:33d4e66780c0 29 * property whatsoever. Maxim Integrated Products, Inc. retains all
IanBenzMaxim 0:33d4e66780c0 30 * ownership rights.
IanBenzMaxim 0:33d4e66780c0 31 *******************************************************************************/
IanBenzMaxim 0:33d4e66780c0 32
IanBenzMaxim 0:33d4e66780c0 33 #include <stdint.h>
IanBenzMaxim 4:cd2dc3e7433f 34 #include <stdio.h>
IanBenzMaxim 0:33d4e66780c0 35 #include <cassert>
IanBenzMaxim 3:d2799d8497c0 36 #include <cstdio>
IanBenzMaxim 0:33d4e66780c0 37 #include <string>
IanBenzMaxim 16:a004191a79ab 38 #include <MaximInterfaceCore/HexString.hpp>
IanBenzMaxim 16:a004191a79ab 39 #include <MaximInterfaceCore/span.hpp>
IanBenzMaxim 16:a004191a79ab 40 #include <MaximInterfaceDevices/DS28C36_DS2476.hpp>
IanBenzMaxim 16:a004191a79ab 41 #include <rapidjson/stringbuffer.h>
IanBenzMaxim 16:a004191a79ab 42 #include <rapidjson/writer.h>
IanBenzMaxim 13:6a6225690c2e 43 #include "DisplayGraphicWindow.hpp"
IanBenzMaxim 13:6a6225690c2e 44 #include "DisplayIdWindow.hpp"
IanBenzMaxim 13:6a6225690c2e 45 #include "ErrorWindow.hpp"
IanBenzMaxim 0:33d4e66780c0 46 #include "Image.hpp"
IanBenzMaxim 13:6a6225690c2e 47 #include "MakeFunction.hpp"
IanBenzMaxim 13:6a6225690c2e 48 #include "NormalOperationWindow.hpp"
IanBenzMaxim 0:33d4e66780c0 49 #include "Text.hpp"
IanBenzMaxim 0:33d4e66780c0 50 #include "WindowManager.hpp"
IanBenzMaxim 13:6a6225690c2e 51
IanBenzMaxim 16:a004191a79ab 52 #define TRY MaximInterfaceCore_TRY
IanBenzMaxim 16:a004191a79ab 53 #define TRY_VALUE MaximInterfaceCore_TRY_VALUE
IanBenzMaxim 16:a004191a79ab 54
IanBenzMaxim 16:a004191a79ab 55 namespace Core = MaximInterfaceCore;
IanBenzMaxim 16:a004191a79ab 56 using MaximInterfaceDevices::DS2476;
IanBenzMaxim 0:33d4e66780c0 57
IanBenzMaxim 0:33d4e66780c0 58 extern DS2476 coproc;
IanBenzMaxim 0:33d4e66780c0 59 extern SensorNode sensorNode;
IanBenzMaxim 0:33d4e66780c0 60 extern std::string webId;
IanBenzMaxim 0:33d4e66780c0 61
IanBenzMaxim 16:a004191a79ab 62 extern "C" void ComputeSHA256(unsigned char * message, short length,
IanBenzMaxim 16:a004191a79ab 63 unsigned short skipconst, unsigned short reverse,
IanBenzMaxim 16:a004191a79ab 64 unsigned char * digest);
IanBenzMaxim 0:33d4e66780c0 65
IanBenzMaxim 13:6a6225690c2e 66 // Default allocation size for rapidjson.
IanBenzMaxim 13:6a6225690c2e 67 static const size_t defaultChunkSize = 256;
IanBenzMaxim 16:a004191a79ab 68
IanBenzMaxim 13:6a6225690c2e 69 // Number of decimal places to use when writing JSON.
IanBenzMaxim 13:6a6225690c2e 70 static const int jsonMaxDecimalPlaces = 2;
IanBenzMaxim 0:33d4e66780c0 71
IanBenzMaxim 0:33d4e66780c0 72 // Separate multiple JSON commands received on the socket.
IanBenzMaxim 0:33d4e66780c0 73 // Returns a list of begin and end iterators within the input message.
IanBenzMaxim 16:a004191a79ab 74 static std::vector<Core::span<const char> >
IanBenzMaxim 16:a004191a79ab 75 separateCommands(Core::span<const char> receivedData) {
IanBenzMaxim 16:a004191a79ab 76 std::vector<Core::span<const char> > commands;
IanBenzMaxim 13:6a6225690c2e 77 int counter = 0;
IanBenzMaxim 16:a004191a79ab 78 Core::span<const char>::index_type beginIdx;
IanBenzMaxim 16:a004191a79ab 79 for (Core::span<const char>::index_type i = 0; i < receivedData.size(); ++i) {
IanBenzMaxim 13:6a6225690c2e 80 if (receivedData[i] == '{') {
IanBenzMaxim 13:6a6225690c2e 81 if (counter == 0) {
IanBenzMaxim 13:6a6225690c2e 82 beginIdx = i;
IanBenzMaxim 13:6a6225690c2e 83 }
IanBenzMaxim 16:a004191a79ab 84 ++counter;
IanBenzMaxim 13:6a6225690c2e 85 } else if (receivedData[i] == '}') {
IanBenzMaxim 13:6a6225690c2e 86 if (counter > 0) {
IanBenzMaxim 16:a004191a79ab 87 --counter;
IanBenzMaxim 13:6a6225690c2e 88 if (counter == 0) {
IanBenzMaxim 13:6a6225690c2e 89 commands.push_back(
IanBenzMaxim 16:a004191a79ab 90 Core::make_span(&receivedData[beginIdx], &receivedData[i + 1]));
IanBenzMaxim 0:33d4e66780c0 91 }
IanBenzMaxim 13:6a6225690c2e 92 }
IanBenzMaxim 0:33d4e66780c0 93 }
IanBenzMaxim 13:6a6225690c2e 94 }
IanBenzMaxim 13:6a6225690c2e 95 return commands;
IanBenzMaxim 0:33d4e66780c0 96 }
IanBenzMaxim 0:33d4e66780c0 97
IanBenzMaxim 16:a004191a79ab 98 Core::Result<void>
IanBenzMaxim 16:a004191a79ab 99 NormalOperationWindow::addCommandChallenge(rapidjson::Document & document) {
IanBenzMaxim 16:a004191a79ab 100 TRY(coproc.readRng(commandChallenge));
IanBenzMaxim 16:a004191a79ab 101 document.AddMember("challenge",
IanBenzMaxim 16:a004191a79ab 102 rapidjson::Value(toHexString(commandChallenge).c_str(),
IanBenzMaxim 16:a004191a79ab 103 document.GetAllocator())
IanBenzMaxim 16:a004191a79ab 104 .Move(),
IanBenzMaxim 16:a004191a79ab 105 document.GetAllocator());
IanBenzMaxim 16:a004191a79ab 106 return Core::none;
IanBenzMaxim 12:46c5974a565f 107 }
IanBenzMaxim 12:46c5974a565f 108
IanBenzMaxim 16:a004191a79ab 109 Core::Result<void>
IanBenzMaxim 16:a004191a79ab 110 NormalOperationWindow::signData(rapidjson::Document & document,
IanBenzMaxim 16:a004191a79ab 111 bool validSignature,
IanBenzMaxim 16:a004191a79ab 112 const std::vector<uint8_t> & challenge) {
IanBenzMaxim 13:6a6225690c2e 113 // Move contents of the document to a new location, and create an empty object
IanBenzMaxim 13:6a6225690c2e 114 // in the document.
IanBenzMaxim 13:6a6225690c2e 115 rapidjson::Value data(rapidjson::kObjectType);
IanBenzMaxim 13:6a6225690c2e 116 data.Swap(document);
IanBenzMaxim 13:6a6225690c2e 117 // Convert data to a string and generate a signature from that string.
IanBenzMaxim 13:6a6225690c2e 118 rapidjson::StringBuffer dataBuffer;
IanBenzMaxim 13:6a6225690c2e 119 rapidjson::Writer<rapidjson::StringBuffer> writer(dataBuffer);
IanBenzMaxim 13:6a6225690c2e 120 writer.SetMaxDecimalPlaces(jsonMaxDecimalPlaces);
IanBenzMaxim 13:6a6225690c2e 121 data.Accept(writer);
IanBenzMaxim 13:6a6225690c2e 122 std::vector<uint8_t> signDataBuffer(
IanBenzMaxim 13:6a6225690c2e 123 dataBuffer.GetString(), dataBuffer.GetString() + dataBuffer.GetLength());
IanBenzMaxim 13:6a6225690c2e 124 signDataBuffer.insert(signDataBuffer.end(), challenge.begin(),
IanBenzMaxim 13:6a6225690c2e 125 challenge.end());
IanBenzMaxim 16:a004191a79ab 126 uint8_t hash[32];
IanBenzMaxim 16:a004191a79ab 127 ComputeSHA256(&signDataBuffer[0], signDataBuffer.size(), false, false, hash);
IanBenzMaxim 16:a004191a79ab 128 TRY(coproc.writeBuffer(hash));
IanBenzMaxim 16:a004191a79ab 129 Core::Ecc256::Signature::array signatureBuffer;
IanBenzMaxim 16:a004191a79ab 130 TRY_VALUE(signatureBuffer, coproc.generateEcdsaSignature(DS2476::KeyNumA));
IanBenzMaxim 16:a004191a79ab 131 if (!validSignature) {
IanBenzMaxim 16:a004191a79ab 132 ++signatureBuffer.r[0];
IanBenzMaxim 13:6a6225690c2e 133 }
IanBenzMaxim 16:a004191a79ab 134 // Construct the final document with the original data and the generated
IanBenzMaxim 16:a004191a79ab 135 // signature.
IanBenzMaxim 16:a004191a79ab 136 rapidjson::Value signature(rapidjson::kObjectType);
IanBenzMaxim 16:a004191a79ab 137 signature.AddMember(
IanBenzMaxim 16:a004191a79ab 138 "r",
IanBenzMaxim 16:a004191a79ab 139 rapidjson::Value(Core::toHexString(signatureBuffer.r).c_str(),
IanBenzMaxim 16:a004191a79ab 140 document.GetAllocator())
IanBenzMaxim 16:a004191a79ab 141 .Move(),
IanBenzMaxim 16:a004191a79ab 142 document.GetAllocator());
IanBenzMaxim 16:a004191a79ab 143 signature.AddMember(
IanBenzMaxim 16:a004191a79ab 144 "s",
IanBenzMaxim 16:a004191a79ab 145 rapidjson::Value(Core::toHexString(signatureBuffer.s).c_str(),
IanBenzMaxim 16:a004191a79ab 146 document.GetAllocator())
IanBenzMaxim 16:a004191a79ab 147 .Move(),
IanBenzMaxim 16:a004191a79ab 148 document.GetAllocator());
IanBenzMaxim 16:a004191a79ab 149 document.AddMember("data", data, document.GetAllocator());
IanBenzMaxim 16:a004191a79ab 150 document.AddMember("signature", signature, document.GetAllocator());
IanBenzMaxim 16:a004191a79ab 151 return Core::none;
IanBenzMaxim 0:33d4e66780c0 152 }
IanBenzMaxim 0:33d4e66780c0 153
IanBenzMaxim 16:a004191a79ab 154 Core::Result<void> NormalOperationWindow::finalizeResponse(
IanBenzMaxim 16:a004191a79ab 155 rapidjson::Document & document, bool validSignature,
IanBenzMaxim 16:a004191a79ab 156 const std::vector<uint8_t> & responseChallenge) {
IanBenzMaxim 16:a004191a79ab 157 TRY(addCommandChallenge(document));
IanBenzMaxim 16:a004191a79ab 158 TRY(signData(document, validSignature, responseChallenge));
IanBenzMaxim 16:a004191a79ab 159 return Core::none;
IanBenzMaxim 12:46c5974a565f 160 }
IanBenzMaxim 12:46c5974a565f 161
IanBenzMaxim 16:a004191a79ab 162 Core::Result<void>
IanBenzMaxim 16:a004191a79ab 163 NormalOperationWindow::verifySignedData(rapidjson::Document & signedData,
IanBenzMaxim 16:a004191a79ab 164 Core::span<const char> verifyDataIn) {
IanBenzMaxim 13:6a6225690c2e 165 using rapidjson::Value;
IanBenzMaxim 13:6a6225690c2e 166 using std::string;
IanBenzMaxim 13:6a6225690c2e 167
IanBenzMaxim 13:6a6225690c2e 168 // Parse string and validate object schema.
IanBenzMaxim 16:a004191a79ab 169 string verifyData(verifyDataIn.begin(), verifyDataIn.end());
IanBenzMaxim 13:6a6225690c2e 170 signedData.Parse(verifyData.c_str());
IanBenzMaxim 13:6a6225690c2e 171 if (!(signedData.IsObject() && signedData.HasMember("data") &&
IanBenzMaxim 13:6a6225690c2e 172 signedData.HasMember("signature"))) {
IanBenzMaxim 13:6a6225690c2e 173 signedData.RemoveAllMembers();
IanBenzMaxim 16:a004191a79ab 174 return DS2476::AuthenticationError;
IanBenzMaxim 13:6a6225690c2e 175 }
IanBenzMaxim 13:6a6225690c2e 176 Value & data = signedData["data"];
IanBenzMaxim 13:6a6225690c2e 177 const Value & signature = signedData["signature"];
IanBenzMaxim 13:6a6225690c2e 178 if (!(data.IsObject() && signature.IsObject() && signature.HasMember("r") &&
IanBenzMaxim 13:6a6225690c2e 179 signature.HasMember("s"))) {
IanBenzMaxim 13:6a6225690c2e 180 signedData.RemoveAllMembers();
IanBenzMaxim 16:a004191a79ab 181 return DS2476::AuthenticationError;
IanBenzMaxim 13:6a6225690c2e 182 }
IanBenzMaxim 13:6a6225690c2e 183 const Value & signatureR = signature["r"];
IanBenzMaxim 13:6a6225690c2e 184 const Value & signatureS = signature["s"];
IanBenzMaxim 13:6a6225690c2e 185 if (!(signatureR.IsString() && signatureS.IsString())) {
IanBenzMaxim 13:6a6225690c2e 186 signedData.RemoveAllMembers();
IanBenzMaxim 16:a004191a79ab 187 return DS2476::AuthenticationError;
IanBenzMaxim 13:6a6225690c2e 188 }
IanBenzMaxim 13:6a6225690c2e 189
IanBenzMaxim 13:6a6225690c2e 190 // Parse signature.
IanBenzMaxim 16:a004191a79ab 191 Core::Optional<std::vector<uint8_t> > parsedBytes = Core::fromHexString(
IanBenzMaxim 16:a004191a79ab 192 Core::make_span(signatureR.GetString(), signatureR.GetStringLength()));
IanBenzMaxim 16:a004191a79ab 193 Core::Ecc256::Signature::array signatureBuffer;
IanBenzMaxim 16:a004191a79ab 194 if (!(parsedBytes && parsedBytes->size() == signatureBuffer.r.size())) {
IanBenzMaxim 13:6a6225690c2e 195 signedData.RemoveAllMembers();
IanBenzMaxim 16:a004191a79ab 196 return DS2476::AuthenticationError;
IanBenzMaxim 13:6a6225690c2e 197 }
IanBenzMaxim 16:a004191a79ab 198 std::copy(parsedBytes->begin(), parsedBytes->end(),
IanBenzMaxim 16:a004191a79ab 199 signatureBuffer.r.begin());
IanBenzMaxim 16:a004191a79ab 200 parsedBytes = Core::fromHexString(
IanBenzMaxim 16:a004191a79ab 201 Core::make_span(signatureS.GetString(), signatureS.GetStringLength()));
IanBenzMaxim 16:a004191a79ab 202 if (!(parsedBytes && parsedBytes->size() == signatureBuffer.s.size())) {
IanBenzMaxim 13:6a6225690c2e 203 signedData.RemoveAllMembers();
IanBenzMaxim 16:a004191a79ab 204 return DS2476::AuthenticationError;
IanBenzMaxim 13:6a6225690c2e 205 }
IanBenzMaxim 16:a004191a79ab 206 std::copy(parsedBytes->begin(), parsedBytes->end(),
IanBenzMaxim 16:a004191a79ab 207 signatureBuffer.s.begin());
IanBenzMaxim 13:6a6225690c2e 208
IanBenzMaxim 13:6a6225690c2e 209 // Get data to hash.
IanBenzMaxim 13:6a6225690c2e 210 // Need to use string searching here since there isn't currently a way to
IanBenzMaxim 13:6a6225690c2e 211 // access raw elements in rapidjson, and creating another copy of the data
IanBenzMaxim 13:6a6225690c2e 212 // might consume too much memory.
IanBenzMaxim 13:6a6225690c2e 213 const string rawDataSearch("\"data\":");
IanBenzMaxim 13:6a6225690c2e 214 string::size_type rawDataBegin = verifyData.find(rawDataSearch);
IanBenzMaxim 13:6a6225690c2e 215 if ((rawDataBegin == string::npos) ||
IanBenzMaxim 13:6a6225690c2e 216 ((rawDataBegin + rawDataSearch.size()) >= verifyData.size())) {
IanBenzMaxim 13:6a6225690c2e 217 signedData.RemoveAllMembers();
IanBenzMaxim 16:a004191a79ab 218 return DS2476::AuthenticationError;
IanBenzMaxim 13:6a6225690c2e 219 }
IanBenzMaxim 13:6a6225690c2e 220 rawDataBegin += rawDataSearch.size();
IanBenzMaxim 13:6a6225690c2e 221 string::size_type rawDataEnd =
IanBenzMaxim 13:6a6225690c2e 222 verifyData.find(",\"signature\"", rawDataBegin);
IanBenzMaxim 13:6a6225690c2e 223 if (rawDataEnd == string::npos) {
IanBenzMaxim 13:6a6225690c2e 224 signedData.RemoveAllMembers();
IanBenzMaxim 16:a004191a79ab 225 return DS2476::AuthenticationError;
IanBenzMaxim 13:6a6225690c2e 226 }
IanBenzMaxim 13:6a6225690c2e 227 verifyData.erase(rawDataEnd);
IanBenzMaxim 13:6a6225690c2e 228 verifyData.erase(0, rawDataBegin);
IanBenzMaxim 13:6a6225690c2e 229 // Add in command challenge to data that will be verified.
IanBenzMaxim 13:6a6225690c2e 230 verifyData.append(commandChallenge.begin(), commandChallenge.end());
IanBenzMaxim 13:6a6225690c2e 231
IanBenzMaxim 13:6a6225690c2e 232 // Compute hash of the data.
IanBenzMaxim 16:a004191a79ab 233 Core::Result<void> result = computeMultiblockHash(
IanBenzMaxim 16:a004191a79ab 234 coproc,
IanBenzMaxim 16:a004191a79ab 235 Core::make_span(reinterpret_cast<const uint8_t *>(verifyData.data()),
IanBenzMaxim 16:a004191a79ab 236 verifyData.size()));
IanBenzMaxim 16:a004191a79ab 237 if (!result) {
IanBenzMaxim 13:6a6225690c2e 238 signedData.RemoveAllMembers();
IanBenzMaxim 0:33d4e66780c0 239 return result;
IanBenzMaxim 13:6a6225690c2e 240 }
IanBenzMaxim 13:6a6225690c2e 241 // Verify signature.
IanBenzMaxim 13:6a6225690c2e 242 result = coproc.verifyEcdsaSignature(DS2476::KeyNumC, DS2476::THASH,
IanBenzMaxim 13:6a6225690c2e 243 signatureBuffer);
IanBenzMaxim 16:a004191a79ab 244 if (!result) {
IanBenzMaxim 13:6a6225690c2e 245 signedData.RemoveAllMembers();
IanBenzMaxim 13:6a6225690c2e 246 return result;
IanBenzMaxim 13:6a6225690c2e 247 }
IanBenzMaxim 13:6a6225690c2e 248
IanBenzMaxim 13:6a6225690c2e 249 // Strip signing information from document.
IanBenzMaxim 13:6a6225690c2e 250 rapidjson::Value swapObject(rapidjson::kObjectType);
IanBenzMaxim 13:6a6225690c2e 251 swapObject.Swap(data);
IanBenzMaxim 13:6a6225690c2e 252 swapObject.Swap(signedData);
IanBenzMaxim 16:a004191a79ab 253 return Core::none;
IanBenzMaxim 0:33d4e66780c0 254 }
IanBenzMaxim 0:33d4e66780c0 255
IanBenzMaxim 16:a004191a79ab 256 void NormalOperationWindow::sendJson(const rapidjson::Value & document) {
IanBenzMaxim 13:6a6225690c2e 257 rapidjson::StringBuffer buffer;
IanBenzMaxim 13:6a6225690c2e 258 rapidjson::Writer<rapidjson::StringBuffer> writer(buffer);
IanBenzMaxim 13:6a6225690c2e 259 writer.SetMaxDecimalPlaces(jsonMaxDecimalPlaces);
IanBenzMaxim 13:6a6225690c2e 260 document.Accept(writer);
IanBenzMaxim 16:a004191a79ab 261 socket->send(buffer.GetString(), buffer.GetLength());
IanBenzMaxim 0:33d4e66780c0 262 }
IanBenzMaxim 0:33d4e66780c0 263
IanBenzMaxim 13:6a6225690c2e 264 void NormalOperationWindow::sendMessage(const char * message) {
IanBenzMaxim 13:6a6225690c2e 265 rapidjson::MemoryPoolAllocator<> allocator(defaultChunkSize);
IanBenzMaxim 13:6a6225690c2e 266 rapidjson::Document document(rapidjson::kObjectType, &allocator);
IanBenzMaxim 13:6a6225690c2e 267 document.AddMember("message", rapidjson::StringRef(message),
IanBenzMaxim 13:6a6225690c2e 268 document.GetAllocator());
IanBenzMaxim 16:a004191a79ab 269 sendJson(document);
IanBenzMaxim 0:33d4e66780c0 270 }
IanBenzMaxim 0:33d4e66780c0 271
IanBenzMaxim 13:6a6225690c2e 272 static std::string getValidSignatureButtonText(bool validSignature) {
IanBenzMaxim 13:6a6225690c2e 273 return validSignature ? "Use invalid sig." : "Use valid sig.";
IanBenzMaxim 0:33d4e66780c0 274 }
IanBenzMaxim 0:33d4e66780c0 275
IanBenzMaxim 13:6a6225690c2e 276 void NormalOperationWindow::showWebId(Button *) {
IanBenzMaxim 16:a004191a79ab 277 if (windowManager()) {
IanBenzMaxim 13:6a6225690c2e 278 std::auto_ptr<Window> window(
IanBenzMaxim 13:6a6225690c2e 279 new DisplayIdWindow(DisplayIdWindow::PopupMode));
IanBenzMaxim 13:6a6225690c2e 280 windowManager()->push(window);
IanBenzMaxim 13:6a6225690c2e 281 }
IanBenzMaxim 13:6a6225690c2e 282 }
IanBenzMaxim 13:6a6225690c2e 283
IanBenzMaxim 13:6a6225690c2e 284 void NormalOperationWindow::toggleValidSignature(Button *) {
IanBenzMaxim 13:6a6225690c2e 285 validSignature = !validSignature;
IanBenzMaxim 13:6a6225690c2e 286 validSignatureButton.setText(getValidSignatureButtonText(validSignature));
IanBenzMaxim 13:6a6225690c2e 287 }
IanBenzMaxim 13:6a6225690c2e 288
IanBenzMaxim 13:6a6225690c2e 289 NormalOperationWindow::NormalOperationWindow(std::auto_ptr<TCPSocket> & socket)
IanBenzMaxim 13:6a6225690c2e 290 : socket(socket) /* Move construct */, sendChallenge(true),
IanBenzMaxim 13:6a6225690c2e 291 validSignature(true), lastSensorNodeState(SensorNode::Disconnected),
IanBenzMaxim 13:6a6225690c2e 292 lastObjectTemp(0), lastAmbientTemp(0) {
IanBenzMaxim 16:a004191a79ab 293 assert(this->socket.get());
IanBenzMaxim 13:6a6225690c2e 294
IanBenzMaxim 13:6a6225690c2e 295 validSignatureButton.setParent(this);
IanBenzMaxim 13:6a6225690c2e 296 validSignatureButton.setText(getValidSignatureButtonText(validSignature));
IanBenzMaxim 13:6a6225690c2e 297 validSignatureButton.setClickedHandler(
IanBenzMaxim 13:6a6225690c2e 298 makeFunction(this, &NormalOperationWindow::toggleValidSignature));
IanBenzMaxim 13:6a6225690c2e 299 showWebIdButton.setParent(this);
IanBenzMaxim 13:6a6225690c2e 300 showWebIdButton.setText("Show web ID");
IanBenzMaxim 13:6a6225690c2e 301 showWebIdButton.setClickedHandler(
IanBenzMaxim 13:6a6225690c2e 302 makeFunction(this, &NormalOperationWindow::showWebId));
IanBenzMaxim 13:6a6225690c2e 303 validSignatureButton.setFocused();
IanBenzMaxim 0:33d4e66780c0 304 }
IanBenzMaxim 0:33d4e66780c0 305
IanBenzMaxim 16:a004191a79ab 306 NormalOperationWindow::Result NormalOperationWindow::sendStatus(
IanBenzMaxim 16:a004191a79ab 307 const std::vector<uint8_t> & responseChallenge) {
IanBenzMaxim 13:6a6225690c2e 308 rapidjson::MemoryPoolAllocator<> allocator(defaultChunkSize);
IanBenzMaxim 13:6a6225690c2e 309 rapidjson::Document document(rapidjson::kObjectType, &allocator);
IanBenzMaxim 13:6a6225690c2e 310
IanBenzMaxim 13:6a6225690c2e 311 // Insert Web ID.
IanBenzMaxim 13:6a6225690c2e 312 document.AddMember("id", rapidjson::StringRef(webId.c_str()),
IanBenzMaxim 13:6a6225690c2e 313 document.GetAllocator());
IanBenzMaxim 13:6a6225690c2e 314
IanBenzMaxim 13:6a6225690c2e 315 // Insert device public key.
IanBenzMaxim 13:6a6225690c2e 316 rapidjson::Value publicKey(rapidjson::kObjectType);
IanBenzMaxim 16:a004191a79ab 317 Core::Result<DS2476::Page::array> page =
IanBenzMaxim 16:a004191a79ab 318 coproc.readMemory(DS2476::publicKeyAxPage);
IanBenzMaxim 16:a004191a79ab 319 if (!page) {
IanBenzMaxim 16:a004191a79ab 320 if (windowManager()) {
IanBenzMaxim 13:6a6225690c2e 321 std::auto_ptr<Window> window(
IanBenzMaxim 16:a004191a79ab 322 new ErrorWindow("Failed to read Public Key A (x)"));
IanBenzMaxim 13:6a6225690c2e 323 windowManager()->push(window);
IanBenzMaxim 0:33d4e66780c0 324 }
IanBenzMaxim 13:6a6225690c2e 325 return WindowsChanged;
IanBenzMaxim 13:6a6225690c2e 326 }
IanBenzMaxim 16:a004191a79ab 327 publicKey.AddMember("x",
IanBenzMaxim 16:a004191a79ab 328 rapidjson::Value(toHexString(page.value()).c_str(),
IanBenzMaxim 16:a004191a79ab 329 document.GetAllocator())
IanBenzMaxim 16:a004191a79ab 330 .Move(),
IanBenzMaxim 16:a004191a79ab 331 document.GetAllocator());
IanBenzMaxim 16:a004191a79ab 332 page = coproc.readMemory(DS2476::publicKeyAyPage);
IanBenzMaxim 16:a004191a79ab 333 if (!page) {
IanBenzMaxim 16:a004191a79ab 334 if (windowManager()) {
IanBenzMaxim 13:6a6225690c2e 335 std::auto_ptr<Window> window(
IanBenzMaxim 16:a004191a79ab 336 new ErrorWindow("Failed to read Public Key A (y)"));
IanBenzMaxim 13:6a6225690c2e 337 windowManager()->push(window);
IanBenzMaxim 0:33d4e66780c0 338 }
IanBenzMaxim 13:6a6225690c2e 339 return WindowsChanged;
IanBenzMaxim 13:6a6225690c2e 340 }
IanBenzMaxim 16:a004191a79ab 341 publicKey.AddMember("y",
IanBenzMaxim 16:a004191a79ab 342 rapidjson::Value(toHexString(page.value()).c_str(),
IanBenzMaxim 16:a004191a79ab 343 document.GetAllocator())
IanBenzMaxim 16:a004191a79ab 344 .Move(),
IanBenzMaxim 16:a004191a79ab 345 document.GetAllocator());
IanBenzMaxim 13:6a6225690c2e 346 document.AddMember("publicKey", publicKey, document.GetAllocator());
IanBenzMaxim 0:33d4e66780c0 347
IanBenzMaxim 13:6a6225690c2e 348 // Insert device certificate.
IanBenzMaxim 13:6a6225690c2e 349 rapidjson::Value certificate(rapidjson::kObjectType);
IanBenzMaxim 16:a004191a79ab 350 page = coproc.readMemory(14);
IanBenzMaxim 16:a004191a79ab 351 if (!page) {
IanBenzMaxim 16:a004191a79ab 352 if (windowManager()) {
IanBenzMaxim 13:6a6225690c2e 353 std::auto_ptr<Window> window(
IanBenzMaxim 16:a004191a79ab 354 new ErrorWindow("Failed to read User Data 14"));
IanBenzMaxim 13:6a6225690c2e 355 windowManager()->push(window);
IanBenzMaxim 0:33d4e66780c0 356 }
IanBenzMaxim 13:6a6225690c2e 357 return WindowsChanged;
IanBenzMaxim 13:6a6225690c2e 358 }
IanBenzMaxim 16:a004191a79ab 359 certificate.AddMember("r",
IanBenzMaxim 16:a004191a79ab 360 rapidjson::Value(toHexString(page.value()).c_str(),
IanBenzMaxim 16:a004191a79ab 361 document.GetAllocator())
IanBenzMaxim 16:a004191a79ab 362 .Move(),
IanBenzMaxim 16:a004191a79ab 363 document.GetAllocator());
IanBenzMaxim 16:a004191a79ab 364 page = coproc.readMemory(15);
IanBenzMaxim 16:a004191a79ab 365 if (!page) {
IanBenzMaxim 16:a004191a79ab 366 if (windowManager()) {
IanBenzMaxim 13:6a6225690c2e 367 std::auto_ptr<Window> window(
IanBenzMaxim 16:a004191a79ab 368 new ErrorWindow("Failed to read User Data 15"));
IanBenzMaxim 13:6a6225690c2e 369 windowManager()->push(window);
IanBenzMaxim 0:33d4e66780c0 370 }
IanBenzMaxim 13:6a6225690c2e 371 return WindowsChanged;
IanBenzMaxim 13:6a6225690c2e 372 }
IanBenzMaxim 16:a004191a79ab 373 certificate.AddMember("s",
IanBenzMaxim 16:a004191a79ab 374 rapidjson::Value(toHexString(page.value()).c_str(),
IanBenzMaxim 16:a004191a79ab 375 document.GetAllocator())
IanBenzMaxim 16:a004191a79ab 376 .Move(),
IanBenzMaxim 16:a004191a79ab 377 document.GetAllocator());
IanBenzMaxim 13:6a6225690c2e 378 document.AddMember("certificate", certificate, document.GetAllocator());
IanBenzMaxim 13:6a6225690c2e 379
IanBenzMaxim 13:6a6225690c2e 380 // Sign data and transmit to server.
IanBenzMaxim 16:a004191a79ab 381 if (!finalizeResponse(document, validSignature, responseChallenge)) {
IanBenzMaxim 16:a004191a79ab 382 if (windowManager()) {
IanBenzMaxim 13:6a6225690c2e 383 std::auto_ptr<Window> window(new ErrorWindow("Failed to sign data"));
IanBenzMaxim 13:6a6225690c2e 384 windowManager()->push(window);
IanBenzMaxim 0:33d4e66780c0 385 }
IanBenzMaxim 13:6a6225690c2e 386 return WindowsChanged;
IanBenzMaxim 13:6a6225690c2e 387 }
IanBenzMaxim 16:a004191a79ab 388 sendJson(document);
IanBenzMaxim 13:6a6225690c2e 389 return NoChange;
IanBenzMaxim 0:33d4e66780c0 390 }
IanBenzMaxim 0:33d4e66780c0 391
IanBenzMaxim 13:6a6225690c2e 392 NormalOperationWindow::Result NormalOperationWindow::sendObjectTemp(
IanBenzMaxim 16:a004191a79ab 393 const std::vector<uint8_t> & responseChallenge) {
IanBenzMaxim 13:6a6225690c2e 394 rapidjson::MemoryPoolAllocator<> allocator(defaultChunkSize);
IanBenzMaxim 13:6a6225690c2e 395 rapidjson::Document document(rapidjson::kObjectType, &allocator);
IanBenzMaxim 13:6a6225690c2e 396
IanBenzMaxim 13:6a6225690c2e 397 // Read object temperature and add to document.
IanBenzMaxim 13:6a6225690c2e 398 double objectTemp;
IanBenzMaxim 16:a004191a79ab 399 if (const Core::Result<double> sensorResult =
IanBenzMaxim 16:a004191a79ab 400 sensorNode.readTemp(SensorNode::ObjectTemp)) {
IanBenzMaxim 16:a004191a79ab 401 objectTemp = sensorResult.value();
IanBenzMaxim 16:a004191a79ab 402 } else {
IanBenzMaxim 16:a004191a79ab 403 if (windowManager()) {
IanBenzMaxim 13:6a6225690c2e 404 std::auto_ptr<Window> window(
IanBenzMaxim 13:6a6225690c2e 405 new ErrorWindow("Failed to read object temperature"));
IanBenzMaxim 13:6a6225690c2e 406 windowManager()->push(window);
IanBenzMaxim 0:33d4e66780c0 407 }
IanBenzMaxim 13:6a6225690c2e 408 return WindowsChanged;
IanBenzMaxim 13:6a6225690c2e 409 }
IanBenzMaxim 13:6a6225690c2e 410 document.AddMember("objectTemp", objectTemp, document.GetAllocator());
IanBenzMaxim 13:6a6225690c2e 411
IanBenzMaxim 13:6a6225690c2e 412 // Sign data and transmit to server.
IanBenzMaxim 16:a004191a79ab 413 if (!finalizeResponse(document, validSignature, responseChallenge)) {
IanBenzMaxim 16:a004191a79ab 414 if (windowManager()) {
IanBenzMaxim 13:6a6225690c2e 415 std::auto_ptr<Window> window(new ErrorWindow("Failed to sign data"));
IanBenzMaxim 13:6a6225690c2e 416 windowManager()->push(window);
IanBenzMaxim 0:33d4e66780c0 417 }
IanBenzMaxim 13:6a6225690c2e 418 return WindowsChanged;
IanBenzMaxim 13:6a6225690c2e 419 }
IanBenzMaxim 16:a004191a79ab 420 sendJson(document);
IanBenzMaxim 0:33d4e66780c0 421
IanBenzMaxim 13:6a6225690c2e 422 lastObjectTemp = objectTemp;
IanBenzMaxim 13:6a6225690c2e 423 return NoChange;
IanBenzMaxim 0:33d4e66780c0 424 }
IanBenzMaxim 0:33d4e66780c0 425
IanBenzMaxim 13:6a6225690c2e 426 NormalOperationWindow::Result NormalOperationWindow::sendAmbientTemp(
IanBenzMaxim 16:a004191a79ab 427 const std::vector<uint8_t> & responseChallenge) {
IanBenzMaxim 13:6a6225690c2e 428 rapidjson::MemoryPoolAllocator<> allocator(defaultChunkSize);
IanBenzMaxim 13:6a6225690c2e 429 rapidjson::Document document(rapidjson::kObjectType, &allocator);
IanBenzMaxim 13:6a6225690c2e 430
IanBenzMaxim 13:6a6225690c2e 431 // Read ambient temperature and add to document.
IanBenzMaxim 13:6a6225690c2e 432 double ambientTemp;
IanBenzMaxim 16:a004191a79ab 433 if (const Core::Result<double> sensorResult =
IanBenzMaxim 16:a004191a79ab 434 sensorNode.readTemp(SensorNode::AmbientTemp)) {
IanBenzMaxim 16:a004191a79ab 435 ambientTemp = sensorResult.value();
IanBenzMaxim 16:a004191a79ab 436 } else {
IanBenzMaxim 16:a004191a79ab 437 if (windowManager()) {
IanBenzMaxim 13:6a6225690c2e 438 std::auto_ptr<Window> window(
IanBenzMaxim 13:6a6225690c2e 439 new ErrorWindow("Failed to read ambient temperature"));
IanBenzMaxim 13:6a6225690c2e 440 windowManager()->push(window);
IanBenzMaxim 0:33d4e66780c0 441 }
IanBenzMaxim 13:6a6225690c2e 442 return WindowsChanged;
IanBenzMaxim 13:6a6225690c2e 443 }
IanBenzMaxim 13:6a6225690c2e 444 document.AddMember("ambientTemp", ambientTemp, document.GetAllocator());
IanBenzMaxim 13:6a6225690c2e 445
IanBenzMaxim 13:6a6225690c2e 446 // Sign data and transmit to server.
IanBenzMaxim 16:a004191a79ab 447 if (!finalizeResponse(document, validSignature, responseChallenge)) {
IanBenzMaxim 16:a004191a79ab 448 if (windowManager()) {
IanBenzMaxim 13:6a6225690c2e 449 std::auto_ptr<Window> window(new ErrorWindow("Failed to sign data"));
IanBenzMaxim 13:6a6225690c2e 450 windowManager()->push(window);
IanBenzMaxim 0:33d4e66780c0 451 }
IanBenzMaxim 13:6a6225690c2e 452 return WindowsChanged;
IanBenzMaxim 13:6a6225690c2e 453 }
IanBenzMaxim 16:a004191a79ab 454 sendJson(document);
IanBenzMaxim 13:6a6225690c2e 455
IanBenzMaxim 13:6a6225690c2e 456 lastAmbientTemp = ambientTemp;
IanBenzMaxim 13:6a6225690c2e 457 return NoChange;
IanBenzMaxim 13:6a6225690c2e 458 }
IanBenzMaxim 13:6a6225690c2e 459
IanBenzMaxim 13:6a6225690c2e 460 void NormalOperationWindow::displayImage(
IanBenzMaxim 13:6a6225690c2e 461 const std::vector<uint8_t> & imageData) {
IanBenzMaxim 16:a004191a79ab 462 if (windowManager()) {
IanBenzMaxim 13:6a6225690c2e 463 std::auto_ptr<Graphic> image(
IanBenzMaxim 13:6a6225690c2e 464 new Image(Bitmap(&imageData[0], imageData.size(), 64)));
IanBenzMaxim 13:6a6225690c2e 465 std::auto_ptr<Window> window(new DisplayGraphicWindow(image));
IanBenzMaxim 13:6a6225690c2e 466 windowManager()->push(window);
IanBenzMaxim 13:6a6225690c2e 467 }
IanBenzMaxim 0:33d4e66780c0 468 }
IanBenzMaxim 0:33d4e66780c0 469
IanBenzMaxim 13:6a6225690c2e 470 NormalOperationWindow::Result
IanBenzMaxim 13:6a6225690c2e 471 NormalOperationWindow::processReceivedData(size_t recvBufSize) {
IanBenzMaxim 13:6a6225690c2e 472 // Separate commands and process each one.
IanBenzMaxim 16:a004191a79ab 473 const std::vector<Core::span<const char> > commands =
IanBenzMaxim 16:a004191a79ab 474 separateCommands(Core::make_span(recvBuf, recvBufSize));
IanBenzMaxim 16:a004191a79ab 475 for (std::vector<Core::span<const char> >::const_iterator it =
IanBenzMaxim 13:6a6225690c2e 476 commands.begin();
IanBenzMaxim 16:a004191a79ab 477 it != commands.end(); ++it) {
IanBenzMaxim 13:6a6225690c2e 478 rapidjson::MemoryPoolAllocator<> allocator(defaultChunkSize);
IanBenzMaxim 13:6a6225690c2e 479 rapidjson::Document data(&allocator);
IanBenzMaxim 13:6a6225690c2e 480 // Verify command signature.
IanBenzMaxim 16:a004191a79ab 481 const Core::Result<void> verifySignedResult = verifySignedData(data, *it);
IanBenzMaxim 16:a004191a79ab 482 if (verifySignedResult) {
IanBenzMaxim 13:6a6225690c2e 483 // Verify command schema.
IanBenzMaxim 13:6a6225690c2e 484 sendMessage("Received data is authentic");
IanBenzMaxim 13:6a6225690c2e 485 if (data.IsObject() && data.HasMember("command")) {
IanBenzMaxim 13:6a6225690c2e 486 const rapidjson::Value & command = data["command"];
IanBenzMaxim 13:6a6225690c2e 487 if (command.IsString()) {
IanBenzMaxim 13:6a6225690c2e 488 // Parse challenge if included.
IanBenzMaxim 16:a004191a79ab 489 std::vector<uint8_t> responseChallenge;
IanBenzMaxim 13:6a6225690c2e 490 if (data.HasMember("challenge")) {
IanBenzMaxim 13:6a6225690c2e 491 const rapidjson::Value & challenge = data["challenge"];
IanBenzMaxim 13:6a6225690c2e 492 if (challenge.IsString()) {
IanBenzMaxim 16:a004191a79ab 493 responseChallenge =
IanBenzMaxim 16:a004191a79ab 494 Core::fromHexString(
IanBenzMaxim 16:a004191a79ab 495 Core::make_span(challenge.GetString(),
IanBenzMaxim 16:a004191a79ab 496 challenge.GetStringLength()))
IanBenzMaxim 16:a004191a79ab 497 .valueOr(std::vector<uint8_t>());
IanBenzMaxim 13:6a6225690c2e 498 }
IanBenzMaxim 13:6a6225690c2e 499 }
IanBenzMaxim 13:6a6225690c2e 500
IanBenzMaxim 13:6a6225690c2e 501 // Execute the command.
IanBenzMaxim 13:6a6225690c2e 502 if (command == "getStatus") {
IanBenzMaxim 16:a004191a79ab 503 const Result result = sendStatus(responseChallenge);
IanBenzMaxim 16:a004191a79ab 504 if (result != NoChange) {
IanBenzMaxim 13:6a6225690c2e 505 return result;
IanBenzMaxim 16:a004191a79ab 506 }
IanBenzMaxim 13:6a6225690c2e 507 } else if (command == "readObjectTemp") {
IanBenzMaxim 13:6a6225690c2e 508 if ((lastSensorNodeState == SensorNode::ValidLaserDisabled) ||
IanBenzMaxim 13:6a6225690c2e 509 (lastSensorNodeState == SensorNode::ValidLaserEnabled)) {
IanBenzMaxim 16:a004191a79ab 510 const Result result = sendObjectTemp(responseChallenge);
IanBenzMaxim 16:a004191a79ab 511 if (result != NoChange) {
IanBenzMaxim 13:6a6225690c2e 512 return result;
IanBenzMaxim 16:a004191a79ab 513 }
IanBenzMaxim 13:6a6225690c2e 514 invalidate();
IanBenzMaxim 13:6a6225690c2e 515 }
IanBenzMaxim 13:6a6225690c2e 516 } else if (command == "readAmbientTemp") {
IanBenzMaxim 13:6a6225690c2e 517 if ((lastSensorNodeState == SensorNode::ValidLaserDisabled) ||
IanBenzMaxim 13:6a6225690c2e 518 (lastSensorNodeState == SensorNode::ValidLaserEnabled)) {
IanBenzMaxim 16:a004191a79ab 519 const Result result = sendAmbientTemp(responseChallenge);
IanBenzMaxim 16:a004191a79ab 520 if (result != NoChange) {
IanBenzMaxim 13:6a6225690c2e 521 return result;
IanBenzMaxim 16:a004191a79ab 522 }
IanBenzMaxim 13:6a6225690c2e 523 invalidate();
IanBenzMaxim 13:6a6225690c2e 524 }
IanBenzMaxim 13:6a6225690c2e 525 } else if (command == "enableModule") {
IanBenzMaxim 13:6a6225690c2e 526 if (lastSensorNodeState == SensorNode::ValidLaserDisabled) {
IanBenzMaxim 16:a004191a79ab 527 if (!sensorNode.setLaserEnabled(
IanBenzMaxim 16:a004191a79ab 528 true, makeFunction(
IanBenzMaxim 16:a004191a79ab 529 this, &NormalOperationWindow::sendMessage))) {
IanBenzMaxim 13:6a6225690c2e 530 lastSensorNodeState = SensorNode::ValidLaserEnabled;
IanBenzMaxim 13:6a6225690c2e 531 invalidate();
IanBenzMaxim 13:6a6225690c2e 532 }
IanBenzMaxim 13:6a6225690c2e 533 }
IanBenzMaxim 13:6a6225690c2e 534 } else if (command == "disableModule") {
IanBenzMaxim 13:6a6225690c2e 535 if (lastSensorNodeState == SensorNode::ValidLaserEnabled) {
IanBenzMaxim 16:a004191a79ab 536 if (!sensorNode.setLaserEnabled(
IanBenzMaxim 16:a004191a79ab 537 false, makeFunction(
IanBenzMaxim 16:a004191a79ab 538 this, &NormalOperationWindow::sendMessage))) {
IanBenzMaxim 13:6a6225690c2e 539 lastSensorNodeState = SensorNode::ValidLaserDisabled;
IanBenzMaxim 13:6a6225690c2e 540 invalidate();
IanBenzMaxim 13:6a6225690c2e 541 }
IanBenzMaxim 13:6a6225690c2e 542 }
IanBenzMaxim 13:6a6225690c2e 543 } else if (command == "displayImage") {
IanBenzMaxim 13:6a6225690c2e 544 if (data.HasMember("image")) {
IanBenzMaxim 13:6a6225690c2e 545 const rapidjson::Value & image = data["image"];
IanBenzMaxim 13:6a6225690c2e 546 if (image.IsString()) {
IanBenzMaxim 16:a004191a79ab 547 displayImage(Core::fromHexString(
IanBenzMaxim 16:a004191a79ab 548 Core::make_span(image.GetString(),
IanBenzMaxim 16:a004191a79ab 549 image.GetStringLength()))
IanBenzMaxim 16:a004191a79ab 550 .valueOr(std::vector<uint8_t>()));
IanBenzMaxim 13:6a6225690c2e 551 return WindowsChanged;
IanBenzMaxim 13:6a6225690c2e 552 }
IanBenzMaxim 13:6a6225690c2e 553 }
IanBenzMaxim 13:6a6225690c2e 554 }
IanBenzMaxim 13:6a6225690c2e 555 }
IanBenzMaxim 13:6a6225690c2e 556 }
IanBenzMaxim 16:a004191a79ab 557 } else if (verifySignedResult.error() == DS2476::AuthenticationError) {
IanBenzMaxim 13:6a6225690c2e 558 const char message[] = "Received data is not authentic";
IanBenzMaxim 13:6a6225690c2e 559 sendMessage(message);
IanBenzMaxim 13:6a6225690c2e 560 std::auto_ptr<Graphic> messageText(new Text);
IanBenzMaxim 13:6a6225690c2e 561 Text & messageTextRef = *static_cast<Text *>(messageText.get());
IanBenzMaxim 13:6a6225690c2e 562 messageTextRef.setText(message);
IanBenzMaxim 13:6a6225690c2e 563 messageTextRef.setWordWrap(true);
IanBenzMaxim 16:a004191a79ab 564 if (windowManager()) {
IanBenzMaxim 13:6a6225690c2e 565 std::auto_ptr<Window> window(new DisplayGraphicWindow(messageText));
IanBenzMaxim 7:66c5dedc750b 566 windowManager()->push(window);
IanBenzMaxim 13:6a6225690c2e 567 }
IanBenzMaxim 13:6a6225690c2e 568 return WindowsChanged;
IanBenzMaxim 13:6a6225690c2e 569 } else {
IanBenzMaxim 13:6a6225690c2e 570 const char message[] = "Unable to verify received data";
IanBenzMaxim 13:6a6225690c2e 571 sendMessage(message);
IanBenzMaxim 16:a004191a79ab 572 if (windowManager()) {
IanBenzMaxim 13:6a6225690c2e 573 std::auto_ptr<Window> window(new ErrorWindow(message));
IanBenzMaxim 13:6a6225690c2e 574 windowManager()->push(window);
IanBenzMaxim 13:6a6225690c2e 575 }
IanBenzMaxim 13:6a6225690c2e 576 return WindowsChanged;
IanBenzMaxim 0:33d4e66780c0 577 }
IanBenzMaxim 13:6a6225690c2e 578 }
IanBenzMaxim 13:6a6225690c2e 579 return NoChange;
IanBenzMaxim 0:33d4e66780c0 580 }
IanBenzMaxim 0:33d4e66780c0 581
IanBenzMaxim 13:6a6225690c2e 582 void NormalOperationWindow::resized() {
IanBenzMaxim 13:6a6225690c2e 583 showWebIdButton.resize(width(), showWebIdButton.preferredHeight());
IanBenzMaxim 13:6a6225690c2e 584 showWebIdButton.move(0, height() - showWebIdButton.height());
IanBenzMaxim 13:6a6225690c2e 585 validSignatureButton.resize(width(), validSignatureButton.preferredHeight());
IanBenzMaxim 13:6a6225690c2e 586 validSignatureButton.move(0, showWebIdButton.y() -
IanBenzMaxim 13:6a6225690c2e 587 validSignatureButton.height() - 1);
IanBenzMaxim 13:6a6225690c2e 588 }
IanBenzMaxim 13:6a6225690c2e 589
IanBenzMaxim 13:6a6225690c2e 590 static std::string doubleToString(double input) {
IanBenzMaxim 13:6a6225690c2e 591 char inputString[8];
IanBenzMaxim 13:6a6225690c2e 592 snprintf(inputString, sizeof(inputString) / sizeof(inputString[0]), "%.2f",
IanBenzMaxim 13:6a6225690c2e 593 input);
IanBenzMaxim 13:6a6225690c2e 594 return std::string(inputString);
IanBenzMaxim 13:6a6225690c2e 595 }
IanBenzMaxim 13:6a6225690c2e 596
IanBenzMaxim 13:6a6225690c2e 597 void NormalOperationWindow::doRender(Bitmap & bitmap, int xOffset,
IanBenzMaxim 13:6a6225690c2e 598 int yOffset) const {
IanBenzMaxim 13:6a6225690c2e 599 // Format current status text.
IanBenzMaxim 13:6a6225690c2e 600 std::string sensorNodeStateText;
IanBenzMaxim 13:6a6225690c2e 601 switch (lastSensorNodeState) {
IanBenzMaxim 13:6a6225690c2e 602 case SensorNode::Disconnected:
IanBenzMaxim 13:6a6225690c2e 603 sensorNodeStateText = "Disconnected";
IanBenzMaxim 13:6a6225690c2e 604 break;
IanBenzMaxim 13:6a6225690c2e 605
IanBenzMaxim 13:6a6225690c2e 606 case SensorNode::Invalid:
IanBenzMaxim 13:6a6225690c2e 607 sensorNodeStateText = "Invalid";
IanBenzMaxim 13:6a6225690c2e 608 break;
IanBenzMaxim 13:6a6225690c2e 609
IanBenzMaxim 13:6a6225690c2e 610 case SensorNode::ValidLaserDisabled:
IanBenzMaxim 13:6a6225690c2e 611 sensorNodeStateText = "Valid, laser disabled";
IanBenzMaxim 13:6a6225690c2e 612 break;
IanBenzMaxim 13:6a6225690c2e 613
IanBenzMaxim 13:6a6225690c2e 614 case SensorNode::ValidLaserEnabled:
IanBenzMaxim 13:6a6225690c2e 615 sensorNodeStateText = "Valid, laser enabled";
IanBenzMaxim 13:6a6225690c2e 616 break;
IanBenzMaxim 13:6a6225690c2e 617 }
IanBenzMaxim 13:6a6225690c2e 618
IanBenzMaxim 13:6a6225690c2e 619 Text description;
IanBenzMaxim 13:6a6225690c2e 620 description.setText("Object temp: " + doubleToString(lastObjectTemp) +
IanBenzMaxim 13:6a6225690c2e 621 "\nAmbient temp: " + doubleToString(lastAmbientTemp) +
IanBenzMaxim 13:6a6225690c2e 622 "\nSensor node: " + sensorNodeStateText);
IanBenzMaxim 13:6a6225690c2e 623 description.resize(width(), validSignatureButton.y());
IanBenzMaxim 13:6a6225690c2e 624 description.setWordWrap(true);
IanBenzMaxim 13:6a6225690c2e 625 description.render(bitmap, xOffset + x(), yOffset + y());
IanBenzMaxim 13:6a6225690c2e 626 validSignatureButton.render(bitmap, xOffset + x(), yOffset + y());
IanBenzMaxim 13:6a6225690c2e 627 showWebIdButton.render(bitmap, xOffset + x(), yOffset + y());
IanBenzMaxim 0:33d4e66780c0 628 }
IanBenzMaxim 0:33d4e66780c0 629
IanBenzMaxim 13:6a6225690c2e 630 void NormalOperationWindow::updated() {
IanBenzMaxim 13:6a6225690c2e 631 // Detect sensor node.
IanBenzMaxim 16:a004191a79ab 632 const SensorNode::State sensorNodeState = sensorNode.detect();
IanBenzMaxim 16:a004191a79ab 633 if (sensorNodeState != lastSensorNodeState) {
IanBenzMaxim 16:a004191a79ab 634 lastSensorNodeState = sensorNodeState;
IanBenzMaxim 13:6a6225690c2e 635 invalidate();
IanBenzMaxim 13:6a6225690c2e 636 }
IanBenzMaxim 6:0c9050b02876 637
IanBenzMaxim 13:6a6225690c2e 638 // Send challenge on first connection.
IanBenzMaxim 13:6a6225690c2e 639 if (sendChallenge) {
IanBenzMaxim 13:6a6225690c2e 640 rapidjson::MemoryPoolAllocator<> allocator(defaultChunkSize);
IanBenzMaxim 13:6a6225690c2e 641 rapidjson::Document document(rapidjson::kObjectType, &allocator);
IanBenzMaxim 16:a004191a79ab 642 if (addCommandChallenge(document)) {
IanBenzMaxim 16:a004191a79ab 643 sendJson(document);
IanBenzMaxim 13:6a6225690c2e 644 sendChallenge = false;
IanBenzMaxim 0:33d4e66780c0 645 }
IanBenzMaxim 16:a004191a79ab 646 } else {
IanBenzMaxim 16:a004191a79ab 647 // Process socket data.
IanBenzMaxim 16:a004191a79ab 648 const int recvResult =
IanBenzMaxim 13:6a6225690c2e 649 socket->recv(recvBuf, sizeof(recvBuf) / sizeof(recvBuf[0]));
IanBenzMaxim 13:6a6225690c2e 650 if (recvResult > 0) {
IanBenzMaxim 13:6a6225690c2e 651 std::printf("%*s\n", recvResult, recvBuf);
IanBenzMaxim 16:a004191a79ab 652 const Result result = processReceivedData(recvResult);
IanBenzMaxim 13:6a6225690c2e 653 if (result != NoChange)
IanBenzMaxim 13:6a6225690c2e 654 return;
IanBenzMaxim 13:6a6225690c2e 655 } else if (recvResult != NSAPI_ERROR_WOULD_BLOCK) {
IanBenzMaxim 16:a004191a79ab 656 if (windowManager()) {
IanBenzMaxim 13:6a6225690c2e 657 std::auto_ptr<Window> window(new ErrorWindow("Socket receive failed"));
IanBenzMaxim 13:6a6225690c2e 658 windowManager()->push(window);
IanBenzMaxim 13:6a6225690c2e 659 }
IanBenzMaxim 13:6a6225690c2e 660 return;
IanBenzMaxim 13:6a6225690c2e 661 }
IanBenzMaxim 13:6a6225690c2e 662 }
IanBenzMaxim 0:33d4e66780c0 663 }
IanBenzMaxim 0:33d4e66780c0 664
IanBenzMaxim 13:6a6225690c2e 665 bool NormalOperationWindow::doProcessKey(Key key) {
IanBenzMaxim 13:6a6225690c2e 666 bool handled;
IanBenzMaxim 13:6a6225690c2e 667 switch (key) {
IanBenzMaxim 13:6a6225690c2e 668 case UpKey:
IanBenzMaxim 13:6a6225690c2e 669 validSignatureButton.setFocused();
IanBenzMaxim 13:6a6225690c2e 670 handled = true;
IanBenzMaxim 13:6a6225690c2e 671 break;
IanBenzMaxim 13:6a6225690c2e 672
IanBenzMaxim 13:6a6225690c2e 673 case DownKey:
IanBenzMaxim 13:6a6225690c2e 674 showWebIdButton.setFocused();
IanBenzMaxim 13:6a6225690c2e 675 handled = true;
IanBenzMaxim 13:6a6225690c2e 676 break;
IanBenzMaxim 13:6a6225690c2e 677
IanBenzMaxim 13:6a6225690c2e 678 default:
IanBenzMaxim 13:6a6225690c2e 679 handled = false;
IanBenzMaxim 13:6a6225690c2e 680 break;
IanBenzMaxim 13:6a6225690c2e 681 }
IanBenzMaxim 13:6a6225690c2e 682 return handled;
IanBenzMaxim 0:33d4e66780c0 683 }