Implementation of 1-Wire with added Alarm Search Functionality

Dependents:   Max32630_One_Wire_Interface

OneWire_Memory/Authenticators/DS28E15_22_25/DS28E15_22_25.cpp

Committer:
IanBenzMaxim
Date:
2016-03-22
Revision:
25:bdb1c5a53b58
Child:
27:d5aaefa252f1

File content as of revision 25:bdb1c5a53b58:

//------------Copyright (C) 2013 Maxim Integrated Products --------------
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY,  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
// IN NO EVENT SHALL MAXIM INTEGRATED PRODCUTS BE LIABLE FOR ANY CLAIM, DAMAGES
// OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
// OTHER DEALINGS IN THE SOFTWARE.
//
// Except as contained in this notice, the name of Maxim Integrated Products
// shall not be used except as stated in the Maxim Integrated Products
// Branding Policy.
// ---------------------------------------------------------------------------

#include "DS28E15_22_25.hpp"
#include "mbed.h"

// delay durations
#ifdef LOW_VOLTAGE
#define SHA_COMPUTATION_DELAY    4   
#define EEPROM_WRITE_DELAY       15  
#define SECRET_EEPROM_DELAY      200
#else
#define SHA_COMPUTATION_DELAY    3   
#define EEPROM_WRITE_DELAY       10  
#define SECRET_EEPROM_DELAY      90
#endif

// 1-Wire commands
#define CMD_WRITE_MEMORY         0x55
#define CMD_READ_MEMORY          0xF0
#define CMD_LOAD_LOCK_SECRET     0x33
#define CMD_COMPUTE_LOCK_SECRET  0x3C
#define CMD_SELECT_SECRET        0x0F
#define CMD_COMPUTE_PAGEMAC      0xA5
#define CMD_READ_STATUS          0xAA
#define CMD_WRITE_BLOCK_PROTECT  0xC3
#define CMD_WRITE_AUTH_MEMORY    0x5A
#define CMD_WRITE_AUTH_PROTECT   0xCC
#define CMD_PIO_READ             0xDD
#define CMD_PIO_WRITE            0x96

#define BLOCK_READ_PROTECT       0x80
#define BLOCK_WRITE_PROTECT      0x40
#define BLOCK_EPROM_PROTECT      0x20
#define BLOCK_WRITE_AUTH_PROTECT 0x10

#define PROT_BIT_AUTHWRITE 0x10
#define PROT_BIT_EPROM     0x20
#define PROT_BIT_WRITE     0x40
#define PROT_BIT_READ      0x80

DS28E15_22_25::DS28E15_22_25(OneWireMaster& OW_master)
  : m_OW_master(OW_master)
{
  std::memset(manId, 0x00, manIdLen);
}

DS28E15_22_25::DevicePages DS28E15_22_25::devicePages()
{
  DevicePages pages;
  
  switch (romId.familyCode())
  {
  case DS28E25_FAMILY:
    pages = DS28E25_PAGES;
    break;
    
  case DS28E22_FAMILY:
    pages = DS28E22_PAGES;
    break;
    
  case DS28E15_FAMILY:
    pages = DS28E15_PAGES;
    break;
    
  default:
    pages = UNKNOWN_PAGES;
    break;
  }
  
  return pages;
}

DS28E15_22_25::DeviceBlocks DS28E15_22_25::deviceBlocks()
{
  DeviceBlocks blocks;
  
  switch (romId.familyCode())
  {
  case DS28E25_FAMILY:
    blocks = DS28E25_BLOCKS;
    break;
    
  case DS28E22_FAMILY:
    blocks = DS28E22_BLOCKS;
    break;
    
  case DS28E15_FAMILY:
    blocks = DS28E15_BLOCKS;
    break;
    
  default:
    blocks = UNKNOWN_BLOCKS;
    break;
  }
  
  return blocks;
}

