//---------------------------------------------------------------------------
// 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. 
//--------------------------------------------------------------------------
//
//  atod26.c - Reads the voltage on the 1-Wire of the DS2438. 
//  version 1.00
//

// Include Files
#include <stdio.h>
#include "ownet.h"
#include "atod26.h"

/**
 * Sets the DS2438 to read Vad or Vdd
 *
 * portnum  the port number of the port being used for the
 *          1-Wire Network.
 * vdd      flag indicating weather to read the Vdd or the Vad
 * SNum     the serial number for the part that the read is
 *          to be done on.
 *
 * @return 'true' if the read was complete
 */
int SetupAtoD(int portnum, int vdd, uchar *SNum)
{
   uchar send_block[50];
   uchar test;
   int send_cnt=0;
   int i;
   ushort lastcrc8 = 0;
   int busybyte; 

   owSerialNum(portnum,SNum,FALSE);
   // Recall the Status/Configuration page
   // Recall command
   send_block[send_cnt++] = 0xB8;

   // Page to Recall
   send_block[send_cnt++] = 0x00;

   if(!owBlock(portnum,FALSE,send_block,send_cnt))
      return FALSE;

   send_cnt = 0;

   if(owAccess(portnum))
   {
      // Read the Status/Configuration byte
      // Read scratchpad command
      send_block[send_cnt++] = 0xBE;

      // Page for the Status/Configuration byte
      send_block[send_cnt++] = 0x00;

      for(i=0;i<9;i++)
         send_block[send_cnt++] = 0xFF;

      if(owBlock(portnum,FALSE,send_block,send_cnt))
      {
         setcrc8(portnum,0);

         for(i=2;i<send_cnt;i++)
            lastcrc8 = docrc8(portnum,send_block[i]);

         if(lastcrc8 != 0x00)
            return FALSE;
      }//Block
      else
         return FALSE;

      test = send_block[2] & 0x08;
      if(((test == 0x08) && vdd) || ((test == 0x00) && !(vdd)))
         return TRUE;
   }//Access

   if(owAccess(portnum))
   {
      send_cnt = 0;
      // Write the Status/Configuration byte
      // Write scratchpad command
      send_block[send_cnt++] = 0x4E;

      // Write page
      send_block[send_cnt++] = 0x00;

      if(vdd)
         send_block[send_cnt++] = send_block[2] | 0x08;
      else
         send_block[send_cnt++] = send_block[2] & 0xF7;

      for(i=0;i<7;i++)
         send_block[send_cnt++] = send_block[i+4];

      if(owBlock(portnum,FALSE,send_block,send_cnt))
      {
         send_cnt = 0;

         if(owAccess(portnum))
         {
            // Copy the Status/Configuration byte
            // Copy scratchpad command
            send_block[send_cnt++] = 0x48;

            // Copy page
            send_block[send_cnt++] = 0x00;

            if(owBlock(portnum,FALSE,send_block,send_cnt))
            {
               busybyte = owReadByte(portnum);
         
               while(busybyte == 0)
                  busybyte = owReadByte(portnum);

               return TRUE;
            }//Block
         }//Access
      }//Block

   }//Access

   return FALSE;
}
      
/**
 * Read the Vdd or the Vad from the DS2438
 *
 * portnum  the port number of the port being used for the
 *          1-Wire Network.
 * vdd      flag indicating weather to read the Vdd or the Vad
 * SNum     the serial number for the part that the read is
 *          to be done on.
 *
 * @return the floating point value of Vad or Vdd
 */
