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); }