//--------------------------------------------------------------------------
//  Write page protection byte. 
// 
//  Parameters
//     block - block number (0 to 7) which covers two pages each
//     new_value - new protection byte
//     old_value - old protection byte
//     manid - manufacturer ID
//     contflag - Flag to indicate the write is continued from the last
//
//  Returns: true - protection written
//           false - Failed to set protection
//
OneWireSlave::CmdResult DS28E15_22_25::WriteAuthBlockProtection(const ISha256MacCoprocessor & MacCoproc, std::uint8_t newProtection, std::uint8_t oldProtection, bool contflag)	
{
   std::uint8_t buf[256], cs;
   int cnt = 0;

   buf[cnt++] = CMD_WRITE_AUTH_PROTECT;
   buf[cnt++] = newProtection;

   // Send command
   m_OW_master.OWWriteBlock(&buf[0], 2);

   // read first CRC byte
   m_OW_master.OWReadByte(buf[cnt++]);

   // read the last CRC and enable
   m_OW_master.OWReadBytePower(buf[cnt++]);

   // now wait for the MAC computation.
   wait_ms(SHA_COMPUTATION_DELAY);

   // disable strong pullup
   m_OW_master.OWLevel(OneWireMaster::LEVEL_NORMAL);
   
   // check CRC16
   if (OneWireMaster::calculateCRC16(buf, 0, cnt) != 0xB001)
      return CommunicationError;

   ISha256MacCoprocessor::CmdResult result;
   result = CalculateProtectionWriteMAC256(MacCoproc, newProtection, oldProtection, romId, manId, reinterpret_cast<std::uint8_t (&)[macLen]>(buf));
   if (result != ISha256MacCoprocessor::Success)
     return OperationFailure;
   cnt = macLen;

   // send the MAC
   m_OW_master.OWWriteBlock(&buf[0], macLen);

   // Read CRC and CS byte
   m_OW_master.OWReadBlock(&buf[cnt], 3);
   cnt += 3;

   // ckeck CRC16
   if (OneWireMaster::calculateCRC16(buf, 0, (cnt - 1)) != 0xB001)
      return CommunicationError;

   // check CS
   if (buf[cnt-1] != 0xAA)
      return OperationFailure;
   
   // send release and strong pull-up
   // DATASHEET_CORRECTION - last bit in release is a read-zero so don't check echo of write byte
   m_OW_master.OWWriteBytePower(0xAA);

   // now wait for the MAC computation.
   wait_ms(EEPROM_WRITE_DELAY);

   // disable strong pullup
   m_OW_master.OWLevel(OneWireMaster::LEVEL_NORMAL);

   // read the CS byte
   m_OW_master.OWReadByte(cs);

   if (cs == 0xAA)
     return Success;
   // else
   return OperationFailure;
}

//--------------------------------------------------------------------------
//  Write page protection byte. 
// 
//  Parameters
//     block - block number (0 to 7) which covers two pages each
//     prot - protection byte
//     contflag - Flag to indicate the write is continued from the last
//
//  Returns: true - protection written
//           false - Failed to set protection
//
OneWireSlave::CmdResult DS28E15_22_25::WriteBlockProtection(std::uint8_t protection, bool continuing)	
{
   std::uint8_t buf[256], cs;
   int cnt = 0;

   // check if not continuing a previous block write
   if (!continuing)
   {
      buf[cnt++] = CMD_WRITE_BLOCK_PROTECT;
   }

   // compute parameter byte 
   buf[cnt++] = protection;

   m_OW_master.OWWriteBlock(&buf[0], cnt);

   // Read CRC
   m_OW_master.OWReadBlock(&buf[cnt], 2);
   cnt += 2;

   // check CRC16
   if (OneWireMaster::calculateCRC16(buf, 0, cnt) != 0xB001)
      return CommunicationError;

   // DATASHEET_CORRECTION, on continue need second release byte    
   if (continuing)
      m_OW_master.OWWriteByte(0xAA);

   // sent release
   m_OW_master.OWWriteBytePower(0xAA);

   // now wait for programming
   wait_ms(EEPROM_WRITE_DELAY);

   // disable strong pullup
   m_OW_master.OWLevel(OneWireMaster::LEVEL_NORMAL);

   // read the CS byte
   m_OW_master.OWReadByte(cs);

   if (cs == 0xAA)
     return Success;
   // else
   return OperationFailure;
}




OneWireSlave::CmdResult DS28E15_22_25::ReadBlockProtectionStatus(unsigned int blockNum, std::uint8_t & status)
{
  unsigned char buf;
  CmdResult result = ReadStatus(false, false, blockNum, &buf);
  if (result == Success)
    status = buf;
  return result;
}

