//---------------------------------------------------------------------------
// 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.
//---------------------------------------------------------------------------
//
//  weather.c - To find what kind of weather station or if it is there.
//              There are also modules to find the direction of the weather
//              station and read/write output files
//
//  Version: 2.00
//
//
// --------------------------------------------------------------------------

#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <time.h>
#include "ownet.h"
#include "swt12.h"
#include "findtype.h"
#include "weather.h"
#include "atod20.h"
#include "temp10.h"
#include "cnt1d.h"

// defines
#define MAXDEVICES           8

// family codes of devices
#define TEMP_FAMILY        0x10
#define SWITCH_FAMILY      0x12
#define ATOD_FAMILY        0X20
#define COUNT_FAMILY       0x1D
#define DIR_FAMILY         0x01
// misc
#define MAXTEMPS           1
#define MAXSWITCH          1
#define MAXCOUNT           1
#define MAXATOD            1
#define MAXDIR             8


static int conv[8] = {0,14,12,10,8,6,4,2};
static double conv_table[16][4] = { {0.06, 4.64, 4.64, 4.64},
                                    {0.06, 0.06, 4.60, 4.60},
                                    {4.64, 0.06, 4.64, 4.64},
                                    {4.62, 0.06, 0.06, 4.60},
                                    {4.64, 4.64, 0.06, 4.64},
                                    {4.60, 4.60, 0.06, 0.06},
                                    {4.64, 4.64, 4.64, 0.06},
                                    {2.36, 4.62, 4.60, 0.06},
                                    {2.38, 4.66, 4.66, 4.66},
                                    {3.20, 3.20, 4.66, 4.64},
                                    {4.66, 2.38, 4.66, 4.66},
                                    {4.66, 3.18, 3.20, 4.64},
                                    {4.66, 4.66, 2.38, 4.66},
                                    {4.66, 4.66, 3.18, 3.18},
                                    {4.66, 4.66, 4.66, 2.38},
                                    {0.06, 4.62, 4.62, 2.34} };


