Implementation of 1-Wire with added Alarm Search Functionality

Dependents:   Max32630_One_Wire_Interface

OneWire_Masters/DS2465/DS2465.cpp

Committer:
IanBenzMaxim
Date:
2016-03-21
Revision:
21:00c94aeb533e
Child:
22:686273e55cdc

File content as of revision 21:00c94aeb533e:

#include "DS2465.hpp"

#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 config bits
#define CONFIG_APU  0x01
#define CONFIG_PDN  0x02
#define CONFIG_SPU  0x04
#define CONFIG_1WS  0x08

// 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

// delays (if not polling for complete)
#define EEPROM_WRITE_DELAY    30  
#define LOAD_SECRET_DELAY     90
#define SHA_COMPUTATION_DELAY 5

static const int I2C_WRITE_OK = 0;

DS2465::DS2465(I2C & I2C_interface, unsigned char I2C_address)
  : m_I2C_interface(I2C_interface), m_I2C_address(I2C_address)
{
  
}




OneWireMaster::CmdResult DS2465::OWInitMaster()
{
  return Detect();
}


//--------------------------------------------------------------------------
// Compute Next Master Secret DS2465 
//
// 'swap' - 1 if swapping a page into the computation
// 'page' - page number to swap in
// 'region' - (1) first 1/2 page, (2) second 1/2 page, (3) entire page 
//
// Returns: true write successful
//          false failure to complete read
//
OneWireMaster::CmdResult DS2465::Compute_NextMasterSecret(bool swap, unsigned int pageNum, PageRegion region)
{
   uint8_t par;

   // create parameter byte
   if (!swap)
      par = 0xBF;
   else
      par = (0xC8 | (pageNum << 4) | region); 

   return Write_Command_Reg(CMD_CNMS, par, false);
}

//--------------------------------------------------------------------------
// Compute Write MAC DS2465 
//
// 'regwrite' - true if writing to a register, false if regular memory
// 'swap' - true if swapping a page into the computation
// 'page' - page number to swap in
// 'segment' - segment number if swaping 
//
// Returns: true write successful
//          false failure to complete read
//
OneWireMaster::CmdResult DS2465::Compute_WriteMAC(bool regwrite, bool swap, unsigned int pageNum, unsigned int segmentNum) const
{
   uint8_t par;

   // create parameter byte
   par = ((regwrite << 7) | (swap << 6) | (pageNum << 4) | segmentNum); 
   
   return Write_Command_Reg(CMD_CSWM, par, false);
}

//--------------------------------------------------------------------------
// Compute Slave Authentication MAC DS2465 
//
// 'swap' - true if swapping a page into the computation
// 'page' - page number to swap in
// 'region' - (1) first 1/2 page, (2) second 1/2 page, (3) entire page 
//
// Returns: true write successful
//          false failure to complete read
//
OneWireMaster::CmdResult DS2465::Compute_AuthMAC(bool swap, unsigned int pageNum, PageRegion region) const
{
   uint8_t par;

   // create parameter byte
   if (!swap)
      par = 0xBF;
   else
      par = (0xC8 | (pageNum << 4) | region); 
   
   return Write_Command_Reg(CMD_CSAM, par, false);
}

//--------------------------------------------------------------------------
// Compute S-Secret on DS2465 
//
// 'swap' - true if swapping a page into the computation
// 'page' - page number to swap in
// 'region' - (1) first 1/2 page, (2) second 1/2 page, (3) entire page 
//
// Returns: true write successful
//          false failure to complete read
//
OneWireMaster::CmdResult DS2465::Compute_SSecret(bool swap, unsigned int pageNum, PageRegion region)
{
   uint8_t par;

   // create parameter byte
   if (!swap)
      par = 0xBF;
   else
      par = (0xC8 | (pageNum << 4) | region); 
   
   return Write_Command_Reg(CMD_CSS, par, false);
}




ISha256MacCoprocessor::CmdResult DS2465::setMasterSecret(const std::uint8_t (&secret)[secret_len])
{
  OneWireMaster::CmdResult result;
  result = WriteScratchpad(ADDR_SPAD, secret, secret_len);
  if (result == OneWireMaster::Success)
    result = CopyScratchpad(1, 0, 1, 0);
  if (result == OneWireMaster::Success)
    wait_ms(8 * EEPROM_WRITE_DELAY);
  return (result == OneWireMaster::Success ? ISha256MacCoprocessor::Success : ISha256MacCoprocessor::OperationFailure);
}

ISha256MacCoprocessor::CmdResult DS2465::ComputeAndRead_WriteMAC(const std::uint8_t (&WriteMAC_data)[WriteMAC_data_len], std::uint8_t (&mac)[mac_len]) const
{
  OneWireMaster::CmdResult result;
  // Write input data to scratchpad
  result = WriteScratchpad(ADDR_SPAD, WriteMAC_data, WriteMAC_data_len);
  // Compute MAC
  if (result == OneWireMaster::Success)
    result = Compute_WriteMAC(false, false, 0, 0);
  if (result == OneWireMaster::Success)
  {
    wait_ms(SHA_COMPUTATION_DELAY);
    // Read MAC from register
    result = ReadMemory(ADDR_MAC_READ, mac, mac_len, true);
  }
  return (result == OneWireMaster::Success ? ISha256MacCoprocessor::Success : ISha256MacCoprocessor::OperationFailure);
}

ISha256MacCoprocessor::CmdResult DS2465::ComputeAndRead_AuthMAC(const std::uint8_t (&devicePage)[devicePage_len], const std::uint8_t (&challenge)[deviceScratchpad_len],
                                    const std::uint8_t (&AuthMAC_data)[AuthMAC_data_len], std::uint8_t (&mac)[mac_len]) const
{
  OneWireMaster::CmdResult result;
  int addr = ADDR_SPAD;
  // Write input data to scratchpad
  result = WriteScratchpad(addr, devicePage, devicePage_len);
  if (result == OneWireMaster::Success)
  {
    addr += devicePage_len;
    result = WriteScratchpad(addr, challenge, deviceScratchpad_len);
  }
  if (result == OneWireMaster::Success)
  {
    addr += deviceScratchpad_len;
    result = WriteScratchpad(addr, AuthMAC_data, AuthMAC_data_len);
  }
  // Compute MAC
  if (result == OneWireMaster::Success)
    result = Compute_AuthMAC(false, 0, REGION_FULL_PAGE);
  if (result == OneWireMaster::Success)
  {
    wait_ms(SHA_COMPUTATION_DELAY * 2);
    // Read MAC from register
    result = ReadMemory(ADDR_MAC_READ, mac, mac_len, true);
  }
  return (result == OneWireMaster::Success ? ISha256MacCoprocessor::Success : ISha256MacCoprocessor::OperationFailure);
}