//--------------------------------------------------------------------------
//  Read status bytes, either personality or page protection. 
// 
//  Parameters
//     personality - flag to indicate the read is the 4 personality bytes (true)
//                  or page page protection (false)
//     allpages - flag to indicate if just one page (false) or all (true) page protection 
//                 bytes. 
//     page_num - page number if reading protection 0 to 1
//     rdbuf - 16 byte buffer personality bytes (length 4) or page protection 
//            (length 1 or 16) 
//
//  Returns: true - status read
//           false - Failed to read status
//
OneWireSlave::CmdResult DS28E15_22_25::ReadStatus(bool personality, bool allpages, unsigned int pageNum, unsigned char *rdbuf) const
{
   unsigned char buf[256];
   int cnt, offset, rdnum;

   cnt = 0;
   offset = 0;

   buf[cnt++] = CMD_READ_STATUS;   
   if (personality)
      buf[cnt++] = 0xE0;
   else if (!allpages)
      buf[cnt++] = pageNum;
   else
      buf[cnt++] = 0;  

   // send the command
   m_OW_master.OWWriteBlock(&buf[0], 2);

   offset = cnt + 2;

   // adjust data length
   if ((romId.familyCode() == DS28E25_FAMILY) || (romId.familyCode() == DS28E22_FAMILY))
   {
      if (personality)
         rdnum = 8;
      else if (allpages)
         rdnum = 20;
      else
         rdnum = 5;
   }
   else
   {
      if ((personality) || (allpages))
         rdnum = 8;
      else
         rdnum = 5;
   }

   // Read the bytes 
   m_OW_master.OWReadBlock(&buf[cnt],rdnum);
   cnt += rdnum;

   // check the first CRC16
   if (OneWireMaster::calculateCRC16(buf, 0, offset) != 0xB001)
      return CommunicationError;

   if ((((romId.familyCode() == DS28E25_FAMILY) || (romId.familyCode() == DS28E22_FAMILY)) 
        && (allpages || (pageNum == 15))) ||
       (personality || allpages || (pageNum == 1)))
   {
      // check the second CRC16
      if (OneWireMaster::calculateCRC16(buf, offset, (cnt - offset)) != 0xB001)
         return CommunicationError;
   }

   // copy the data to the read buffer
   memcpy(rdbuf, &buf[offset], rdnum - 4);

   return Success;
}




ISha256MacCoprocessor::CmdResult DS28E15_22_25::CalculateAuthMAC256(const ISha256MacCoprocessor & MacCoproc, unsigned int pageNum, const std::uint8_t (&challenge)[scratchpadSize], const std::uint8_t (&pageData)[pageSize], const RomId & romId, const std::uint8_t (&manId)[manIdLen], bool anon, std::uint8_t (&mac)[macLen])
{
   std::uint8_t pageBuf[pageSize], challengeBuf[scratchpadSize], AuthMAC_data[ISha256MacCoprocessor::AuthMAC_data_len];

   // insert page data
   std::memcpy(pageBuf, pageData, pageSize);

   // insert challenge
   std::memcpy(challengeBuf, challenge, scratchpadSize);
   
   // insert ROM number or FF
   if (anon)
     std::memset(AuthMAC_data, 0xFF, RomId::byteLen);
   else
     std::memcpy(AuthMAC_data, romId, RomId::byteLen);

   AuthMAC_data[10] = pageNum;

   AuthMAC_data[9] = manId[0];
   AuthMAC_data[8] = manId[1];
   
   AuthMAC_data[11] = 0x00;

   return MacCoproc.ComputeAndRead_AuthMAC(pageBuf, challengeBuf, AuthMAC_data, mac);
}

//--------------------------------------------------------------------------
//  Verify provided MAC and page data. Optionally do
//  annonymous mode (anon != 0). 
// 
//  Parameters
//     page_num - page number to read 0 - 16
//     challange - 32 byte buffer containing the challenge
//     page_data - 32 byte buffer to contain the data read
//     manid - 2 byte buffer containing the manufacturer ID (general device: 00h,00h)
//     mac - 32 byte buffer of mac read
//     anon - Flag to indicate Annonymous mode
//
//  Returns: true - page read has correct MAC
//           false - Failed to read page or incorrect MAC
//
ISha256MacCoprocessor::CmdResult DS28E15_22_25::AuthVerify(const ISha256MacCoprocessor & MacCoproc, unsigned int page_num, const std::uint8_t (&challenge)[scratchpadSize], const std::uint8_t (&pageData)[pageSize], const RomId & romId, const std::uint8_t (&manId)[manIdLen], bool anon, const std::uint8_t (&mac)[macLen])	
{
  std::uint8_t calc_mac[macLen];
  ISha256MacCoprocessor::CmdResult result;
  result = CalculateAuthMAC256(MacCoproc, page_num, challenge, pageData, romId, manId, anon, calc_mac);
  if (result == ISha256MacCoprocessor::Success)
  {
   if (memcmp(mac, calc_mac, macLen) != 0)
     result = ISha256MacCoprocessor::OperationFailure;
  }
  return result;
}