// -------------------------------------------------------------------------
// SUBROUTINE - FindWeather
//
// This routine finds which weather station is attached to the 1-wire
// network and returns the serial numbers for the weather station.  If
// it is the new weather station then it is not going to have an DS2401s.
//
// 'ds1820' - This will be the serial number for the DS1820 in the station
// 'ds2423' - This will be the serial number for the DS2423 in the station
// 'dsdir'  - This will either be the DS2450 or the DS2406 serial num.
// 'ds2401' - This will be the list of DS2401s if the old weather station.
//
// Returns: TRUE if a weather station is found and the listing of the
//          devices file is found or made.  FALSE if a weather station
//          is not found or the device file is not found or can not be made.
//
int FindSetupWeather(int portnum, WeatherStruct *wet)
{
   int ret = FALSE;
   FILE *fptr;
   char filename[] = "ini.txt";
   char TempSN[190];
   uchar SNs[90];
   int i,j;
   int num;
   char msg[45];
   uchar temp[MAXDIR][8];

   temp[0][0] = 0x00;
   wet->weather_a = FALSE;
   wet->weather_b = FALSE;
   wet->found_2401 = 0;
   wet->found_2423 = FALSE;
   wet->found_1820 = FALSE;
   wet->found_dir  = FALSE;
   wet->north = 0;

   if((fptr = fopen(filename, "r")) == NULL)
   {
      printf("error opening file but try to create file\n");

      // Create ini.txt if weather station has DS2450

      // find the DS1820 temperature
      num = FindDevices(portnum, &temp[0], TEMP_FAMILY, MAXTEMPS);

      // check if not at least 1 temperature device
      if(num == 0)
         wet->found_1820 = FALSE;
      else
      {
         for(i=0;i<8;i++)
            wet->ds1820[i] = temp[0][i]; 
         wet->found_1820 = TRUE;
      }

      // find the DS2450 switch
      num = FindDevices(portnum, &temp[0], ATOD_FAMILY, MAXATOD);

      // check if not at least 1 switch device
      if(num == 0)
         wet->found_dir = FALSE;
      else
      {
         for(i=0;i<8;i++)
            wet->dsdir[i] = temp[0][i];
         wet->found_dir = TRUE;
      }

      // find the DS2423 switch
      num = FindDevices(portnum, &temp[0], COUNT_FAMILY, MAXCOUNT);

      // check if not at least 1 count device
      if(num == 0)
         wet->found_2423 = FALSE;
      else
      {
         for(i=0;i<8;i++)
            wet->ds2423[i] = temp[0][i];
         wet->found_2423 = TRUE;
      }

      // Create the output file ini.txt
      if(wet->found_1820 && wet->found_dir && wet->found_2423)
      {
         if(SetupAtoDControl(portnum, &wet->dsdir[0], &wet->ctrl[0], &msg[0]))
            if(WriteAtoD(portnum, FALSE, &wet->dsdir[0], &wet->ctrl[0], 0x08, 0x11))
            {

               if((fptr = fopen(filename, "w")) == NULL)
                  printf("error tring to create file\n");
               else
               {
                  wet->weather_b = TRUE;
                  ret = TRUE;

                  // Printing the Serial number for DS2450
                  printf("Found DS2450\n");
                  for(i=7; i>=0; i--)
                     printf("%02X", wet->dsdir[i]);
                  printf("\n");
                  for(i=7; i>=0; i--)
                     fprintf(fptr, "%02X", wet->dsdir[i]);
                  fprintf(fptr, "\n");

                  // Printing the Serial number for DS1820
                  printf("Found DS1820\n");
                  for(i=7; i>=0; i--)
                     printf("%02X", wet->ds1820[i]);
                  printf("\n");
                  for(i=7; i>=0; i--)
                     fprintf(fptr, "%02X", wet->ds1820[i]);
                  fprintf(fptr, "\n");

                  // Printing the Serial number for DS2423
                  printf("Found DS2423\n");
                  for(i=7; i>=0; i--)
                     printf("%02X", wet->ds2423[i]);
                  printf("\n");
                  for(i=7; i>=0; i--)
                     fprintf(fptr, "%02X", wet->ds2423[i]);
                  fprintf(fptr, "\n");

                  // Printing the Default Wind Direction
                  printf("The Default Wind Direction is 0\n");
                  fprintf(fptr, "0\n");
               }
            }
      }
   }
   else
   {
      num = fread(TempSN, sizeof(char), 189, fptr);

      num = ParseData(TempSN, num, &SNs[0], 90);

      if(!wet->weather_a && !wet->weather_b)
      {
         if(SNs[7] == 0x01)
            wet->weather_a = TRUE;
         else
            wet->weather_b = TRUE;
      }

      j = 0;
      while((SNs[7+8*j] == 0x01) || (SNs[7+8*j] == 0x20) || (SNs[7+8*j] == 0x12) ||
            (SNs[7+8*j] == 0x1D) || (SNs[7+8*j] == 0x10))
      {
         if(SNs[7+8*j] == 0x01)
         {
            for(i=0; i<8; i++)
               wet->ds2401[wet->found_2401][7-i] = SNs[8*j + i];

            printf("Found DS2401\n");
            for(i=7; i>=0; i--)
               printf("%02X", wet->ds2401[wet->found_2401][i]);
            printf("\n");

            wet->found_2401++;
         }

         if(SNs[7+8*j] == 0x20)
         {
            if(!wet->found_dir)
            {
               for(i=0; i<8; i++)
                  wet->dsdir[7-i] = SNs[8*j + i];

               owSerialNum(portnum, wet->dsdir, FALSE);
               if(!owVerify(portnum, FALSE))
                  ret = FALSE;

               wet->found_dir = TRUE;
               printf("Found DS2450\n");
               for(i=7; i>=0; i--)
                  printf("%02X", wet->dsdir[i]);
               printf("\n");

               if(!SetupAtoDControl(portnum, wet->dsdir, &wet->ctrl[0], &msg[0]))
                  return FALSE;
               if(!WriteAtoD(portnum, FALSE, wet->dsdir, &wet->ctrl[0], 0x08, 0x11))
                  return FALSE;

            }
         }

         if(SNs[7+8*j] == 0x12)
         {
            if(!wet->found_dir)
            {
               for(i=0; i<8; i++)
                  wet->dsdir[7-i] = SNs[8*j + i];

               owSerialNum(portnum, wet->dsdir, FALSE);
               if(!owVerify(portnum, FALSE))
                  ret = FALSE;

               wet->found_dir = TRUE;
               printf("Found DS2406\n");
               for(i=7; i>=0; i--)
                  printf("%02X", wet->dsdir[i]);
               printf("\n");
            }
         }

         if(SNs[7+8*j] == 0x1D)
         {
            for(i=0; i<8; i++)
               wet->ds2423[7-i] = SNs[8*j + i];

            owSerialNum(portnum, wet->ds2423, FALSE);
            if(!owVerify(portnum, FALSE))
               ret = FALSE;

            wet->found_2423 = TRUE;
            printf("Found DS2423\n");
            for(i=7; i>=0; i--)
               printf("%02X", wet->ds2423[i]);
            printf("\n");
         }

         if(SNs[7+8*j] == 0x10)
         {
            for(i=0; i<8; i++)
               wet->ds1820[7-i] = SNs[8*j + i];

            owSerialNum(portnum, wet->ds1820, FALSE);
            if(!owVerify(portnum, FALSE))
               ret = FALSE;

            wet->found_1820 = TRUE;
            printf("Found DS1820\n");
            for(i=7; i>=0; i--)
               printf("%02X", wet->ds1820[i]);
            printf("\n");
         }

         j++;
      }

      if(wet->weather_a)
      {
         if((TempSN[0xBB] <= 0x40) && (TempSN[0xBB] >= 0x30))
            if((TempSN[0xBC] <= 0x40) && (TempSN[0xBC] >= 0x30))
               wet->north = (TempSN[0xBB]-0x30)*10 + (TempSN[0xBC]-0x30);
            else
               wet->north = TempSN[0xBB] - 0x30;
         else
            wet->north = 0;

         if(wet->found_dir && wet->found_1820 && wet->found_2423 &&
           (wet->found_2401 == 8))
            ret = TRUE;
      }
      else if(wet->weather_b)
      {
         if((TempSN[0x33] <= 0x40) && (TempSN[0x33] >= 0x30))
            if((TempSN[0x34] <= 0x40) && (TempSN[0x34] >= 0x30))
               wet->north = (TempSN[0x33]-0x30)*10 + (TempSN[0x34]-0x30);
            else
               wet->north = TempSN[0x33] - 0x30;
         else
            wet->north = 0;

         if(wet->found_dir && wet->found_1820 && wet->found_2423)
            ret = TRUE;
      }

   }

   if(wet->weather_a || wet->weather_b)
   {
      if(fptr != 0)
      {
         fclose(fptr);
      }
   }

   return ret;
}