ISha256MacCoprocessor::CmdResult DS2465::Compute_SSecret(const unsigned char (&devicePage)[devicePage_len], const unsigned char (&deviceScratchpad)[deviceScratchpad_len],
                             const unsigned char (&SSecret_data)[SSecret_data_len])
{
  OneWireMaster::CmdResult result;
  int addr = ADDR_SPAD;
  // Write input data to scratchpad
  result = WriteScratchpad(addr, devicePage, devicePage_len);
  if (result == OneWireMaster::Success)
  {
    addr += devicePage_len;
    result = WriteScratchpad(addr, deviceScratchpad, deviceScratchpad_len);
  }
  if (result == OneWireMaster::Success)
  {
    addr += deviceScratchpad_len;
    result = WriteScratchpad(addr, SSecret_data, SSecret_data_len);
  }
  // Compute secret
  if (result == OneWireMaster::Success)
    result = Compute_SSecret(false, 0, REGION_FULL_PAGE);
  if (result == OneWireMaster::Success)
    wait_ms(SHA_COMPUTATION_DELAY * 2);
  return (result == OneWireMaster::Success ? ISha256MacCoprocessor::Success : ISha256MacCoprocessor::OperationFailure);
}

//--------------------------------------------------------------------------
// Copy Scratchpad on DS2465 to either secret or memory page
//
// 'dest_secret' - 1 if destination is secret, 0 if memory page
// 'page' - page number if dest_secret=0
// 'notfull' - 0 if only 4 byte segment, 1 if writing to full page, 
// 'seg' - Segment number if full=0.
//
// Returns: true write successful
//          false failure to complete read
//
OneWireMaster::CmdResult DS2465::CopyScratchpad(bool dest_secret, unsigned int pageNum, bool notFull, unsigned int segmentNum)	
{
   uint8_t par;

   // create parameter byte
   if (dest_secret)
      par = 0;
   else
      par = (0x80 | (pageNum << 4) | (notFull << 3) | segmentNum); 
   
   return Write_Command_Reg(CMD_CPS, par, false);
}

//--------------------------------------------------------------------------
// APU enable or disable
//
// 'readflag' - 1 if reading current configuration
// 'apu_enable' - 1 to enable
//
// Returns:  true  if write successful, or return configuration value if reading
//   
OneWireMaster::CmdResult DS2465::ConfigureAPU(bool apu_enable)	
{
   // clear power down bit in the global config state
   cAPU = apu_enable ? CONFIG_APU : 0;

   // write the new config
   return Write_Config(c1WS | cSPU | cPDN | cAPU);
}

//--------------------------------------------------------------------------
// Power up 1-Wire using extended function
//
// Returns:  true  successful
//           false failure during communication
//
OneWireMaster::CmdResult DS2465::OWPowerUp(void)
{
   OneWireMaster::CmdResult rt;

  // clear power down bit in the global config state
   cPDN = 0;

   // write the new config
   rt = Write_Config(c1WS | cSPU | cPDN | cAPU);

   // delay 2ms to allow units to power up
   wait_ms(2);

   return rt;
}

//--------------------------------------------------------------------------
// Power down 1-Wire using extended function
//
// Returns:  true  successful
//           false program voltage not available
//
OneWireMaster::CmdResult DS2465::OWPowerDown(void)
{
   // set power down bit in the global config state
   cPDN = CONFIG_PDN;

   // write the new config
   return Write_Config(c1WS | cSPU | cPDN | cAPU);
}

//--------------------------------------------------------------------------
// Send 1 bit of communication to the 1-Wire Net and verify that the
// response matches the 'applyPowerResponse' bit and apply power delivery
// to the 1-Wire net.  Note that some implementations may apply the power
// first and then turn it off if the response is incorrect.
//
// 'applyPowerResponse' - 1 bit response to check, if correct then start
//                        power delivery 
//
// Returns:  true: bit written and response correct, strong pullup now on
//           false: response incorrect
//
OneWireMaster::CmdResult DS2465::OWReadBitPower(uint8_t applyPowerResponse)
{
  OneWireMaster::CmdResult result;
  uint8_t rdbit;

  // set strong pull-up enable
  cSPU = CONFIG_SPU;

  // write the new config
  result = Write_Config(c1WS | cSPU | cPDN | cAPU);
  if (result != OneWireMaster::Success)
    return result;

  // perform read bit
  result = OWReadBit(rdbit);
  if (result != OneWireMaster::Success)
    return result;

  // check if response was correct, if not then turn off strong pull-up
  if (rdbit != applyPowerResponse)
  {
    OWLevel(LEVEL_NORMAL);
    return OneWireMaster::OperationFailure;
  }

  return OneWireMaster::Success;
}

//--------------------------------------------------------------------------
// Read 8 bits of communication from the 1-Wire Net.  After the
// 8 bits are read then change the level of the 1-Wire net.
//
// Returns:  8 bits read from 1-Wire Net
//
OneWireMaster::CmdResult DS2465::OWReadBytePower(uint8_t & recvbyte)
{
  OneWireMaster::CmdResult result;
  
  // set strong pull-up enable
  cSPU = CONFIG_SPU;

  // write the new config
  result = Write_Config(c1WS | cSPU | cPDN | cAPU);
  if (result != OneWireMaster::Success)
    return result;

  // do the read byte
  result = OWReadByte(recvbyte);
  return result;
}

//--------------------------------------------------------------------------
// Send 8 bits of communication to the 1-Wire Net and verify that the
// 8 bits read from the 1-Wire Net is the same (write operation).  
// The parameter 'sendbyte' least significant 8 bits are used.  After the
// 8 bits are sent change the level of the 1-Wire net.
//
// 'sendbyte' - 8 bits to send (least significant bit)
//
OneWireMaster::CmdResult DS2465::OWWriteBytePower(uint8_t sendbyte)
{
  OneWireMaster::CmdResult result;
  
  // set strong pull-up enable
  cSPU = CONFIG_SPU;

  // write the new config
  result = Write_Config(c1WS | cSPU | cPDN | cAPU);
  if (result != OneWireMaster::Success)
    return result;

  // perform write byte
  return OWWriteByte(sendbyte);
}

//--------------------------------------------------------------------------
// Set the 1-Wire Net line level pull-up to normal. The DS2465 does only
// allows enabling strong pull-up on a bit or byte event. Consequently this
// function only allows the MODE_STANDARD argument. To enable strong pull-up
// use OWWriteBytePower or OWReadBitPower.  
//
// 'new_level' - new level defined as
//                MODE_STANDARD     0x00
//
// Returns:  current 1-Wire Net level
//
OneWireMaster::CmdResult DS2465::OWLevel(OW_LEVEL new_level)
{
   // function only will turn back to non-strong pull-up
   if (new_level != LEVEL_NORMAL)
      return OneWireMaster::OperationFailure;

   // clear the strong pull-up bit in the global config state
   cSPU = 0;

   // write the new config
   return Write_Config(c1WS | cSPU | cPDN | cAPU);
}