//--------------------------------------------------------------------------
//  Do Compute Page MAC command and return MAC. Optionally do
//  annonymous mode (anon != 0). 
// 
//  Parameters
//     sn  - secret number 0 or 1
//     page_num - page number to read 0 - 16
//     challange - 32 byte buffer containing the challenge
//     mac - 32 byte buffer for page data read
//     anon - Flag to indicate Annonymous mode
//
//  Returns: true - page read has correct MAC
//           false - Failed to read page or incorrect MAC
//
OneWireSlave::CmdResult DS28E15_22_25::ComputeReadPageMAC(unsigned int page_num, bool anon, std::uint8_t (&mac)[macLen]) const	
{
   std::uint8_t buf[256],cs;
   int cnt = 0;

   buf[cnt++] = CMD_COMPUTE_PAGEMAC;                 
   buf[cnt++] = ((anon) ? 0xE0 : 0x00) | page_num;  

   // Send command
   m_OW_master.OWWriteBlock(&buf[0], 2);

   // read first CRC byte
   m_OW_master.OWReadByte(buf[cnt++]);

   // read the last CRC and enable
   m_OW_master.OWReadBytePower(buf[cnt++]);

   // now wait for the MAC computation.
   wait_ms(SHA_COMPUTATION_DELAY * 2);

   // disable strong pullup
   m_OW_master.OWLevel(OneWireMaster::LEVEL_NORMAL);

   // check CRC16
   if (OneWireMaster::calculateCRC16(buf, 0, cnt) != 0xB001)
      return CommunicationError;

   // read the CS byte
   m_OW_master.OWReadByte(cs);
   if (cs != 0xAA)
      return OperationFailure;

   // read the MAC and CRC
   m_OW_master.OWReadBlock(&buf[0], (macLen + 2));

   // check CRC16
   if (OneWireMaster::calculateCRC16(buf, 0, (macLen + 2)) != 0xB001)
      return CommunicationError;      

   // copy MAC to return buffer
   memcpy(mac, buf, macLen);

   return Success;
}

//----------------------------------------------------------------------
// Compute secret operation on the DS28E25/DS28E22/DS28E15.
//
// 'sn'        - secret number 0 or 1
// 'partial'   - partial secret to load (32 bytes)
// 'pagedata'  - page data to compute (32 bytes)
// 'lock'      - option to lock the secret after the load (lock = true)
//
// Return: true - load complete
//         false - error during load, device not present
//
OneWireSlave::CmdResult DS28E15_22_25::ComputeSecret(unsigned int page_num, bool lock) 
{
  std::uint8_t buf[256], cs;
  int cnt = 0;

  buf[cnt++] = CMD_COMPUTE_LOCK_SECRET;                 
  buf[cnt++] = (lock) ? (0xE0 | page_num) : page_num;  // lock flag 

  // Send command
  m_OW_master.OWWriteBlock(&buf[0], 2);

  // Read CRC
  m_OW_master.OWReadBlock(&buf[cnt], 2);
  cnt += 2;

  // check CRC16
  if (OneWireMaster::calculateCRC16(buf, 0, cnt) != 0xB001)
    return CommunicationError;

  // send release and strong pull-up
  m_OW_master.OWWriteBytePower(0xAA);

  // now wait for the MAC computation.
  wait_ms(SHA_COMPUTATION_DELAY * 2 + SECRET_EEPROM_DELAY);

  // disable strong pullup
  m_OW_master.OWLevel(OneWireMaster::LEVEL_NORMAL);

  // read the CS byte
  m_OW_master.OWReadByte(cs);

  if (cs == 0xAA)
    return Success;
  // else
  return OperationFailure;
}

//----------------------------------------------------------------------
// Write the scratchpad (challenge or secret)
//
// 'sn'        - secret number 0 or 1
// 'data'      - data to write to the scratchpad (32 bytes)
//
// Return: true - select complete
//         false - error during select, device not present
//
OneWireSlave::CmdResult DS28E15_22_25::WriteScratchpad(const uint8_t (&data)[scratchpadSize]) const
{
   std::uint8_t buf[256];
   int cnt = 0, offset;

   buf[cnt++] = CMD_SELECT_SECRET;      
   if ((romId.familyCode() == DS28E25_FAMILY) || (romId.familyCode() == DS28E22_FAMILY))
      buf[cnt++] = 0x20;
   else
      buf[cnt++] = 0x00;  
   
   // Send command
   m_OW_master.OWWriteBlock(&buf[0], 2);

   // Read CRC
   m_OW_master.OWReadBlock(&buf[cnt], 2);
   cnt += 2;

   offset = cnt;

   // add the data
   memcpy(&buf[cnt], data, scratchpadSize);
   cnt += scratchpadSize;

   // Send the data
   m_OW_master.OWWriteBlock(data, scratchpadSize);

   // Read CRC
   m_OW_master.OWReadBlock(&buf[cnt], 2);
   cnt += 2;
   
   // check first CRC16
   if (OneWireMaster::calculateCRC16(buf, 0, offset) != 0xB001)
      return CommunicationError;

   // check the second CRC16
   if (OneWireMaster::calculateCRC16(buf, offset, (cnt - offset)) != 0xB001)
      return CommunicationError;

   return Success;
}