// -------------------------------------------------------------------------
// SUBROUTINE - SetupWet
//
// This routine sets up a weather station given the serial numbers for the
// weather station.
//
// Returns: TRUE, if the weather station was setup and FALSE if it was not.
//
int SetupWet(int portnum, WeatherStruct *wet, int nor)
{
   int i,j;
   int ret = FALSE;
   char msg[45];

   wet->north = nor;

   if((wet->ds2401 == NULL) || wet->weather_b)
   {
      wet->weather_b = TRUE;
      wet->weather_a = FALSE;

      // Setting up the DS2450
      owSerialNum(portnum, wet->dsdir, FALSE);
      if(!owVerify(portnum, FALSE))
      {
         printf("The DS2450 was not found.\n");
         return FALSE;
      }
      else
      {
         // Printing the Serial number for DS2450
         printf("Set DS2450\n");
         for(i=7; i>=0; i--)
            printf("%02X", wet->dsdir[i]);
         printf("\n");
      }

      // Setting up the DS1820
      owSerialNum(portnum, wet->ds1820, FALSE);
      if(!owVerify(portnum, FALSE))
      {
         printf("The DS1820 was not found.\n");
         return FALSE;
      }
      else
      {
         // Printing the Serial number for DS1820
         printf("Set DS1820\n");
         for(i=7; i>=0; i--)
            printf("%02X", wet->ds1820[i]);
         printf("\n");
      }

      // Setting up the DS2423
      owSerialNum(portnum, wet->ds2423, FALSE);
      if(!owVerify(portnum, FALSE))
      {
         printf("The DS2423 was not found.\n");
         return FALSE;
      }
      else
      {
         // Printing the Serial number for DS2423
         printf("Set DS2423\n");
         for(i=7; i>=0; i--)
            printf("%02X", wet->ds2423[i]);
         printf("\n");
      }

      if(SetupAtoDControl(portnum, &wet->dsdir[0], &wet->ctrl[0], &msg[0]))
         if(WriteAtoD(portnum, FALSE, &wet->dsdir[0], &wet->ctrl[0], 0x08, 0x11))
            ret = TRUE;

   }
   else
   {
      wet->weather_a = TRUE;
      wet->weather_b = FALSE;

      printf("Set DS2401\n");
      for(i=0; i<8; i++)
      {
         // Printing the Serial number for DS2401
         for(j=7; j>=0; j--)
            printf("%02X", wet->ds2401[i][j]);
         printf("\n");
      }

      // Setting up the DS2423
      owSerialNum(portnum, wet->ds2423, FALSE);
      if(!owVerify(portnum, FALSE))
      {
         printf("The DS2423 was not found.\n");
         return FALSE;
      }
      else
      {
         // Printing the Serial number for DS2423
         printf("Set DS2423\n");
         for(i=7; i>=0; i--)
            printf("%02X", wet->ds2423[i]);
         printf("\n");
      }

      // Setting up the DS1820
      owSerialNum(portnum, wet->ds1820, FALSE);
      if(!owVerify(portnum, FALSE))
      {
         printf("The DS1820 was not found.\n");
         return FALSE;
      }
      else
      {
         // Printing the Serial number for DS1820
         printf("Set DS1820\n");
         for(i=7; i>=0; i--)
            printf("%02X", wet->ds1820[i]);
         printf("\n");
      }

      // Setting up the DS2406
      owSerialNum(portnum, wet->dsdir, FALSE);
      if(!owVerify(portnum, FALSE))
      {
         printf("The DS2406 was not found.\n");
         return FALSE;
      }
      else
      {
         // Printing the Serial number for DS2406
         printf("Set DS2450\n");
         for(i=7; i>=0; i--)
            printf("%02X", wet->dsdir[i]);
         printf("\n");
      }

      ret = TRUE;
   }

   return ret;
}


