Library to communicate with Maxim OneWire protocol devices Modified timings and IRQ overrides

Dependents:   RdGasUseMonitor

Fork of Onewire by Simon Barker

Onewire.cpp

Committer:
Bobty
Date:
2015-10-16
Revision:
8:5d0bd95b586f
Parent:
7:0a87f8c2d9e6

File content as of revision 8:5d0bd95b586f:

// Code derived from a number of sources including:
// simonbarker on MBED
// The search code is a port of Jim Studt's Adruino One Wire lib
// Can handle multiple devices per pin
// Rob Dobson, 2015

#include "Onewire.h"

Onewire::Onewire(PinName oneBus):oneBus_(oneBus)
{    
}

void Onewire::writeBit(int bit) 
{
    __disable_irq();
    bit = bit & 0x01;
    if (bit) 
    {
        // Write '1' bit
        __disable_irq();
        oneBus_.output();
        oneBus_ = 0;
        wait_us(10);
        oneBus_ = 1;
        __enable_irq();        
        wait_us(55);
    }
    else
    {
        // Write '0' bit
        __disable_irq();
        oneBus_.output();
        oneBus_ = 0;
        wait_us(65);
        oneBus_ = 1;
        __enable_irq();        
        wait_us(5);
    }
    __enable_irq();
}

int Onewire::readBit() 
{
    char result;

    __disable_irq();
    oneBus_.output();
    oneBus_ = 0;
    wait_us(3);
    oneBus_.input();
    wait_us(10);
    result = oneBus_.read();
    __enable_irq();
    wait_us(53);
    return result;
}

int Onewire::init()
{
    // Ensure bus is high to start
    oneBus_.input();
    int MAX_RETRY_TEST_BUS_HIGH = 125;
    for (int i = 0; i < MAX_RETRY_TEST_BUS_HIGH; i++)
    {
        if (oneBus_.read() == 1)
            break;
        wait_us(2);
    }
    if (oneBus_.read() != 1)
        return ONEWIRE_FAIL_STUCK_LOW;
    
    // Pull LOW for 480us
    __disable_irq();
    oneBus_.output();
    oneBus_ = 0;
    __enable_irq();
    wait_us(480);
    
    // Allow to float and test to ensure presence of devices
    // (which pull the bus low)
    __disable_irq();
    oneBus_.input();
    wait_us(70);
    int readVal = oneBus_.read();
    __enable_irq();
    wait_us(410);
    return (readVal == 0) ? ONEWIRE_OK : ONEWIRE_SEARCH_INIT_FAIL;
}

int Onewire::readByte() 
{
    int result = 0;

    for (int loop = 0; loop < ONEWIRE_ADDR_BYTES; loop++) {
        // shift the result to get it ready for the next bit
        result >>= 1;

        // if result is one, then set MS bit
        if (readBit())
            result |= 0x80;
    }
    return result;
}

void Onewire::writeByte(char data) 
{
    // Loop to write each bit in the byte, LS-bit first
    for (int loop = 0; loop < ONEWIRE_ADDR_BYTES; loop++) {
        writeBit(data & 0x01);

        // shift the data byte for the next bit
        data >>= 1;
    }
}

unsigned char Onewire::CRC(unsigned char* addr, unsigned char len) 
{
    unsigned char i, j;
    unsigned char crc = 0;

    for (i = 0; i < len; i++) {
        unsigned char inbyte = addr[i];
        for (j = 0; j < ONEWIRE_ADDR_BYTES; j++) {
            unsigned char mix = (crc ^ inbyte) & 0x01;
            crc >>= 1;
            if (mix) crc ^= 0x8C;
            inbyte >>= 1;
        }
    }
    return crc;
}

//
// You need to use this function to start a search again from the beginning.
// You do not need to do it for the first search, though you could.
//
void Onewire::reset_search()
{
    // reset the search state
    _search_LastDiscrepancy = 0;
    _search_LastDeviceFlag = false;
    _search_LastFamilyDiscrepancy = 0;
    for(int i = ONEWIRE_ADDR_BYTES-1; i >= 0; i--) 
        _search_ROM_NO[i] = 0;
}

