DeepCover Embedded Security in IoT: Public-key Secured Data Paths
Dependencies: MaximInterface
NormalOperationWindow.cpp
00001 /******************************************************************************* 00002 * Copyright (C) Maxim Integrated Products, Inc., All Rights Reserved. 00003 * 00004 * Permission is hereby granted, free of charge, to any person obtaining a 00005 * copy of this software and associated documentation files (the "Software"), 00006 * to deal in the Software without restriction, including without limitation 00007 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 00008 * and/or sell copies of the Software, and to permit persons to whom the 00009 * Software is furnished to do so, subject to the following conditions: 00010 * 00011 * The above copyright notice and this permission notice shall be included 00012 * in all copies or substantial portions of the Software. 00013 * 00014 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 00015 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 00016 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 00017 * IN NO EVENT SHALL MAXIM INTEGRATED BE LIABLE FOR ANY CLAIM, DAMAGES 00018 * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 00019 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 00020 * OTHER DEALINGS IN THE SOFTWARE. 00021 * 00022 * Except as contained in this notice, the name of Maxim Integrated 00023 * Products, Inc. shall not be used except as stated in the Maxim Integrated 00024 * Products, Inc. Branding Policy. 00025 * 00026 * The mere transfer of this software does not imply any licenses 00027 * of trade secrets, proprietary technology, copyrights, patents, 00028 * trademarks, maskwork rights, or any other form of intellectual 00029 * property whatsoever. Maxim Integrated Products, Inc. retains all 00030 * ownership rights. 00031 *******************************************************************************/ 00032 00033 #include <stdint.h> 00034 #include <stdio.h> 00035 #include <cassert> 00036 #include <cstdio> 00037 #include <string> 00038 #include <MaximInterfaceCore/HexString.hpp> 00039 #include <MaximInterfaceCore/span.hpp> 00040 #include <MaximInterfaceDevices/DS28C36_DS2476.hpp> 00041 #include <rapidjson/stringbuffer.h> 00042 #include <rapidjson/writer.h> 00043 #include "DisplayGraphicWindow.hpp" 00044 #include "DisplayIdWindow.hpp" 00045 #include "ErrorWindow.hpp" 00046 #include "Image.hpp" 00047 #include "MakeFunction.hpp" 00048 #include "NormalOperationWindow.hpp" 00049 #include "Text.hpp" 00050 #include "WindowManager.hpp" 00051 00052 #define TRY MaximInterfaceCore_TRY 00053 #define TRY_VALUE MaximInterfaceCore_TRY_VALUE 00054 00055 namespace Core = MaximInterfaceCore; 00056 using MaximInterfaceDevices::DS2476; 00057 00058 extern DS2476 coproc; 00059 extern SensorNode sensorNode; 00060 extern std::string webId; 00061 00062 extern "C" void ComputeSHA256(unsigned char * message, short length, 00063 unsigned short skipconst, unsigned short reverse, 00064 unsigned char * digest); 00065 00066 // Default allocation size for rapidjson. 00067 static const size_t defaultChunkSize = 256; 00068 00069 // Number of decimal places to use when writing JSON. 00070 static const int jsonMaxDecimalPlaces = 2; 00071 00072 // Separate multiple JSON commands received on the socket. 00073 // Returns a list of begin and end iterators within the input message. 00074 static std::vector<Core::span<const char> > 00075 separateCommands(Core::span<const char> receivedData) { 00076 std::vector<Core::span<const char> > commands; 00077 int counter = 0; 00078 Core::span<const char>::index_type beginIdx; 00079 for (Core::span<const char>::index_type i = 0; i < receivedData.size(); ++i) { 00080 if (receivedData[i] == '{') { 00081 if (counter == 0) { 00082 beginIdx = i; 00083 } 00084 ++counter; 00085 } else if (receivedData[i] == '}') { 00086 if (counter > 0) { 00087 --counter; 00088 if (counter == 0) { 00089 commands.push_back( 00090 Core::make_span(&receivedData[beginIdx], &receivedData[i + 1])); 00091 } 00092 } 00093 } 00094 } 00095 return commands; 00096 } 00097 00098 Core::Result<void> 00099 NormalOperationWindow::addCommandChallenge(rapidjson::Document & document) { 00100 TRY(coproc.readRng(commandChallenge)); 00101 document.AddMember("challenge", 00102 rapidjson::Value(toHexString(commandChallenge).c_str(), 00103 document.GetAllocator()) 00104 .Move(), 00105 document.GetAllocator()); 00106 return Core::none; 00107 } 00108 00109 Core::Result<void> 00110 NormalOperationWindow::signData(rapidjson::Document & document, 00111 bool validSignature, 00112 const std::vector<uint8_t> & challenge) { 00113 // Move contents of the document to a new location, and create an empty object 00114 // in the document. 00115 rapidjson::Value data(rapidjson::kObjectType); 00116 data.Swap(document); 00117 // Convert data to a string and generate a signature from that string. 00118 rapidjson::StringBuffer dataBuffer; 00119 rapidjson::Writer<rapidjson::StringBuffer> writer(dataBuffer); 00120 writer.SetMaxDecimalPlaces(jsonMaxDecimalPlaces); 00121 data.Accept(writer); 00122 std::vector<uint8_t> signDataBuffer( 00123 dataBuffer.GetString(), dataBuffer.GetString() + dataBuffer.GetLength()); 00124 signDataBuffer.insert(signDataBuffer.end(), challenge.begin(), 00125 challenge.end()); 00126 uint8_t hash[32]; 00127 ComputeSHA256(&signDataBuffer[0], signDataBuffer.size(), false, false, hash); 00128 TRY(coproc.writeBuffer(hash)); 00129 Core::Ecc256::Signature::array signatureBuffer; 00130 TRY_VALUE(signatureBuffer, coproc.generateEcdsaSignature(DS2476::KeyNumA)); 00131 if (!validSignature) { 00132 ++signatureBuffer.r[0]; 00133 } 00134 // Construct the final document with the original data and the generated 00135 // signature. 00136 rapidjson::Value signature(rapidjson::kObjectType); 00137 signature.AddMember( 00138 "r", 00139 rapidjson::Value(Core::toHexString(signatureBuffer.r).c_str(), 00140 document.GetAllocator()) 00141 .Move(), 00142 document.GetAllocator()); 00143 signature.AddMember( 00144 "s", 00145 rapidjson::Value(Core::toHexString(signatureBuffer.s).c_str(), 00146 document.GetAllocator()) 00147 .Move(), 00148 document.GetAllocator()); 00149 document.AddMember("data", data, document.GetAllocator()); 00150 document.AddMember("signature", signature, document.GetAllocator()); 00151 return Core::none; 00152 } 00153 00154 Core::Result<void> NormalOperationWindow::finalizeResponse( 00155 rapidjson::Document & document, bool validSignature, 00156 const std::vector<uint8_t> & responseChallenge) { 00157 TRY(addCommandChallenge(document)); 00158 TRY(signData(document, validSignature, responseChallenge)); 00159 return Core::none; 00160 } 00161 00162 Core::Result<void> 00163 NormalOperationWindow::verifySignedData(rapidjson::Document & signedData, 00164 Core::span<const char> verifyDataIn) { 00165 using rapidjson::Value; 00166 using std::string; 00167 00168 // Parse string and validate object schema. 00169 string verifyData(verifyDataIn.begin(), verifyDataIn.end()); 00170 signedData.Parse(verifyData.c_str()); 00171 if (!(signedData.IsObject() && signedData.HasMember("data") && 00172 signedData.HasMember("signature"))) { 00173 signedData.RemoveAllMembers(); 00174 return DS2476::AuthenticationError; 00175 } 00176 Value & data = signedData["data"]; 00177 const Value & signature = signedData["signature"]; 00178 if (!(data.IsObject() && signature.IsObject() && signature.HasMember("r") && 00179 signature.HasMember("s"))) { 00180 signedData.RemoveAllMembers(); 00181 return DS2476::AuthenticationError; 00182 } 00183 const Value & signatureR = signature["r"]; 00184 const Value & signatureS = signature["s"]; 00185 if (!(signatureR.IsString() && signatureS.IsString())) { 00186 signedData.RemoveAllMembers(); 00187 return DS2476::AuthenticationError; 00188 } 00189 00190 // Parse signature. 00191 Core::Optional<std::vector<uint8_t> > parsedBytes = Core::fromHexString( 00192 Core::make_span(signatureR.GetString(), signatureR.GetStringLength())); 00193 Core::Ecc256::Signature::array signatureBuffer; 00194 if (!(parsedBytes && parsedBytes->size() == signatureBuffer.r.size())) { 00195 signedData.RemoveAllMembers(); 00196 return DS2476::AuthenticationError; 00197 } 00198 std::copy(parsedBytes->begin(), parsedBytes->end(), 00199 signatureBuffer.r.begin()); 00200 parsedBytes = Core::fromHexString( 00201 Core::make_span(signatureS.GetString(), signatureS.GetStringLength())); 00202 if (!(parsedBytes && parsedBytes->size() == signatureBuffer.s.size())) { 00203 signedData.RemoveAllMembers(); 00204 return DS2476::AuthenticationError; 00205 } 00206 std::copy(parsedBytes->begin(), parsedBytes->end(), 00207 signatureBuffer.s.begin()); 00208 00209 // Get data to hash. 00210 // Need to use string searching here since there isn't currently a way to 00211 // access raw elements in rapidjson, and creating another copy of the data 00212 // might consume too much memory. 00213 const string rawDataSearch("\"data\":"); 00214 string::size_type rawDataBegin = verifyData.find(rawDataSearch); 00215 if ((rawDataBegin == string::npos) || 00216 ((rawDataBegin + rawDataSearch.size()) >= verifyData.size())) { 00217 signedData.RemoveAllMembers(); 00218 return DS2476::AuthenticationError; 00219 } 00220 rawDataBegin += rawDataSearch.size(); 00221 string::size_type rawDataEnd = 00222 verifyData.find(",\"signature\"", rawDataBegin); 00223 if (rawDataEnd == string::npos) { 00224 signedData.RemoveAllMembers(); 00225 return DS2476::AuthenticationError; 00226 } 00227 verifyData.erase(rawDataEnd); 00228 verifyData.erase(0, rawDataBegin); 00229 // Add in command challenge to data that will be verified. 00230 verifyData.append(commandChallenge.begin(), commandChallenge.end()); 00231 00232 // Compute hash of the data. 00233 Core::Result<void> result = computeMultiblockHash( 00234 coproc, 00235 Core::make_span(reinterpret_cast<const uint8_t *>(verifyData.data()), 00236 verifyData.size())); 00237 if (!result) { 00238 signedData.RemoveAllMembers(); 00239 return result; 00240 } 00241 // Verify signature. 00242 result = coproc.verifyEcdsaSignature(DS2476::KeyNumC, DS2476::THASH, 00243 signatureBuffer); 00244 if (!result) { 00245 signedData.RemoveAllMembers(); 00246 return result; 00247 } 00248 00249 // Strip signing information from document. 00250 rapidjson::Value swapObject(rapidjson::kObjectType); 00251 swapObject.Swap(data); 00252 swapObject.Swap(signedData); 00253 return Core::none; 00254 } 00255 00256 void NormalOperationWindow::sendJson(const rapidjson::Value & document) { 00257 rapidjson::StringBuffer buffer; 00258 rapidjson::Writer<rapidjson::StringBuffer> writer(buffer); 00259 writer.SetMaxDecimalPlaces(jsonMaxDecimalPlaces); 00260 document.Accept(writer); 00261 socket->send(buffer.GetString(), buffer.GetLength()); 00262 } 00263 00264 void NormalOperationWindow::sendMessage(const char * message) { 00265 rapidjson::MemoryPoolAllocator<> allocator(defaultChunkSize); 00266 rapidjson::Document document(rapidjson::kObjectType, &allocator); 00267 document.AddMember("message", rapidjson::StringRef(message), 00268 document.GetAllocator()); 00269 sendJson(document); 00270 } 00271 00272 static std::string getValidSignatureButtonText(bool validSignature) { 00273 return validSignature ? "Use invalid sig." : "Use valid sig."; 00274 } 00275 00276 void NormalOperationWindow::showWebId(Button *) { 00277 if (windowManager()) { 00278 std::auto_ptr<Window> window( 00279 new DisplayIdWindow(DisplayIdWindow::PopupMode)); 00280 windowManager()->push(window); 00281 } 00282 } 00283 00284 void NormalOperationWindow::toggleValidSignature(Button *) { 00285 validSignature = !validSignature; 00286 validSignatureButton.setText(getValidSignatureButtonText(validSignature)); 00287 } 00288 00289 NormalOperationWindow::NormalOperationWindow (std::auto_ptr<TCPSocket> & socket) 00290 : socket(socket) /* Move construct */, sendChallenge(true), 00291 validSignature(true), lastSensorNodeState(SensorNode::Disconnected), 00292 lastObjectTemp(0), lastAmbientTemp(0) { 00293 assert(this->socket.get()); 00294 00295 validSignatureButton.setParent (this); 00296 validSignatureButton.setText(getValidSignatureButtonText(validSignature)); 00297 validSignatureButton.setClickedHandler( 00298 makeFunction(this, &NormalOperationWindow::toggleValidSignature)); 00299 showWebIdButton.setParent (this); 00300 showWebIdButton.setText("Show web ID"); 00301 showWebIdButton.setClickedHandler( 00302 makeFunction(this, &NormalOperationWindow::showWebId)); 00303 validSignatureButton.setFocused(); 00304 } 00305 00306 NormalOperationWindow::Result NormalOperationWindow::sendStatus( 00307 const std::vector<uint8_t> & responseChallenge) { 00308 rapidjson::MemoryPoolAllocator<> allocator(defaultChunkSize); 00309 rapidjson::Document document(rapidjson::kObjectType, &allocator); 00310 00311 // Insert Web ID. 00312 document.AddMember("id", rapidjson::StringRef(webId.c_str()), 00313 document.GetAllocator()); 00314 00315 // Insert device public key. 00316 rapidjson::Value publicKey(rapidjson::kObjectType); 00317 Core::Result<DS2476::Page::array> page = 00318 coproc.readMemory(DS2476::publicKeyAxPage); 00319 if (!page) { 00320 if (windowManager()) { 00321 std::auto_ptr<Window> window( 00322 new ErrorWindow("Failed to read Public Key A (x)")); 00323 windowManager()->push(window); 00324 } 00325 return WindowsChanged; 00326 } 00327 publicKey.AddMember("x", 00328 rapidjson::Value(toHexString(page.value()).c_str(), 00329 document.GetAllocator()) 00330 .Move(), 00331 document.GetAllocator()); 00332 page = coproc.readMemory(DS2476::publicKeyAyPage); 00333 if (!page) { 00334 if (windowManager()) { 00335 std::auto_ptr<Window> window( 00336 new ErrorWindow("Failed to read Public Key A (y)")); 00337 windowManager()->push(window); 00338 } 00339 return WindowsChanged; 00340 } 00341 publicKey.AddMember("y", 00342 rapidjson::Value(toHexString(page.value()).c_str(), 00343 document.GetAllocator()) 00344 .Move(), 00345 document.GetAllocator()); 00346 document.AddMember("publicKey", publicKey, document.GetAllocator()); 00347 00348 // Insert device certificate. 00349 rapidjson::Value certificate(rapidjson::kObjectType); 00350 page = coproc.readMemory(14); 00351 if (!page) { 00352 if (windowManager()) { 00353 std::auto_ptr<Window> window( 00354 new ErrorWindow("Failed to read User Data 14")); 00355 windowManager()->push(window); 00356 } 00357 return WindowsChanged; 00358 } 00359 certificate.AddMember("r", 00360 rapidjson::Value(toHexString(page.value()).c_str(), 00361 document.GetAllocator()) 00362 .Move(), 00363 document.GetAllocator()); 00364 page = coproc.readMemory(15); 00365 if (!page) { 00366 if (windowManager()) { 00367 std::auto_ptr<Window> window( 00368 new ErrorWindow("Failed to read User Data 15")); 00369 windowManager()->push(window); 00370 } 00371 return WindowsChanged; 00372 } 00373 certificate.AddMember("s", 00374 rapidjson::Value(toHexString(page.value()).c_str(), 00375 document.GetAllocator()) 00376 .Move(), 00377 document.GetAllocator()); 00378 document.AddMember("certificate", certificate, document.GetAllocator()); 00379 00380 // Sign data and transmit to server. 00381 if (!finalizeResponse(document, validSignature, responseChallenge)) { 00382 if (windowManager()) { 00383 std::auto_ptr<Window> window(new ErrorWindow("Failed to sign data")); 00384 windowManager()->push(window); 00385 } 00386 return WindowsChanged; 00387 } 00388 sendJson(document); 00389 return NoChange; 00390 } 00391 00392 NormalOperationWindow::Result NormalOperationWindow::sendObjectTemp( 00393 const std::vector<uint8_t> & responseChallenge) { 00394 rapidjson::MemoryPoolAllocator<> allocator(defaultChunkSize); 00395 rapidjson::Document document(rapidjson::kObjectType, &allocator); 00396 00397 // Read object temperature and add to document. 00398 double objectTemp; 00399 if (const Core::Result<double> sensorResult = 00400 sensorNode.readTemp(SensorNode::ObjectTemp)) { 00401 objectTemp = sensorResult.value(); 00402 } else { 00403 if (windowManager()) { 00404 std::auto_ptr<Window> window( 00405 new ErrorWindow("Failed to read object temperature")); 00406 windowManager()->push(window); 00407 } 00408 return WindowsChanged; 00409 } 00410 document.AddMember("objectTemp", objectTemp, document.GetAllocator()); 00411 00412 // Sign data and transmit to server. 00413 if (!finalizeResponse(document, validSignature, responseChallenge)) { 00414 if (windowManager()) { 00415 std::auto_ptr<Window> window(new ErrorWindow("Failed to sign data")); 00416 windowManager()->push(window); 00417 } 00418 return WindowsChanged; 00419 } 00420 sendJson(document); 00421 00422 lastObjectTemp = objectTemp; 00423 return NoChange; 00424 } 00425 00426 NormalOperationWindow::Result NormalOperationWindow::sendAmbientTemp( 00427 const std::vector<uint8_t> & responseChallenge) { 00428 rapidjson::MemoryPoolAllocator<> allocator(defaultChunkSize); 00429 rapidjson::Document document(rapidjson::kObjectType, &allocator); 00430 00431 // Read ambient temperature and add to document. 00432 double ambientTemp; 00433 if (const Core::Result<double> sensorResult = 00434 sensorNode.readTemp(SensorNode::AmbientTemp)) { 00435 ambientTemp = sensorResult.value(); 00436 } else { 00437 if (windowManager()) { 00438 std::auto_ptr<Window> window( 00439 new ErrorWindow("Failed to read ambient temperature")); 00440 windowManager()->push(window); 00441 } 00442 return WindowsChanged; 00443 } 00444 document.AddMember("ambientTemp", ambientTemp, document.GetAllocator()); 00445 00446 // Sign data and transmit to server. 00447 if (!finalizeResponse(document, validSignature, responseChallenge)) { 00448 if (windowManager()) { 00449 std::auto_ptr<Window> window(new ErrorWindow("Failed to sign data")); 00450 windowManager()->push(window); 00451 } 00452 return WindowsChanged; 00453 } 00454 sendJson(document); 00455 00456 lastAmbientTemp = ambientTemp; 00457 return NoChange; 00458 } 00459 00460 void NormalOperationWindow::displayImage( 00461 const std::vector<uint8_t> & imageData) { 00462 if (windowManager()) { 00463 std::auto_ptr<Graphic> image( 00464 new Image(Bitmap(&imageData[0], imageData.size(), 64))); 00465 std::auto_ptr<Window> window(new DisplayGraphicWindow(image)); 00466 windowManager()->push(window); 00467 } 00468 } 00469 00470 NormalOperationWindow::Result 00471 NormalOperationWindow::processReceivedData(size_t recvBufSize) { 00472 // Separate commands and process each one. 00473 const std::vector<Core::span<const char> > commands = 00474 separateCommands(Core::make_span(recvBuf, recvBufSize)); 00475 for (std::vector<Core::span<const char> >::const_iterator it = 00476 commands.begin(); 00477 it != commands.end(); ++it) { 00478 rapidjson::MemoryPoolAllocator<> allocator(defaultChunkSize); 00479 rapidjson::Document data(&allocator); 00480 // Verify command signature. 00481 const Core::Result<void> verifySignedResult = verifySignedData(data, *it); 00482 if (verifySignedResult) { 00483 // Verify command schema. 00484 sendMessage("Received data is authentic"); 00485 if (data.IsObject() && data.HasMember("command")) { 00486 const rapidjson::Value & command = data["command"]; 00487 if (command.IsString()) { 00488 // Parse challenge if included. 00489 std::vector<uint8_t> responseChallenge; 00490 if (data.HasMember("challenge")) { 00491 const rapidjson::Value & challenge = data["challenge"]; 00492 if (challenge.IsString()) { 00493 responseChallenge = 00494 Core::fromHexString( 00495 Core::make_span(challenge.GetString(), 00496 challenge.GetStringLength())) 00497 .valueOr(std::vector<uint8_t>()); 00498 } 00499 } 00500 00501 // Execute the command. 00502 if (command == "getStatus") { 00503 const Result result = sendStatus(responseChallenge); 00504 if (result != NoChange) { 00505 return result; 00506 } 00507 } else if (command == "readObjectTemp") { 00508 if ((lastSensorNodeState == SensorNode::ValidLaserDisabled) || 00509 (lastSensorNodeState == SensorNode::ValidLaserEnabled)) { 00510 const Result result = sendObjectTemp(responseChallenge); 00511 if (result != NoChange) { 00512 return result; 00513 } 00514 invalidate(); 00515 } 00516 } else if (command == "readAmbientTemp") { 00517 if ((lastSensorNodeState == SensorNode::ValidLaserDisabled) || 00518 (lastSensorNodeState == SensorNode::ValidLaserEnabled)) { 00519 const Result result = sendAmbientTemp(responseChallenge); 00520 if (result != NoChange) { 00521 return result; 00522 } 00523 invalidate(); 00524 } 00525 } else if (command == "enableModule") { 00526 if (lastSensorNodeState == SensorNode::ValidLaserDisabled) { 00527 if (!sensorNode.setLaserEnabled( 00528 true, makeFunction( 00529 this, &NormalOperationWindow::sendMessage))) { 00530 lastSensorNodeState = SensorNode::ValidLaserEnabled; 00531 invalidate(); 00532 } 00533 } 00534 } else if (command == "disableModule") { 00535 if (lastSensorNodeState == SensorNode::ValidLaserEnabled) { 00536 if (!sensorNode.setLaserEnabled( 00537 false, makeFunction( 00538 this, &NormalOperationWindow::sendMessage))) { 00539 lastSensorNodeState = SensorNode::ValidLaserDisabled; 00540 invalidate(); 00541 } 00542 } 00543 } else if (command == "displayImage") { 00544 if (data.HasMember("image")) { 00545 const rapidjson::Value & image = data["image"]; 00546 if (image.IsString()) { 00547 displayImage(Core::fromHexString( 00548 Core::make_span(image.GetString(), 00549 image.GetStringLength())) 00550 .valueOr(std::vector<uint8_t>())); 00551 return WindowsChanged; 00552 } 00553 } 00554 } 00555 } 00556 } 00557 } else if (verifySignedResult.error() == DS2476::AuthenticationError) { 00558 const char message[] = "Received data is not authentic"; 00559 sendMessage(message); 00560 std::auto_ptr<Graphic> messageText(new Text); 00561 Text & messageTextRef = *static_cast<Text *>(messageText.get()); 00562 messageTextRef.setText(message); 00563 messageTextRef.setWordWrap(true); 00564 if (windowManager()) { 00565 std::auto_ptr<Window> window(new DisplayGraphicWindow(messageText)); 00566 windowManager()->push(window); 00567 } 00568 return WindowsChanged; 00569 } else { 00570 const char message[] = "Unable to verify received data"; 00571 sendMessage(message); 00572 if (windowManager()) { 00573 std::auto_ptr<Window> window(new ErrorWindow(message)); 00574 windowManager()->push(window); 00575 } 00576 return WindowsChanged; 00577 } 00578 } 00579 return NoChange; 00580 } 00581 00582 void NormalOperationWindow::resized() { 00583 showWebIdButton.resize(width(), showWebIdButton.preferredHeight()); 00584 showWebIdButton.move(0, height() - showWebIdButton.height()); 00585 validSignatureButton.resize(width(), validSignatureButton.preferredHeight()); 00586 validSignatureButton.move(0, showWebIdButton.y() - 00587 validSignatureButton.height() - 1); 00588 } 00589 00590 static std::string doubleToString(double input) { 00591 char inputString[8]; 00592 snprintf(inputString, sizeof(inputString) / sizeof(inputString[0]), "%.2f", 00593 input); 00594 return std::string(inputString); 00595 } 00596 00597 void NormalOperationWindow::doRender(Bitmap & bitmap, int xOffset, 00598 int yOffset) const { 00599 // Format current status text. 00600 std::string sensorNodeStateText; 00601 switch (lastSensorNodeState) { 00602 case SensorNode::Disconnected: 00603 sensorNodeStateText = "Disconnected"; 00604 break; 00605 00606 case SensorNode::Invalid: 00607 sensorNodeStateText = "Invalid"; 00608 break; 00609 00610 case SensorNode::ValidLaserDisabled: 00611 sensorNodeStateText = "Valid, laser disabled"; 00612 break; 00613 00614 case SensorNode::ValidLaserEnabled: 00615 sensorNodeStateText = "Valid, laser enabled"; 00616 break; 00617 } 00618 00619 Text description; 00620 description.setText("Object temp: " + doubleToString(lastObjectTemp) + 00621 "\nAmbient temp: " + doubleToString(lastAmbientTemp) + 00622 "\nSensor node: " + sensorNodeStateText); 00623 description.resize(width(), validSignatureButton.y()); 00624 description.setWordWrap(true); 00625 description.render(bitmap, xOffset + x(), yOffset + y()); 00626 validSignatureButton.render(bitmap, xOffset + x(), yOffset + y()); 00627 showWebIdButton.render(bitmap, xOffset + x(), yOffset + y()); 00628 } 00629 00630 void NormalOperationWindow::updated() { 00631 // Detect sensor node. 00632 const SensorNode::State sensorNodeState = sensorNode.detect(); 00633 if (sensorNodeState != lastSensorNodeState) { 00634 lastSensorNodeState = sensorNodeState; 00635 invalidate(); 00636 } 00637 00638 // Send challenge on first connection. 00639 if (sendChallenge) { 00640 rapidjson::MemoryPoolAllocator<> allocator(defaultChunkSize); 00641 rapidjson::Document document(rapidjson::kObjectType, &allocator); 00642 if (addCommandChallenge(document)) { 00643 sendJson(document); 00644 sendChallenge = false; 00645 } 00646 } else { 00647 // Process socket data. 00648 const int recvResult = 00649 socket->recv(recvBuf, sizeof(recvBuf) / sizeof(recvBuf[0])); 00650 if (recvResult > 0) { 00651 std::printf("%*s\n", recvResult, recvBuf); 00652 const Result result = processReceivedData(recvResult); 00653 if (result != NoChange) 00654 return; 00655 } else if (recvResult != NSAPI_ERROR_WOULD_BLOCK) { 00656 if (windowManager()) { 00657 std::auto_ptr<Window> window(new ErrorWindow("Socket receive failed")); 00658 windowManager()->push(window); 00659 } 00660 return; 00661 } 00662 } 00663 } 00664 00665 bool NormalOperationWindow::doProcessKey(Key key) { 00666 bool handled; 00667 switch (key) { 00668 case UpKey: 00669 validSignatureButton.setFocused(); 00670 handled = true; 00671 break; 00672 00673 case DownKey: 00674 showWebIdButton.setFocused(); 00675 handled = true; 00676 break; 00677 00678 default: 00679 handled = false; 00680 break; 00681 } 00682 return handled; 00683 }
Generated on Tue Jul 12 2022 12:06:49 by 1.7.2