Implementation of 1-Wire with added Alarm Search Functionality

Dependents:   Max32630_One_Wire_Interface

Revision:
73:2cecc1372acc
Parent:
72:6892702709ee
Child:
74:23be10c32fa3
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Masters/DS2465/DS2465.cpp	Thu May 12 14:38:16 2016 -0500
@@ -0,0 +1,590 @@
+#include "DS2465.h"
+#include "I2C.h"
+#include "wait_api.h"
+
+#define I2C_WRITE 0
+#define I2C_READ 1
+
+// DS2465 commands
+#define CMD_1WMR   0xF0
+#define CMD_WCFG   0xD2
+#define CMD_CHSL   0xC3
+#define CMD_SRP    0xE1
+
+#define CMD_1WRS   0xB4
+#define CMD_1WWB   0xA5
+#define CMD_1WRB   0x96
+#define CMD_1WSB   0x87
+#define CMD_1WT    0x78
+#define CMD_1WTB   0x69
+#define CMD_1WRF   0xE1
+#define CMD_CPS    0x5A
+#define CMD_CSS    0x4B
+#define CMD_CSAM   0x3C
+#define CMD_CSWM   0x2D
+#define CMD_CNMS   0x1E
+#define CMD_SPR    0x0F
+
+// DS2465 status bits 
+#define STATUS_1WB  0x01
+#define STATUS_PPD  0x02
+#define STATUS_SD   0x04
+#define STATUS_LL   0x08
+#define STATUS_RST  0x10
+#define STATUS_SBR  0x20
+#define STATUS_TSB  0x40
+#define STATUS_DIR  0x80
+
+using OneWire::Masters::OneWireMaster;
+using OneWire::Masters::DS2465;
+using OneWire::Authenticators::ISha256MacCoproc;
+
+static const int I2C_WRITE_OK = 0;
+
+uint8_t DS2465::Config::readByte() const
+{
+  uint8_t config = 0;
+  if (get1WS())
+    config |= 0x08;
+  if (getSPU())
+    config |= 0x04;
+  if (getPDN())
+    config |= 0x02;
+  if (getAPU())
+    config |= 0x01;
+  return config;
+}
+
+uint8_t DS2465::Config::writeByte() const
+{
+  uint8_t config = readByte();
+  return ((~config << 4) | config);
+}
+
+void DS2465::Config::reset()
+{
+  set1WS(false);
+  setSPU(false);
+  setPDN(false);
+  setAPU(true);
+}
+
+DS2465::DS2465(mbed::I2C & I2C_interface, uint8_t I2C_address)
+  : m_I2C_interface(I2C_interface), m_I2C_address(I2C_address)
+{
+  
+}
+
+OneWireMaster::CmdResult DS2465::OWInitMaster()
+{
+  OneWireMaster::CmdResult result;
+  
+  // reset DS2465 
+  result = reset();
+  if (result != OneWireMaster::Success)
+    return result;
+
+  // write the default configuration setup
+  Config defaultConfig;
+  result = writeConfig(defaultConfig, true);
+  return result;
+}
+
+OneWireMaster::CmdResult DS2465::computeNextMasterSecret(bool swap, unsigned int pageNum, PageRegion region)
+{
+   uint8_t command[2] = { CMD_CNMS, (uint8_t)(swap ? (0xC8 | (pageNum << 4) | region) : 0xBF) };
+   return writeMemory(ADDR_CMD_REG, command, 2);
+}
+
+OneWireMaster::CmdResult DS2465::computeWriteMac(bool regwrite, bool swap, unsigned int pageNum, unsigned int segmentNum) const
+{
+   uint8_t command[2] = { CMD_CSWM, (uint8_t)((regwrite << 7) | (swap << 6) | (pageNum << 4) | segmentNum) };
+   return cWriteMemory(ADDR_CMD_REG, command, 2);
+}
+
+OneWireMaster::CmdResult DS2465::computeAuthMac(bool swap, unsigned int pageNum, PageRegion region) const
+{
+   uint8_t command[2] = { CMD_CSAM, (uint8_t)(swap ? (0xC8 | (pageNum << 4) | region) : 0xBF) };
+   return cWriteMemory(ADDR_CMD_REG, command, 2);
+}
+
+OneWireMaster::CmdResult DS2465::computeSlaveSecret(bool swap, unsigned int pageNum, PageRegion region)
+{
+   uint8_t command[2] = { CMD_CSS, (uint8_t)(swap ? (0xC8 | (pageNum << 4) | region) : 0xBF) };
+   return writeMemory(ADDR_CMD_REG, command, 2);
+}
+
+ISha256MacCoproc::CmdResult DS2465::setMasterSecret(const Secret & masterSecret)
+{
+  OneWireMaster::CmdResult result;
+  result = writeMemory(ADDR_SPAD, masterSecret, masterSecret.length);
+  if (result == OneWireMaster::Success)
+    result = copyScratchpadToSecret();
+  if (result == OneWireMaster::Success)
+    wait_ms(eepromPageWriteDelayMs);
+  return (result == OneWireMaster::Success ? ISha256MacCoproc::Success : ISha256MacCoproc::OperationFailure);
+}
+
+ISha256MacCoproc::CmdResult DS2465::computeWriteMac(const WriteMacData & writeMacData, Mac & mac) const
+{
+  OneWireMaster::CmdResult result;
+  // Write input data to scratchpad
+  result = writeScratchpad(writeMacData, writeMacData.length);
+  // Compute MAC
+  if (result == OneWireMaster::Success)
+    result = computeWriteMac(false);
+  if (result == OneWireMaster::Success)
+  {
+    wait_ms(shaComputationDelayMs);
+    // Read MAC from register
+    result = readMemory(ADDR_MAC_READ, mac, mac.length, true);
+  }
+  return (result == OneWireMaster::Success ? ISha256MacCoproc::Success : ISha256MacCoproc::OperationFailure);
+}
+
+ISha256MacCoproc::CmdResult DS2465::computeAuthMac(const DevicePage & devicePage, const DeviceScratchpad & challenge, const AuthMacData & authMacData, Mac & mac) const
+{
+  OneWireMaster::CmdResult result;
+  int addr = ADDR_SPAD;
+  // Write input data to scratchpad
+  result = cWriteMemory(addr, devicePage, devicePage.length);
+  if (result == OneWireMaster::Success)
+  {
+    addr += devicePage.length;
+    result = cWriteMemory(addr, challenge, challenge.length);
+  }
+  if (result == OneWireMaster::Success)
+  {
+    addr += challenge.length;
+    result = cWriteMemory(addr, authMacData, authMacData.length);
+  }
+  // Compute MAC
+  if (result == OneWireMaster::Success)
+    result = computeAuthMac();
+  if (result == OneWireMaster::Success)
+  {
+    wait_ms(shaComputationDelayMs * 2);
+    // Read MAC from register
+    result = readMemory(ADDR_MAC_READ, mac, mac.length, true);
+  }
+  return (result == OneWireMaster::Success ? ISha256MacCoproc::Success : ISha256MacCoproc::OperationFailure);
+}
+
+ISha256MacCoproc::CmdResult DS2465::computeSlaveSecret(const DevicePage & devicePage, const DeviceScratchpad & deviceScratchpad, const SlaveSecretData & slaveSecretData)
+{
+  OneWireMaster::CmdResult result;
+  int addr = ADDR_SPAD;
+  // Write input data to scratchpad
+  result = writeMemory(addr, devicePage, devicePage.length);
+  if (result == OneWireMaster::Success)
+  {
+    addr += devicePage.length;
+    result = writeMemory(addr, deviceScratchpad, deviceScratchpad.length);
+  }
+  if (result == OneWireMaster::Success)
+  {
+    addr += deviceScratchpad.length;
+    result = writeMemory(addr, slaveSecretData, slaveSecretData.length);
+  }
+  // Compute secret
+  if (result == OneWireMaster::Success)
+    result = computeSlaveSecret();
+  if (result == OneWireMaster::Success)
+    wait_ms(shaComputationDelayMs * 2);
+  return (result == OneWireMaster::Success ? ISha256MacCoproc::Success : ISha256MacCoproc::OperationFailure);
+}
+
+OneWireMaster::CmdResult DS2465::copyScratchpad(bool destSecret, unsigned int pageNum, bool notFull, unsigned int segmentNum)   
+{
+  uint8_t command[2] = { CMD_CPS, (uint8_t)(destSecret ? 0 : (0x80 | (pageNum << 4) | (notFull << 3) | segmentNum)) };
+  return writeMemory(ADDR_CMD_REG, command, 2);
+}
+
+OneWireMaster::CmdResult DS2465::configureLevel(OWLevel level)
+{
+  OneWireMaster::CmdResult result;
+  if (m_curConfig.getSPU() != (level == LEVEL_STRONG))
+  {
+    Config newConfig = m_curConfig;
+    newConfig.setSPU(level == LEVEL_STRONG);
+    result = writeConfig(newConfig, true);
+  }
+  else
+  {
+    result = OneWireMaster::Success;
+  }
+  return result;
+}
+
+OneWireMaster::CmdResult DS2465::OWSetLevel(OWLevel new_level)
+{
+  if (new_level == LEVEL_STRONG)
+    return OneWireMaster::OperationFailure;
+  
+  return configureLevel(new_level);
+}
+
+OneWireMaster::CmdResult DS2465::OWSetSpeed(OWSpeed new_speed)
+{
+  // Requested speed is already set
+  if (m_curConfig.get1WS() == (new_speed == SPEED_OVERDRIVE))
+    return OneWireMaster::Success;
+       
+  // set the speed
+  Config newConfig = m_curConfig;
+  newConfig.set1WS(new_speed == SPEED_OVERDRIVE);
+
+  // write the new config
+  return writeConfig(newConfig, true);
+}
+
+OneWireMaster::CmdResult DS2465::OWTriplet(SearchDirection & search_direction, uint8_t & sbr, uint8_t & tsb) 
+{
+  // 1-Wire Triplet (Case B)
+  //   S AD,0 [A] 1WT [A] SS [A] Sr AD,1 [A] [Status] A [Status] A\ P
+  //                                         \--------/        
+  //                           Repeat until 1WB bit has changed to 0
+  //  [] indicates from slave
+  //  SS indicates byte containing search direction bit value in msbit
+  
+  OneWireMaster::CmdResult result;
+  uint8_t command[2] = { CMD_1WT, (uint8_t)((search_direction == DIRECTION_WRITE_ONE) ? 0x80 : 0x00) };
+  result = writeMemory(ADDR_CMD_REG, command, 2);
+  if (result == OneWireMaster::Success)
+  {
+    uint8_t status;
+    result = pollBusy(&status);
+    if (result == OneWireMaster::Success)
+    {
+      // check bit results in status byte
+      sbr = ((status & STATUS_SBR) == STATUS_SBR);
+      tsb = ((status & STATUS_TSB) == STATUS_TSB);
+      search_direction = ((status & STATUS_DIR) == STATUS_DIR) ? DIRECTION_WRITE_ONE : DIRECTION_WRITE_ZERO;
+    }
+  }
+  return result;
+}
+
+OneWireMaster::CmdResult DS2465::OWReadBlock(uint8_t *rx_buf, uint8_t rx_len)   
+{
+  // 1-Wire Receive Block (Case A)
+  //   S AD,0 [A] ADDR_CMD_REG [A] 1WRF [A] PR [A] P
+  //  [] indicates from slave
+  //  PR indicates byte containing parameter
+
+  OneWireMaster::CmdResult result;
+  uint8_t command[2] = { CMD_1WRF, rx_len };
+  
+  result = writeMemory(ADDR_CMD_REG, command, 2);
+  if (result == OneWireMaster::Success)
+    result = pollBusy();
+  if (result == OneWireMaster::Success) 
+    result = readMemory(ADDR_SPAD, rx_buf, rx_len, false);
+
+  return result;
+}
+
+OneWireMaster::CmdResult DS2465::OWWriteBlock(const uint8_t *tran_buf, uint8_t tran_len)
+{
+  return OWWriteBlock(false, tran_buf, tran_len);
+}
+
+OneWireMaster::CmdResult DS2465::OWWriteBlockMac()
+{
+  return OWWriteBlock(true, NULL, 0);
+}
+
+OneWireMaster::CmdResult DS2465::OWWriteBlock(bool tx_mac, const uint8_t *tran_buf, uint8_t tran_len)
+{
+  OneWireMaster::CmdResult result;
+  uint8_t command[2] = { CMD_1WTB, (uint8_t)(tx_mac ? 0xFF : tran_len) };
+
+  if (!tx_mac)
+  {
+    // prefill scratchpad with required data
+    result = writeMemory(ADDR_SPAD, tran_buf, tran_len);
+    if (result != OneWireMaster::Success)
+      return result;
+  }
+
+  // 1-Wire Transmit Block (Case A)
+  //   S AD,0 [A] ADDR_CMD_REG [A] 1WTB [A] PR [A] P
+  //  [] indicates from slave
+  //  PR indicates byte containing parameter
+  
+  result = writeMemory(ADDR_CMD_REG, command, 2);
+  
+  if (result == OneWireMaster::Success)
+    result = pollBusy();
+
+  return result;
+}
+
+OneWireMaster::CmdResult DS2465::OWReadByteSetLevel(uint8_t & recvbyte, OWLevel after_level)    
+{
+  // 1-Wire Read Bytes (Case C)
+  //   S AD,0 [A] ADDR_CMD_REG [A] 1WRB [A] Sr AD,1 [A] [Status] A [Status] A 
+  //                                                  \--------/        
+  //                     Repeat until 1WB bit has changed to 0
+  //   Sr AD,0 [A] SRP [A] E1 [A] Sr AD,1 [A] DD A\ P
+  //                                  
+  //  [] indicates from slave
+  //  DD data read
+  
+  OneWireMaster::CmdResult result;
+  uint8_t buf;
+  
+  result = configureLevel(after_level);
+  if (result != OneWireMaster::Success)
+    return result;
+   
+  buf = CMD_1WRB;
+  result = writeMemory(ADDR_CMD_REG, &buf, 1);
+
+  if (result == OneWireMaster::Success)
+    result = pollBusy();
+
+  if (result == OneWireMaster::Success)
+    result = readMemory(ADDR_DATA_REG, &buf, 1);
+  
+  if (result == OneWireMaster::Success)
+    recvbyte = buf;
+   
+  return result;
+}
+
+OneWireMaster::CmdResult DS2465::OWWriteByteSetLevel(uint8_t sendbyte, OWLevel after_level) 
+{    
+  // 1-Wire Write Byte (Case B)
+  //   S AD,0 [A] ADDR_CMD_REG [A] 1WWB [A] DD [A] Sr AD,1 [A] [Status] A [Status] A\ P
+  //                                                           \--------/        
+  //                             Repeat until 1WB bit has changed to 0
+  //  [] indicates from slave
+  //  DD data to write
+  
+  OneWireMaster::CmdResult result;
+  
+  result = configureLevel(after_level);
+  if (result != OneWireMaster::Success)
+    return result;
+  
+  uint8_t command[2] = { CMD_1WWB, sendbyte };
+  
+  result = writeMemory(ADDR_CMD_REG, command, 2);
+  if (result == OneWireMaster::Success)
+    result = pollBusy();
+
+  return result;
+}
+
+OneWireMaster::CmdResult DS2465::OWTouchBitSetLevel(uint8_t & sendrecvbit, OWLevel after_level) 
+{
+  // 1-Wire bit (Case B)
+  //   S AD,0 [A] ADDR_CMD_REG [A] 1WSB [A] BB [A] Sr AD,1 [A] [Status] A [Status] A\ P
+  //                                                          \--------/        
+  //                           Repeat until 1WB bit has changed to 0
+  //  [] indicates from slave
+  //  BB indicates byte containing bit value in msbit
+
+  OneWireMaster::CmdResult result;
+  
+  result = configureLevel(after_level);
+  if (result != OneWireMaster::Success)
+    return result;
+  
+  uint8_t command[2] = { CMD_1WSB, (uint8_t)(sendrecvbit ? 0x80 : 0x00) };
+  uint8_t status;
+  
+  result = writeMemory(ADDR_CMD_REG, command, 2);
+  
+  if (result == OneWireMaster::Success)
+    result = pollBusy(&status);
+ 
+  if (result == OneWireMaster::Success)
+    sendrecvbit = (status & STATUS_SBR);
+  
+  return result;
+}
+
+OneWireMaster::CmdResult DS2465::cWriteMemory(uint8_t addr, const uint8_t * buf, size_t bufLen) const
+{
+  int i;
+
+  // Write SRAM (Case A)
+  //   S AD,0 [A] VSA [A] DD [A]  P
+  //                      \-----/
+  //                        Repeat for each data byte
+  //  [] indicates from slave
+  //  VSA valid SRAM memory address
+  //  DD memory data to write
+  
+  m_I2C_interface.start();
+  if (m_I2C_interface.write((m_I2C_address | I2C_WRITE)) != I2C_WRITE_OK)
+  {
+     m_I2C_interface.stop();
+     return OneWireMaster::CommunicationWriteError;
+  }
+  if (m_I2C_interface.write(addr) != I2C_WRITE_OK)
+  {
+     m_I2C_interface.stop();
+     return OneWireMaster::CommunicationWriteError;
+  }
+  // loop to write each byte
+  for (i = 0; i < bufLen; i++)
+  {
+     if (m_I2C_interface.write(buf[i]) != I2C_WRITE_OK)
+     {
+        m_I2C_interface.stop();
+        return OneWireMaster::CommunicationWriteError;
+     }
+  }
+  m_I2C_interface.stop();
+   
+  return OneWireMaster::Success;
+}
+
+OneWireMaster::CmdResult DS2465::readMemory(uint8_t addr, uint8_t * buf, size_t bufLen, bool skipSetPointer) const
+{
+  int i;
+
+  // Read (Case A)
+  //   S AD,0 [A] MA [A] Sr AD,1 [A] [DD] A [DD] A\ P
+  //                                 \-----/
+  //                                   Repeat for each data byte, NAK last byte
+  //  [] indicates from slave
+  //  MA memory address
+  //  DD memory data read
+
+  m_I2C_interface.start();
+  if (!skipSetPointer)
+  {
+     if (m_I2C_interface.write((m_I2C_address | I2C_WRITE)) != I2C_WRITE_OK)
+     {
+        m_I2C_interface.stop();
+        return OneWireMaster::CommunicationWriteError;
+     }
+     if (m_I2C_interface.write(addr) != I2C_WRITE_OK)
+     {
+        m_I2C_interface.stop();
+        return OneWireMaster::CommunicationWriteError;
+     }
+     m_I2C_interface.start();
+  }
+
+  if (m_I2C_interface.write((m_I2C_address | I2C_READ)) != I2C_WRITE_OK)
+  {
+     m_I2C_interface.stop();
+     return OneWireMaster::CommunicationWriteError;
+  }
+  // loop to read each byte, NAK last byte
+  for (i = 0; i < bufLen; i++)
+  {
+     buf[i] = m_I2C_interface.read((i == (bufLen - 1)) ? mbed::I2C::NoACK : mbed::I2C::ACK);
+  }
+  m_I2C_interface.stop();
+  
+  return OneWireMaster::Success;
+}
+
+OneWireMaster::CmdResult DS2465::writeConfig(const Config & config, bool verify)
+{
+  uint8_t configBuf;
+  OneWireMaster::CmdResult result;
+   
+  configBuf = config.writeByte();
+  result = writeMemory(ADDR_WCFG_REG, &configBuf, 1);
+  if (verify)
+  {
+    if (result == OneWireMaster::Success)
+    {
+      result = readMemory(ADDR_WCFG_REG, &configBuf, 1);
+    }
+    if (result == OneWireMaster::Success)
+    {
+      if (configBuf != config.readByte())
+        result = OneWireMaster::OperationFailure;
+    }
+  }
+  
+  if (result == OneWireMaster::Success)
+    m_curConfig = config;
+
+  return result;
+}
+
+OneWireMaster::CmdResult DS2465::pollBusy(uint8_t * pStatus)
+{
+  const unsigned int pollLimit = 200;
+
+  OneWireMaster::CmdResult result;
+  uint8_t status;
+  unsigned int pollCount = 0;
+   
+  do
+  {
+    result = readMemory(ADDR_STATUS_REG, &status, 1, true);
+    if (result != OneWireMaster::Success)
+      return result;
+    if (pStatus != NULL)
+        *pStatus = status;
+    if (pollCount++ >= pollLimit)
+      return OneWireMaster::TimeoutError;
+  } while (status & STATUS_1WB);
+
+  return OneWireMaster::Success;
+}
+
+OneWireMaster::CmdResult DS2465::OWReset(void)
+{     
+  // 1-Wire reset (Case B)
+  //   S AD,0 [A] ADDR_CMD_REG  [A] 1WRS [A] Sr AD,1 [A] [Status] A [Status] A\ P
+  //                                                  \--------/        
+  //                       Repeat until 1WB bit has changed to 0
+  //  [] indicates from slave
+   
+  OneWireMaster::CmdResult result;
+  uint8_t buf;
+    
+  buf = CMD_1WRS;
+  result = writeMemory(ADDR_CMD_REG, &buf, 1);
+
+  if (result == OneWireMaster::Success)
+    result = pollBusy(&buf);
+  
+  if (result == OneWireMaster::Success)
+  {       
+    // check for presence detect
+    if ((buf & STATUS_PPD) != STATUS_PPD)
+      result = OneWireMaster::OperationFailure;
+  }
+
+  return result;
+}
+
+OneWireMaster::CmdResult DS2465::reset(void)
+{  
+  // Device Reset
+  //   S AD,0 [A] ADDR_CMD_REG [A] 1WMR [A] Sr AD,1 [A] [SS] A\ P
+  //  [] indicates from slave
+  //  SS status byte to read to verify state
+  
+  OneWireMaster::CmdResult result;
+  uint8_t buf;
+  
+  buf = CMD_1WMR;
+  result = writeMemory(ADDR_CMD_REG, &buf, 1);
+  
+  if (result == OneWireMaster::Success)
+    result = readMemory(ADDR_STATUS_REG, &buf, 1, true);
+
+  if (result == OneWireMaster::Success)
+  {
+    if ((buf & 0xF7) != 0x10)
+      result = OneWireMaster::OperationFailure;
+  }
+   
+  if (result == OneWireMaster::Success)
+    OWReset(); // do a command to get 1-Wire master reset out of holding state
+
+  return result;
+}