//--------------------------------------------------------------------------
// The 'OWOverdriveMatchROM' function does an overdrive Match-ROM using the
// global ROM_NO device
//
// Returns:   true (1) : OWReset successful and match rom sent. 
//            false (0): OWReset did not have presence
//
OneWireMaster::CmdResult DS2465::OWOverdriveMatchROM(const RomId & romId)
{
  OneWireMaster::CmdResult result;
  // use overdrive MatchROM 
  OWSpeed(SPEED_STANDARD);
  result = OWReset();
  if (result == OneWireMaster::Success)
  {
    result = OWWriteByte(0x69);
    if (result == OneWireMaster::Success)
    {
      OWSpeed(SPEED_OVERDRIVE);
      // send ROM
      result = OWWriteBlock(false, romId, RomId::byteLen);
    }
  }
  return result;
}

//--------------------------------------------------------------------------
// The 'OWMatchROM' function does a Match-ROM using the global ROM_NO device
//
// Returns:   true (1) : OWReset successful and match rom sent. 
//            false (0): OWReset did not have presence
//
OneWireMaster::CmdResult DS2465::OWMatchROM(const RomId & romId)
{
  OneWireMaster::CmdResult result;
  uint8_t buf[1 + RomId::byteLen];

  // use MatchROM 
  result = OWReset();
  if (result == OneWireMaster::Success)
  {
    buf[0] = 0x55;
    std::memcpy(&buf[1], romId, RomId::byteLen);
    // send command and rom
    result = OWWriteBlock(false, buf, 1 + RomId::byteLen);
  }
  
  return result;
}

//--------------------------------------------------------------------------
// Setup the search to skip the current device type on the next call
// to OWNext().
//
void DS2465::OWFamilySkipSetup(void)
{
   // set the Last discrepancy to last family discrepancy
   m_lastDiscrepancy = m_lastFamilyDiscrepancy;

   // clear the last family discrpepancy
   m_lastFamilyDiscrepancy = 0;

   // check for end of list
   if (m_lastDiscrepancy == 0) 
      m_lastDeviceFlag = true;
}

//--------------------------------------------------------------------------
// Setup the search to find the device type 'family_code' on the next call
// to OWNext() if it is present.
//
void DS2465::OWTargetSetup(RomId & romId)
{
   // set the search state to find SearchFamily type devices
   for (int i = 1; i < 8; i++)
      romId[i] = 0;
   m_lastDiscrepancy = 64;
   m_lastFamilyDiscrepancy = 0;
   m_lastDeviceFlag = false;
}

//--------------------------------------------------------------------------
// Verify the device with the ROM number in ROM_NO buffer is present.
// Return true  : device verified present
//        false : device not present
//
OneWireMaster::CmdResult DS2465::OWVerify(const RomId & romId)
{
  OneWireMaster::CmdResult result;
  RomId romIdCopy(romId);
  int ld_backup, ldf_backup, lfd_backup;

  // keep a backup copy of the current state
  ld_backup = m_lastDiscrepancy;
  ldf_backup = m_lastDeviceFlag;
  lfd_backup = m_lastFamilyDiscrepancy;

  // set search to find the same device
  m_lastDiscrepancy = 64;
  m_lastDeviceFlag = false;

  result = OWSearch(romIdCopy);
  if (result == OneWireMaster::Success)
  {
    // check if same device found
    if (romId != romIdCopy)
    {
       result = OneWireMaster::OperationFailure;
    }
  }

  // restore the search state
  m_lastDiscrepancy = ld_backup;
  m_lastDeviceFlag = ldf_backup;
  m_lastFamilyDiscrepancy = lfd_backup;

  // return the result of the verify
  return result;
}

//--------------------------------------------------------------------------
// Find the 'next' devices on the 1-Wire network
// Return true  : device found, ROM number in ROM_NO buffer
//        false : device not found, end of search
//
OneWireMaster::CmdResult DS2465::OWNext(RomId & romId)
{
   // leave the search state alone
   return OWSearch(romId);
}

//--------------------------------------------------------------------------
// Set the 1-Wire Net communication speed.
//
// 'new_speed' - new speed defined as
//                MODE_STANDARD   0x00
//                MODE_OVERDRIVE  0x01
//
// Returns:  current 1-Wire Net speed
//
OneWireMaster::CmdResult DS2465::OWSpeed(OW_SPEED new_speed)
{
   // set the speed 
   if (new_speed == SPEED_OVERDRIVE)
      c1WS = CONFIG_1WS;
   else
      c1WS = 0;

   // write the new config
   return Write_Config(c1WS | cSPU | cPDN | cAPU);
}

//--------------------------------------------------------------------------
// The 'OWOverdriveSkipROM' function does an Overdrive skip-ROM. Ignores
// result from standard speed OWReset().
// 
// Returns:   true (1) : OWReset and skip rom sent. 
//            false (0): Could not change to overdrive
//
OneWireMaster::CmdResult DS2465::OWOverdriveSkipROM(void)
{
  OneWireMaster::CmdResult result = OWSpeed(SPEED_STANDARD);
  if (result == OneWireMaster::Success)
    result = OWReset();
  if (result == OneWireMaster::Success)
    result = OWWriteByte(0x3C);
  if (result == OneWireMaster::Success)
    result = OWSpeed(SPEED_OVERDRIVE);
  return result;
}

//--------------------------------------------------------------------------
// The 'OWResume' function does a Resume command 0xA5.
//
// Returns:   true (1) : OWReset successful and RESUME sent. 
//            false (0): OWReset did not have presence
//
OneWireMaster::CmdResult DS2465::OWResume(void)
{
  OneWireMaster::CmdResult result;
  result = OWReset();
  if (result == OneWireMaster::Success)
  {
    result = OWWriteByte(0xA5);
  }
  return result;
}

//--------------------------------------------------------------------------
// The 'OWSkipROM' function does a skip-ROM.  This function
// uses the Skip-ROM function CCh.
//
// Returns:   true (1) : OWReset successful and skip rom sent. 
//            false (0): OWReset did not have presence
//
OneWireMaster::CmdResult DS2465::OWSkipROM(void)
{
  OneWireMaster::CmdResult result;
  result = OWReset();
  if (result == OneWireMaster::Success)
  {
    result = OWWriteByte(0xCC);
  }
  return result;
}

