This file is part of OneWire routines

by Isaac Marino Bavaresco

This is file "OneWire.c"
/*============================================================================*/
/*
 Copyright (c) 2016-2019, Isaac Marino Bavaresco
 All rights reserved.
 isaacbavaresco@yahoo.com.br

 Redistribution and use in source and binary forms, with or without
 modification, are permitted provided that the following conditions are met:
     * Redistributions of source code must retain the above copyright
       notice, this list of conditions and the following disclaimer.
     * Neither the name of the author nor the
       names of its contributors may be used to endorse or promote products
       derived from this software without specific prior written permission.

 THIS SOFTWARE IS PROVIDED BY THE AUTHOR ''AS IS'' AND ANY
 EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
 DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/*============================================================================*/
#include <string.h>
#include <xc.h>
#include "OneWire.h"
/*============================================================================*/
static onewirestatus_t OneWireWriteBit( onewireint_t Value )
    {
    if( Value )
        return OneWireWriteOne();
    else
        return OneWireWriteZero();
    }
/*============================================================================*/
onewirestatus_t OneWireWriteByte( unsigned char Value )
    {
    onewirestatus_t Status;
    onewireint_t    BitNumber;

    for( BitNumber = 0; BitNumber < 8; BitNumber++, Value >>= 1 )
        {
        if(( Status = OneWireWriteBit( Value & 0x01 )) != ONE_WIRE_STATUS_OK )
            return Status;
        }

    return ONE_WIRE_STATUS_OK;
    }
/*============================================================================*/
int OneWireReadByte( void )
    {
    unsigned char   Value;
    onewirestatus_t Status;
    onewireint_t    BitNumber;

    for( BitNumber = 0, Value = 0; BitNumber < 8; BitNumber++ )
        {
        if(( Status = OneWireReadBit() ) < ONE_WIRE_STATUS_OK )
            return (int)Status;
        Value = (unsigned char)(( Value >> 1 ) | ( Status > ONE_WIRE_STATUS_OK ? 0x80 : 0x00 ));
        }

    return (unsigned int)Value;
    }
/*============================================================================*/
unsigned char CalcCRC8( unsigned char Seed, unsigned char Value )
    {
    static const unsigned char  CRC8Table[256] =
        {
          0,  94, 188, 226,  97,  63, 221, 131, 194, 156, 126,  32, 163, 253,  31,  65,
        157, 195,  33, 127, 252, 162,  64,  30,  95,   1, 227, 189,  62,  96, 130, 220,
         35, 125, 159, 193,  66,  28, 254, 160, 225, 191,  93,   3, 128, 222,  60,  98,
        190, 224,   2,  92, 223, 129,  99,  61, 124,  34, 192, 158,  29,  67, 161, 255,
         70,  24, 250, 164,  39, 121, 155, 197, 132, 218,  56, 102, 229, 187,  89,   7,
        219, 133, 103,  57, 186, 228,   6,  88,  25,  71, 165, 251, 120,  38, 196, 154,
        101,  59, 217, 135,   4,  90, 184, 230, 167, 249,  27,  69, 198, 152, 122,  36,
        248, 166,  68,  26, 153, 199,  37, 123,  58, 100, 134, 216,  91,   5, 231, 185,
        140, 210,  48, 110, 237, 179,  81,  15,  78,  16, 242, 172,  47, 113, 147, 205,
         17,  79, 173, 243, 112,  46, 204, 146, 211, 141, 111,  49, 178, 236,  14,  80,
        175, 241,  19,  77, 206, 144, 114,  44, 109,  51, 209, 143,  12,  82, 176, 238,
         50, 108, 142, 208,  83,  13, 239, 177, 240, 174,  76,  18, 145, 207,  45, 115,
        202, 148, 118,  40, 171, 245,  23,  73,   8,  86, 180, 234, 105,  55, 213, 139,
         87,   9, 235, 181,  54, 104, 138, 212, 149, 203,  41, 119, 244, 170,  72,  22,
        233, 183,  85,  11, 136, 214,  52, 106,  43, 117, 151, 201,  74,  20, 246, 168,
        116,  42, 200, 150,  21,  75, 169, 247, 182, 232,  10,  84, 215, 137, 107,  53
        };

    return CRC8Table[(unsigned char)( Seed ^ Value )];
    }
