Implementation of 1-Wire with added Alarm Search Functionality

Dependents:   Max32630_One_Wire_Interface

Revision:
73:2cecc1372acc
Parent:
62:43039aeca2ab
Child:
74:23be10c32fa3
diff -r 6892702709ee -r 2cecc1372acc Authenticators/DS28E15_22_25/DS28E15_22_25.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Authenticators/DS28E15_22_25/DS28E15_22_25.cpp	Thu May 12 14:38:16 2016 -0500
@@ -0,0 +1,1031 @@
+//------------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.h"
+#include "Masters/OneWireMaster.h"
+#include "wait_api.h"
+
+using OneWire::Authenticators::DS28E15_22_25;
+using OneWire::Authenticators::ISha256MacCoproc;
+using OneWire::OneWireSlave;
+using OneWire::Masters::OneWireMaster;
+
+/// 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::Segment DS28E15_22_25::Page::toSegment(unsigned int segmentNum) const
+{
+  if (segmentNum > (segmentsPerPage - 1))
+    segmentNum = (segmentsPerPage - 1);
+  return Segment(*reinterpret_cast<const Segment::Buffer *>(&m_data[segmentNum * sizeof(Segment::Buffer)]));
+}
+
+void DS28E15_22_25::Page::fromSegment(unsigned int segmentNum, const Segment & segment)
+{
+  if (segmentNum > (segmentsPerPage - 1))
+    segmentNum = (segmentsPerPage - 1);
+  std::memcpy(&m_data[segmentNum * sizeof(Segment::Buffer)], &static_cast<const Segment::Buffer &>(segment), Segment::length);
+}
+
+DS28E15_22_25::BlockProtection::BlockProtection(bool readProtection, bool writeProtection, bool eepromEmulation, bool authProtection, uint8_t blockNum)
+{
+  setReadProtection(readProtection);
+  setWriteProtection(writeProtection);
+  setEepromEmulation(eepromEmulation);
+  setAuthProtection(authProtection);
+  setBlockNum(blockNum);
+}
+
+void DS28E15_22_25::BlockProtection::setBlockNum(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 ISha256MacCoproc & MacCoproc, const BlockProtection & newProtection, const BlockProtection & oldProtection)  
+{
+   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;
+
+   ISha256MacCoproc::CmdResult result;
+   result = computeProtectionWriteMac(MacCoproc, newProtection, oldProtection, romId, manId, mac);
+   if (result != ISha256MacCoproc::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;
+
+   // check CRC16
+   if (OneWireMaster::calculateCRC16(buf, 0, (cnt - 1), OneWireMaster::calculateCRC16(mac, 0, mac.length)) != 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) 
+{
+   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)
+{
+  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
+{
+  uint8_t buf[blocks];
+  CmdResult result = readStatus(false, true, 0, buf);
+  if (result == Success)
+  {
+    for (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, uint8_t * rdbuf) const
+{
+  const size_t crcLen = 4, ds28e22_25_pagesPerBlock = 2;
+  
+  uint8_t buf[256];
+  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
+  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 (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;
+}
+
+ISha256MacCoproc::CmdResult DS28E15_22_25::computeAuthMac(const ISha256MacCoproc & MacCoproc, const Page & pageData, unsigned int pageNum, const Scratchpad & challenge, const RomId & romId, const ManId & manId, Mac & mac)
+{
+  ISha256MacCoproc::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(ISha256MacCoproc::DevicePage(pageData), challenge, authMacData, mac);
+}
+
+ISha256MacCoproc::CmdResult DS28E15_22_25::computeAuthMacAnon(const ISha256MacCoproc & 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    
+{
+   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
+   std::memcpy(mac, buf, Mac::length);
+
+   return Success;
+}
+
+OneWireSlave::CmdResult DS28E15_22_25::computeSecret(unsigned int page_num, bool lock) 
+{
+  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
+{
+   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
+   std::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
+{
+   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
+   std::memcpy(data, &buf[offset], data.length);
+
+   return Success;
+}
+
+OneWireSlave::CmdResult DS28E15_22_25::loadSecret(bool lock)
+{
+   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 
+{
+   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
+   std::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)    
+{
+   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;
+}
+
+ISha256MacCoproc::CmdResult DS28E15_22_25::computeSegmentWriteMac(const ISha256MacCoproc & MacCoproc, unsigned int pageNum, unsigned int segmentNum, const Segment & newData, const Segment & oldData, const RomId & romId, const ManId & manId, Mac & mac)   
+{
+  ISha256MacCoproc::WriteMacData MT;
+
+  // insert ROM number
+  std::memcpy(&MT[0], romId, RomId::byteLen);
+
+  MT[11] = segmentNum;
+  MT[10] = pageNum;
+  MT[9] = manId[0];
+  MT[8] = manId[1];
+
+  // insert old data
+  std::memcpy(&MT[12], oldData, Segment::length);
+
+  // insert new data
+  std::memcpy(&MT[16], newData, Segment::length);
+  
+  return MacCoproc.computeWriteMac(MT, mac);
+}
+
+ISha256MacCoproc::CmdResult DS28E15_22_25::computeProtectionWriteMac(const ISha256MacCoproc & MacCoproc, const BlockProtection & newProtection, const BlockProtection & oldProtection, const RomId & romId, const ManId & manId, Mac & mac)
+{
+   ISha256MacCoproc::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 ISha256MacCoproc & MacCoproc, unsigned int pageNum, unsigned int segmentNum, const Segment & newData, const Segment & oldData, bool continuing)
+{
+  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
+   ISha256MacCoproc::CmdResult result;
+   Mac mac;
+   result = computeSegmentWriteMac(MacCoproc, pageNum, segmentNum, newData, oldData, romId, manId, mac);
+   if (result != ISha256MacCoproc::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;
+  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)   
+{
+   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;
+}
+
+ISha256MacCoproc::CmdResult DS28E15_22_25::computeNextSecret(ISha256MacCoproc & MacCoproc, const Page & bindingPage, unsigned int bindingPageNum, const Scratchpad & partialSecret, const RomId & romId, const ManId & manId)
+{
+  ISha256MacCoproc::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(ISha256MacCoproc::DevicePage(bindingPage), partialSecret, slaveSecretData);
+}