Implementation of 1-Wire with added Alarm Search Functionality

Dependents:   Max32630_One_Wire_Interface

OneWire_Masters/DS2480B/ds2480b.cpp

Committer:
j3
Date:
2016-04-19
Revision:
63:422be898443a
Parent:
32:bce180b544ed
Child:
65:a28ac52ca127

File content as of revision 63:422be898443a:

/******************************************************************//**
* 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 "ds2480b.h"

#define WRITE_FUNCTION                 0
#define READ_FUNCTION                  1

// Mode Commands
#define MODE_DATA                      0xE1
#define MODE_COMMAND                   0xE3
#define MODE_STOP_PULSE                0xF1

// Return byte value
#define RB_CHIPID_MASK                 0x1C
#define RB_RESET_MASK                  0x03
#define RB_1WIRESHORT                  0x00
#define RB_PRESENCE                    0x01
#define RB_ALARMPRESENCE               0x02
#define RB_NOPRESENCE                  0x03

#define RB_BIT_MASK                    0x03
#define RB_BIT_ONE                     0x03
#define RB_BIT_ZERO                    0x00

// Masks for all bit ranges
#define CMD_MASK                       0x80
#define FUNCTSEL_MASK                  0x60
#define BITPOL_MASK                    0x10
#define SPEEDSEL_MASK                  0x0C
#define MODSEL_MASK                    0x02
#define PARMSEL_MASK                   0x70
#define PARMSET_MASK                   0x0E

// Command or config bit
#define CMD_COMM                       0x81
#define CMD_CONFIG                     0x01

// Function select bits
#define FUNCTSEL_BIT                   0x00
#define FUNCTSEL_SEARCHON              0x30
#define FUNCTSEL_SEARCHOFF             0x20
#define FUNCTSEL_RESET                 0x40
#define FUNCTSEL_CHMOD                 0x60

// Bit polarity/Pulse voltage bits
#define BITPOL_ONE                     0x10
#define BITPOL_ZERO                    0x00
#define BITPOL_5V                      0x00
#define BITPOL_12V                     0x10

// One Wire speed bits
#define SPEEDSEL_STD                   0x00
#define SPEEDSEL_FLEX                  0x04
#define SPEEDSEL_OD                    0x08
#define SPEEDSEL_PULSE                 0x0C

// Data/Command mode select bits
#define MODSEL_DATA                    0x00
#define MODSEL_COMMAND                 0x02

// 5V Follow Pulse select bits 
#define PRIME5V_TRUE                   0x02
#define PRIME5V_FALSE                  0x00

// Parameter select bits
#define PARMSEL_PARMREAD               0x00
#define PARMSEL_SLEW                   0x10
#define PARMSEL_12VPULSE               0x20
#define PARMSEL_5VPULSE                0x30
#define PARMSEL_WRITE1LOW              0x40
#define PARMSEL_SAMPLEOFFSET           0x50
#define PARMSEL_ACTIVEPULLUPTIME       0x60
#define PARMSEL_BAUDRATE               0x70

// Pull down slew rate.
#define PARMSET_Slew15Vus              0x00
#define PARMSET_Slew2p2Vus             0x02
#define PARMSET_Slew1p65Vus            0x04
#define PARMSET_Slew1p37Vus            0x06
#define PARMSET_Slew1p1Vus             0x08
#define PARMSET_Slew0p83Vus            0x0A
#define PARMSET_Slew0p7Vus             0x0C
#define PARMSET_Slew0p55Vus            0x0E

// 12V programming pulse time table
#define PARMSET_32us                   0x00
#define PARMSET_64us                   0x02
#define PARMSET_128us                  0x04
#define PARMSET_256us                  0x06
#define PARMSET_512us                  0x08
#define PARMSET_1024us                 0x0A
#define PARMSET_2048us                 0x0C
#define PARMSET_infinite               0x0E

// 5V strong pull up pulse time table
#define PARMSET_16p4ms                 0x00
#define PARMSET_65p5ms                 0x02
#define PARMSET_131ms                  0x04
#define PARMSET_262ms                  0x06
#define PARMSET_524ms                  0x08
#define PARMSET_1p05s                  0x0A
#define PARMSET_dynamic                0x0C
#define PARMSET_infinite               0x0E

// Write 1 low time
#define PARMSET_Write8us               0x00
#define PARMSET_Write9us               0x02
#define PARMSET_Write10us              0x04
#define PARMSET_Write11us              0x06
#define PARMSET_Write12us              0x08
#define PARMSET_Write13us              0x0A
#define PARMSET_Write14us              0x0C
#define PARMSET_Write15us              0x0E

// Data sample offset and Write 0 recovery time
#define PARMSET_SampOff3us             0x00
#define PARMSET_SampOff4us             0x02
#define PARMSET_SampOff5us             0x04
#define PARMSET_SampOff6us             0x06
#define PARMSET_SampOff7us             0x08
#define PARMSET_SampOff8us             0x0A
#define PARMSET_SampOff9us             0x0C
#define PARMSET_SampOff10us            0x0E

// Active pull up on time
#define PARMSET_PullUp0p0us            0x00
#define PARMSET_PullUp0p5us            0x02
#define PARMSET_PullUp1p0us            0x04
#define PARMSET_PullUp1p5us            0x06
#define PARMSET_PullUp2p0us            0x08
#define PARMSET_PullUp2p5us            0x0A
#define PARMSET_PullUp3p0us            0x0C
#define PARMSET_PullUp3p5us            0x0E

// Baud rate bits
#define PARMSET_9600                   0x00
#define PARMSET_19200                  0x02
#define PARMSET_57600                  0x04
#define PARMSET_115200                 0x06

// DS2480B program voltage available
#define DS2480BPROG_MASK                0x20

// mode bit flags
#define MODE_NORMAL                    0x00
#define MODE_OVERDRIVE                 0x01
#define MODE_STRONG5                   0x02
#define MODE_PROGRAM                   0x04
#define MODE_BREAK                     0x08

#define MAX_BAUD                       PARMSET_115200



//*********************************************************************
Ds2480b::Ds2480b(Serial &p_serial)
:_p_serial(&p_serial), _serial_owner(false)
{
}


//*********************************************************************
Ds2480b::Ds2480b(PinName tx, PinName rx)
:_p_serial(new Serial(tx, rx)), _serial_owner(true)
{
}


//*********************************************************************
Ds2480b::~Ds2480b()
{
    if(_serial_owner)
    {
        delete _p_serial;
    }
}


//*********************************************************************
void Ds2480b::rx_callback(void)
{
    rx_buffer.buff[rx_buffer.w_idx++] = _p_serial->getc();
    
    if(rx_buffer.w_idx == rx_buffer.r_idx)
    {
        rx_buffer.wrap_error = true;
    }
}


//*********************************************************************
void Ds2480b::tx_callback(void)
{
}


//*********************************************************************
OneWireMaster::CmdResult Ds2480b::OWInitMaster(void)
{
    _p_serial->attach(this, &Ds2480b::rx_callback, Serial::RxIrq);
    _p_serial->attach(this, &Ds2480b::tx_callback, Serial::TxIrq);
    
    rx_buffer.w_idx = 0;
    rx_buffer.r_idx = 0;
    rx_buffer.wrap_error = false;
    
    _ULevel = OneWireMaster::LEVEL_NORMAL;
    _UBaud = BPS_9600;
    _UMode = MODSEL_COMMAND;
    _USpeed = OneWireMaster::SPEED_STANDARD;
    
    return DS2480B_Detect();
}


//*********************************************************************
OneWireMaster::CmdResult Ds2480b::OWReset(void)
{
    OneWireMaster::CmdResult result;

    uint8_t readbuffer[10],sendpacket[10];
    uint8_t sendlen=0;

    // make sure normal level
    result = OWSetLevel(OneWireMaster::LEVEL_NORMAL);
    if(result == OneWireMaster::Success) 
    {
        // check for correct mode
        if(_UMode != MODSEL_COMMAND) 
        {
            _UMode = MODSEL_COMMAND;
            sendpacket[sendlen++] = MODE_COMMAND;
        }

        // construct the command
        sendpacket[sendlen++] = (uint8_t)(CMD_COMM | FUNCTSEL_RESET | _USpeed);
        
        FlushCOM();

        // send the packet
        result = WriteCOM(sendlen,sendpacket);
        if(result == OneWireMaster::Success) 
        {
            // read back the 1 byte response
            result = ReadCOM(1,readbuffer);
            if(result == OneWireMaster::Success) 
            {
                // make sure this byte looks like a reset byte
                if(((readbuffer[0] & RB_RESET_MASK) == RB_PRESENCE) || ((readbuffer[0] & RB_RESET_MASK) == RB_ALARMPRESENCE))
                {
                    result = OneWireMaster::Success;
                }
                else
                {
                    result = OneWireMaster::OperationFailure;
                }
            }
        }
        
        if(result != OneWireMaster::Success)
        {
            // an error occured so re-sync with DS2480B
            DS2480B_Detect();
        }
    }

    return result;
}


//*********************************************************************
OneWireMaster::CmdResult Ds2480b::OWTouchBit(uint8_t & sendrecvbit, OWLevel after_level)
{
    OneWireMaster::CmdResult result = OneWireMaster::OperationFailure;

    uint8_t readbuffer[10],sendpacket[10];
    uint8_t sendlen=0;

    // make sure normal level
    OWSetLevel(OneWireMaster::LEVEL_NORMAL);

    // check for correct mode
    if(_UMode != MODSEL_COMMAND) 
    {
        _UMode = MODSEL_COMMAND;
        sendpacket[sendlen++] = MODE_COMMAND;
    }

    // construct the command
    sendpacket[sendlen] = (sendrecvbit != 0) ? BITPOL_ONE : BITPOL_ZERO;
    sendpacket[sendlen++] |= CMD_COMM | FUNCTSEL_BIT | _USpeed;

    // flush the buffers
    FlushCOM();

    // send the packet
    result = WriteCOM(sendlen,sendpacket);
    if(result == OneWireMaster::Success) 
    {
        // read back the response
        result = ReadCOM(1,readbuffer);
        if(result == OneWireMaster::Success) 
        {
            // interpret the response
            if (((readbuffer[0] & 0xE0) == 0x80) && ((readbuffer[0] & RB_BIT_MASK) == RB_BIT_ONE))
            {
                sendrecvbit = 1;
                result = OneWireMaster::Success;
            }
            else
            {
                sendrecvbit = 0;
                result = OneWireMaster::Success;
            }
        }
        else
        {
            result = OneWireMaster::CommunicationReadError;
        }
    }
    else
    {
        result = OneWireMaster::CommunicationWriteError;
    }

    // an error occured so re-sync with DS2480B
    if(result != OneWireMaster::Success)
    {
        DS2480B_Detect();
    }
    else
    {
       result = OWSetLevel(after_level);
    }

    return result;
}


//*********************************************************************
OneWireMaster::CmdResult Ds2480b::OWWriteByte(uint8_t sendbyte, OWLevel after_level)
{
    OneWireMaster::CmdResult result = OneWireMaster::OperationFailure;

    uint8_t readbuffer[10],sendpacket[10];
    uint8_t sendlen=0;

    // make sure normal level
    OWSetLevel(OneWireMaster::LEVEL_NORMAL);

    // check for correct mode
    if (_UMode != MODSEL_DATA) 
    {
        _UMode = MODSEL_DATA;
        sendpacket[sendlen++] = MODE_DATA;
    }

    // add the byte to send
    sendpacket[sendlen++] = sendbyte;

    // check for duplication of data that looks like COMMAND mode
    if(sendbyte == MODE_COMMAND)
    {
        sendpacket[sendlen++] = sendbyte;
    }

    // flush the buffers
    FlushCOM();

    // send the packet
    result = WriteCOM(sendlen,sendpacket);
    if(result == OneWireMaster::Success) 
    {
        // read back the 1 byte response
        result = ReadCOM(1,readbuffer);
        if((result == OneWireMaster::Success) && (readbuffer[0] == sendbyte)) 
        {
            result = OneWireMaster::Success;
        }
        else
        {
            result = OneWireMaster::CommunicationReadError;
        }
    }
    else
    {
        result = OneWireMaster::CommunicationWriteError;
    }

    // an error occured so re-sync with DS2480B
    if(result != OneWireMaster::Success)
    {
        DS2480B_Detect();
    }
    else
    {
       result = OWSetLevel(after_level);
    }

    return result;
}


//*********************************************************************
OneWireMaster::CmdResult Ds2480b::OWReadByte(uint8_t & recvbyte, OWLevel after_level)
{
    OneWireMaster::CmdResult result = OneWireMaster::OperationFailure;

    uint8_t readbuffer[10],sendpacket[10];
    uint8_t sendlen=0;

    // make sure normal level
    OWSetLevel(OneWireMaster::LEVEL_NORMAL);

    // check for correct mode
    if (_UMode != MODSEL_DATA) 
    {
        _UMode = MODSEL_DATA;
        sendpacket[sendlen++] = MODE_DATA;
    }

    // add the byte to send
    sendpacket[sendlen++] = 0xFF;

    // flush the buffers
    FlushCOM();

    // send the packet
    result = WriteCOM(sendlen,sendpacket);
    if(result == OneWireMaster::Success) 
    {
        // read back the 1 byte response
        result = ReadCOM(1,readbuffer);
        if(result == OneWireMaster::Success) 
        {
            recvbyte = readbuffer[0];
            result = OneWireMaster::Success;
        }
        else
        {
            result = OneWireMaster::CommunicationReadError;
        }
    }
    else
    {
        result = OneWireMaster::CommunicationWriteError;
    }

    // an error occured so re-sync with DS2480B
    if(result != OneWireMaster::Success)
    {
        DS2480B_Detect();
    }
    else
    {
       result = OWSetLevel(after_level);
    }

    return result;
}


//*********************************************************************
OneWireMaster::CmdResult Ds2480b::OWWriteBlock(const uint8_t *tran_buf, uint8_t tran_len)
{
    OneWireMaster::CmdResult result;
    uint8_t idx = 0;

    do
    {
        result = OWWriteByte(tran_buf[idx++], OneWireMaster::LEVEL_NORMAL);
    }
    while((result == OneWireMaster::Success) && (idx < tran_len));

    return result;
}


//*********************************************************************
OneWireMaster::CmdResult Ds2480b::OWReadBlock(uint8_t *rx_buf, uint8_t rx_len)
{
    OneWireMaster::CmdResult result;
    uint8_t idx = 0;

    do
    {
        result = OWReadByte(rx_buf[idx++], OneWireMaster::LEVEL_NORMAL);
    }
    while((result == OneWireMaster::Success) && (idx < rx_len));

    return result;
}


//*********************************************************************
OneWireMaster::CmdResult Ds2480b::OWSetSpeed(OWSpeed new_speed)
{
    OneWireMaster::CmdResult result = OneWireMaster::OperationFailure;
    
    //TODO
    
    return result;
}


//*********************************************************************
OneWireMaster::CmdResult Ds2480b::OWSetLevel(OWLevel new_level)
{
    OneWireMaster::CmdResult result = OneWireMaster::Success;

    uint8_t sendpacket[10],readbuffer[10];
    uint8_t sendlen=0;

    // check if need to change level
    if(new_level != _ULevel) 
    {
        // check for correct mode
        if(_UMode != MODSEL_COMMAND) 
        {
            _UMode = MODSEL_COMMAND;
            sendpacket[sendlen++] = MODE_COMMAND;
        }
        
        // check if just putting back to normal
        if(new_level == OneWireMaster::LEVEL_NORMAL) 
        {
            // stop pulse command
            sendpacket[sendlen++] = MODE_STOP_PULSE;

            // add the command to begin the pulse WITHOUT prime
            sendpacket[sendlen++] = CMD_COMM | FUNCTSEL_CHMOD | SPEEDSEL_PULSE | BITPOL_5V | PRIME5V_FALSE;

            // stop pulse command
            sendpacket[sendlen++] = MODE_STOP_PULSE;
            
            FlushCOM();

            // send the packet
            result = WriteCOM(sendlen,sendpacket);
            if(result == OneWireMaster::Success) 
            {
                // read back the 1 byte response
                result = ReadCOM(2,readbuffer);
                if(result == OneWireMaster::Success) 
                {
                    // check response byte
                    if (((readbuffer[0] & 0xE0) == 0xE0) && ((readbuffer[1] & 0xE0) == 0xE0)) 
                    {
                        _ULevel = OneWireMaster::LEVEL_NORMAL;
                    }
                    else
                    {
                        result = OneWireMaster::OperationFailure;
                    }
                }
            }
        }
        // set new level
        else 
        {
            // set the SPUD time value
            sendpacket[sendlen++] = CMD_CONFIG | PARMSEL_5VPULSE | PARMSET_infinite;
            // add the command to begin the pulse
            sendpacket[sendlen++] = CMD_COMM | FUNCTSEL_CHMOD | SPEEDSEL_PULSE | BITPOL_5V;
            
            FlushCOM();

            // send the packet
            result = WriteCOM(sendlen,sendpacket);
            if(result == OneWireMaster::Success) 
            {
                // read back the 1 byte response from setting time limit
                result = ReadCOM(1,readbuffer);
                if(result == OneWireMaster::Success) 
                {
                    // check response byte
                    if ((readbuffer[0] & 0x81) == 0) 
                    {
                        _ULevel = new_level;
                    }
                    else
                    {
                        result = OneWireMaster::OperationFailure;
                    }
                }
            }
        }

        // if lost communication with DS2480B then reset
        if(result != OneWireMaster::Success)
        {
            DS2480B_Detect();
        }
            
    }

    return result;
}


//*********************************************************************
OneWireMaster::CmdResult Ds2480b::DS2480B_Detect(void)
{
    OneWireMaster::CmdResult result;

    uint8_t sendpacket[10],readbuffer[10];
    uint8_t sendlen=0;

    // reset modes
    _UMode = MODSEL_COMMAND;
    _UBaud = BPS_9600;
    _USpeed = SPEEDSEL_FLEX;

    // set the baud rate to 9600
    SetBaudCOM(_UBaud);

    // send a break to reset the DS2480B
    BreakCOM();

    // delay to let line settle
    wait_ms(2);
    
    FlushCOM();

    // send the timing byte
    sendpacket[0] = 0xC1;
    result = WriteCOM(1,sendpacket);
    if(result == OneWireMaster::Success) 
    {
        // delay to let line settle
        wait_ms(2);

        // set the FLEX configuration parameters
        // default PDSRC = 1.37Vus
        sendpacket[sendlen++] = CMD_CONFIG | PARMSEL_SLEW | PARMSET_Slew1p37Vus;
        // default W1LT = 10us
        sendpacket[sendlen++] = CMD_CONFIG | PARMSEL_WRITE1LOW | PARMSET_Write10us;
        // default DSO/WORT = 8us
        sendpacket[sendlen++] = CMD_CONFIG | PARMSEL_SAMPLEOFFSET | PARMSET_SampOff8us;

        // construct the command to read the baud rate (to test command block)
        sendpacket[sendlen++] = CMD_CONFIG | PARMSEL_PARMREAD | (PARMSEL_BAUDRATE >> 3);

        // also do 1 bit operation (to test 1-Wire block)
        sendpacket[sendlen++] = CMD_COMM | FUNCTSEL_BIT | _UBaud | BITPOL_ONE;
        
        FlushCOM();

        // send the packet
        result = WriteCOM(sendlen,sendpacket);
        if(result == OneWireMaster::Success) 
        {
            // read back the response
            result = ReadCOM(5,readbuffer);
            if(result == OneWireMaster::Success) 
            {
                // look at the baud rate and bit operation
                // to see if the response makes sense
                if (((readbuffer[3] & 0xF1) == 0x00) && ((readbuffer[3] & 0x0E) == _UBaud) &&  ((readbuffer[4] & 0xF0) == 0x90) && ((readbuffer[4] & 0x0C) == _UBaud)) 
                {
                    result = OneWireMaster::Success;
                }
                else
                {
                    result = OneWireMaster::OperationFailure;
                }
            }
        }
    }
    
    return result;
}


//*********************************************************************
OneWireMaster::CmdResult Ds2480b::DS2480B_ChangeBaud(DS2480B_BPS newbaud)
{
   OneWireMaster::CmdResult result = OneWireMaster::OperationFailure;
   
   uint8_t rt=0;
   uint8_t readbuffer[5],sendpacket[5],sendpacket2[5];
   uint8_t sendlen=0,sendlen2=0;

   // see if diffenent then current baud rate
   if (_UBaud == newbaud)
   {
      //return _UBaud;
   }
   else
   {
      // build the command packet
      // check for correct mode
      if (_UMode != MODSEL_COMMAND)
      {
         _UMode = MODSEL_COMMAND;
         sendpacket[sendlen++] = MODE_COMMAND;
      }
      // build the command
      sendpacket[sendlen++] = CMD_CONFIG | PARMSEL_BAUDRATE | newbaud;

      // flush the buffers
      FlushCOM();

      // send the packet
      if (!WriteCOM(sendlen,sendpacket))
         rt = 0;
      else
      {
         // make sure buffer is flushed
         wait_ms(5);

         // change our baud rate
         SetBaudCOM(newbaud);
         _UBaud = newbaud;

         // wait for things to settle
         wait_ms(5);

         // build a command packet to read back baud rate
         sendpacket2[sendlen2++] = CMD_CONFIG | PARMSEL_PARMREAD | (PARMSEL_BAUDRATE >> 3);

         // flush the buffers
         FlushCOM();

         // send the packet
         if(WriteCOM(sendlen2,sendpacket2))
         {
            // read back the 1 byte response
            if (ReadCOM(1,readbuffer) == 1)
            {
               // verify correct baud
               if (((readbuffer[0] & 0x0E) == (sendpacket[sendlen-1] & 0x0E)))
                  rt = 1;
            }
         }
      }
   }

   // if lost communication with DS2480B then reset
   if (rt != 1)
      DS2480B_Detect();

   return result;
}


//*********************************************************************
OneWireMaster::CmdResult Ds2480b::WriteCOM(uint32_t outlen, uint8_t *outbuf)
{
    OneWireMaster::CmdResult result = OneWireMaster::OperationFailure;
    
    Timer t;
    uint32_t t_val;
    uint32_t timeout;
    uint8_t idx = 0;
    
    //calculate timeout, the time needed to tx 1 byte
    switch(_UBaud) 
    {
        case BPS_115200:
            timeout = ((1000000/115200)*10);
            break;
            
        case BPS_57600:
            timeout = ((1000000/57600)*10);
            break;
            
        case BPS_19200:
            timeout = ((1000000/19200)*10);
            break;
            
        case BPS_9600:
        default:
            timeout = ((1000000/9600)*10);
            break;
    }
    
    t.start();
    do
    {
        t.reset();
        do
        {
            t_val = t.read_us();
        }
        while(!_p_serial->writeable() && (t_val < timeout));
        
        if(t_val < timeout)
        {
            _p_serial->putc(outbuf[idx++]);
            result = OneWireMaster::Success;
        }
        else
        {
            result = OneWireMaster::TimeoutError;
        }
    }
    while((idx < outlen) && (result == OneWireMaster::Success));
    
    return result;
}


//*********************************************************************
OneWireMaster::CmdResult Ds2480b::ReadCOM(uint32_t inlen, uint8_t *inbuf)
{
    OneWireMaster::CmdResult result;
    uint32_t num_bytes_read= 0;
    uint32_t timeout;
    
    //calculate timeout, 5x the time needed to recieve inlen bytes 
    switch(_UBaud) 
    {
        case BPS_115200:
            timeout = ((1000000/115200)*50)*inlen;
            break;
            
        case BPS_57600:
            timeout = ((1000000/57600)*50)*inlen;
            break;
            
        case BPS_19200:
            timeout = ((1000000/19200)*50)*inlen;
            break;
            
        case BPS_9600:
        default:
            timeout = ((1000000/9600)*50)*inlen;
            break;
    }
    
    wait_us(timeout);
    
    if(rx_buffer.wrap_error)
    {
        //reset rx buffer, error, and return failure
        rx_buffer.w_idx = 0;
        rx_buffer.r_idx = 0;
        rx_buffer.wrap_error = false;
        
        result = OneWireMaster::OperationFailure;
    }
    else
    {
        if(rx_buffer.w_idx != rx_buffer.r_idx)
        {
            do
            {
                inbuf[num_bytes_read++] = rx_buffer.buff[rx_buffer.r_idx++];
            }
            while((num_bytes_read < inlen) && (rx_buffer.w_idx != rx_buffer.r_idx));
            
            if(num_bytes_read == inlen)
            {
                result = OneWireMaster::Success;
            }
            else
            {
                result = OneWireMaster::CommunicationReadError;
            }
        }
        else
        {
            //buffer empty
            result = OneWireMaster::OperationFailure;
        }
    }
    
    return result;
}


//*********************************************************************
void Ds2480b::BreakCOM(void)
{
    while(!_p_serial->writeable()); 
    //for some reason send_break wouldn't work unless first sending char
    _p_serial->putc(0);
    _p_serial->send_break();
}


void Ds2480b::FlushCOM(void)
{
    //reset soft rx_buffer
    rx_buffer.w_idx = 0;
    rx_buffer.r_idx = 0;
    rx_buffer.wrap_error = false;
    
    //make sure hardware rx buffer is empty
    while(_p_serial->readable())
    {
        _p_serial->getc();
    }
}


//*********************************************************************
void Ds2480b::SetBaudCOM(uint8_t new_baud)
{
    switch(new_baud) 
    {
        case BPS_115200:
            _p_serial->baud(115200);
            break;
            
        case BPS_57600:
            _p_serial->baud(57600);
            break;
            
        case BPS_19200:
            _p_serial->baud(19200);
            break;
            
        case BPS_9600:
        default:
            _p_serial->baud(9600);
            break;
    }
}


//*********************************************************************
int32_t Ds2480b::bitacc(uint32_t op, uint32_t state, uint32_t loc, uint8_t *buf)
{
   int nbyt,nbit;

   nbyt = (loc / 8);
   nbit = loc - (nbyt * 8);

   if (op == WRITE_FUNCTION)
   {
      if (state)
         buf[nbyt] |= (0x01 << nbit);
      else
         buf[nbyt] &= ~(0x01 << nbit);

      return 1;
   }
   else
      return ((buf[nbyt] >> nbit) & 0x01);
}