/*============================================================================*/
onewirestatus_t OneWireMatchROM( const ibuttonsn_t *SerialNumber )
    {
    onewirestatus_t Status;
    onewireint_t    i;

    if(( Status = OneWireWriteByte( ONE_WIRE_COMMAND_MATCH_ROM )) != ONE_WIRE_STATUS_OK )
        return Status;

    for( i = 0; i < (onewireint_t)sizeof *SerialNumber; i++ )
        {
        if(( Status = OneWireWriteByte( SerialNumber->Bytes[i] )) != ONE_WIRE_STATUS_OK )
            return Status;
        }

    return ONE_WIRE_STATUS_OK;
    }
/*============================================================================*/
onewirestatus_t OneWireReadSerialNumber( ibuttonsn_t *SerialNumber )
    {
    unsigned char   CRC;
    onewirestatus_t Status;
    onewireint_t    i;
    int             Result;

    if(( Status = OneWireReset() ) != ONE_WIRE_STATUS_OK )
        return Status;

    if(( Status = OneWireWriteByte( ONE_WIRE_COMMAND_READ_ROM )) != ONE_WIRE_STATUS_OK )
        return Status;

    for( CRC = 0, i = 0; i < ONE_WIRE_SERIAL_NUMBER_SIZE; i++ )
        {
        if(( Result = OneWireReadByte() ) < ONE_WIRE_STATUS_OK )
            return (onewirestatus_t)Result;
        CRC = CalcCRC8( CRC, SerialNumber->Bytes[i] = (unsigned char)Result );
        }

    if( CRC != 0 )
        return ONE_WIRE_STATUS_CRC_ERROR;
    else
        return ONE_WIRE_STATUS_OK;
    }
/*============================================================================*/
/*============================================================================*/
#if         defined USE_INLINE
static inline onewirestatus_t BitVectorExtract( unsigned char *V, onewireint_t Bit )
    {
    return ( V[ Bit / 8 ] >> Bit % 8 ) & 0x01;
    }
#else   /*  defined USE_INLINE */
#define BitVectorExtract(v,b)   (((v)[(b)>>3]>>((b)&7))&0x01)
#endif  /*  defined USE_INLINE */
/*============================================================================*/
#if         defined USE_INLINE
static inline void BitVectorInsert( unsigned char *V, onewireint_t Bit, onewireint_t Value )
    {
    V[ Bit / 8 ]    = ( V[ Bit / 8 ] & ~( 1 << Bit % 8 )) | (( Value & 0x01 ) << Bit % 8 );
    }
#else   /*  defined USE_INLINE */
#define BitVectorInsert(v,b,l) ((v)[(b)>>3]=((v)[(b)>>3]&~(1<<((b)&7)))|(((l)&0x01)<<((b)&7)))
#endif  /*  defined USE_INLINE */
/*============================================================================*/
void OneWireSearchInit( onewiresearch_t *SearchStruct, int FamilyCode )
    {
    memset( SearchStruct->SerialNumber, 0x00, sizeof SearchStruct->SerialNumber );
    memset( SearchStruct->Branches, 0x00, sizeof SearchStruct->Branches );
    if( FamilyCode >= 0 && FamilyCode <= 255 )
        {
        SearchStruct->SerialNumber[0]   = (unsigned char)FamilyCode;
        SearchStruct->NumberOfFixedBits = 8;
        }
    else
        SearchStruct->NumberOfFixedBits = 0;

    SearchStruct->FirstSearch   = 1;
    SearchStruct->Finished      = 0;
    }
