Maxim Integrated / Mbed OS MAXREFDES155#

Dependencies:   MaximInterface

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers SensorNode.cpp Source File

SensorNode.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 <string>
00034 #include <MaximInterfaceCore/HexString.hpp>
00035 #include <mbed-os/drivers/I2C.h>
00036 #include "SensorNode.hpp"
00037 
00038 #define TRY MaximInterfaceCore_TRY
00039 #define TRY_VALUE MaximInterfaceCore_TRY_VALUE
00040 
00041 using namespace MaximInterfaceCore;
00042 using MaximInterfaceDevices::DS2476;
00043 using MaximInterfaceDevices::DS28C36;
00044 
00045 // I2C address of the MLX90614.
00046 static const uint8_t mlx90614Addr = 0xB4;
00047 
00048 SensorNode::SensorNode (Sleep & sleep, I2CMaster & i2c, DS2476 & ds2476)
00049     : i2c(&i2c), ds28c36(sleep, i2c), ds2476(&ds2476) {}
00050 
00051 SensorNode::State  SensorNode::detect() {
00052   if (Result<DS28C36::Page::array> page =
00053           ds28c36.readMemory(DS28C36::romOptionsPage)) {
00054     const DS28C36::RomOptions romOptions(page.value());
00055     copy(romOptions.romId(), make_span(romId));
00056     copy(romOptions.manId(), make_span(manId));
00057   } else {
00058     return Disconnected;
00059   }
00060 
00061   if (!valid(romId)) {
00062     return Disconnected;
00063   }
00064 
00065   {
00066     const Result<void> result = authenticate();
00067     if (!result) {
00068       return (result.error() == DS28C36::AuthenticationError) ? Invalid
00069                                                               : Disconnected;
00070     }
00071   }
00072 
00073   const Result<bool> laserEnabled = getLaserEnabled();
00074   return laserEnabled
00075              ? (laserEnabled.value() ? ValidLaserEnabled : ValidLaserDisabled)
00076              : Disconnected;
00077 }
00078 
00079 Result<double> SensorNode::readTemp(TempStyle style) {
00080   uint8_t data[2];
00081   switch (style) {
00082   case ObjectTemp:
00083   default:
00084     data[0] = 0x07;
00085     break;
00086 
00087   case AmbientTemp:
00088     data[0] = 0x06;
00089     break;
00090   }
00091   TRY(i2c->writePacket(mlx90614Addr, make_span(data, 1),
00092                        I2CMaster::StopOnError));
00093   TRY(i2c->readPacket(mlx90614Addr, data, I2CMaster::Stop));
00094   return ((static_cast<unsigned int>(data[1]) << 8) | data[0]) * 0.02 - 273.15;
00095 }
00096 
00097 Result<void> SensorNode::authenticate() {
00098   // Compute slave secret on coprocessor.
00099   DS28C36::PageAuthenticationData message;
00100   message.setPageNum(0);
00101   if (const Result<DS28C36::Page::array> page =
00102           ds28c36.readMemory(message.pageNum())) {
00103     message.setPage(page.value());
00104   } else {
00105     return page.error();
00106   }
00107   message.setRomId(romId);
00108   message.setManId(manId);
00109   TRY(ds2476->writeBuffer(message.result()));
00110   TRY(ds2476->computeSha2UniqueSecret(DS2476::SecretNumA));
00111 
00112   // Compute HMAC on coprocessor.
00113   // ROM ID, Page 0, and MAN ID are already in message.
00114   TRY(ds2476->readRng(message.challenge()));
00115   TRY(ds2476->writeBuffer(message.result()));
00116   DS2476::Page::array computedHmac;
00117   TRY_VALUE(computedHmac, ds2476->computeSha2Hmac());
00118 
00119   // Compute HMAC on device.
00120   TRY(ds28c36.writeBuffer(message.challenge()));
00121   DS28C36::Page::array deviceHmac;
00122   TRY_VALUE(deviceHmac, ds28c36.computeAndReadPageAuthentication(
00123                             message.pageNum(), DS28C36::SecretNumA));
00124 
00125   return (computedHmac == deviceHmac) ? makeResult(none)
00126                                       : DS28C36::AuthenticationError;
00127 }
00128 
00129 Result<void> SensorNode::setLaserEnabled(bool enabled,
00130                                          const PrintHandler & print) {
00131   if (print) {
00132     print((std::string(enabled ? "Enabling" : "Disabling") + " laser").c_str());
00133   }
00134 
00135   // Compute write HMAC.
00136   // ROM ID and MAN ID are already in message.
00137   if (print) {
00138     print("Reading GPIO Control page");
00139     print((std::string(
00140                "Modify copy of GPIO Control page to set GPIO B state to ") +
00141            (enabled ? "conducting" : "high-impedance"))
00142               .c_str());
00143   }
00144   DS28C36::WriteAuthenticationData message;
00145   message.setPageNum(DS28C36::gpioControlPage);
00146   if (const Result<DS28C36::Page::array> oldPage =
00147           ds28c36.readMemory(message.pageNum())) {
00148     message.setOldPage(oldPage.value());
00149   } else {
00150     return oldPage.error();
00151   }
00152   message.setNewPage(message.oldPage());
00153   DS28C36::GpioControl(message.newPage()).setPiobConducting(enabled);
00154   message.setRomId(romId);
00155   message.setManId(manId);
00156   if (print) {
00157     print(("Creating HMAC message (ROM ID | Old Page Data | New Page Data | "
00158            "Page # | MAN ID): " +
00159            toHexString(message.result()))
00160               .c_str());
00161     print("Writing HMAC message to DS2476 buffer");
00162   }
00163   TRY(ds2476->writeBuffer(message.result()));
00164   DS2476::Page::array hmac;
00165   TRY_VALUE(hmac, ds2476->computeSha2Hmac());
00166 
00167   if (print) {
00168     print(("DS2476 computes write authentication HMAC from slave secret "
00169            "(Secret S) and message in buffer: " +
00170            toHexString(hmac))
00171               .c_str());
00172     print("Write authentication HMAC is written to DS28C36 buffer");
00173     print("DS28C36 computes an HMAC to compare to the write authentication "
00174           "HMAC after receiving Page # and New Page Data");
00175   }
00176 
00177   // Write page data.
00178   TRY(ds28c36.writeBuffer(hmac));
00179   TRY(ds28c36.authenticatedSha2WriteMemory(
00180       message.pageNum(), DS28C36::SecretNumA, message.newPage()));
00181   if (print) {
00182     print("DS28C36 updates page data which changes GPIO B state");
00183     print((std::string("Laser is now ") + (enabled ? "enabled" : "disabled"))
00184               .c_str());
00185   }
00186   return none;
00187 }
00188 
00189 Result<bool> SensorNode::getLaserEnabled() {
00190   DS28C36::Page::array page;
00191   TRY_VALUE(page, ds28c36.readMemory(DS28C36::gpioControlPage));
00192   return DS28C36::GpioControl(page).piobConducting();
00193 }