//----------------------------------------------------------------------
// Load first secret operation on the DS28E25/DS28E22/DS28E15.
//
// 'sn'        - secret number 0 or 1
// 'secret'    - secret to load (32 bytes)
// 'lock'      - option to lock the secret after the load (lock = true)
//
// Return: true - load complete
//         false - error during load, device not present
//
OneWireSlave::CmdResult DS28E15_22_25::LoadSecret(bool lock)
{
   std::uint8_t buf[256], cs;
   int cnt = 0;

   buf[cnt++] = CMD_LOAD_LOCK_SECRET;                 
   buf[cnt++] = (lock) ? 0xE0 : 0x00;  // lock flag 

   // Send command
   m_OW_master.OWWriteBlock(&buf[0], 2);

   // Read CRC
   m_OW_master.OWReadBlock(&buf[cnt], 2);
   cnt += 2;

   // check CRC16
   if (OneWireMaster::calculateCRC16(buf, 0, cnt) != 0xB001)
      return CommunicationError;

   // send release and strong pull-up
   m_OW_master.OWWriteBytePower(0xAA);

   // now wait for the MAC computation.
   wait_ms(SECRET_EEPROM_DELAY);

   // disable strong pullup
   m_OW_master.OWLevel(OneWireMaster::LEVEL_NORMAL);

   // read the CS byte
   m_OW_master.OWReadByte(cs);

   if (cs == 0xAA)
     return Success;
   // else
   return OperationFailure;
}

//--------------------------------------------------------------------------
//  Read page and verify CRC. Multiple pages can
//  be read without re-selecting the device using the continue flag. 
// 
//  Parameters
//     page - page number where the block to write is located (0 to 15)
//     rdbuf - 32 byte buffer to contain the data to read
//     contflag - Flag to indicate the write is continued from the last
//
//  Returns: true - block read and verified CRC
//           false - Failed to write block (no presence or invalid CRC16)
//
OneWireSlave::CmdResult DS28E15_22_25::readPage(unsigned int page, std::uint8_t (&rdbuf)[pageSize], bool continuing) const	
{
   std::uint8_t buf[256];
   int cnt, offset;

   cnt = 0;
   offset = 0;
   
   // check if not continuing a previous block write
   if (!continuing)
   {
      buf[cnt++] = CMD_READ_MEMORY;                 
      buf[cnt++] = page;   // address 

      // Send command
      m_OW_master.OWWriteBlock(&buf[0], 2);

      // Read CRC
      m_OW_master.OWReadBlock(&buf[cnt], 2);
      cnt += 2;

      offset = cnt;
   }

   // read data and CRC16
   m_OW_master.OWReadBlock(&buf[cnt], (pageSize + 2));
   cnt+=34;

   // check the first CRC16
   if (!continuing)
   {
      if (OneWireMaster::calculateCRC16(buf, 0, offset) != 0xB001)
         return CommunicationError;
   }

   // check the second CRC16
   if (OneWireMaster::calculateCRC16(buf, offset, (cnt - offset)) != 0xB001)
      return CommunicationError;

   // copy the data to the read buffer
   memcpy(rdbuf, &buf[offset], pageSize);

   return Success;
}

