Implementation of 1-Wire with added Alarm Search Functionality

Dependents:   Max32630_One_Wire_Interface

Masters/OneWireMaster.cpp

Committer:
IanBenzMaxim
Date:
2016-05-12
Revision:
73:2cecc1372acc
Parent:
OneWire_Masters/OneWireMaster.cpp@ 71:562f5c702094
Child:
74:23be10c32fa3

File content as of revision 73:2cecc1372acc:

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