//--------------------------------------------------------------------------
// The 'OWReadROM' function does a Read-ROM.  This function
// uses the read-ROM function 33h to read a ROM number and verify CRC8.
//
// Returns:   true (1) : OWReset successful and Serial Number placed 
//                       in the global ROM, CRC8 valid 
//            false (0): OWReset did not have presence or CRC8 invalid
//
OneWireMaster::CmdResult DS2465::OWReadROM(RomId & romId)	
{
  OneWireMaster::CmdResult result;
  uint8_t buf[2 + RomId::byteLen];

  result = OWReset();
  if (result == OneWireMaster::Success)
    result = OWWriteByte(0x33); // READ ROM
      
  // read the ROM
  if (result == OneWireMaster::Success)
    result = OWReadBlock(buf, RomId::byteLen);

  // verify CRC8
  if ((result == OneWireMaster::Success) && (RomId::calculateCRC8(buf, RomId::byteLen) == 0) && (buf[1] != 0))
    romId = RomId(reinterpret_cast<std::uint8_t (&)[RomId::byteLen]>(buf[0]));

  return result;
}

//--------------------------------------------------------------------------
// Use the DS2465 help command '1-Wire triplet' to perform one bit of a 1-Wire
// search. This command does two read bits and one write bit. The write bit
// is either the default direction (all device have same bit) or in case of 
// a discripancy, the 'search_direction' parameter is used. 
//
// Returns – The DS2465 status byte result from the triplet command
//
OneWireMaster::CmdResult DS2465::Triplet(Direction search_direction, uint8_t & status) 
{
  int poll_count = 0;

  // 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
     
  m_I2C_interface.start();
  if (m_I2C_interface.write((unsigned char)(m_I2C_address | I2C_WRITE)) != I2C_WRITE_OK)
  {
     m_I2C_interface.stop();
     return OneWireMaster::CommunicationWriteError;
  }
  if (m_I2C_interface.write(ADDR_CMD_REG) != I2C_WRITE_OK)
  {
     m_I2C_interface.stop();
     return OneWireMaster::CommunicationWriteError;
  }
  if (m_I2C_interface.write(CMD_1WT) != I2C_WRITE_OK)
  {
     m_I2C_interface.stop();
     return OneWireMaster::CommunicationWriteError;
  }
  if (m_I2C_interface.write((unsigned char)((search_direction == DIRECTION_WRITE_ONE) ? 0x80 : 0x00)) != I2C_WRITE_OK)
  {
     m_I2C_interface.stop();
     return OneWireMaster::CommunicationWriteError;
  }
  m_I2C_interface.start();
  if (m_I2C_interface.write((unsigned char)(m_I2C_address | I2C_READ)) != I2C_WRITE_OK)
  {
     m_I2C_interface.stop();
     return OneWireMaster::CommunicationWriteError;
  }

  // loop checking 1WB bit for completion of 1-Wire operation 
  // abort if poll limit reached
  status = STATUS_1WB;
  while ((status & STATUS_1WB) && (poll_count++ < POLL_LIMIT))
  {
     status = m_I2C_interface.read(status & STATUS_1WB);
  }
   
  // one last read with NACK  
  m_I2C_interface.read(m_I2C_interface.NoACK);

  m_I2C_interface.stop();

  // check for failure due to poll limit reached
  if (poll_count >= POLL_LIMIT)
  {
     // handle error
     // ...
     Reset();
     return OneWireMaster::TimeoutError;
  }
 
  // return status byte
  return OneWireMaster::Success;
}

//--------------------------------------------------------------------------
// The 'OWSearch' function does a general search.  This function
// continues from the previos search state. The search state
// can be reset by using the 'OWFirst' function.
// This function contains one parameter 'alarm_only'.
// When 'alarm_only' is true (1) the find alarm command
// 0xEC is sent instead of the normal search command 0xF0.
// Using the find alarm command 0xEC will limit the search to only
// 1-Wire devices that are in an 'alarm' state.
//
// Returns:   true (1) : when a 1-Wire device was found and it's
//                       Serial Number placed in the global ROM 
//            false (0): when no new device was found.  Either the
//                       last search was the last device or there
//                       are no devices on the 1-Wire Net.
//
OneWireMaster::CmdResult DS2465::OWSearch(RomId & romId)
{
   int id_bit_number;
   int last_zero, rom_byte_number;
   int id_bit, cmp_id_bit;
   unsigned char rom_byte_mask, status;
   bool search_result;
   unsigned char crc8 = 0;
   Direction search_direction;

   // initialize for search
   id_bit_number = 1;
   last_zero = 0;
   rom_byte_number = 0;
   rom_byte_mask = 1;
   search_result = false;

   // if the last call was not the last one
   if (!m_lastDeviceFlag)
   {       
      // 1-Wire reset
      OneWireMaster::CmdResult result = OWReset();
      if (result != OneWireMaster::Success)
      {
         // reset the search
         m_lastDiscrepancy = 0;
         m_lastDeviceFlag = false;
         m_lastFamilyDiscrepancy = 0;
         return result;
      }

      // issue the search command 
      OWWriteByte(0xF0);  

      // loop to do the search
      do
      {
         // if this discrepancy if before the Last Discrepancy
         // on a previous next then pick the same as last time
         if (id_bit_number < m_lastDiscrepancy)
         {
            if ((romId[rom_byte_number] & rom_byte_mask) > 0)
               search_direction = DIRECTION_WRITE_ONE;
            else
               search_direction = DIRECTION_WRITE_ZERO;
         }
         else
         {
            // if equal to last pick 1, if not then pick 0
            if (id_bit_number == m_lastDiscrepancy)
               search_direction = DIRECTION_WRITE_ONE;
            else
               search_direction = DIRECTION_WRITE_ZERO;
         }

         // Peform a triple operation on the DS2465 which will perform 2 read bits and 1 write bit
         Triplet(search_direction, status);

         // check bit results in status byte
         id_bit = ((status & STATUS_SBR) == STATUS_SBR);
         cmp_id_bit = ((status & STATUS_TSB) == STATUS_TSB);
         search_direction = ((status & STATUS_DIR) == STATUS_DIR) ? DIRECTION_WRITE_ONE : DIRECTION_WRITE_ZERO;

         // check for no devices on 1-wire
         if ((id_bit) && (cmp_id_bit))
            break;
         else
         {
            if ((!id_bit) && (!cmp_id_bit) && (search_direction == DIRECTION_WRITE_ZERO))
            {
               last_zero = id_bit_number;

               // check for Last discrepancy in family
               if (last_zero < 9)
                  m_lastFamilyDiscrepancy = last_zero;
            }

            // set or clear the bit in the ROM byte rom_byte_number
            // with mask rom_byte_mask
            if (search_direction == DIRECTION_WRITE_ONE)
               romId[rom_byte_number] |= rom_byte_mask;
            else
               romId[rom_byte_number] &= (unsigned char)~rom_byte_mask;

            // increment the byte counter id_bit_number
            // and shift the mask rom_byte_mask
            id_bit_number++;
            rom_byte_mask <<= 1;

            // if the mask is 0 then go to new SerialNum byte rom_byte_number and reset mask
            if (rom_byte_mask == 0)
            {
               crc8 = RomId::calculateCRC8(crc8, romId[rom_byte_number]);  // accumulate the CRC
               rom_byte_number++;
               rom_byte_mask = 1;
            }
         }
      }
      while(rom_byte_number < RomId::byteLen);  // loop until through all ROM bytes 0-7

      // if the search was successful then
      if (!((id_bit_number <= (RomId::byteLen * 8)) || (crc8 != 0)))
      {
         // search successful so set m_lastDiscrepancy,m_lastDeviceFlag,search_result
         m_lastDiscrepancy = last_zero;

         // check for last device
         if (m_lastDiscrepancy == 0)
            m_lastDeviceFlag = true;

         search_result = true;
      }
   }

   // if no device found then reset counters so next 'search' will be like a first
   if (!search_result || (romId.familyCode() == 0))
   {
      m_lastDiscrepancy = 0;
      m_lastDeviceFlag = false;
      m_lastFamilyDiscrepancy = 0;
      search_result = false;
   }

   return search_result ? OneWireMaster::Success : OneWireMaster::OperationFailure;
}