//--------------------------------------------------------------------------
//  Write a 4 byte memory block using an authenticated write (with MAC). 
//  The MAC must be pre-calculated. 
// 
//  Parameters
//     page - page number where the block to write is located (0 to 15)
//     block - block number in page (0 to 7)
//     new_data - 4 byte buffer containing the data to write
//     mac - mac to use for the write
//     contflag - Flag to indicate the write is continued from the last
//
//  Returns: true - block written
//           false - Failed to write block (no presence or invalid CRC16)
//
OneWireSlave::CmdResult DS28E15_22_25::writeAuthSegmentMAC(unsigned int pageNum, unsigned int segmentNum, const std::uint8_t (&newData)[segmentSize], const std::uint8_t (&mac)[macLen], bool continuing)	
{
   std::uint8_t buf[256], cs;
   int cnt, i, offset;

   cnt = 0;
   offset = 0;
   
   // check if not continuing a previous block write
   if (!continuing)
   {
      buf[cnt++] = CMD_WRITE_AUTH_MEMORY;                 
      buf[cnt++] = (segmentNum << 5) | pageNum;   // address 

      // Send command
      m_OW_master.OWWriteBlock(&buf[0], 2);

      // Read CRC
      m_OW_master.OWReadBlock(&buf[cnt], 2);
      cnt += 2;

      offset = cnt;
   }

   // add the data
   for (i = 0; i < 4; i++)
      buf[cnt++] = newData[i];

   // Send data
   m_OW_master.OWWriteBlock(newData, segmentSize);

   // read first CRC byte
   m_OW_master.OWReadByte(buf[cnt++]);

   // read the last CRC and enable power
   m_OW_master.OWReadBytePower(buf[cnt++]);

      // now wait for the MAC computation.
   wait_ms(SHA_COMPUTATION_DELAY);

   // disable strong pullup
   m_OW_master.OWLevel(OneWireMaster::LEVEL_NORMAL);

   // check the first CRC16
   if (!continuing)
   {
      if (OneWireMaster::calculateCRC16(buf, 0, offset) != 0xB001)
         return CommunicationError;
   }

   // check the second CRC16
   unsigned short CRC16 = 0;

   // DS28E25/DS28E22, crc gets calculagted with CS byte 
   if ((romId.familyCode() == DS28E25_FAMILY) || (romId.familyCode() == DS28E22_FAMILY))
   {
      if (continuing)
         CRC16 = OneWireMaster::calculateCRC16(CRC16, 0xAA);
   }

   CRC16 = OneWireMaster::calculateCRC16(buf, offset, (cnt - offset), CRC16);

   if (CRC16 != 0xB001)
      return CommunicationError;

   // transmit MAC as a block
   m_OW_master.OWWriteBlock(mac, macLen);

   // calculate CRC on MAC
   CRC16 = OneWireMaster::calculateCRC16(mac, 0, macLen);

   // append read of CRC16 and CS byte
   m_OW_master.OWReadBlock(&buf[0], 3);
   cnt = 3;

   // ckeck CRC16
   CRC16 = OneWireMaster::calculateCRC16(buf, 0, (cnt - 1), CRC16);

   if (CRC16 != 0xB001)
      return CommunicationError;

   // check CS
   if (buf[cnt-1] != 0xAA)
      return OperationFailure;

   // send release and strong pull-up
   m_OW_master.OWWriteBytePower(0xAA);

   // now wait for the MAC computation.
   wait_ms(EEPROM_WRITE_DELAY);

   // disable strong pullup
   m_OW_master.OWLevel(OneWireMaster::LEVEL_NORMAL);

   // read the CS byte
   m_OW_master.OWReadByte(cs);

   if (cs == 0xAA)
     return Success;
   // else
   return OperationFailure;
}

//--------------------------------------------------------------------------
//  Compute MAC to write a 4 byte memory block using an authenticated 
//  write.
// 
//  Parameters
//     page - page number where the block to write is located (0 to 15)
//     block - block number in page (0 to 7)
//     new_data - 4 byte buffer containing the data to write
//     old_data - 4 byte buffer containing the data to write
//     manid - 2 byte buffer containing the manufacturer ID (general device: 00h,00h)
//     mac - buffer to put the calculated mac into
//
//  Returns: true - mac calculated
//           false - Failed to calculate
//
ISha256MacCoprocessor::CmdResult DS28E15_22_25::CalculateSegmentWriteMAC256(const ISha256MacCoprocessor & MacCoproc, unsigned int pageNum, unsigned int segmentNum, const std::uint8_t (&newData)[segmentSize], const std::uint8_t (&oldData)[segmentSize], const RomId & romId, const std::uint8_t (&manId)[manIdLen], std::uint8_t (&mac)[macLen])	
{
  std::uint8_t MT[ISha256MacCoprocessor::WriteMAC_data_len];

  // insert ROM number
  memcpy(&MT[0], romId, RomId::byteLen);

  MT[11] = segmentNum;
  MT[10] = pageNum;
  MT[9] = manId[0];
  MT[8] = manId[1];

  // insert old data
  memcpy(&MT[12], oldData, segmentSize);

  // insert new data
  memcpy(&MT[16], newData, segmentSize);
  
  return MacCoproc.ComputeAndRead_WriteMAC(MT, mac);
}




ISha256MacCoprocessor::CmdResult DS28E15_22_25::CalculateProtectionWriteMAC256(const ISha256MacCoprocessor & MacCoproc, std::uint8_t newProtection, std::uint8_t oldProtection, const RomId & romId, const std::uint8_t (&manId)[manIdLen], std::uint8_t (&mac)[macLen])
{
   std::uint8_t MT[ISha256MacCoprocessor::WriteMAC_data_len];
  
   // insert ROM number
   std::memcpy(MT, romId, RomId::byteLen);

   // instert block and page
   MT[11] = 0;
   MT[10] = newProtection & 0x0F;

   MT[9] = manId[0];
   MT[8] = manId[1];

   // old data
   MT[12] = (oldProtection & PROT_BIT_AUTHWRITE) ? 0x01 : 0x00;  
   MT[13] = (oldProtection & PROT_BIT_EPROM) ? 0x01 : 0x00;
   MT[14] = (oldProtection & PROT_BIT_WRITE) ? 0x01 : 0x00;
   MT[15] = (oldProtection & PROT_BIT_READ) ? 0x01 : 0x00;
   // new data
   MT[16] = (newProtection & PROT_BIT_AUTHWRITE) ? 0x01 : 0x00;  
   MT[17] = (newProtection & PROT_BIT_EPROM) ? 0x01 : 0x00;
   MT[18] = (newProtection & PROT_BIT_WRITE) ? 0x01 : 0x00;
   MT[19] = (newProtection & PROT_BIT_READ) ? 0x01 : 0x00;

   // compute the mac
   return MacCoproc.ComputeAndRead_WriteMAC(MT, mac);
}

