1-Wire implementation, using DS2480B controller interfaced with serial port, working example to read DS18B20, based on work already in progress / Dallas - Public domain code

Dependencies:   mbed

Revision:
0:1193dbfe28e2
diff -r 000000000000 -r 1193dbfe28e2 ownet.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ownet.cpp	Thu Mar 24 17:21:29 2011 +0000
@@ -0,0 +1,538 @@
+//---------------------------------------------------------------------------
+// Copyright (C) 2000 Dallas Semiconductor Corporation, 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 DALLAS SEMICONDUCTOR 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 Dallas Semiconductor
+// shall not be used except as stated in the Dallas Semiconductor
+// Branding Policy.
+//---------------------------------------------------------------------------
+//
+//  ownet.C - Network functions for 1-Wire net devices.
+//
+//  Version: 3.00
+//
+//  History: 1.00 -> 1.01  Change to owFamilySearchSetup, LastDiscrepancy[portnum]
+//                         was set to 64 instead of 8 to enable devices with
+//                         early contention to go in the '0' direction first.
+//           1.02 -> 1.03  Initialized goodbits in  owVerify
+//           1.03 -> 2.00  Changed 'MLan' to 'ow'. Added support for
+//                         multiple ports.
+//           2.00 -> 2.01  Added support for owError library
+//           2.01 -> 3.00  Make search functions consistent with AN187
+//
+
+#include <stdio.h>
+#include "ownet.h"
+
+// exportable functions defined in ownet.c
+SMALLINT bitacc(SMALLINT,SMALLINT,SMALLINT,uchar *);
+
+// global variables for this module to hold search state information
+static SMALLINT LastDiscrepancy[MAX_PORTNUM];
+static SMALLINT LastFamilyDiscrepancy[MAX_PORTNUM];
+static SMALLINT LastDevice[MAX_PORTNUM];
+uchar SerialNum[MAX_PORTNUM][8];
+
+//--------------------------------------------------------------------------
+// The 'owFirst' finds the first device on the 1-Wire Net  This function
+// contains one parameter 'alarm_only'.  When
+// 'alarm_only' is TRUE (1) the find alarm command 0xEC is
+// sent instead of the normal search command 0xF0.
+// Using the find alarm command 0xEC will limit the search to only
+// 1-Wire devices that are in an 'alarm' state.
+//
+// 'portnum'    - number 0 to MAX_PORTNUM-1.  This number is provided to
+//                indicate the symbolic port number.
+// 'do_reset'   - TRUE (1) perform reset before search, FALSE (0) do not
+//                perform reset before search.
+// 'alarm_only' - TRUE (1) the find alarm command 0xEC is
+//                sent instead of the normal search command 0xF0
+//
+// Returns:   TRUE (1) : when a 1-Wire device was found and it's
+//                        Serial Number placed in the global SerialNum[portnum]
+//            FALSE (0): There are no devices on the 1-Wire Net.
+//
+SMALLINT owFirst(int portnum, SMALLINT do_reset, SMALLINT alarm_only)
+{
+   // reset the search state
+   LastDiscrepancy[portnum] = 0;
+   LastDevice[portnum] = FALSE;
+   LastFamilyDiscrepancy[portnum] = 0;
+
+   return owNext(portnum,do_reset,alarm_only);
+}
+
+//--------------------------------------------------------------------------
+// The 'owNext' function does a general search.  This function
+// continues from the previos search state. The search state
+// can be reset by using the 'owFirst' function.
+// This function contains one parameter 'alarm_only'.
+// When 'alarm_only' is TRUE (1) the find alarm command
+// 0xEC is sent instead of the normal search command 0xF0.
+// Using the find alarm command 0xEC will limit the search to only
+// 1-Wire devices that are in an 'alarm' state.
+//
+// 'portnum'    - number 0 to MAX_PORTNUM-1.  This number is provided to
+//                indicate the symbolic port number.
+// 'do_reset'   - TRUE (1) perform reset before search, FALSE (0) do not
+//                perform reset before search.
+// 'alarm_only' - TRUE (1) the find alarm command 0xEC is
+//                sent instead of the normal search command 0xF0
+//
+// Returns:   TRUE (1) : when a 1-Wire device was found and it's
+//                       Serial Number placed in the global SerialNum[portnum]
+//            FALSE (0): when no new device was found.  Either the
+//                       last search was the last device or there
+//                       are no devices on the 1-Wire Net.
+//
+SMALLINT owNext(int portnum, SMALLINT do_reset, SMALLINT alarm_only)
+{
+   uchar bit_test, search_direction, bit_number;
+   uchar last_zero, serial_byte_number, next_result;
+   uchar serial_byte_mask;
+   uchar lastcrc8=0;
+
+   // initialize for search
+   bit_number = 1;
+   last_zero = 0;
+   serial_byte_number = 0;
+   serial_byte_mask = 1;
+   next_result = 0;
+   setcrc8(portnum,0);
+
+   // if the last call was not the last one
+   if (!LastDevice[portnum])
+   {
+      // check if reset first is requested
+      if (do_reset)
+      {
+         // reset the 1-wire
+         // if there are no parts on 1-wire, return FALSE
+         if (!owTouchReset(portnum))
+         {
+            // printf("owTouchReset failed\r\n");
+            // reset the search
+            LastDiscrepancy[portnum] = 0;
+            LastFamilyDiscrepancy[portnum] = 0;
+            OWERROR(OWERROR_NO_DEVICES_ON_NET);
+            return FALSE;
+         }
+      }
+
+      // If finding alarming devices issue a different command
+      if (alarm_only)
+         owWriteByte(portnum,0xEC);  // issue the alarming search command
+      else
+         owWriteByte(portnum,0xF0);  // issue the search command
+
+      //pause before beginning the search
+      //usDelay(100);
+
+      // loop to do the search
+      do
+      {
+         // read a bit and its compliment
+         bit_test = owTouchBit(portnum,1) << 1;
+         bit_test |= owTouchBit(portnum,1);
+
+         // check for no devices on 1-wire
+         if (bit_test == 3)
+            break;
+         else
+         {
+            // all devices coupled have 0 or 1
+            if (bit_test > 0)
+              search_direction = !(bit_test & 0x01);  // bit write value for search
+            else
+            {
+               // if this discrepancy if before the Last Discrepancy
+               // on a previous next then pick the same as last time
+               if (bit_number < LastDiscrepancy[portnum])
+                  search_direction = ((SerialNum[portnum][serial_byte_number] & serial_byte_mask) > 0);
+               else
+                  // if equal to last pick 1, if not then pick 0
+                  search_direction = (bit_number == LastDiscrepancy[portnum]);
+
+               // if 0 was picked then record its position in LastZero
+               if (search_direction == 0)
+               {
+                  last_zero = bit_number;
+
+                  // check for Last discrepancy in family
+                  if (last_zero < 9)
+                     LastFamilyDiscrepancy[portnum] = last_zero;
+               }
+            }
+
+            // set or clear the bit in the SerialNum[portnum] byte serial_byte_number
+            // with mask serial_byte_mask
+            if (search_direction == 1)
+              SerialNum[portnum][serial_byte_number] |= serial_byte_mask;
+            else
+              SerialNum[portnum][serial_byte_number] &= ~serial_byte_mask;
+
+            // serial number search direction write bit
+            owTouchBit(portnum,search_direction);
+
+            // increment the byte counter bit_number
+            // and shift the mask serial_byte_mask
+            bit_number++;
+            serial_byte_mask <<= 1;
+
+            // if the mask is 0 then go to new SerialNum[portnum] byte serial_byte_number
+            // and reset mask
+            if (serial_byte_mask == 0)
+            {
+               // The below has been added to accomidate the valid CRC with the
+               // possible changing serial number values of the DS28E04.
+               if (((SerialNum[portnum][0] & 0x7F) == 0x1C) && (serial_byte_number == 1))
+                  lastcrc8 = docrc8(portnum,0x7F);
+               else
+                  lastcrc8 = docrc8(portnum,SerialNum[portnum][serial_byte_number]);  // accumulate the CRC
+
+               serial_byte_number++;
+               serial_byte_mask = 1;
+            }
+         }
+      }
+      while(serial_byte_number < 8);  // loop until through all SerialNum[portnum] bytes 0-7
+
+      // if the search was successful then
+      if (!((bit_number < 65) || lastcrc8))
+      {
+         // search successful so set LastDiscrepancy[portnum],LastDevice[portnum],next_result
+         LastDiscrepancy[portnum] = last_zero;
+         LastDevice[portnum] = (LastDiscrepancy[portnum] == 0);
+         next_result = TRUE;
+      }
+   }
+
+   // if no device found then reset counters so next 'next' will be
+   // like a first
+   if (!next_result || !SerialNum[portnum][0])
+   {
+      LastDiscrepancy[portnum] = 0;
+      LastDevice[portnum] = FALSE;
+      LastFamilyDiscrepancy[portnum] = 0;
+      next_result = FALSE;
+   }
+
+   return next_result;
+}
+
+//--------------------------------------------------------------------------
+// The 'owSerialNum' function either reads or sets the SerialNum buffer
+// that is used in the search functions 'owFirst' and 'owNext'.
+// This function contains two parameters, 'serialnum_buf' is a pointer
+// to a buffer provided by the caller.  'serialnum_buf' should point to
+// an array of 8 unsigned chars.  The second parameter is a flag called
+// 'do_read' that is TRUE (1) if the operation is to read and FALSE
+// (0) if the operation is to set the internal SerialNum buffer from
+// the data in the provided buffer.
+//
+// 'portnum'       - number 0 to MAX_PORTNUM-1.  This number is provided to
+//                   indicate the symbolic port number.
+// 'serialnum_buf' - buffer to that contains the serial number to set
+//                   when do_read = FALSE (0) and buffer to get the serial
+//                   number when do_read = TRUE (1).
+// 'do_read'       - flag to indicate reading (1) or setting (0) the current
+//                   serial number.
+//
+void owSerialNum(int portnum, uchar *serialnum_buf, SMALLINT do_read)
+{
+   uchar i;
+
+   // read the internal buffer and place in 'serialnum_buf'
+   if (do_read)
+   {
+      for (i = 0; i < 8; i++)
+         serialnum_buf[i] = SerialNum[portnum][i];
+   }
+   // set the internal buffer from the data in 'serialnum_buf'
+   else
+   {
+      for (i = 0; i < 8; i++)
+         SerialNum[portnum][i] = serialnum_buf[i];
+   }
+}
+
+//--------------------------------------------------------------------------
+// Setup the search algorithm to find a certain family of devices
+// the next time a search function is called 'owNext'.
+//
+// 'portnum'       - number 0 to MAX_PORTNUM-1.  This number was provided to
+//                   OpenCOM to indicate the port number.
+// 'search_family' - family code type to set the search algorithm to find
+//                   next.
+//
+void owFamilySearchSetup(int portnum, SMALLINT search_family)
+{
+   uchar i;
+
+   // set the search state to find SearchFamily type devices
+   SerialNum[portnum][0] = search_family;
+   for (i = 1; i < 8; i++)
+      SerialNum[portnum][i] = 0;
+   LastDiscrepancy[portnum] = 64;
+   LastDevice[portnum] = FALSE;
+}
+
+//--------------------------------------------------------------------------
+// Set the current search state to skip the current family code.
+//
+// 'portnum'     - number 0 to MAX_PORTNUM-1.  This number is provided to
+//                 indicate the symbolic port number.
+//
+void owSkipFamily(int portnum)
+{
+   // set the Last discrepancy to last family discrepancy
+   LastDiscrepancy[portnum] = LastFamilyDiscrepancy[portnum];
+   LastFamilyDiscrepancy[portnum] = 0;
+
+   // check for end of list
+   if (LastDiscrepancy[portnum] == 0)
+      LastDevice[portnum] = TRUE;
+}
+
+//--------------------------------------------------------------------------
+// The 'owAccess' function resets the 1-Wire and sends a MATCH Serial
+// Number command followed by the current SerialNum code. After this
+// function is complete the 1-Wire device is ready to accept device-specific
+// commands.
+//
+// 'portnum'     - number 0 to MAX_PORTNUM-1.  This number is provided to
+//                 indicate the symbolic port number.
+//
+// Returns:   TRUE (1) : reset indicates present and device is ready
+//                       for commands.
+//            FALSE (0): reset does not indicate presence or echos 'writes'
+//                       are not correct.
+//
+SMALLINT owAccess(int portnum)
+{
+   uchar sendpacket[9];
+   uchar i;
+
+   // reset the 1-wire
+   if (owTouchReset(portnum))
+   {
+      // create a buffer to use with block function
+      // match Serial Number command 0x55
+      sendpacket[0] = 0x55;
+      // Serial Number
+      for (i = 1; i < 9; i++)
+         sendpacket[i] = SerialNum[portnum][i-1];
+
+      // send/recieve the transfer buffer
+      if (owBlock(portnum,FALSE,sendpacket,9))
+      {
+         // verify that the echo of the writes was correct
+         for (i = 1; i < 9; i++)
+            if (sendpacket[i] != SerialNum[portnum][i-1])
+               return FALSE;
+         if (sendpacket[0] != 0x55)
+         {
+            OWERROR(OWERROR_WRITE_VERIFY_FAILED);
+            return FALSE;
+         }
+         else
+            return TRUE;
+      }
+      else
+         OWERROR(OWERROR_BLOCK_FAILED);
+   }
+   else
+      OWERROR(OWERROR_NO_DEVICES_ON_NET);
+
+   // reset or match echo failed
+   return FALSE;
+}
+
+//----------------------------------------------------------------------
+// The function 'owVerify' verifies that the current device
+// is in contact with the 1-Wire Net.
+// Using the find alarm command 0xEC will verify that the device
+// is in contact with the 1-Wire Net and is in an 'alarm' state.
+//
+// 'portnum'     - number 0 to MAX_PORTNUM-1.  This number is provided to
+//                 indicate the symbolic port number.
+// 'alarm_only'  - TRUE (1) the find alarm command 0xEC
+//                 is sent instead of the normal search
+//                 command 0xF0.
+//
+// Returns:   TRUE (1) : when the 1-Wire device was verified
+//                       to be on the 1-Wire Net
+//                       with alarm_only == FALSE
+//                       or verified to be on the 1-Wire Net
+//                       AND in an alarm state when
+//                       alarm_only == TRUE.
+//            FALSE (0): the 1-Wire device was not on the
+//                       1-Wire Net or if alarm_only
+//                       == TRUE, the device may be on the
+//                       1-Wire Net but in a non-alarm state.
+//
+SMALLINT owVerify(int portnum, SMALLINT alarm_only)
+{
+   uchar i,sendlen=0,goodbits=0,cnt=0,s,tst;
+   uchar sendpacket[50];
+
+   // construct the search
+   if (alarm_only)
+      sendpacket[sendlen++] = 0xEC; // issue the alarming search command
+   else
+      sendpacket[sendlen++] = 0xF0; // issue the search command
+   // set all bits at first
+   for (i = 1; i <= 24; i++)
+      sendpacket[sendlen++] = 0xFF;
+   // now set or clear apropriate bits for search
+   for (i = 0; i < 64; i++)
+      bitacc(WRITE_FUNCTION,bitacc(READ_FUNCTION,0,i,&SerialNum[portnum][0]),(int)((i+1)*3-1),&sendpacket[1]);
+
+   // send/recieve the transfer buffer
+   if (owBlock(portnum,TRUE,sendpacket,sendlen))
+   {
+      // check results to see if it was a success
+      for (i = 0; i < 192; i += 3)
+      {
+         tst = (bitacc(READ_FUNCTION,0,i,&sendpacket[1]) << 1) |
+                bitacc(READ_FUNCTION,0,(int)(i+1),&sendpacket[1]);
+
+         s = bitacc(READ_FUNCTION,0,cnt++,&SerialNum[portnum][0]);
+
+         if (tst == 0x03)  // no device on line
+         {
+              goodbits = 0;    // number of good bits set to zero
+              break;     // quit
+         }
+
+         if (((s == 0x01) && (tst == 0x02)) ||
+             ((s == 0x00) && (tst == 0x01))    )  // correct bit
+            goodbits++;  // count as a good bit
+      }
+
+      // check too see if there were enough good bits to be successful
+      if (goodbits >= 8)
+         return TRUE;
+   }
+   else
+      OWERROR(OWERROR_BLOCK_FAILED);
+
+   // block fail or device not present
+   return FALSE;
+}
+
+//----------------------------------------------------------------------
+// Perform a overdrive MATCH command to select the 1-Wire device with
+// the address in the ID data register.
+//
+// 'portnum'     - number 0 to MAX_PORTNUM-1.  This number is provided to
+//                 indicate the symbolic port number.
+//
+// Returns:  TRUE: If the device is present on the 1-Wire Net and
+//                 can do overdrive then the device is selected.
+//           FALSE: Device is not present or not capable of overdrive.
+//
+//  *Note: This function could be converted to send DS2480
+//         commands in one packet.
+//
+SMALLINT owOverdriveAccess(int portnum)
+{
+   uchar sendpacket[8];
+   uchar i, bad_echo = FALSE;
+
+   // make sure normal level
+   owLevel(portnum,MODE_NORMAL);
+
+   // force to normal communication speed
+   owSpeed(portnum,MODE_NORMAL);
+
+   // call the 1-Wire Net reset function
+   if (owTouchReset(portnum))
+   {
+      // send the match command 0x69
+      if (owWriteByte(portnum,0x69))
+      {
+         // switch to overdrive communication speed
+         owSpeed(portnum,MODE_OVERDRIVE);
+
+         // create a buffer to use with block function
+         // Serial Number
+         for (i = 0; i < 8; i++)
+            sendpacket[i] = SerialNum[portnum][i];
+
+         // send/recieve the transfer buffer
+         if (owBlock(portnum,FALSE,sendpacket,8))
+         {
+            // verify that the echo of the writes was correct
+            for (i = 0; i < 8; i++)
+               if (sendpacket[i] != SerialNum[portnum][i])
+                  bad_echo = TRUE;
+            // if echo ok then success
+            if (!bad_echo)
+               return TRUE;
+            else
+               OWERROR(OWERROR_WRITE_VERIFY_FAILED);
+         }
+         else
+            OWERROR(OWERROR_BLOCK_FAILED);
+      }
+      else
+         OWERROR(OWERROR_WRITE_BYTE_FAILED);
+   }
+   else
+      OWERROR(OWERROR_NO_DEVICES_ON_NET);
+
+   // failure, force back to normal communication speed
+   owSpeed(portnum,MODE_NORMAL);
+
+   return FALSE;
+}
+
+//--------------------------------------------------------------------------
+// Bit utility to read and write a bit in the buffer 'buf'.
+//
+// 'op'    - operation (1) to set and (0) to read
+// 'state' - set (1) or clear (0) if operation is write (1)
+// 'loc'   - bit number location to read or write
+// 'buf'   - pointer to array of bytes that contains the bit
+//           to read or write
+//
+// Returns: 1   if operation is set (1)
+//          0/1 state of bit number 'loc' if operation is reading
+//
+SMALLINT bitacc(SMALLINT op, SMALLINT state, SMALLINT loc, uchar *buf)
+{
+   SMALLINT 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);
+}