/*============================================================================*/
onewirestatus_t OneWireSearch( onewiresearch_t *SearchStruct, ibuttonsn_t *SerialNumber )
    {
    onewirestatus_t BitTrue, BitNegated, CurrentBit;
    onewirestatus_t Status;
    onewireint_t    BitNumber;

    if( SearchStruct->Finished != 0 )
        return ONE_WIRE_SEARCH_STATUS_NOT_FOUND;

    if(( Status = OneWireReset() ) != ONE_WIRE_STATUS_OK )
        return Status;

    /*
    If this is not the first search iteration we must unwind the tree before
    starting the next iteration.
    */
    if( SearchStruct->FirstSearch == 0 )
        {
        /*
        We start at a leaf of the tree and walk up until we reach the closest
        branch where we took a left turn and then switch it to a right turn (set serial number bit),
        while we zero the bits for all other occurrences.
        */
        for( BitNumber = 8 * ONE_WIRE_SERIAL_NUMBER_SIZE - 1; BitNumber >= SearchStruct->NumberOfFixedBits; BitNumber-- )
            {
            if( BitVectorExtract( SearchStruct->Branches, BitNumber ) == 1 && BitVectorExtract( SearchStruct->SerialNumber, BitNumber ) == 0 )
                {
                BitVectorInsert( SearchStruct->SerialNumber, BitNumber, 1 );
                break;
                }
            BitVectorInsert( SearchStruct->SerialNumber, BitNumber, 0 );
            BitVectorInsert( SearchStruct->Branches, BitNumber, 0 );
            }
        if( BitNumber < SearchStruct->NumberOfFixedBits )
            {
            SearchStruct->Finished  = 1;
            return ONE_WIRE_SEARCH_STATUS_NOT_FOUND;
            }
        }

    SearchStruct->FirstSearch   = 0;

    /* Issue the command SEARCH ROM to all devices on the bus. */
    if(( Status = OneWireWriteByte( ONE_WIRE_COMMAND_SEARCH_ROM )) != ONE_WIRE_STATUS_OK )
        return Status;

    /*
    Walk down the tree marking the branches and taking the left path
    unless in a previous excursion we already took the left path.
    */
    for( BitNumber = 0; BitNumber < 8 * ONE_WIRE_SERIAL_NUMBER_SIZE; BitNumber++ )
        {
        /* Read the logical AND of the true values of the bits in this position of all devices on the bus. */
        if(( BitTrue = OneWireReadBit() ) < ONE_WIRE_STATUS_OK )
            /* ...but an error happened. */
            return BitTrue;
        /* Read the logical AND of the negated values of the bits in this position of all devices on the bus. */
        if(( BitNegated = OneWireReadBit() ) < ONE_WIRE_STATUS_OK )
            /* ...but an error happened. */
            return BitNegated;

        /* There was no response... */
        if( BitTrue == 1 && BitNegated == 1 )
            {
            SearchStruct->Finished  = 1;
            return ONE_WIRE_STATUS_NO_RESPONSE;
            }

        /* We are searching devices with a specific bit value in this position... */
        if( BitNumber < SearchStruct->NumberOfFixedBits )
            {
            /* ...get the value that we want for the bit. */
            CurrentBit  = BitVectorExtract( SearchStruct->SerialNumber, BitNumber );
            /* No device on the bus has the value we are expecting in this bit position... */
            if( CurrentBit != BitTrue )
                /* ...return a NOT FOUND status. */
                return ONE_WIRE_SEARCH_STATUS_NOT_FOUND;
            }
        /* We found at least two devices with opposite bit values in this bit position... */
        else if( BitTrue == 0 && BitNegated == 0 )
            {
            /* ...so we mark that there is a branch in this position... */
            BitVectorInsert( SearchStruct->Branches, BitNumber, 1 );
            /* ...and get the value we want to select. */
            CurrentBit  = BitVectorExtract( SearchStruct->SerialNumber, BitNumber );
            }
        /* All devices on the bus have the same value in this bit position... */
        else
            {
            /* ...so we save the value of the bit found. */
            BitVectorInsert( SearchStruct->SerialNumber, BitNumber, BitTrue );
            CurrentBit  = BitTrue;
            }

        /* Send the bit value to select only the devices that have the value we want in this bit position. */
        if(( Status = OneWireWriteBit( CurrentBit )) != ONE_WIRE_STATUS_OK )
            /* ...but an error happened. */
            return Status;
        }

    /* Save the serial number of the device that we just found... */
    memcpy( SerialNumber, SearchStruct->SerialNumber, sizeof SearchStruct->SerialNumber );

    /* ...and return a success status. */
    return ONE_WIRE_SEARCH_STATUS_FOUND;
    }
/*============================================================================*/