//--------------------------------------------------------------------------
//  Write a 4 byte memory block using an authenticated write (with MAC). 
//  The block location is selected by the 
//  page number and offset block within the page. Multiple blocks can
//  be programmed without re-selecting the device using the continue flag. 
//  This function does not use the Authenticated Write operation. 
// 
//  Parameters
//     page - page number where the block to write is located (0 to 15)
//     block - block number in page (0 to 7)
//     new_data - 4 byte buffer containing the data to write
//     old_data - 4 byte buffer containing the data to write
//     manid - 2 byte buffer containing the manufacturer ID (general device: 00h,00h)
//     contflag - Flag to indicate the write is continued from the last
//
//  Returns: true - block written
//           false - Failed to write block (no presence or invalid CRC16)
//
OneWireSlave::CmdResult DS28E15_22_25::writeAuthSegment(const ISha256MacCoprocessor & MacCoproc, unsigned int pageNum, unsigned int segmentNum, const std::uint8_t (&newData)[segmentSize], const std::uint8_t (&oldData)[segmentSize], bool continuing)
{
  std::uint8_t buf[256], cs;
  int cnt, offset;

   cnt = 0;
   offset = 0;
   
   // check if not continuing a previous block write
   if (!continuing)
   {
      buf[cnt++] = CMD_WRITE_AUTH_MEMORY;                 
      buf[cnt++] = (segmentNum << 5) | pageNum;   // address 

      // Send command
      m_OW_master.OWWriteBlock(&buf[0], 2);

      // Read CRC
      m_OW_master.OWReadBlock(&buf[cnt], 2);
      cnt += 2;

      offset = cnt;
   }

   // add the data
   for (size_t i = 0; i < segmentSize; i++)
      buf[cnt++] = newData[i];

   // Send data
   m_OW_master.OWWriteBlock(newData, segmentSize);

   // read first CRC byte
   m_OW_master.OWReadByte(buf[cnt++]);

   // read the last CRC and enable power
   m_OW_master.OWReadBytePower(buf[cnt++]);

   // now wait for the MAC computation.
   wait_ms(SHA_COMPUTATION_DELAY);

   // disable strong pullup
   m_OW_master.OWLevel(OneWireMaster::LEVEL_NORMAL);

   // check the first CRC16
   if (!continuing)
   {
      if (OneWireMaster::calculateCRC16(buf, 0, offset) != 0xB001)
         return CommunicationError;
   }

   // check the second CRC16
   unsigned short CRC16 = 0;

   // DS28E25/DS28E22, crc gets calculagted with CS byte
   if ((romId.familyCode() == DS28E25_FAMILY) || (romId.familyCode() == DS28E22_FAMILY))
   {
      if (continuing)
         CRC16 = OneWireMaster::calculateCRC16(CRC16, 0xAA);
   }
   
   CRC16 = OneWireMaster::calculateCRC16(buf, offset, (cnt - offset), CRC16);

   if (CRC16 != 0xB001)
      return CommunicationError;

    // compute the mac
   ISha256MacCoprocessor::CmdResult result;
   result = CalculateSegmentWriteMAC256(MacCoproc, pageNum, segmentNum, newData, oldData, romId, manId, reinterpret_cast<std::uint8_t (&)[macLen]>(buf));
   if (result != ISha256MacCoprocessor::Success)
      return OperationFailure;

   // transmit MAC as a block
   cnt = 0;
   m_OW_master.OWWriteBlock(buf, macLen);

   // calculate CRC on MAC
   CRC16 = OneWireMaster::calculateCRC16(buf, 0, macLen);

   // append read of CRC16 and CS byte
   m_OW_master.OWReadBlock(&buf[0], 3);
   cnt = 3;

   // ckeck CRC16
   CRC16 = OneWireMaster::calculateCRC16(buf, 0, (cnt - 1), CRC16);

   if (CRC16 != 0xB001)
      return CommunicationError;

   // check CS
   if (buf[cnt-1] != 0xAA)
      return OperationFailure;

   // send release and strong pull-up
   m_OW_master.OWWriteBytePower(0xAA);

   // now wait for the MAC computation.
   wait_ms(EEPROM_WRITE_DELAY);

   // disable strong pullup
   m_OW_master.OWLevel(OneWireMaster::LEVEL_NORMAL);

   // read the CS byte
   m_OW_master.OWReadByte(cs);

   if (cs == 0xAA)
     return Success;
   // else
   return OperationFailure;
}




