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-04-11
Revision:
51:a65f031e997b
Parent:
50:e967f9befbd0
Child:
61:268612a10614

File content as of revision 51:a65f031e997b:

//------------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 "OneWire_Masters/OneWireMaster.h"
#include "mbed.h"

/// 1-Wire device commands.
enum Command
{
  CMD_WRITE_MEMORY =          0x55,
  CMD_READ_MEMORY =           0xF0,
  CMD_LOAD_LOCK_SECRET =      0x33,
  CMD_COMPUTE_LOCK_SECRET =   0x3C,
  CMD_READ_WRITE_SCRATCHPAD = 0x0F,
  CMD_COMPUTE_PAGEMAC =       0xA5,
  CMD_READ_STATUS =           0xAA,
  CMD_WRITE_BLOCK_PROTECT =   0xC3,
  CMD_WRITE_AUTH_MEMORY =     0x5A,
  CMD_WRITE_AUTH_PROTECT =    0xCC,
};

DS28E15_22_25::BlockProtection::BlockProtection(bool readProtection, bool writeProtection, bool eepromEmulation, bool authProtection, std::uint8_t blockNum)
{
  setReadProtection(readProtection);
  setWriteProtection(writeProtection);
  setEepromEmulation(eepromEmulation);
  setAuthProtection(authProtection);
  setBlockNum(blockNum);
}

void DS28E15_22_25::BlockProtection::setBlockNum(std::uint8_t blockNum)
{
  m_status &= ~blockNumMask;
  m_status |= (blockNum & blockNumMask);
}

bool DS28E15_22_25::BlockProtection::noProtection() const
{
  return !readProtection() && !writeProtection() && !eepromEmulation() && !authProtection();
}

void DS28E15_22_25::BlockProtection::setReadProtection(bool readProtection)
{
  if (readProtection)
    m_status |= readProtectionMask;
  else
    m_status &= ~readProtectionMask;
}

void DS28E15_22_25::BlockProtection::setWriteProtection(bool writeProtection)
{
  if (writeProtection)
    m_status |= writeProtectionMask;
  else
    m_status &= ~writeProtectionMask;
}

void DS28E15_22_25::BlockProtection::setEepromEmulation(bool eepromEmulation)
{
  if (eepromEmulation)
    m_status |= eepromEmulationMask;
  else
    m_status &= ~eepromEmulationMask;
}

void DS28E15_22_25::BlockProtection::setAuthProtection(bool authProtection)
{
  if (authProtection)
    m_status |= authProtectionMask;
  else
    m_status &= ~authProtectionMask;
}

DS28E15_22_25::DS28E15_22_25(OneWireMaster& OW_master, bool lowVoltage)
  : lowVoltage(lowVoltage), m_OW_master(OW_master)
{
  std::memset(manId, 0x00, manId.length);
}