// -------------------------------------------------------------------------
// SUBROUTINE - ReadWet
//
// 'temp'  - The temperature from the DS1820 in F
// 'dir'   - The wind direction from 0-15
// 'revol' - The wind speed in revolutions per second
//
// Returns:  TRUE, if the reads were successfull and FALSE if they were not.
//
int ReadWet(int portnum, WeatherStruct *wet, float *temp, int *dir, double *revol)
{
   int ret = TRUE;
   unsigned int start_count=0, end_count=0, start_time, end_time;
   float current_temp;

   // read the current counter
   // use this reference to calculate wind speed later
   if (!ReadCounter(portnum, &wet->ds2423[0], 15, &start_count))
   {
      printf("\nError reading counter, verify device present:%d\n",
              (int)owVerify(portnum, FALSE));
      ret = FALSE;
   }

   // get a time stamp (mS)
   start_time = msGettick();

   // read the temperature and print in F
   if (ReadTemperature(portnum, &wet->ds1820[0],&current_temp,1000))
      *temp = current_temp * 9 / 5 + 32;
   else
   {
      printf("\nError reading temperature, verify device present:%d\n",
              (int)owVerify(portnum, FALSE));
      ret = FALSE;
   }

   // read the wind direction
   *dir = TrueDir(portnum, wet);

   // read the counter again
   if (!ReadCounter(portnum, &wet->ds2423[0], 15, &end_count))
   {
      printf("Error reading counter, verify device present:%d\n",
              (int)owVerify(portnum, FALSE));
      ret = FALSE;
   }

   // get a time stamp (mS)
   end_time = msGettick();

   // calculate the wind speed based on the revolutions per second
   *revol = (((end_count - start_count) * 1000.0) /
              (end_time - start_time)) / 2.0;

   return ret;
}
// -------------------------------------------------------------------------
// SUBROUTINE - GetDir
//
// This routine looks at the DS2401 serial numbers or the DS2450 volts to
// determine which direction the wind is blowing.
//
// Returns: The direction in a 0-15 order and 16 for no DS2401s found
//
int GetDir(int portnum, WeatherStruct *wet)
{
   SwitchProps st;
   uchar temp_dir[MAXDIR][8];
   int i,j;
   int numdir = 0;
   int firstmatch = 0, secondmatch = 0;
   int firstindex = 0;
   int found = TRUE;
   int ret = 16;
   float prslt[4];

   temp_dir[0][0] = 0x00;

   if(wet->weather_a)
   {
      st.Chan_A = FALSE;
      st.Chan_B = TRUE;
      if(SetSwitch12(portnum, &wet->dsdir[0], st))
      {
         numdir = FindDevices(portnum, &temp_dir[0], DIR_FAMILY, MAXDIR);
      }
      else
         printf("Error on setting up the switch\n");

      if(numdir == 0)
         ret = 16;

      if(numdir == 2)
      {
         for(i=0; i<8; i++)
         {
            for(j=0; j<8; j++)
               if(temp_dir[0][j] != wet->ds2401[i][j])
               {
                  found = FALSE;
                  break;
               }
               else
                  found = TRUE;

            if(found)
            {
               firstindex = i;
               firstmatch = conv[i];
               found = FALSE;
               break;
            }
         }

         for(i=0; i<8; i++)
         {
            if(i != firstindex)
            {
               for(j=0; j<8; j++)
               {
                  if(temp_dir[1][j] != wet->ds2401[i][j])
                  {
                     found = FALSE;
                     break;
                  }
                  else
                     found = TRUE;
               }
            }
            if(found)
            {
               secondmatch = conv[i];
               break;
            }
         }

         if(((firstmatch == 0) || (secondmatch == 0)) &&
            ((firstmatch == 14) || (secondmatch == 14)))
            ret = 15;
         else
            ret = (firstmatch+secondmatch)/2;
      }

      if(numdir == 1)
      {
         for(i=0; i<8; i++)
         {
            found = TRUE;

            for(j=0; j<8; j++)
               if(temp_dir[0][j] != wet->ds2401[i][j])
                  found = FALSE;

            if(found)
            {
               ret = conv[i];
               break;
            }
         }

      }

      st.Chan_A = FALSE;
      st.Chan_B = FALSE;
      if(!SetSwitch12(portnum, &wet->dsdir[0], st))
      {
         msDelay(10);
         if(!SetSwitch12(portnum, &wet->dsdir[0], st))
         {
            printf("Failed to close channel B\n");
         }
      }
   }
   else if(wet->weather_b)
   {
      // read wind direction for the DS2450 weather station
      if(DoAtoDConversion(portnum, FALSE, &wet->dsdir[0]))
      {
         if(ReadAtoDResults(portnum, FALSE, &wet->dsdir[0], &prslt[0], &wet->ctrl[0]))
         {
            for(i=0; i<16; i++)
            {
               if( ((prslt[0] <= (float)conv_table[i][0]+0.25) &&
                    (prslt[0] >= (float)conv_table[i][0]-0.25)) &&
                   ((prslt[1] <= (float)conv_table[i][1]+0.25) &&
                    (prslt[1] >= (float)conv_table[i][1]-0.25)) &&
                   ((prslt[2] <= (float)conv_table[i][2]+0.25) &&
                    (prslt[2] >= (float)conv_table[i][2]-0.25)) &&
                   ((prslt[3] <= (float)conv_table[i][3]+0.25) &&
                    (prslt[3] >= (float)conv_table[i][3]-0.25)) )
               {
                  ret = i;
                  break;
               }
            }
         }
         else
         {
            printf("\n");
            printf("\nError reading channel, verify device present: %d\n",
            (int)owVerify(portnum, FALSE));
         }
      }
   }

   return ret;
}