OneWireSlave::CmdResult DS28E15_22_25::readSegment(unsigned int page, unsigned int segment, std::uint8_t (&data)[segmentSize]) const
{
  OneWireMaster::CmdResult result;
  std::uint8_t buf[2];
  
  buf[0] = CMD_READ_MEMORY;
  buf[1] = (segment << 5) | page;
  
  // Transmit command
  m_OW_master.OWWriteBlock(buf, 2);
  
  // Receive CRC
  result = m_OW_master.OWReadBlock(buf, 2);
  
  // Receive data
  if (result == OneWireMaster::Success)
    result = m_OW_master.OWReadBlock(data, segmentSize);
  
  return (result == OneWireMaster::Success ? OneWireSlave::Success : OneWireSlave::CommunicationError);
}

//--------------------------------------------------------------------------
//  Write a 4 byte memory block. The block location is selected by the 
//  page number and offset blcok within the page. Multiple blocks can
//  be programmed without re-selecting the device using the continue flag. 
//  This function does not use the Authenticated Write operation. 
// 
//  Parameters
//     page - page number where the block to write is located (0 to 15)
//     block - block number in page (0 to 7)
//     data - 4 byte buffer containing the data to write
//     contflag - Flag to indicate the write is continued from the last
//
//  Returns: true - block written
//           false - Failed to write block (no presence or invalid CRC16)
//
OneWireSlave::CmdResult DS28E15_22_25::writeSegment(unsigned int page, unsigned int block, const std::uint8_t (&data)[segmentSize], bool continuing)	
{
   std::uint8_t buf[256], cs;
   int cnt, offset;

   cnt = 0;
   offset = 0;
   
   // check if not continuing a previous block write
   if (!continuing)
   {
      buf[cnt++] = CMD_WRITE_MEMORY;                 
      buf[cnt++] = (block << 5) | page;   // address 

      // Send command 
      m_OW_master.OWWriteBlock(&buf[0], 2);

      // Read CRC
      m_OW_master.OWReadBlock(&buf[cnt], 2);
      cnt += 2;

      offset = cnt;
   }

   // add the data
   for (size_t i = 0; i < segmentSize; i++)
      buf[cnt++] = data[i];

   // Send data
   m_OW_master.OWWriteBlock(data, segmentSize);

   // Read CRC
   m_OW_master.OWReadBlock(&buf[cnt], 2);
   cnt += 2;
   
   // check the first CRC16
   if (!continuing)
   {
      if (OneWireMaster::calculateCRC16(buf, 0, offset) != 0xB001)
         return CommunicationError;
   }

   // check the second CRC16
   if (OneWireMaster::calculateCRC16(buf, offset, (cnt - offset)) != 0xB001)
      return CommunicationError;

   // send release and strong pull-up
   m_OW_master.OWWriteBytePower(0xAA);

   // now wait for the MAC computation.
   wait_ms(EEPROM_WRITE_DELAY);

   // disable strong pullup
   m_OW_master.OWLevel(OneWireMaster::LEVEL_NORMAL);

   // read the CS byte
   m_OW_master.OWReadByte(cs);

   if (cs == 0xAA)
     return Success;
   // else
   return OperationFailure;
}

//----------------------------------------------------------------------
// Performs a Compute Next SHA-256 calculation given the provided 32-bytes
// of binding data and 8 byte partial secret. The first 8 bytes of the
// resulting MAC is set as the new secret.
// 
// 'binding'  - 32 byte buffer containing the binding data
// 'partial'  - 8 byte buffer with new partial secret
// 'page_num'  - page number that the compute is calculated on
// 'manid'  - manufacturer ID
//
// Globals used : SECRET used in calculation and set to new secret
//
// Returns: true if compute successful
//          false failed to do compute
//
ISha256MacCoprocessor::CmdResult DS28E15_22_25::CalculateNextSecret(ISha256MacCoprocessor & MacCoproc, const std::uint8_t (&binding)[pageSize], const std::uint8_t (&partial)[scratchpadSize], const RomId & romId, const std::uint8_t (&manId)[manIdLen], unsigned int pageNum)
{
  std::uint8_t devicePage[pageSize], deviceScratchpad[scratchpadSize], SSecret_data[ISha256MacCoprocessor::SSecret_data_len];

   // insert page data
   memcpy(devicePage, binding, pageSize);

   // insert challenge
   memcpy(deviceScratchpad, partial, scratchpadSize);

   // insert ROM number
   std::memcpy(SSecret_data, romId, RomId::byteLen);

   SSecret_data[11] = 0x00;
   SSecret_data[10] = pageNum;
   SSecret_data[9] = manId[0];
   SSecret_data[8] = manId[1];

   return MacCoproc.Compute_SSecret(devicePage, deviceScratchpad, SSecret_data);
}