//--------------------------------------------------------------------------
// Find the 'first' devices on the 1-Wire network
// Return true  : device found, ROM number in ROM_NO buffer
//        false : no device present
//
OneWireMaster::CmdResult DS2465::OWFirst(RomId & romId)		
{
   // reset the search state
   m_lastDiscrepancy = 0;
   m_lastDeviceFlag = false;
   m_lastFamilyDiscrepancy = 0;

   return OWSearch(romId);
}

//--------------------------------------------------------------------------
// The 'OWReadBlock' receives a block of data from the
// 1-Wire Net. The destination is the mac buffer (rx_mac=1) or 
// the scratchpad (rx_mac=0). The result is buffer is returned. 
//
// 'rx_buf'   - pointer to a block to receive bytes
//              of length 'rx_len' from 1-Wire Net
// 'rx_len' - length in bytes to read. Only valid numbers are 8,16,20,32;
//
OneWireMaster::CmdResult DS2465::OWReadBlock(uint8_t *rx_buf, uint8_t rx_len)	
{
  uint8_t status;
  int poll_count = 0;
  OneWireMaster::CmdResult result;

  // 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
   
  m_I2C_interface.start();
  if (m_I2C_interface.write((unsigned char)(m_I2C_address | I2C_WRITE)) != I2C_WRITE_OK)
  {
     m_I2C_interface.stop();
     return OneWireMaster::CommunicationWriteError;
  }
  if (m_I2C_interface.write(ADDR_CMD_REG) != I2C_WRITE_OK)
  {
     m_I2C_interface.stop();
     return OneWireMaster::CommunicationWriteError;
  }
  if (m_I2C_interface.write(CMD_1WRF) != I2C_WRITE_OK)
  {
     m_I2C_interface.stop();
     return OneWireMaster::CommunicationWriteError;
  }
  if (m_I2C_interface.write((unsigned char)rx_len) != I2C_WRITE_OK)
  {
     m_I2C_interface.stop();
     return OneWireMaster::CommunicationWriteError;
  }
  m_I2C_interface.stop();
  status = STATUS_1WB;
   
   // loop checking 1WB bit for completion of 1-Wire operation 
   // abort if poll limit reached
   while ((status & STATUS_1WB) && (poll_count++ < POLL_LIMIT))
   {
      result = ReadMemory(ADDR_STATUS_REG, &status, 1, false);
      if (result != OneWireMaster::Success)
        return result;
   }

   // check for failure due to poll limit reached
   if (poll_count >= POLL_LIMIT)
   {
      // handle error
      // ...
      //Reset();
      return OneWireMaster::TimeoutError;
   }

   result = ReadMemory(ADDR_SPAD, rx_buf, rx_len, false);

   // read out the data
   return result;
}




OneWireMaster::CmdResult DS2465::OWWriteBlock(const uint8_t *tran_buf, uint8_t tran_len)
{
  return OWWriteBlock(false, tran_buf, tran_len);
}