DS28E15_22_25::MemoryPages DS28E15_22_25::memoryPages()
{
  MemoryPages 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::ProtectionBlocks DS28E15_22_25::protectionBlocks()
{
  ProtectionBlocks 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;
}

OneWireSlave::CmdResult DS28E15_22_25::writeAuthBlockProtection(const ISha256MacCoprocessor & MacCoproc, const BlockProtection & newProtection, const BlockProtection & oldProtection)	
{
   std::uint8_t buf[256], cs;
   int cnt = 0;
   Mac mac;

   buf[cnt++] = CMD_WRITE_AUTH_PROTECT;
   buf[cnt++] = newProtection.statusByte();

   // 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(shaComputationDelayMs);

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

   ISha256MacCoprocessor::CmdResult result;
   result = computeProtectionWriteMac(MacCoproc, newProtection, oldProtection, romId, manId, mac);
   if (result != ISha256MacCoprocessor::Success)
     return OperationFailure;
   cnt = 0;

   // send the MAC
   m_OW_master.OWWriteBlock(mac, mac.length);

   // 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 programming.
   wait_ms(eepromWriteDelayMs);

   // disable strong pullup
   m_OW_master.OWSetLevel(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::writeBlockProtection(const BlockProtection & protection)	
{
   std::uint8_t buf[256], cs;
   int cnt = 0;

   buf[cnt++] = CMD_WRITE_BLOCK_PROTECT;

   // compute parameter byte 
   buf[cnt++] = protection.statusByte();

   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;

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

   // now wait for the programming.
   wait_ms(eepromWriteDelayMs);

   // disable strong pullup
   m_OW_master.OWSetLevel(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::readBlockProtection(unsigned int blockNum, BlockProtection & protection)
{
  std::uint8_t buf;
  CmdResult result = readStatus(false, false, blockNum, &buf);
  if (result == Success)
    protection.setStatusByte(buf);
  return result;
}

template <DS28E15_22_25::ProtectionBlocks blocks> OneWireSlave::CmdResult DS28E15_22_25::readAllBlockProtection(BlockProtection (&protection)[blocks]) const
{
  std::uint8_t buf[blocks];
  CmdResult result = readStatus(false, true, 0, buf);
  if (result == Success)
  {
    for (std::size_t i = 0; i < blocks; i++)
      protection[i].setStatusByte(buf[i]);
  }
  return result;
}

OneWireSlave::CmdResult DS28E15_22_25::readAllBlockProtection(BlockProtection (&protection)[DS28E15_BLOCKS]) const
{
  return readAllBlockProtection<DS28E15_BLOCKS>(protection);
}

OneWireSlave::CmdResult DS28E15_22_25::readAllBlockProtection(BlockProtection (&protection)[DS28E25_BLOCKS]) const
{
  return readAllBlockProtection<DS28E25_BLOCKS>(protection);
}

OneWireSlave::CmdResult DS28E15_22_25::readPersonality(Personality & personality) const
{
  return readStatus(true, false, 0, personality.bytes);
}

OneWireSlave::CmdResult DS28E15_22_25::readStatus(bool personality, bool allpages, unsigned int blockNum, std::uint8_t * rdbuf) const
{
  const std::size_t crcLen = 4, ds28e22_25_pagesPerBlock = 2;
  
  std::uint8_t buf[256];
  std::size_t cnt = 0, offset = 0;

  buf[cnt++] = CMD_READ_STATUS;   
  if (personality)
    buf[cnt++] = 0xE0;
  else if (allpages)
    buf[cnt++] = 0;
  else
  {
    // Convert to page number for DS28E22 and DS28E25
    buf[cnt] = blockNum;
    if ((romId.familyCode() == DS28E25_FAMILY) || (romId.familyCode() == DS28E22_FAMILY))
      buf[cnt] *= ds28e22_25_pagesPerBlock;
    cnt++;
  }

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

  offset = cnt + 2;

  // Set data length
  std::size_t rdnum;
  if (personality)
    rdnum = 4;
  else if (!allpages)
    rdnum = 1;
  else if ((romId.familyCode() == DS28E22_FAMILY) || (romId.familyCode() == DS28E25_FAMILY))
    rdnum = DS28E25_PAGES; // Need to read extra data on DS28E22 to get CRC16.
  else // DS28E15
    rdnum = DS28E15_BLOCKS;
  rdnum += crcLen; // Add in CRC length

  // 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 (personality || allpages)
  {
    // check the second CRC16
    if (OneWireMaster::calculateCRC16(buf, offset, (cnt - offset)) != 0xB001)
       return CommunicationError;
  }

  // copy the data to the read buffer
  rdnum -= crcLen;
  if (allpages && ((romId.familyCode() == DS28E25_FAMILY) || (romId.familyCode() == DS28E22_FAMILY)))
  {
    if (romId.familyCode() == DS28E22_FAMILY)
      rdnum -= (DS28E25_PAGES - DS28E22_PAGES);
      
    for (std::size_t i = 0; i < (rdnum / ds28e22_25_pagesPerBlock); i++)
    {
      rdbuf[i] = (buf[offset + (i * ds28e22_25_pagesPerBlock)] & 0xF0); // Upper nibble
      rdbuf[i] |= ((buf[offset + (i * ds28e22_25_pagesPerBlock)] & 0x0F) / ds28e22_25_pagesPerBlock); // Lower nibble
    }
  }
  else
  {
    std::memcpy(rdbuf, &buf[offset], rdnum);
  }

  return Success;
}

ISha256MacCoprocessor::CmdResult DS28E15_22_25::computeAuthMac(const ISha256MacCoprocessor & MacCoproc, const Page & pageData, unsigned int pageNum, const Scratchpad & challenge, const RomId & romId, const ManId & manId, Mac & mac)
{
  ISha256MacCoprocessor::AuthMacData authMacData;

  // insert ROM number or FF
  std::memcpy(authMacData, romId, RomId::byteLen);

  authMacData[10] = pageNum;

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

  authMacData[11] = 0x00;

  return MacCoproc.computeAuthMac(pageData, challenge, authMacData, mac);
}

ISha256MacCoprocessor::CmdResult DS28E15_22_25::computeAuthMacAnon(const ISha256MacCoprocessor & MacCoproc, const Page & pageData, unsigned int pageNum, const Scratchpad & challenge, const ManId & manId, Mac & mac)
{
  RomId romId;
  std::memset(romId, 0xFF, RomId::byteLen);
  return computeAuthMac(MacCoproc, pageData, pageNum, challenge, romId, manId, mac);
}

OneWireSlave::CmdResult DS28E15_22_25::computeReadPageMac(unsigned int page_num, bool anon, Mac & mac) 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(shaComputationDelayMs * 2);

   // disable strong pullup
   m_OW_master.OWSetLevel(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], (Mac::length + 2));

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

   // copy MAC to return buffer
   memcpy(mac, buf, Mac::length);

   return Success;
}

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 computations and secret programming.
  wait_ms(shaComputationDelayMs * 2 + secretEepromWriteDelayMs());

  // disable strong pullup
  m_OW_master.OWSetLevel(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::writeScratchpad(const Scratchpad & data) const
{
   std::uint8_t buf[256];
   int cnt = 0, offset;

   buf[cnt++] = CMD_READ_WRITE_SCRATCHPAD;      
   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, data.length);
   cnt += data.length;

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

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

OneWireSlave::CmdResult DS28E15_22_25::readScratchpad(Scratchpad & data) const
{
   std::uint8_t buf[256];
   int cnt = 0, offset;

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

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

   offset = cnt;

   // Receive the data
   m_OW_master.OWReadBlock(&buf[cnt], data.length);
   cnt += data.length;

   // 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;
      
   // Copy to output
   memcpy(data, &buf[offset], data.length);

   return Success;
}

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 secret programming.
   wait_ms(secretEepromWriteDelayMs());

   // disable strong pullup
   m_OW_master.OWSetLevel(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::readPage(unsigned int page, Page & rdbuf, 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], (rdbuf.length + 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], rdbuf.length);

   return Success;
}

OneWireSlave::CmdResult DS28E15_22_25::writeAuthSegmentMac(unsigned int pageNum, unsigned int segmentNum, const Segment & newData, const Mac & mac, 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 < newData.length; i++)
      buf[cnt++] = newData[i];

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

   // 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(shaComputationDelayMs);

   // disable strong pullup
   m_OW_master.OWSetLevel(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, mac.length);

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

   // 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 programming.
   wait_ms(eepromWriteDelayMs);

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

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

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

ISha256MacCoprocessor::CmdResult DS28E15_22_25::computeSegmentWriteMac(const ISha256MacCoprocessor & MacCoproc, unsigned int pageNum, unsigned int segmentNum, const Segment & newData, const Segment & oldData, const RomId & romId, const ManId & manId, Mac & mac)	
{
  ISha256MacCoprocessor::WriteMacData MT;

  // 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, Segment::length);

  // insert new data
  memcpy(&MT[16], newData, Segment::length);
  
  return MacCoproc.computeWriteMac(MT, mac);
}

ISha256MacCoprocessor::CmdResult DS28E15_22_25::computeProtectionWriteMac(const ISha256MacCoprocessor & MacCoproc, const BlockProtection & newProtection, const BlockProtection & oldProtection, const RomId & romId, const ManId & manId, Mac & mac)
{
   ISha256MacCoprocessor::WriteMacData MT;
  
   // insert ROM number
   std::memcpy(MT, romId, RomId::byteLen);

   // instert block and page
   MT[11] = 0;
   MT[10] = newProtection.blockNum();

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

   // old data
   MT[12] = oldProtection.authProtection() ? 0x01 : 0x00;  
   MT[13] = oldProtection.eepromEmulation() ? 0x01 : 0x00;
   MT[14] = oldProtection.writeProtection() ? 0x01 : 0x00;
   MT[15] = oldProtection.readProtection() ? 0x01 : 0x00;
   // new data
   MT[16] = newProtection.authProtection() ? 0x01 : 0x00;  
   MT[17] = newProtection.eepromEmulation() ? 0x01 : 0x00;
   MT[18] = newProtection.writeProtection() ? 0x01 : 0x00;
   MT[19] = newProtection.readProtection() ? 0x01 : 0x00;

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

OneWireSlave::CmdResult DS28E15_22_25::writeAuthSegment(const ISha256MacCoprocessor & MacCoproc, unsigned int pageNum, unsigned int segmentNum, const Segment & newData, const Segment & oldData, 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 < newData.length; i++)
      buf[cnt++] = newData[i];

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

   // 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(shaComputationDelayMs);

   // disable strong pullup
   m_OW_master.OWSetLevel(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;
   Mac mac;
   result = computeSegmentWriteMac(MacCoproc, pageNum, segmentNum, newData, oldData, romId, manId, mac);
   if (result != ISha256MacCoprocessor::Success)
      return OperationFailure;

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

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

   // 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 programming.
   wait_ms(eepromWriteDelayMs);

   // disable strong pullup
   m_OW_master.OWSetLevel(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, Segment & data, bool continuing) const
{
  OneWireMaster::CmdResult result;
  std::uint8_t buf[2];
  
  if (!continuing)
  {
    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);
  }
  else if (segment == 0)
  {
    // Receive CRC from previous read
    result = m_OW_master.OWReadBlock(buf, 2);
  }
  
  // Receive data
  if (result == OneWireMaster::Success)
    result = m_OW_master.OWReadBlock(data, data.length);
  
  return (result == OneWireMaster::Success ? OneWireSlave::Success : OneWireSlave::CommunicationError);
}

OneWireSlave::CmdResult DS28E15_22_25::writeSegment(unsigned int page, unsigned int block, const Segment & data, 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 < data.length; i++)
      buf[cnt++] = data[i];

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

   // 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 programming.
   wait_ms(eepromWriteDelayMs);

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

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

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

ISha256MacCoprocessor::CmdResult DS28E15_22_25::computeNextSecret(ISha256MacCoprocessor & MacCoproc, const Page & bindingPage, unsigned int bindingPageNum, const Scratchpad & partialSecret, const RomId & romId, const ManId & manId)
{
  ISha256MacCoprocessor::SlaveSecretData slaveSecretData;

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

  slaveSecretData[11] = 0x00;
  slaveSecretData[10] = bindingPageNum;
  slaveSecretData[9] = manId[0];
  slaveSecretData[8] = manId[1];

  return MacCoproc.computeSlaveSecret(bindingPage, partialSecret, slaveSecretData);
}