// Search Based on Maxim DS18B20 Algorithm
// https://www.maximintegrated.com/en/app-notes/index.mvp/id/187
//
// Perform a search, returns:
// ONEWIRE_OK if a new address has been returned.
// ONEWIRE_SEARCH_ALL_DONE = all devices found
// ONEWIRE_SEARCH_INIT_FAIL = failed to init
// ONEWIRE_SEARCH_NOT_FOUND = no devices found If this function returns a '1' then it has
// ONEWIRE_SEARCH_STUCK_HIGH = bus is stuck high
// ONEWIRE_SEARCH_COMP_BIT_ERR = complement bit error
//
uint8_t Onewire::search(uint8_t *newAddr)
{
    // initialize for search
    uint8_t last_zero = 0;
    unsigned char search_direction = 0;

    // if the previous call was the last one
    if (_search_LastDeviceFlag)
        return ONEWIRE_SEARCH_ALL_DONE;
        
    // 1-Wire reset
    int initRslt = init();
    if (initRslt != ONEWIRE_OK)
    {
        // reset the search
        reset_search();
        return initRslt;
    }
    
    // issue the search command
    writeByte(0xF0);
    
    // loop to do the search
    for (int id_bit_number = 1; id_bit_number <= 64; id_bit_number++)
    {
        // read a bit and its complement
        uint8_t id_bit = readBit();
        uint8_t cmp_id_bit = readBit();
        
        // check for no devices on 1-wire
        if ((id_bit == 1) && (cmp_id_bit == 1))
        {
            reset_search();
            return ONEWIRE_SEARCH_COMP_BIT_ERR;
        }

        // all devices coupled have 0 or 1
        int byteNo = (id_bit_number - 1) / 8;
        int byteMask = 1 << ((id_bit_number - 1) % 8);
        if (id_bit != cmp_id_bit)
        {
            search_direction = id_bit;  // bit write value for search
        }           
        else
        {
            if (id_bit_number == _search_LastDiscrepancy)
            {
                search_direction = 1;
            }
            else if (id_bit_number > _search_LastDiscrepancy)
            {
                search_direction = 0;
            }
            else
            {
                search_direction = ((_search_ROM_NO[byteNo] & byteMask) > 0);
            }
            
            // if 0 was picked then record its position in LastZero
            if (search_direction == 0)
            {
                last_zero = id_bit_number;
                // check for Last discrepancy in family
                if (last_zero < 9)
                    _search_LastFamilyDiscrepancy = last_zero;
            }
        }
        
        // set or clear the bit in the ROM byte rom_byte_number
        // with mask rom_byte_mask
        
        if (search_direction == 1)
            _search_ROM_NO[byteNo] |= byteMask;
        else
            _search_ROM_NO[byteNo] &= ~byteMask;
        
        // serial number search direction write bit
        writeBit(search_direction);
    }
    
    // search successful so set LastDiscrepancy,LastDeviceFlag,search_result
    _search_LastDiscrepancy = last_zero;
    // check for last device
    if (_search_LastDiscrepancy == 0)
        _search_LastDeviceFlag = true;
    
    // Copy address to return
    for (int i = 0; i < ONEWIRE_ADDR_BYTES; i++)
        newAddr[i] = _search_ROM_NO[i];
        
    return ONEWIRE_OK;
}

char* Onewire::GetErrorStr(int errCode)
{
    switch(errCode)
    {
        case ONEWIRE_OK: return "OK";
        case ONEWIRE_FAIL_STUCK_LOW: return "Stuck Low";
        case ONEWIRE_SEARCH_ALL_DONE: return "All Done";
        case ONEWIRE_SEARCH_INIT_FAIL: return "Init Fail";
        case ONEWIRE_SEARCH_NOT_FOUND: return "Not Found";
        case ONEWIRE_SEARCH_COMP_BIT_ERR: return "Comp Bit Err";
    }
    return "Unknown Err";
}