float ReadAtoD(int portnum, int vdd, uchar *SNum)
{
   uchar send_block[50];
   int send_cnt=0;
   int i;
   int busybyte; 
   ushort lastcrc8 = 0;
   ushort volts;
   float ret= (float) -1.0;
   int done = TRUE;

   do
   {
      if(SetupAtoD(portnum,vdd,SNum))
      {

         if(owAccess(portnum))
         {
            if(!owWriteByte(portnum,0xB4))
            {
               OWERROR(OWERROR_WRITE_BYTE_FAILED);
               return ret;
            }

            busybyte = owReadByte(portnum);
         
            while(busybyte == 0)
               busybyte = owReadByte(portnum);
         }

         if(owAccess(portnum))
         {
            // Recall the Status/Configuration page
            // Recall command
            send_block[send_cnt++] = 0xB8;

            // Page to Recall
            send_block[send_cnt++] = 0x00;

            if(!owBlock(portnum,FALSE,send_block,send_cnt))
               return ret;
         }

         send_cnt = 0;

         if(owAccess(portnum))
         {
            // Read the Status/Configuration byte
            // Read scratchpad command
            send_block[send_cnt++] = 0xBE;

            // Page for the Status/Configuration byte
            send_block[send_cnt++] = 0x00;

            for(i=0;i<9;i++)
               send_block[send_cnt++] = 0xFF;

            if(owBlock(portnum,FALSE,send_block,send_cnt))
            {
               setcrc8(portnum,0);

               for(i=2;i<send_cnt;i++)
                  lastcrc8 = docrc8(portnum,send_block[i]);

               if(lastcrc8 != 0x00)
                  return ret;

            }
            else
               return ret;    
      
            if((!vdd) && ((send_block[2] & 0x08) == 0x08))
               done = FALSE;
            else
               done = TRUE;

            volts = (send_block[6] << 8) | send_block[5];
            ret = (float) volts/100;
         }//Access
      }
   } while(!done);

   return ret;

}

/**
 * Reads the temperature from the DS2438.
 *
 * portnum  the port number of the port being used for the
 *          1-Wire Network.
 * SNum     the serial number for the part that the read is
 *          to be done on.
 *
 * @return the temperature in returned in C.
 */
double Get_Temperature(int portnum,uchar *SNum)
{
   double ret=-1.0;
   uchar send_block[50];
   int send_cnt=0;
   int i;
   ushort lastcrc8 = 0;

   owSerialNum(portnum,SNum,FALSE);

   if(owAccess(portnum))
   {
      // Convert Temperature command
      if(!owWriteByte(portnum,0x44))
      {
         OWERROR(OWERROR_WRITE_BYTE_FAILED);
         return FALSE;
      }
   }

   msDelay(10);

   if(owAccess(portnum))
   {
      // Recall the Status/Configuration page
      // Recall command
      send_block[send_cnt++] = 0xB8;

      // Page to Recall
      send_block[send_cnt++] = 0x00;

      if(!owBlock(portnum,FALSE,send_block,send_cnt))
         return FALSE;

      send_cnt = 0;
   }

   if(owAccess(portnum))
   {
      // Read the Status/Configuration byte
      // Read scratchpad command
      send_block[send_cnt++] = 0xBE;

      // Page for the Status/Configuration byte
      send_block[send_cnt++] = 0x00;

      for(i=0;i<9;i++)
         send_block[send_cnt++] = 0xFF;

      if(owBlock(portnum,FALSE,send_block,send_cnt))
      {
         setcrc8(portnum,0);

         for(i=2;i<send_cnt;i++)
            lastcrc8 = docrc8(portnum,send_block[i]);

         if(lastcrc8 != 0x00)
            return ret;

      }
      else
         return ret;    

       // JH - fix sign for -ve values
       short itemp;
       itemp = ((send_block[4] << 8) | send_block[3]) >> 3 ;
       if (itemp & 0x1000) itemp |= ~0xFFF ;
       ret = itemp * 0.03125;
   }//Access

   return ret;
}

/**
 * Sets the DS2438 to read Vsens
 *
 * portnum  the port number of the port being used for the
 *          1-Wire Network.
 * SNum     the serial number for the part that the read is
 *          to be done on.
 *
 * @return 'true' if the read was complete
 */
