Implementation of 1-Wire with added Alarm Search Functionality

Dependents:   Max32630_One_Wire_Interface

Revision:
73:2cecc1372acc
Parent:
71:562f5c702094
Child:
74:23be10c32fa3
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Masters/OneWireMaster.cpp	Thu May 12 14:38:16 2016 -0500
@@ -0,0 +1,447 @@
+/******************************************************************//**
+* Copyright (C) 2016 Maxim Integrated Products, Inc., All Rights Reserved.
+*
+* 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 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, Inc. shall not be used except as stated in the Maxim Integrated
+* Products, Inc. Branding Policy.
+*
+* The mere transfer of this software does not imply any licenses
+* of trade secrets, proprietary technology, copyrights, patents,
+* trademarks, maskwork rights, or any other form of intellectual
+* property whatsoever. Maxim Integrated Products, Inc. retains all
+* ownership rights.
+**********************************************************************/
+
+#include "OneWireMaster.h"
+#include "RomId.h"
+
+using OneWire::Masters::OneWireMaster;
+
+enum OW_ROM_CMD
+{
+    READ_ROM = 0x33,
+    MATCH_ROM = 0x55,
+    SEARCH_ROM = 0xF0,
+    SKIP_ROM = 0xCC,
+    RESUME = 0xA5,
+    OVERDRIVE_SKIP_ROM = 0x3C,
+    OVERDRIVE_MATCH_ROM = 0x69
+};
+
+
+//*********************************************************************
+OneWireMaster::CmdResult OneWireMaster::OWWriteBlock(const uint8_t *tran_buf, uint8_t tran_len)
+{
+    CmdResult result;
+    
+    for(uint8_t idx = 0; idx < tran_len; idx++)
+    {
+        result = OWWriteByte(tran_buf[idx]);
+        if(result != Success)
+        {
+            break;
+        }
+    }
+    
+    return result;
+}
+
+
+//*********************************************************************
+OneWireMaster::CmdResult OneWireMaster::OWReadBlock(uint8_t *rx_buf, uint8_t rx_len)
+{
+    CmdResult result;
+    
+    for(uint8_t idx = 0; idx < rx_len; idx++)
+    {
+        result = OWReadByte(rx_buf[idx]);
+        if(result != Success)
+        {
+            break;
+        }
+    }
+    
+    return result;
+}
+
+
+OneWireMaster::CmdResult OneWireMaster::OWFirst(SearchState & searchState)
+{
+    // reset the search state
+    searchState.reset();
+
+   return OWSearch(searchState);  
+}
+
+
+//*********************************************************************
+OneWireMaster::CmdResult OneWireMaster::OWNext(SearchState & searchState)
+{
+    // leave the search state alone
+    return OWSearch(searchState);
+}
+
+
+//*********************************************************************
+OneWireMaster::CmdResult OneWireMaster::OWVerify(const RomId & romId)
+{
+    OneWireMaster::CmdResult result;
+    SearchState searchState;
+    
+    searchState.romId = romId;
+
+    // set search to find the same device
+    searchState.last_discrepancy = 64;
+    searchState.last_device_flag = false;
+
+    result = OWSearch(searchState);
+    if (result == OneWireMaster::Success) 
+    {
+        // check if same device found
+        if (romId != searchState.romId) 
+        {
+            result = OneWireMaster::OperationFailure;
+        }
+    }
+
+    return result;
+}
+
+
+//*********************************************************************
+void OneWireMaster::OWTargetSetup(SearchState & searchState)
+{
+    // set the search state to find SearchFamily type devices
+    uint8_t familyCode = searchState.romId.familyCode();
+    searchState.reset();
+    searchState.romId.setFamilyCode(familyCode);
+    searchState.last_discrepancy = 64;
+}
+
+
+//*********************************************************************
+void OneWireMaster::OWFamilySkipSetup(SearchState & searchState)
+{
+    // set the Last discrepancy to last family discrepancy
+    searchState.last_discrepancy = searchState.last_family_discrepancy;
+
+    // clear the last family discrpepancy
+    searchState.last_family_discrepancy = 0;
+
+    // check for end of list
+    if (searchState.last_discrepancy == 0)
+    {
+        searchState.last_device_flag = true;
+    }
+}
+
+
+//*********************************************************************
+OneWireMaster::CmdResult OneWireMaster::OWReadROM(RomId & romId)
+{
+    OneWireMaster::CmdResult result;
+    uint8_t buf[2 + RomId::byteLen];
+
+    result = OWReset();
+    if (result == OneWireMaster::Success)
+    {
+        result = OWWriteByte(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))
+    {
+        romId = RomId(reinterpret_cast<uint8_t (&)[RomId::byteLen]>(buf[0]));
+    }
+
+    return result;
+}
+    
+
+//*********************************************************************    
+OneWireMaster::CmdResult OneWireMaster::OWSkipROM(void)
+{
+    OneWireMaster::CmdResult result;
+    
+    result = OWReset();
+    if (result == OneWireMaster::Success) 
+    {
+        result = OWWriteByte(SKIP_ROM);
+    }
+    
+    return result;
+}
+    
+
+//*********************************************************************    
+OneWireMaster::CmdResult OneWireMaster::OWMatchROM(const RomId & romId)
+{
+    OneWireMaster::CmdResult result;
+    
+    uint8_t buf[1 + RomId::byteLen];
+
+    // use MatchROM
+    result = OWReset();
+    if (result == OneWireMaster::Success) 
+    {
+        buf[0] = MATCH_ROM;
+        std::memcpy(&buf[1], romId, RomId::byteLen);
+        // send command and rom
+        result = OWWriteBlock(buf, 1 + RomId::byteLen);
+    }
+
+    return result;
+}
+    
+
+//*********************************************************************    
+OneWireMaster::CmdResult OneWireMaster::OWOverdriveSkipROM(void)
+{
+    OneWireMaster::CmdResult result = OWSetSpeed(SPEED_STANDARD);
+    
+    if (result == OneWireMaster::Success)
+    {
+        result = OWReset();
+    }
+    
+    if (result == OneWireMaster::Success)
+    {
+        result = OWWriteByte(OVERDRIVE_SKIP_ROM);
+    }
+    
+    if (result == OneWireMaster::Success)
+    {
+        result = OWSetSpeed(SPEED_OVERDRIVE);
+    }
+    
+    return result;
+}
+    
+
+//*********************************************************************    
+OneWireMaster::CmdResult OneWireMaster::OWOverdriveMatchROM(const RomId & romId)
+{
+    OneWireMaster::CmdResult result;
+    
+    // use overdrive MatchROM
+    OWSetSpeed(SPEED_STANDARD);
+    
+    result = OWReset();
+    if (result == OneWireMaster::Success) 
+    {
+        result = OWWriteByte(OVERDRIVE_MATCH_ROM);
+        if (result == OneWireMaster::Success) 
+        {
+            OWSetSpeed(SPEED_OVERDRIVE);
+            // send ROM
+            result = OWWriteBlock(romId, RomId::byteLen);
+        }
+    }
+    return result;
+}
+    
+
+//*********************************************************************    
+OneWireMaster::CmdResult OneWireMaster::OWResume(void)
+{
+    OneWireMaster::CmdResult result;
+    
+    result = OWReset();
+    if (result == OneWireMaster::Success) 
+    {
+        result = OWWriteByte(RESUME);
+    }
+    
+    return result;
+}
+
+
+OneWireMaster::CmdResult OneWireMaster::OWSearch(SearchState & searchState)
+{
+   uint8_t id_bit_number;
+   uint8_t last_zero, rom_byte_number;
+   uint8_t id_bit, cmp_id_bit;
+   uint8_t rom_byte_mask;
+   bool search_result;
+   uint8_t crc8 = 0;
+   SearchDirection 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 (!searchState.last_device_flag)
+   {       
+      // 1-Wire reset
+      OneWireMaster::CmdResult result = OWReset();
+      if (result != OneWireMaster::Success)
+      {
+         // reset the search
+         searchState.reset();
+         return result;
+      }
+
+      // issue the search command 
+      OneWireMaster::OWWriteByte(SEARCH_ROM);  
+
+      // 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 < searchState.last_discrepancy)
+         {
+            if ((searchState.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 == searchState.last_discrepancy)
+               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
+         result = OWTriplet(search_direction, id_bit, cmp_id_bit);
+         if (result != OneWireMaster::Success)
+           return result;
+
+         // 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)
+                  searchState.last_family_discrepancy = 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)
+               searchState.romId[rom_byte_number] |= rom_byte_mask;
+            else
+               searchState.romId[rom_byte_number] &= (uint8_t)~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, searchState.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_last_discrepancy,m_last_device_flag,search_result
+         searchState.last_discrepancy = last_zero;
+
+         // check for last device
+         if (searchState.last_discrepancy == 0)
+            searchState.last_device_flag = true;
+
+         search_result = true;
+      }
+   }
+
+   // if no device found then reset counters so next 'search' will be like a first
+   if (!search_result || (searchState.romId.familyCode() == 0))
+   {
+      searchState.reset();
+      search_result = false;
+   }
+
+   return search_result ? OneWireMaster::Success : OneWireMaster::OperationFailure;
+}
+
+
+OneWireMaster::CmdResult OneWireMaster::OWTriplet(SearchDirection & search_direction, uint8_t & sbr, uint8_t & tsb)
+{
+    CmdResult result;
+    result = OWReadBit(sbr);
+    if (result == Success)
+        result = OWReadBit(tsb);
+    if (result == Success)
+    {
+        if (sbr)
+            search_direction = DIRECTION_WRITE_ONE;
+        else if (tsb)
+            search_direction = DIRECTION_WRITE_ZERO;
+        // else: use search_direction parameter
+        
+        result = OWWriteBit((search_direction == DIRECTION_WRITE_ONE) ? 1 : 0);
+    }
+    return result;
+}
+
+
+uint16_t OneWireMaster::calculateCRC16(uint16_t CRC16, uint16_t data)
+{
+   const uint16_t _oddparity[] = { 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0 };
+    
+   data = (data ^ (CRC16 & 0xff)) & 0xff;
+   CRC16 >>= 8;
+
+   if (_oddparity[data & 0xf] ^ _oddparity[data >> 4])
+     CRC16 ^= 0xc001;
+
+   data <<= 6;
+   CRC16  ^= data;
+   data <<= 1;
+   CRC16   ^= data;
+
+   return CRC16;
+}
+
+
+uint16_t OneWireMaster::calculateCRC16(const uint8_t * data, size_t data_offset, size_t data_len, uint16_t crc)
+{  
+  for (size_t i = data_offset; i < (data_len + data_offset); i++)
+    crc = calculateCRC16(crc, data[i]);
+  return crc;
+}