//--------------------------------------------------------------------------
// The 'OWWriteBlock' transfers a block of data to the
// 1-Wire Net. The mac buffer can be sent (tx_mac=1) or a
// portion of the scratchpad can be sent. 
//
// 'tx_mac'   - flag to indicate if the MAC buffer is to be sent (1) or
//              the data provided in teh tran_buf is to be sent (0)
// 'tran_buf' - pointer to a block of bytes
//              of length 'tran_len' that will be sent
//              to the 1-Wire Net
// 'tran_len' - length in bytes to transfer. Only valid numbers are 8,16,20,32;
//
OneWireMaster::CmdResult DS2465::OWWriteBlock(bool tx_mac, const uint8_t *tran_buf, uint8_t tran_len)
{
  OneWireMaster::CmdResult result;
  uint8_t par, status;
  int poll_count = 0;

  // create parameter byte
  if (tx_mac)
    par = 0xFF;
  else
  {
    // scratchpad is source
    par = tran_len; 

    // prefill scratchpad with required data
    result = WriteScratchpad(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

  m_I2C_interface.start();
  if (m_I2C_interface.write((unsigned char)(m_I2C_address | I2C_WRITE)) != I2C_WRITE_OK)
  {
    m_I2C_interface.stop();
    return OneWireMaster::CommunicationWriteError;
  }
  if (m_I2C_interface.write(ADDR_CMD_REG) != I2C_WRITE_OK)
  {
    m_I2C_interface.stop();
    return OneWireMaster::CommunicationWriteError;
  }
  if (m_I2C_interface.write(CMD_1WTB) != I2C_WRITE_OK)
  {
    m_I2C_interface.stop();
    return OneWireMaster::CommunicationWriteError;
  }
  if (m_I2C_interface.write(par) != I2C_WRITE_OK)
  {
    m_I2C_interface.stop();
    return OneWireMaster::CommunicationWriteError;
  }
  m_I2C_interface.stop();

  // loop checking 1WB bit for completion of 1-Wire operation 
  // abort if poll limit reached
  status = STATUS_1WB;
  while ((status & STATUS_1WB) && (poll_count++ < POLL_LIMIT))
  {
    result = ReadMemory(ADDR_STATUS_REG, &status, 1, false);
    if (result != OneWireMaster::Success)
      return result;
  }

  // check for failure due to poll limit reached
  if (poll_count >= POLL_LIMIT)
  {
    // handle error
    // ...
    //Reset();
    return OneWireMaster::TimeoutError;
  }

  return OneWireMaster::Success;
}

//--------------------------------------------------------------------------
// The 'OWBlock' transfers a block of data to and from the
// 1-Wire Net. The result is returned in the same buffer.
//
// 'tran_buf' - pointer to a block of unsigned
//              chars of length 'tran_len' that will be sent
//              to the 1-Wire Net
// 'tran_len' - length in bytes to transfer
//
OneWireMaster::CmdResult DS2465::OWBlock(uint8_t *tran_buf, uint8_t tran_len)
{
  OneWireMaster::CmdResult result;
  for (uint8_t i = 0; i < tran_len; i++)
  {
    result = OWTouchByte(tran_buf[i]);
    if (result != OneWireMaster::Success)
      break;
  }
  return result;
}

//--------------------------------------------------------------------------
// Send 8 bits of communication to the 1-Wire Net and return the
// result 8 bits read from the 1-Wire Net.  The parameter 'sendbyte'
// least significant 8 bits are used and the least significant 8 bits
// of the result is the return byte.
//
// 'sendbyte' - 8 bits to send (least significant byte)
//
// Returns:  8 bits read from sendbyte
//
OneWireMaster::CmdResult DS2465::OWTouchByte(uint8_t & sendrecvbyte)
{
  OneWireMaster::CmdResult result = OWWriteByte(sendrecvbyte);
  if (result == OneWireMaster::Success)
    OWReadByte(sendrecvbyte);
  return result;
}

//--------------------------------------------------------------------------
// Send 8 bits of read communication to the 1-Wire Net and return the
// result 8 bits read from the 1-Wire Net.
//
// Returns:  8 bits read from 1-Wire Net
//
OneWireMaster::CmdResult DS2465::OWReadByte(uint8_t & recvbyte)	
{
   uint8_t status;
   int poll_count = 0;

   // 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
   
  m_I2C_interface.start();
  if (m_I2C_interface.write((unsigned char)(m_I2C_address | I2C_WRITE)) != I2C_WRITE_OK)
  {
     m_I2C_interface.stop();
     return OneWireMaster::CommunicationWriteError;
  }
  if (m_I2C_interface.write(ADDR_CMD_REG) != I2C_WRITE_OK)
  {
     m_I2C_interface.stop();
     return OneWireMaster::CommunicationWriteError;
  }
  if (m_I2C_interface.write(CMD_1WRB) != I2C_WRITE_OK)
  {
     m_I2C_interface.stop();
     return OneWireMaster::CommunicationWriteError;
  }
  m_I2C_interface.start();
  if (m_I2C_interface.write((unsigned char)(m_I2C_address | I2C_READ)) != I2C_WRITE_OK)
     return OneWireMaster::CommunicationWriteError;

  // loop checking 1WB bit for completion of 1-Wire operation 
  // abort if poll limit reached
  status = STATUS_1WB;
  while ((status & STATUS_1WB) && (poll_count++ < POLL_LIMIT))
  {
     status = m_I2C_interface.read(m_I2C_interface.ACK);
  }

  // one last read with NACK
  m_I2C_interface.read(m_I2C_interface.NoACK);

  // check for failure due to poll limit reached
  if (poll_count >= POLL_LIMIT)
  {
     // handle error
     // ...
     //Reset();
     return OneWireMaster::TimeoutError;
  }

  m_I2C_interface.start();
  if (m_I2C_interface.write((unsigned char)(m_I2C_address | I2C_WRITE)) != I2C_WRITE_OK)
  {
     m_I2C_interface.stop();
     return OneWireMaster::CommunicationWriteError;
  }
  if (m_I2C_interface.write(ADDR_DATA_REG) != I2C_WRITE_OK)
  {
     m_I2C_interface.stop();
     return OneWireMaster::CommunicationWriteError;
  }
  m_I2C_interface.start();
  if (m_I2C_interface.write((unsigned char)(m_I2C_address | I2C_READ)) != I2C_WRITE_OK)
  {
     m_I2C_interface.stop();
     return OneWireMaster::CommunicationWriteError;
  }
  recvbyte = m_I2C_interface.read(m_I2C_interface.NoACK);
  
  m_I2C_interface.stop();
   
  return OneWireMaster::Success;
}

//--------------------------------------------------------------------------
// Send 8 bits of communication to the 1-Wire Net and verify that the
// 8 bits read from the 1-Wire Net is the same (write operation).
// The parameter 'sendbyte' least significant 8 bits are used.
//
// 'sendbyte' - 8 bits to send (least significant byte)
//
// Returns:  true: bytes written and echo was the same
//           false: echo was not the same
//
OneWireMaster::CmdResult DS2465::OWWriteByte(uint8_t sendbyte)	
{
  uint8_t status;
  int poll_count = 0;
    
  // 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
   
  m_I2C_interface.start();
  if (m_I2C_interface.write((unsigned char)(m_I2C_address | I2C_WRITE)) != I2C_WRITE_OK)
  {
     m_I2C_interface.stop();
     return OneWireMaster::CommunicationWriteError;
  }
  if (m_I2C_interface.write(ADDR_CMD_REG) != I2C_WRITE_OK)
  {
     m_I2C_interface.stop();
     return OneWireMaster::CommunicationWriteError;
  }
  if (m_I2C_interface.write(CMD_1WWB) != I2C_WRITE_OK)
  {
     m_I2C_interface.stop();
     return OneWireMaster::CommunicationWriteError;
  }
  if (m_I2C_interface.write(sendbyte) != I2C_WRITE_OK)
  {
     m_I2C_interface.stop();
     return OneWireMaster::CommunicationWriteError;
  }

  m_I2C_interface.start();
  if (m_I2C_interface.write((unsigned char)(m_I2C_address | I2C_READ)) != I2C_WRITE_OK)
  {
     m_I2C_interface.stop();
     return OneWireMaster::CommunicationWriteError;
  }

  // loop checking 1WB bit for completion of 1-Wire operation 
  // abort if poll limit reached
  status = STATUS_1WB;
  while ((status & STATUS_1WB) && (poll_count++ < POLL_LIMIT))
  {
     status = m_I2C_interface.read(m_I2C_interface.ACK);
  }

  // one last read with NACK
  m_I2C_interface.read(m_I2C_interface.NoACK);

  m_I2C_interface.stop();

  // check for failure due to poll limit reached
  if (poll_count >= POLL_LIMIT)
  {
     // handle error
     // ...
     //Reset();
    return OneWireMaster::TimeoutError;
  }
  
  return OneWireMaster::Success;
}

//--------------------------------------------------------------------------
// Send 1 bit of communication to the 1-Wire Net and return the
// result 1 bit read from the 1-Wire Net.  The parameter 'sendbit'
// least significant bit is used and the least significant bit
// of the result is the return bit.
//
// 'sendbit' - the least significant bit is the bit to send
//
// Returns: 0:   0 bit read from sendbit
//          1:   1 bit read from sendbit
//
OneWireMaster::CmdResult DS2465::OWTouchBit(uint8_t & sendrecvbit)	
{
  unsigned char status;
  int poll_count = 0;

  // 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
   
  m_I2C_interface.start();
  if (m_I2C_interface.write((unsigned char)(m_I2C_address | I2C_WRITE)) != I2C_WRITE_OK)
  {
   m_I2C_interface.stop();
   return OneWireMaster::CommunicationWriteError;
  }
  if (m_I2C_interface.write(ADDR_CMD_REG) != I2C_WRITE_OK)
  {
   m_I2C_interface.stop();
   return OneWireMaster::CommunicationWriteError;
  }
  if (m_I2C_interface.write(CMD_1WSB) != I2C_WRITE_OK)
  {
   m_I2C_interface.stop();
   return OneWireMaster::CommunicationWriteError;
  }
  if (m_I2C_interface.write(sendrecvbit ? 0x80 : 0x00) != 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 checking 1WB bit for completion of 1-Wire operation 
  // abort if poll limit reached
  status = STATUS_1WB;
  while ((status & STATUS_1WB) && (poll_count++ < POLL_LIMIT))
  {
    status = m_I2C_interface.read(status & STATUS_1WB);
  }

  // one last read with NACK
  m_I2C_interface.read(m_I2C_interface.NoACK);

  m_I2C_interface.stop();

  // check for failure due to poll limit reached
  if (poll_count >= POLL_LIMIT)
  {
   // handle error
   // ...
   //Reset();
   return OneWireMaster::TimeoutError;
  }
 
  // check bit state
  sendrecvbit = (status & STATUS_SBR);
  
  return OneWireMaster::Success;
}

//--------------------------------------------------------------------------
// Reads 1 bit of communication from the 1-Wire Net and returns the
// result
//
// Returns:  1 bit read from 1-Wire Net
//
OneWireMaster::CmdResult DS2465::OWReadBit(uint8_t & recvbit)
{
   recvbit = 0x01;
   return OWTouchBit(recvbit);
}

//--------------------------------------------------------------------------
// Send 1 bit of communication to the 1-Wire Net.
// The parameter 'sendbit' least significant bit is used.
//
// 'sendbit' - 1 bit to send (least significant byte)
//
OneWireMaster::CmdResult DS2465::OWWriteBit(uint8_t sendbit) 
{
   return OWTouchBit(sendbit);
}

//--------------------------------------------------------------------------
// 
//
// 
// 
// 
// 
//
// Returns: 
//          
//
OneWireMaster::CmdResult DS2465::Write_Command_Reg(unsigned char cmd, unsigned char par, bool poll) const
{
  int poll_count = 0, status;
 
  // Generic command
  //   S AD,0 [A] ADDR_CMD_REG [A] CMD [A] PP [A]  P
  //  [] indicates from slave
  //  CMD command
  //  PP parameter 

  m_I2C_interface.start();
  if (m_I2C_interface.write((unsigned char)(m_I2C_address | I2C_WRITE)) != I2C_WRITE_OK)
  {
     m_I2C_interface.stop();
     return OneWireMaster::CommunicationWriteError;
  }
  if (m_I2C_interface.write(ADDR_CMD_REG) != I2C_WRITE_OK)
  {
     m_I2C_interface.stop();
     return OneWireMaster::CommunicationWriteError;
  }
  if (m_I2C_interface.write(cmd) != I2C_WRITE_OK)
  {
     m_I2C_interface.stop();
     return OneWireMaster::CommunicationWriteError;
  }
  if (m_I2C_interface.write(par) != I2C_WRITE_OK)
  {
     m_I2C_interface.stop();
     return OneWireMaster::CommunicationWriteError;
  }

  m_I2C_interface.stop();
   
  poll_count = 0;
  if (poll)
  {
    // Poll for completion by checking for NAK on address
    do
    {
       m_I2C_interface.start();
       status = m_I2C_interface.write((unsigned char)(m_I2C_address | I2C_WRITE));
       m_I2C_interface.stop();
    } while ((status != I2C_WRITE_OK) && (poll_count++ < POLL_LIMIT));
  }
  else
  {  
    // delay instead of poll, longest operation (only for SHA compute)
    wait_ms(SHA_COMPUTATION_DELAY * 2); 
    wait_ms(8); // Additional delay
  }

  // check for failure due to poll limit reached
  if (poll_count >= POLL_LIMIT)
  {
    // handle error
    // ...
    //Reset();
    return OneWireMaster::TimeoutError;
  }

  return OneWireMaster::Success;
}

//--------------------------------------------------------------------------
// Write to Scratchpad (SRAM) memory on the DS2465
//
// 'addr' - address to start writing (must be in SRAM)
// 'buf' - buffer of data to write
// 'len' - length to write
//
// Returns: true write successful
//          false failure to complete write
//
OneWireMaster::CmdResult DS2465::WriteScratchpad(std::uint8_t addr, const std::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((unsigned char)(m_I2C_address | I2C_WRITE)) != I2C_WRITE_OK)
  {
     m_I2C_interface.stop();
     return OneWireMaster::CommunicationWriteError;
  }
  if (m_I2C_interface.write((unsigned char)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;
}

//--------------------------------------------------------------------------
// Read memory from the DS2465
//
// 'addr' - address to start reading
// 'buf' - buffer to hold memory read
// 'len' - length to read
// 'skip_set_pointer' - flag to indicate to skip setting address pointer
//
// Returns: true read successful
//          false failure to complete read
//
OneWireMaster::CmdResult DS2465::ReadMemory(std::uint8_t addr, std::uint8_t * buf, size_t bufLen, bool skip_set_pointer) 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 (!skip_set_pointer)
      {
         if (m_I2C_interface.write((unsigned char)(m_I2C_address | I2C_WRITE)) != I2C_WRITE_OK)
         {
            m_I2C_interface.stop();
            return OneWireMaster::CommunicationWriteError;
         }
         if (m_I2C_interface.write((unsigned char)addr) != I2C_WRITE_OK)
         {
            m_I2C_interface.stop();
            return OneWireMaster::CommunicationWriteError;
         }
         m_I2C_interface.start();
      }

      if (m_I2C_interface.write((unsigned char)(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)) ? m_I2C_interface.NoACK : m_I2C_interface.ACK);
      }
      m_I2C_interface.stop();
  
   return OneWireMaster::Success;
}





OneWireMaster::CmdResult DS2465::ReadOneWireConfig(OWConfigAddr addr, std::uint8_t & config) const
{
  std::uint8_t buf;
  OneWireMaster::CmdResult result = ReadMemory(addr, &buf, 1, false);
  if (result == OneWireMaster::Success)
    config = buf;
  return result;
}





OneWireMaster::CmdResult DS2465::WriteOneWireConfig(OWConfigAddr addr, unsigned int ovr, unsigned int std)
{
  std::uint8_t buf;

   // convert and write value
   buf = (ovr << 4) | std;
   return (WriteScratchpad(addr, &buf, 1));
}

//--------------------------------------------------------------------------
// Write the configuration register in the DS2465. The configuration 
// options are provided in the lower nibble of the provided config byte. 
// The uppper nibble in bitwise inverted when written to the DS2465.
//  
// Returns:  true: config written and response correct
//           false: response incorrect
//
OneWireMaster::CmdResult DS2465::Write_Config(uint8_t config)
{
  unsigned char read_config;
   
  // Write configuration byte
  //   S AD,0 [A] ADDR_WCFG_REG [A] CONIG [A] P
  //  [] indicates from slave
  //  CF configuration byte to write

  m_I2C_interface.start();
  
  if (m_I2C_interface.write((unsigned char)(m_I2C_address | I2C_WRITE)) != I2C_WRITE_OK)
  {
     m_I2C_interface.stop();
     return OneWireMaster::CommunicationWriteError;
  }
  if (m_I2C_interface.write(ADDR_WCFG_REG) != I2C_WRITE_OK)
  {
     m_I2C_interface.stop();
     return OneWireMaster::CommunicationWriteError;
  }
  if (m_I2C_interface.write((unsigned char)(config | (~config << 4))) != I2C_WRITE_OK)
  {
     m_I2C_interface.stop();
     return OneWireMaster::CommunicationWriteError;
  }
  m_I2C_interface.stop();

  // read it back to confirm
  // S AD,0 [A] ADDR_WCFG_REG [A] Sr AD,1 [A] [CF] A\ 

  m_I2C_interface.start();
  if (m_I2C_interface.write((unsigned char)(m_I2C_address | I2C_WRITE)) != I2C_WRITE_OK)
  {
     m_I2C_interface.stop();
     return OneWireMaster::CommunicationWriteError;
  }
  if (m_I2C_interface.write(ADDR_WCFG_REG) != I2C_WRITE_OK)
  {
     m_I2C_interface.stop();
     return OneWireMaster::CommunicationWriteError;
  }
  m_I2C_interface.start();
  if (m_I2C_interface.write((unsigned char)(m_I2C_address | I2C_READ)) != I2C_WRITE_OK)
  {
     m_I2C_interface.stop();
     return OneWireMaster::CommunicationWriteError;
  }
  read_config = m_I2C_interface.read(m_I2C_interface.NoACK);
  m_I2C_interface.stop();
   

   // check for failure due to incorrect read back
   if (config != read_config)
   {
      // handle error
      // ...
      //Reset();

      return OneWireMaster::TimeoutError;  
   }
   
   return OneWireMaster::Success;
}

//--------------------------------------------------------------------------
// Reset all of the devices on the 1-Wire Net and return the result.
//
// Returns: true(1):  presense pulse(s) detected, device(s) reset
//          false(0): no presense pulses detected
//
OneWireMaster::CmdResult DS2465::OWReset(void)
{
   unsigned char status;
   int poll_count = 0;
     
   // 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
   
    m_I2C_interface.start();
    
    if (m_I2C_interface.write((unsigned char)(m_I2C_address | I2C_WRITE)) != I2C_WRITE_OK)
    {
       m_I2C_interface.stop();
       return OneWireMaster::CommunicationWriteError;
    }
    if (m_I2C_interface.write(ADDR_CMD_REG) != I2C_WRITE_OK)
    {
       m_I2C_interface.stop();
       return OneWireMaster::CommunicationWriteError;
    }
    if (m_I2C_interface.write(CMD_1WRS) != I2C_WRITE_OK)
    {
      m_I2C_interface.stop();
       return OneWireMaster::CommunicationWriteError;
    }
    m_I2C_interface.start();
    if (m_I2C_interface.write((unsigned char)(m_I2C_address | I2C_READ)) != I2C_WRITE_OK)
    {
       m_I2C_interface.stop();
       return OneWireMaster::CommunicationWriteError;
    }

    // loop checking 1WB bit for completion of 1-Wire operation 
    // abort if poll limit reached
    status = STATUS_1WB;
    while ((status & STATUS_1WB) && (poll_count++ < POLL_LIMIT))
    {
       status = m_I2C_interface.read(m_I2C_interface.ACK);
    }

    // one last read with NACK
    m_I2C_interface.read(m_I2C_interface.NoACK);

    m_I2C_interface.stop();

    // check for failure due to poll limit reached
    if (poll_count >= POLL_LIMIT)
    {
       // handle error
       // ...
       //Reset();
       return OneWireMaster::TimeoutError;
    }
   
   // check for short condition
   if (status & STATUS_SD)
      short_detected = true;
   else
      short_detected = false;
   

   // check for presence detect
   if (status & STATUS_PPD)
      return OneWireMaster::Success;
   // else
   return OneWireMaster::OperationFailure;
}

OneWireMaster::CmdResult DS2465::Reset(void)
{
  uint8_t status;
  
  // 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
  
  m_I2C_interface.start(); 
  
  if (m_I2C_interface.write((unsigned char)(m_I2C_address | I2C_WRITE)) != I2C_WRITE_OK)
  {
    m_I2C_interface.stop();
    return OneWireMaster::CommunicationWriteError;
  }
  
  if (m_I2C_interface.write(ADDR_CMD_REG) != I2C_WRITE_OK)
  {
     m_I2C_interface.stop();
     return OneWireMaster::CommunicationWriteError;
  }
  
  if (m_I2C_interface.write(CMD_1WMR) != I2C_WRITE_OK)
  {
     m_I2C_interface.stop();
     return OneWireMaster::CommunicationWriteError;
  }
  
  m_I2C_interface.start();
  
  if (m_I2C_interface.write((unsigned char)(m_I2C_address | I2C_READ)) != I2C_WRITE_OK)
  {
     m_I2C_interface.stop();
     return OneWireMaster::CommunicationWriteError;
  }
 
  status = m_I2C_interface.read(m_I2C_interface.NoACK);

  m_I2C_interface.stop();
      
  // do a command to get 1-Wire master reset out of holding state
  OWReset();

  // check for failure due to incorrect read back of status
  return ((status & 0xF7) == 0x10) ? OneWireMaster::Success : OneWireMaster::OperationFailure;
}

OneWireMaster::CmdResult DS2465::Detect(void)
{
  OneWireMaster::CmdResult result;
  
  // reset DS2465 
  result = Reset();
  if (result != OneWireMaster::Success)
    return result;
  
  // default configuration
   c1WS = 0;
   cSPU = 0;
   cPDN = 0;
   cAPU = CONFIG_APU;

   // write the default configuration setup
   result = Write_Config(c1WS | cSPU | cPDN | cAPU);
   return result;
}