static int SetupAtoD_vsens(int portnum, uchar *SNum)
{
   uchar send_block[50];
   int send_cnt=0;
   int i;
   ushort lastcrc8 = 0;
   int busybyte; 

   owSerialNum(portnum,SNum,FALSE);
   // Recall the Status/Configuration page
   // Recall command
   send_block[send_cnt++] = 0xB8;

   // Page to Recall
   send_block[send_cnt++] = 0x00;

   if(!owBlock(portnum,FALSE,send_block,send_cnt))
      return FALSE;

   send_cnt = 0;

   if(owAccess(portnum))
   {
      // Read the Status/Configuration byte
      // Read scratchpad command
      send_block[send_cnt++] = 0xBE;

      // Page for the Status/Configuration byte
      send_block[send_cnt++] = 0x00;

      for(i=0;i<9;i++)
         send_block[send_cnt++] = 0xFF;

      if(owBlock(portnum,FALSE,send_block,send_cnt))
      {
         setcrc8(portnum,0);

         for(i=2;i<send_cnt;i++)
            lastcrc8 = docrc8(portnum,send_block[i]);

         if(lastcrc8 != 0x00)
            return FALSE;
      }//Block
      else
         return FALSE;

      if(send_block[2] & 0x01)
         return TRUE;
   }//Access

   if(owAccess(portnum))
   {
      send_cnt = 0;
      // Write the Status/Configuration byte
      // Write scratchpad command
      send_block[send_cnt++] = 0x4E;

      // Write page
      send_block[send_cnt++] = 0x00;

      send_block[send_cnt++] = send_block[2] | 0x01;

      for(i=0;i<7;i++)
         send_block[send_cnt++] = send_block[i+4];

      if(owBlock(portnum,FALSE,send_block,send_cnt))
      {
         send_cnt = 0;

         if(owAccess(portnum))
         {
            // Copy the Status/Configuration byte
            // Copy scratchpad command
            send_block[send_cnt++] = 0x48;

            // Copy page
            send_block[send_cnt++] = 0x00;

            if(owBlock(portnum,FALSE,send_block,send_cnt))
            {
               busybyte = owReadByte(portnum);
         
               while(busybyte == 0)
                  busybyte = owReadByte(portnum);

               return TRUE;
            }//Block
         }//Access
      }//Block

   }//Access

   return FALSE;
}
      
/**
 * Read the Vsens from the DS2438
 *
 * portnum  the port number of the port being used for the
 *          1-Wire Network.
 * SNum     the serial number for the part that the read is
 *          to be done on.
 *
 * @return the floating point value of Vsens
 */

float ReadVsens(int portnum, uchar *SNum)
{
   uchar send_block[50];
   int send_cnt=0;
   int i;
   int busybyte; 
   ushort lastcrc8 = 0;
   short curr;
   float ret= -1.0;

   if(SetupAtoD_vsens(portnum,SNum))
   {
       if(owAccess(portnum))
       {
           if(!owWriteByte(portnum,0xB4))
           {
               OWERROR(OWERROR_WRITE_BYTE_FAILED);
               return ret;
           }
           
           busybyte = owReadByte(portnum);
           
           while(busybyte == 0)
               busybyte = owReadByte(portnum);
       }
       
       if(owAccess(portnum))
       {
               // Recall the Status/Configuration page
               // Recall command
           send_block[send_cnt++] = 0xB8;
           
               // Page to Recall
           send_block[send_cnt++] = 0x00;
           
           if(!owBlock(portnum,FALSE,send_block,send_cnt))
               return ret;
       }
       
       send_cnt = 0;

       if(owAccess(portnum))
       {
               // Read the Status/Configuration byte
               // Read scratchpad command
           send_block[send_cnt++] = 0xBE;
           
               // Page for the Status/Configuration byte
           send_block[send_cnt++] = 0x00;
           
           for(i=0;i<9;i++)
               send_block[send_cnt++] = 0xFF;
           
           if(owBlock(portnum,FALSE,send_block,send_cnt))
           {
               setcrc8(portnum,0);
               
               for(i=2;i<send_cnt;i++)
                  lastcrc8 = docrc8(portnum,send_block[i]);
               
               if(lastcrc8 != 0x00)
                   return ret;
               
           }
           else
               return ret;    
           
           curr = (send_block[8] << 8) | send_block[7];
               // Can't happen ????????
           if (send_block[8] & 0x80) 
               curr |= ~0x3ff;
           ret = ((float) (curr) * 0.2441);
#if 0
           {
               int k;
               fputs("Buffer: ", stderr);
               for(k=0; k < 9; k++)
               {
                   fprintf(stderr, "%02x ", send_block[k]);
               }
               fputc('\n', stderr);
               fprintf(stderr,"Curr = %d %f\n", curr, ret);
           }
#endif
           
       }//Access
   }
   return ret;
}