// -------------------------------------------------------------------------
// SUBROUTINE - TrueDir
//
// This routine returns the direction given the north direction in 0-15.
//
// Returns: The direction in a 0-15 order with 0 north and clockwise from that.
//          16 is returned for no DS2401s found.
//
int TrueDir(int portnum, WeatherStruct *wet)
{
   int dir;
   int retdir;

   dir = GetDir(portnum, wet);

   if(dir != 16)
   {
      if( (dir-wet->north) < 0 )
         retdir = (dir - wet->north + 16);
      else
         retdir = dir - wet->north;
   }
   else
      retdir = 16;

   return retdir;
}


//----------------------------------------------------------------------
// Parse the raw file data in to an array of uchar's.  The data must
// be hex characters possible seperated by white space
//     12 34 456789ABCD EF
//     FE DC BA 98 7654 32 10
// would be converted to an array of 16 uchars.
// return the array length.  If an invalid hex pair is found then the
// return will be 0.
//
int ParseData(char *inbuf, int insize, uchar *outbuf, int maxsize)
{
   int ps, outlen=0, gotmnib=0;
   uchar mnib = 0;

   // loop until end of data
   for (ps = 0; ps < insize; ps++)
   {
      // check for white space
      if (isspace(inbuf[ps]))
         continue;
      // not white space, make sure hex
      else if (isxdigit(inbuf[ps]))
      {
         // check if have first nibble yet
         if (gotmnib)
         {
            // this is the second nibble
            outbuf[outlen++] = (mnib << 4) | ToHex(inbuf[ps]);
            gotmnib = 0;
         }
         else
         {
            // this is the first nibble
            mnib = ToHex(inbuf[ps]);
            gotmnib = 1;
         }
      }
      else
         return 0;

      // if getting to the max return what we have
      if ((outlen + 1) >= maxsize)
         return outlen;
   }

   return outlen;
}

