Open2300 - Bug Report 2015x 02x 04x 080636
You are here: Foswiki>Open2300 Web>BugReports>BugReport2015x02x04x080636 (04 Feb 2015, TomasJensen)Edit Attach

BUG: Yet one more fix reading and writing via USB->Serial on fast machines

On fast machines with USB->Serial adapters reading and writing fails. In rw2300.c read_data() and write_data() fails I have added some usleep( 10000 ) before reads and write's. After that ALL my reading and writing the WS2305 is 100% successfull.

I have attached the source.

Test case

/*  open2300  - rw2300.c library functions
 *  This is a library of functions common to Linux and Windows
 * 
 *  Version 1.11
 * 
 *  Control WS2300 weather station
 * 
 *  Copyright 2003-2007, Kenneth Lavrsen
 *  This program is published under the GNU General Public license
 */
 
#include "rw2300.h"
 
/********************************************************************/
/* temperature_indoor
 * Read indoor temperature, current temperature only
 *
 * Input: Handle to weatherstation
 *        temperature_conv flag (integer) controlling
 *            convertion to deg F
 *
 * Returns: Temperature (deg C if temperature_conv is 0)
 *                      (deg F if temperature_conv is 1)
 *
 ********************************************************************/
double temperature_indoor(WEATHERSTATION ws2300, int temperature_conv)
{
           unsigned char data[20];
           unsigned char command[25];       //room for write data also
           int address=0x346;
           int bytes=2;
 
           if (read_safe(ws2300, address, bytes, data, command) != bytes)
                      read_error_exit();
 
           if (temperature_conv)
                      return ((((data[1] >> 4) * 10 + (data[1] & 0xF) +
                                (data[0] >> 4) / 10.0 + (data[0] & 0xF) / 100.0) -
                                30.0) * 9 / 5 + 32);
           else
                      return ((((data[1] >> 4) * 10 + (data[1] & 0xF) +
                                (data[0] >> 4) / 10.0 + (data[0] & 0xF) / 100.0) - 30.0));
}
 
 
/********************************************************************/
/* temperature_indoor_minmax
 * Read indoor min/max temperatures with timestamps
 *
 * Input: Handle to weatherstation
 *        temperature_conv flag (integer) controlling
 *            convertion to deg F
 *
 * Output: Temperatures temp_min and temp_max
 *                (deg C if temperature_conv is 0)
 *                (deg F if temperature_conv is 1)
 *         Timestamps for temp_min and temp_max in pointers to
 *                timestamp structures for time_min and time_max
 *
 ********************************************************************/
void temperature_indoor_minmax(WEATHERSTATION ws2300,
                               int temperature_conv,
                               double *temp_min,
                               double *temp_max,
                               struct timestamp *time_min,
                               struct timestamp *time_max)
{
           unsigned char data[20];
           unsigned char command[25];       //room for write data also
           int address=0x34B;
           int bytes=15;
          
           if (read_safe(ws2300, address, bytes, data, command) != bytes)
                      read_error_exit();
          
           *temp_min = ((data[1]>>4)*10 + (data[1]&0xF) + (data[0]>>4)/10.0 +
                        (data[0]&0xF)/100.0) - 30.0;
 
           *temp_max = ((data[4]&0xF)*10 + (data[3]>>4) + (data[3]&0xF)/10.0 +
                        (data[2]>>4)/100.0) - 30.0;
 
           if (temperature_conv)
           {
                      *temp_min = *temp_min * 9/5 + 32;
                      *temp_max = *temp_max * 9/5 + 32;
           }
 
           time_min->minute = ((data[5] & 0xF) * 10) + (data[4] >> 4);
           time_min->hour = ((data[6] & 0xF) * 10) + (data[5] >> 4);
           time_min->day = ((data[7] & 0xF) * 10) + (data[6] >> 4);
           time_min->month = ((data[8] & 0xF) * 10) + (data[7] >> 4);
           time_min->year = 2000 + ((data[9] & 0xF) * 10) + (data[8] >> 4);
                     
           time_max->minute = ((data[10] & 0xF) * 10) + (data[9] >> 4);
           time_max->hour = ((data[11] & 0xF) * 10) + (data[10] >> 4);
           time_max->day = ((data[12] & 0xF) * 10) + (data[11] >> 4);
           time_max->month = ((data[13] & 0xF) * 10) + (data[12] >> 4);
           time_max->year = 2000 + ((data[14] & 0xF) * 10) + (data[13] >> 4);
          
           return;
}
 
/********************************************************************/
/* temperature_indoor_reset
 * Reset indoor min/max temperatures with timestamps
 *
 * Input: Handle to weatherstation
 *        minmax - char (8 bit integer) that controls if minimum,
 *                 maximum or both are reset
 * Output: None
 *
 * Returns: 1 if success
 *
 ********************************************************************/
int temperature_indoor_reset(WEATHERSTATION ws2300, char minmax)
{
           unsigned char data_read[20];
           unsigned char data_value[20];
           unsigned char data_time[20];
           unsigned char command[25];       //room for write data also
           int address;
           int number;
 
           // First read current temperature into data_value
           address=0x346;
           number=2;
          
           if (read_safe(ws2300, address, number, data_read, command) != number)
                      read_error_exit();
          
           data_value[0] = data_read[0]&0xF;
           data_value[1] = data_read[0]>>4;
           data_value[2] = data_read[1]&0xF;
           data_value[3] = data_read[1]>>4;
          
           // Get current time from station
           address=0x23B;
           number=6;
          
           if (read_safe(ws2300, address, number, data_read, command) != number)
                      read_error_exit();
                     
           data_time[0] = data_read[0]&0xF;
           data_time[1] = data_read[0]>>4;
           data_time[2] = data_read[1]&0xF;
           data_time[3] = data_read[1]>>4;
           data_time[4] = data_read[2]>>4;
           data_time[5] = data_read[3]&0xF;
           data_time[6] = data_read[3]>>4;
           data_time[7] = data_read[4]&0xF;
           data_time[8] = data_read[4]>>4;
           data_time[9] = data_read[5]&0xF;
 
           if (minmax & RESET_MIN) // minimum
           {
                      // Set min value to current value
                      address=0x34B;
                      number=4;
                     
                      if (write_safe(ws2300, address, number, WRITENIB, data_value, command) != number)
                                 write_error_exit();
 
                      // Set min value timestamp to current time
                      address=0x354;
                      number=10;
 
                      if (write_safe(ws2300, address, number, WRITENIB, data_time, command) != number)
                                 write_error_exit();
           }
          
           if (minmax & RESET_MAX) // maximum
           {
                      // Set max value to current value
                      address=0x350;
                      number=4;
                     
                      if (write_safe(ws2300, address, number, WRITENIB, data_value, command) != number)
                                 write_error_exit();
 
                      // Set max value timestamp to current time
                      address=0x35E;
                      number=10;
 
                      if (write_safe(ws2300, address, number, WRITENIB, data_time, command) != number)
                                 write_error_exit();
           }
 
           return 1;
}
 
 
/********************************************************************/
/* temperature_outdoor
 * Read indoor temperature, current temperature only
 *
 * Input: Handle to weatherstation
 *        temperature_conv flag (integer) controlling
 *            convertion to deg F
 *
 * Returns: Temperature (deg C if temperature_conv is 0)
 *                      (deg F if temperature_conv is 1)
 *
 ********************************************************************/
double temperature_outdoor(WEATHERSTATION ws2300, int temperature_conv)
{
           unsigned char data[20];
           unsigned char command[25];       //room for write data also
           int address=0x373;
           int bytes=2;
 
           if (read_safe(ws2300, address, bytes, data, command) != bytes)
                      read_error_exit();
 
           if (temperature_conv)
                      return ((((data[1] >> 4) * 10 + (data[1] & 0xF) +
                                (data[0] >> 4) / 10.0 + (data[0] & 0xF) / 100.0) -
                                30.0) * 9 / 5 + 32);
           else
                      return ((((data[1] >> 4) * 10 + (data[1] & 0xF) +
                                (data[0] >> 4) / 10.0 + (data[0] & 0xF) / 100.0) - 30.0));
}
 
 
/********************************************************************
 * temperature_outdoor_minmax
 * Read outdoor min/max temperatures with timestamps
 *
 * Input: Handle to weatherstation
 *        temperature_conv flag (integer) controlling
 *            convertion to deg F
 *
 * Output: Temperatures temp_min and temp_max
 *                (deg C if temperature_conv is 0)
 *                (deg F if temperature_conv is 1)
 *         Timestamps for temp_min and temp_max in pointers to
 *                timestamp structures for time_min and time_max
 *
 ********************************************************************/
void temperature_outdoor_minmax(WEATHERSTATION ws2300,
                                int temperature_conv,
                                double *temp_min,
                                double *temp_max,
                                struct timestamp *time_min,
                                struct timestamp *time_max)
{
           unsigned char data[20];
           unsigned char command[25];       //room for write data also
           int address=0x378;
           int bytes=15;
          
           if (read_safe(ws2300, address, bytes, data, command) != bytes)
                      read_error_exit();
          
           *temp_min = ((data[1]>>4)*10 + (data[1]&0xF) + (data[0]>>4)/10.0 +
                        (data[0]&0xF)/100.0) - 30.0;
 
           *temp_max = ((data[4]&0xF)*10 + (data[3]>>4) + (data[3]&0xF)/10.0 +
                        (data[2]>>4)/100.0) - 30.0;
 
           if (temperature_conv)
           {
                      *temp_min = *temp_min * 9/5 + 32;
                      *temp_max = *temp_max * 9/5 + 32;
           }
 
           time_min->minute = ((data[5] & 0xF) * 10) + (data[4] >> 4);
           time_min->hour = ((data[6] & 0xF) * 10) + (data[5] >> 4);
           time_min->day = ((data[7] & 0xF) * 10) + (data[6] >> 4);
           time_min->month = ((data[8] & 0xF) * 10) + (data[7] >> 4);
           time_min->year = 2000 + ((data[9] & 0xF) * 10) + (data[8] >> 4);
          
           time_max->minute = ((data[10] & 0xF) * 10) + (data[9] >> 4);
           time_max->hour = ((data[11] & 0xF) * 10) + (data[10] >> 4);
           time_max->day = ((data[12] & 0xF) * 10) + (data[11] >> 4);
           time_max->month = ((data[13] & 0xF) * 10) + (data[12] >> 4);
           time_max->year = 2000 + ((data[14] & 0xF) * 10) + (data[13] >> 4);
          
           return;
}
 
 
/********************************************************************/
/* temperature_outdoor_reset
 * Reset outdoor min/max temperatures with timestamps
 *
 * Input: Handle to weatherstation
 *        minmax - char (8 bit integer) that controls if minimum,
 *                 maximum or both are reset
 * Output: None
 *
 * Returns: 1 if success
 *
 ********************************************************************/
int temperature_outdoor_reset(WEATHERSTATION ws2300, char minmax)
{
           unsigned char data_read[20];
           unsigned char data_value[20];
           unsigned char data_time[20];
           unsigned char command[25];       //room for write data also
           int address;
           int number;
 
           // First read current temperature into data_value
           address=0x373;
           number=2;
          
           if (read_safe(ws2300, address, number, data_read, command) != number)
                      read_error_exit();
          
           data_value[0] = data_read[0]&0xF;
           data_value[1] = data_read[0]>>4;
           data_value[2] = data_read[1]&0xF;
           data_value[3] = data_read[1]>>4;
          
           // Get current time from station
           address=0x23B;
           number=6;
          
           if (read_safe(ws2300, address, number, data_read, command) != number)
                      read_error_exit();
                     
           data_time[0] = data_read[0]&0xF;
           data_time[1] = data_read[0]>>4;
           data_time[2] = data_read[1]&0xF;
           data_time[3] = data_read[1]>>4;
           data_time[4] = data_read[2]>>4;
           data_time[5] = data_read[3]&0xF;
           data_time[6] = data_read[3]>>4;
           data_time[7] = data_read[4]&0xF;
           data_time[8] = data_read[4]>>4;
           data_time[9] = data_read[5]&0xF;
 
           if (minmax & RESET_MIN) // minimum
           {
                      // Set min value to current value
                      address=0x378;
                      number=4;
                     
                      if (write_safe(ws2300, address, number, WRITENIB, data_value, command) != number)
                                 write_error_exit();
 
                      // Set min value timestamp to current time
                      address=0x381;
                      number=10;
 
                      if (write_safe(ws2300, address, number, WRITENIB, data_time, command) != number)
                                 write_error_exit();
           }
          
           if (minmax & RESET_MAX) // maximum
           {
                      // Set max value to current value
                      address=0x37D;
                      number=4;
                     
                      if (write_safe(ws2300, address, number, WRITENIB, data_value, command) != number)
                                 write_error_exit();
 
                      // Set max value timestamp to current time
                      address=0x38B;
                      number=10;
 
                      if (write_safe(ws2300, address, number, WRITENIB, data_time, command) != number)
                                 write_error_exit();
           }
 
           return 1;
}
 
 
/********************************************************************
 * dewpoint
 * Read dewpoint, current value only
 *
 * Input: Handle to weatherstation
 *        temperature_conv flag (integer) controlling
 *            convertion to deg F
 *
 * Returns: Dewpoint    (deg C if temperature_conv is 0)
 *                      (deg F if temperature_conv is 1)
 *
 ********************************************************************/
double dewpoint(WEATHERSTATION ws2300, int temperature_conv)
{
           unsigned char data[20];
           unsigned char command[25];       //room for write data also
           int address=0x3CE;
           int bytes=2;
 
           if (read_safe(ws2300, address, bytes, data, command) != bytes)
                      read_error_exit();
 
           if (temperature_conv)
                      return ((((data[1] >> 4) * 10 + (data[1] & 0xF) +
                                (data[0] >> 4) / 10.0 + (data[0] & 0xF) / 100.0) -
                                30.0) * 9 / 5 + 32);
           else
                      return ((((data[1] >> 4) * 10 + (data[1] & 0xF) +
                                (data[0] >> 4) / 10.0 + (data[0] & 0xF) / 100.0) - 30.0));
}
 
 
/********************************************************************
 * dewpoint_minmax
 * Read outdoor min/max dewpoint with timestamps
 *
 * Input: Handle to weatherstation
 *        temperature_conv flag (integer) controlling
 *            convertion to deg F
 *
 * Output: Dewpoints dp_min and dp_max
 *                (deg C if temperature_conv is 0),
 *                (deg F if temperature_conv is 1)
 *         Timestamps for dp_min and dp_max in pointers to
 *                timestamp structures for time_min and time_max
 *
 ********************************************************************/
void dewpoint_minmax(WEATHERSTATION ws2300,
                     int temperature_conv,
                     double *dp_min,
                     double *dp_max,
                     struct timestamp *time_min,
                     struct timestamp *time_max)
{
           unsigned char data[20];
           unsigned char command[25];       //room for write data also
           int address=0x3D3;
           int bytes=15;
          
           if (read_safe(ws2300, address, bytes, data, command) != bytes)
                      read_error_exit();
          
           *dp_min = ((data[1]>>4)*10 + (data[1]&0xF) + (data[0]>>4)/10.0 +
                      (data[0]&0xF)/100.0) - 30.0;
 
           *dp_max = ((data[4]&0xF)*10 + (data[3]>>4) + (data[3]&0xF)/10.0 +
                      (data[2]>>4)/100.0) - 30.0;
 
           if (temperature_conv)
           {
                      *dp_min = *dp_min * 9/5 + 32;
                      *dp_max = *dp_max * 9/5 + 32;
           }
 
           time_min->minute = ((data[5] & 0xF) * 10) + (data[4] >> 4);
           time_min->hour = ((data[6] & 0xF) * 10) + (data[5] >> 4);
           time_min->day = ((data[7] & 0xF) * 10) + (data[6] >> 4);
           time_min->month = ((data[8] & 0xF) * 10) + (data[7] >> 4);
           time_min->year = 2000 + ((data[9] & 0xF) * 10) + (data[8] >> 4);
          
           time_max->minute = ((data[10] & 0xF) * 10) + (data[9] >> 4);
           time_max->hour = ((data[11] & 0xF) * 10) + (data[10] >> 4);
           time_max->day = ((data[12] & 0xF) * 10) + (data[11] >> 4);
           time_max->month = ((data[13] & 0xF) * 10) + (data[12] >> 4);
           time_max->year = 2000 + ((data[14] & 0xF) * 10) + (data[13] >> 4);
          
           return;
}
 
 
/********************************************************************/
/* dewpoint_reset
 * Reset min/max dewpoint with timestamps
 *
 * Input: Handle to weatherstation
 *        minmax - char (8 bit integer) that controls if minimum,
 *                 maximum or both are reset
 * Output: None
 *
 * Returns: 1 if success
 *
 ********************************************************************/
int dewpoint_reset(WEATHERSTATION ws2300, char minmax)
{
           unsigned char data_read[20];
           unsigned char data_value[20];
           unsigned char data_time[20];
           unsigned char command[25];       //room for write data also
           int address;
           int number;
 
           // First read current dewpoint into data_value
           address=0x3CE;
           number=2;
          
           if (read_safe(ws2300, address, number, data_read, command) != number)
                      read_error_exit();
          
           data_value[0] = data_read[0]&0xF;
           data_value[1] = data_read[0]>>4;
           data_value[2] = data_read[1]&0xF;
           data_value[3] = data_read[1]>>4;
          
           // Get current time from station
           address=0x23B;
           number=6;
          
           if (read_safe(ws2300, address, number, data_read, command) != number)
                      read_error_exit();
                     
           data_time[0] = data_read[0]&0xF;
           data_time[1] = data_read[0]>>4;
           data_time[2] = data_read[1]&0xF;
           data_time[3] = data_read[1]>>4;
           data_time[4] = data_read[2]>>4;
           data_time[5] = data_read[3]&0xF;
           data_time[6] = data_read[3]>>4;
           data_time[7] = data_read[4]&0xF;
           data_time[8] = data_read[4]>>4;
           data_time[9] = data_read[5]&0xF;
 
           if (minmax & RESET_MIN) // minimum
           {
                      // Set min value to current value
                      address=0x3D3;
                      number=4;
                     
                      if (write_safe(ws2300, address, number, WRITENIB, data_value, command) != number)
                                 write_error_exit();
 
                      // Set min value timestamp to current time
                      address=0x3DC;
                      number=10;
 
                      if (write_safe(ws2300, address, number, WRITENIB, data_time, command) != number)
                                 write_error_exit();
           }
          
           if (minmax & RESET_MAX) // maximum
           {
                      // Set max value to current value
                      address=0x3D8;
                      number=4;
                     
                      if (write_safe(ws2300, address, number, WRITENIB, data_value, command) != number)
                                 write_error_exit();
 
                      // Set max value timestamp to current time
                      address=0x3E6;
                      number=10;
 
                      if (write_safe(ws2300, address, number, WRITENIB, data_time, command) != number)
                                 write_error_exit();
           }
 
           return 1;
}
 
 
/********************************************************************
 * humidity_indoor
 * Read indoor relative humidity, current value only
 *
 * Input: Handle to weatherstation
 * Returns: relative humidity in percent (integer)
 *
 ********************************************************************/
int humidity_indoor(WEATHERSTATION ws2300)
{
           unsigned char data[20];
           unsigned char command[25];       //room for write data also
           int address=0x3FB;
           int bytes=1;
 
           if (read_safe(ws2300, address, bytes, data, command) != bytes)
                      read_error_exit();
 
           return ((data[0] >> 4) * 10 + (data[0] & 0xF));
}
 
 
/********************************************************************
 * humidity_indoor_all
 * Read both current indoor humidity and min/max values with timestamps
 *
 * Input: Handle to weatherstation
 * Output: Relative humidity in % hum_min and hum_max (integers)
 *         Timestamps for hum_min and hum_max in pointers to
 *                timestamp structures for time_min and time_max
 * Returns: releative humidity current value in % (integer)
 *
 ********************************************************************/
int humidity_indoor_all(WEATHERSTATION ws2300,
                        int *hum_min,
                        int *hum_max,
                        struct timestamp *time_min,
                        struct timestamp *time_max)
{
           unsigned char data[20];
           unsigned char command[25];       //room for write data also
           int address=0x3FB;
           int bytes=13;
          
           if (read_safe(ws2300, address, bytes, data, command) != bytes)
                      read_error_exit();
 
           *hum_min = (data[1] >> 4) * 10 + (data[1] & 0xF);
           *hum_max = (data[2] >> 4) * 10 + (data[2] & 0xF);
 
           time_min->minute = ((data[3] >> 4) * 10) + (data[3] & 0xF);
           time_min->hour = ((data[4] >> 4) * 10) + (data[4] & 0xF);
           time_min->day = ((data[5] >> 4) * 10) + (data[5] & 0xF);
           time_min->month = ((data[6] >> 4) * 10) + (data[6] & 0xF);
           time_min->year = 2000 + ((data[7] >> 4) * 10) + (data[7] & 0xF);
          
           time_max->minute = ((data[8] >> 4) * 10) + (data[8] & 0xF);
           time_max->hour = ((data[9] >> 4) * 10) + (data[9] & 0xF);
           time_max->day = ((data[10] >> 4) * 10) + (data[10] & 0xF);
           time_max->month = ((data[11] >> 4) * 10) + (data[11] & 0xF);
           time_max->year = 2000 + ((data[12] >> 4) * 10) + (data[12] & 0xF);
          
           return ((data[0] >> 4) * 10 + (data[0] & 0xF));
}
 
 
/********************************************************************/
/* humidity_indoor_reset
 * Reset min/max indoor humidity with timestamps
 *
 * Input: Handle to weatherstation
 *        minmax - char (8 bit integer) that controls if minimum,
 *                 maximum or both are reset
 * Output: None
 *
 * Returns: 1 if success
 *
 ********************************************************************/
int humidity_indoor_reset(WEATHERSTATION ws2300, char minmax)
{
           unsigned char data_read[20];
           unsigned char data_value[20];
           unsigned char data_time[20];
           unsigned char command[25];       //room for write data also
           int address;
           int number;
 
           // First read current humidity into data_value
           address=0x3FB;
           number=1;
          
           if (read_safe(ws2300, address, number, data_read, command) != number)
                      read_error_exit();
          
           data_value[0] = data_read[0]&0xF;
           data_value[1] = data_read[0]>>4;
          
           // Get current time from station
           address=0x23B;
           number=6;
          
           if (read_safe(ws2300, address, number, data_read, command) != number)
                      read_error_exit();
                     
           data_time[0] = data_read[0]&0xF;
           data_time[1] = data_read[0]>>4;
           data_time[2] = data_read[1]&0xF;
           data_time[3] = data_read[1]>>4;
           data_time[4] = data_read[2]>>4;
           data_time[5] = data_read[3]&0xF;
           data_time[6] = data_read[3]>>4;
           data_time[7] = data_read[4]&0xF;
           data_time[8] = data_read[4]>>4;
           data_time[9] = data_read[5]&0xF;
 
           if (minmax & RESET_MIN) // minimum
           {
                      // Set min value to current value
                      address=0x3FD;
                      number=2;
                     
                      if (write_safe(ws2300, address, number, WRITENIB, data_value, command) != number)
                                 write_error_exit();
 
                      // Set min value timestamp to current time
                      address=0x401;
                      number=10;
 
                      if (write_safe(ws2300, address, number, WRITENIB, data_time, command) != number)
                                 write_error_exit();
           }
          
           if (minmax & RESET_MAX) // maximum
           {
                      // Set max value to current value
                      address=0x3FF;
                      number=2;
                     
                      if (write_safe(ws2300, address, number, WRITENIB, data_value, command) != number)
                                 write_error_exit();
 
                      // Set max value timestamp to current time
                      address=0x40B;
                      number=10;
 
                      if (write_safe(ws2300, address, number, WRITENIB, data_time, command) != number)
                                 write_error_exit();             
           }
 
           return 1;
}
 
 
/********************************************************************
 * humidity_outdoor
 * Read relative humidity, current value only
 *
 * Input: Handle to weatherstation
 * Returns: relative humidity in percent (integer)
 *
 ********************************************************************/
int humidity_outdoor(WEATHERSTATION ws2300)
{
           unsigned char data[20];
           unsigned char command[25];       //room for write data also
           int address=0x419;
           int bytes=1;
          
           if (read_safe(ws2300, address, bytes, data, command) != bytes)
                      read_error_exit();
 
           return ((data[0] >> 4) * 10 + (data[0] & 0xF));
}
 
 
/********************************************************************
 * humidity_outdoor_all
 * Read both current outdoor humidity and min/max values with timestamps
 *
 * Input: Handle to weatherstation
 * Output: Relative humidity in % hum_min and hum_max (integers)
 *         Timestamps for hum_min and hum_max in pointers to
 *                timestamp structures for time_min and time_max
 *
 * Returns: releative humidity current value in % (integer)
 *
 ********************************************************************/
int humidity_outdoor_all(WEATHERSTATION ws2300,
                         int *hum_min,
                         int *hum_max,
                         struct timestamp *time_min,
                         struct timestamp *time_max)
{
           unsigned char data[20];
           unsigned char command[25];       //room for write data also
           int address=0x419;
           int bytes=13;
          
           if (read_safe(ws2300, address, bytes, data, command) != bytes)
                      read_error_exit();
 
           *hum_min = (data[1] >> 4) * 10 + (data[1] & 0xF);
           *hum_max = (data[2] >> 4) * 10 + (data[2] & 0xF);
 
           time_min->minute = ((data[3] >> 4) * 10) + (data[3] & 0xF);
           time_min->hour = ((data[4] >> 4) * 10) + (data[4] & 0xF);
           time_min->day = ((data[5] >> 4) * 10) + (data[5] & 0xF);
           time_min->month = ((data[6] >> 4) * 10) + (data[6] & 0xF);
           time_min->year = 2000 + ((data[7] >> 4) * 10) + (data[7] & 0xF);
          
           time_max->minute = ((data[8] >> 4) * 10) + (data[8] & 0xF);
           time_max->hour = ((data[9] >> 4) * 10) + (data[9] & 0xF);
           time_max->day = ((data[10] >> 4) * 10) + (data[10] & 0xF);
           time_max->month = ((data[11] >> 4) * 10) + (data[11] & 0xF);
           time_max->year = 2000 + ((data[12] >> 4) * 10) + (data[12] & 0xF);
          
           return ((data[0] >> 4) * 10 + (data[0] & 0xF));
}
 
 
/********************************************************************/
/* humidity_outdoor_reset
 * Reset min/max outdoor humidity with timestamps
 *
 * Input: Handle to weatherstation
 *        minmax - char (8 bit integer) that controls if minimum,
 *                 maximum or both are reset
 * Output: None
 *
 * Returns: 1 if success
 *
 ********************************************************************/
int humidity_outdoor_reset(WEATHERSTATION ws2300, char minmax)
{
           unsigned char data_read[20];
           unsigned char data_value[20];
           unsigned char data_time[20];
           unsigned char command[25];       //room for write data also
           int address;
           int number;
 
           // First read current humidity into data_value
           address=0x419;
           number=1;
          
           if (read_safe(ws2300, address, number, data_read, command) != number)
                      read_error_exit();
          
           data_value[0] = data_read[0]&0xF;
           data_value[1] = data_read[0]>>4;
          
           // Get current time from station
           address=0x23B;
           number=6;
          
           if (read_safe(ws2300, address, number, data_read, command) != number)
                      read_error_exit();
                     
           data_time[0] = data_read[0]&0xF;
           data_time[1] = data_read[0]>>4;
           data_time[2] = data_read[1]&0xF;
           data_time[3] = data_read[1]>>4;
           data_time[4] = data_read[2]>>4;
           data_time[5] = data_read[3]&0xF;
           data_time[6] = data_read[3]>>4;
           data_time[7] = data_read[4]&0xF;
           data_time[8] = data_read[4]>>4;
           data_time[9] = data_read[5]&0xF;
 
           if (minmax & RESET_MIN) // minimum
           {
                      // Set min value to current value
                      address=0x41B;
                      number=2;
                     
                      if (write_safe(ws2300, address, number, WRITENIB, data_value, command) != number)
                                 write_error_exit();
 
                      // Set min value timestamp to current time
                      address=0x41F;
                      number=10;
 
                      if (write_safe(ws2300, address, number, WRITENIB, data_time, command) != number)
                                 write_error_exit();
           }
          
           if (minmax & RESET_MAX) // maximum
           {
                      // Set max value to current value
                      address=0x41D;
                      number=2;
                     
                      if (write_safe(ws2300, address, number, WRITENIB, data_value, command) != number)
                                 write_error_exit();
 
                      // Set max value timestamp to current time
                      address=0x429;
                      number=10;
 
                      if (write_safe(ws2300, address, number, WRITENIB, data_time, command) != number)
                                 write_error_exit();
           }
 
           return 1;
}
 
 
/********************************************************************
 * wind_current
 * Read wind speed, wind direction and last 5 wind directions
 *
 * Input: Handle to weatherstation
 *        wind_speed_conv_factor controlling convertion to other
 *             units than m/s
 *
 * Output: winddir - pointer to double in degrees
 *
 * Returns: Wind speed (double) in the unit given in the loaded config
 *
 ********************************************************************/
double wind_current(WEATHERSTATION ws2300,
                    double wind_speed_conv_factor,
                    double *winddir)
{
           unsigned char data[20];
           unsigned char command[25];       //room for write data also
           int i;
           int address=0x527; //Windspeed and direction
           int bytes=3;
          
           for (i=0; i<MAXWINDRETRIES; i++)
           {
                      if (read_safe(ws2300, address, bytes, data, command)!=bytes) //Wind
                                 read_error_exit();
                     
                      if ( (data[0]!=0x00) ||                            //Invalid wind data
                          ((data[1]==0xFF) && (((data[2]&0xF)==0)||((data[2]&0xF)==1))) )
                      {
                                 sleep_long(10); //wait 10 seconds for new wind measurement
                                 continue;
                      }
                      else
                      {
                                 break;
                      }
           }
          
           //Calculate wind directions
 
           *winddir = (data[2]>>4)*22.5;
 
           //Calculate raw wind speed       - convert from m/s to whatever
           return( (((data[2]&0xF)<<8)+(data[1])) / 10.0 * wind_speed_conv_factor );
}
 
 
/********************************************************************
 * wind_all
 * Read wind speed, wind direction and last 5 wind directions
 *
 * Input: Handle to weatherstation
 *        wind_speed_conv_factor controlling convertion to other
 *             units than m/s
 *
 * Output: winddir_index
 *              Current wind direction expressed as ticks from North
 *              where North=0. Used to convert to direction string
 *         winddir
 *              Array of doubles containing current winddirection
 *              in winddir[0] and the last 5 in the following
 *              positions all given in degrees
 *
 * Returns: Wind speed (double) in the unit given in the loaded config
 *
 ********************************************************************/
double wind_all(WEATHERSTATION ws2300,
                double wind_speed_conv_factor,
                int *winddir_index,
                double *winddir)
{
           unsigned char data[20];
           unsigned char command[25];       //room for write data also
           int i;
           int address=0x527; //Windspeed and direction
           int bytes=6;
          
           for (i=0; i<MAXWINDRETRIES; i++)
           {
                      if (read_safe(ws2300, address, bytes, data, command)!=bytes) //Wind
                                 read_error_exit();
                          
                      if ( (data[0]!=0x00) ||                             //Invalid wind data
                         ((data[1]==0xFF) && (((data[2]&0xF)==0)||( (data[2]&0xF)==1))) )
                      {
                                 sleep_long(10); //wait 10 seconds for new wind measurement
                                 continue;
                      }
                      else
                      {
                                 break;
                      }
           }
          
           //Calculate wind directions
 
           *winddir_index = (data[2]>>4);
           winddir[0] = (data[2]>>4)*22.5;
           winddir[1] = (data[3]&0xF)*22.5;
           winddir[2] = (data[3]>>4)*22.5;
           winddir[3] = (data[4]&0xF)*22.5;
           winddir[4] = (data[4]>>4)*22.5;
           winddir[5] = (data[5]&0xF)*22.5;
 
           //Calculate raw wind speed - convert from m/s to whatever
           return ( (((data[2]&0xF)<<8)+(data[1]) ) / 10.0 * wind_speed_conv_factor);
}
 
 
/********************************************************************
 * wind_minmax
 * Read min/max wind speeds with timestamps
 *
 * Input: Handle to weatherstation
 *        wind_speed_conv_factor controlling convertion to other
 *             units than m/s
 *
 * Output: Wind wind_min and wind_max (double)
 *                unit defined by config conversion factor
 *         Timestamps for wind_min and wind_max in pointers to
 *                timestamp structures for time_min and time_max
 *
 * Returns: wind max (double)
 *
 * Note: The function is made so that if a pointer to
 *       wind_min/max and time_min/max is a NULL pointer the function
 *       ignores this parameter. Example: if you only need wind_max
 *       use the function like this..
 *       windmax = wind_minmax(ws2300,METERS_PER_SECOND,NULL,NULL,NULL,NULL);
 *
 ********************************************************************/
double wind_minmax(WEATHERSTATION ws2300,
                   double wind_speed_conv_factor,
                   double *wind_min,
                   double *wind_max,
                   struct timestamp *time_min,
                   struct timestamp *time_max)
{
           unsigned char data[20];
           unsigned char command[25];       //room for write data also
           int address=0x4EE;
           int bytes=15;
          
           if (read_safe(ws2300, address, bytes, data, command) != bytes)
                                 read_error_exit();
          
           if (wind_min != NULL)
                      *wind_min = (data[1]*256 + data[0])/360.0 * wind_speed_conv_factor;
           if (wind_max != NULL)
                      *wind_max = (data[4]*256 + data[3])/360.0 * wind_speed_conv_factor;
 
           if (time_min != NULL)
           {         
                      time_min->minute = ((data[5] >> 4) * 10) + (data[5] & 0xF);
                      time_min->hour = ((data[6] >> 4) * 10) + (data[6] & 0xF);
                      time_min->day = ((data[7] >> 4) * 10) + (data[7] & 0xF);
                      time_min->month = ((data[8] >> 4) * 10) + (data[8] & 0xF);
                      time_min->year = 2000 + ((data[9] >> 4) * 10) + (data[9] & 0xF);
           }
          
           if (time_max != NULL)
           {
                      time_max->minute = ((data[10] >> 4) * 10) + (data[10] & 0xF);
                      time_max->hour = ((data[11] >> 4) * 10) + (data[11] & 0xF);
                      time_max->day = ((data[12] >> 4) * 10) + (data[12] & 0xF);
                      time_max->month = ((data[13] >> 4) * 10) + (data[13] & 0xF);
                      time_max->year = 2000 + ((data[14] >> 4) * 10) + (data[14] & 0xF);
           }
          
           return ((data[4]*256 + data[3])/360.0 * wind_speed_conv_factor);
}
 
 
/********************************************************************/
/* wind_reset
 * Reset min/max wind with timestamps
 *
 * Input: Handle to weatherstation
 *        minmax - char (8 bit integer) that controls if minimum,
 *                 maximum or both are reset
 * Output: None
 *
 * Returns: 1 if success
 *
 ********************************************************************/
int wind_reset(WEATHERSTATION ws2300, char minmax)
{
           unsigned char data_read[20];
           unsigned char data_value[20];
           unsigned char data_time[20];
           unsigned char command[25];       //room for write data also
           int address;
           int number;
           int i;
           int current_wind;
          
           address=0x527; //Windspeed
           number=3;
          
           for (i=0; i<MAXWINDRETRIES; i++)
           {
                      if (read_safe(ws2300, address, number, data_read, command)!=number)
                                 read_error_exit();
                          
                      if ((data_read[0]!=0x00) ||                            //Invalid wind data
                          ((data_read[1]==0xFF)&&(((data_read[2]&0xF)==0)||((data_read[2]&0xF)==1))))
                      {
                                 sleep_long(10); //wait 10 seconds for new wind measurement
                                 continue;
                      }
                      else
                      {
                                 break;
                      }
           }
          
           current_wind = ( ((data_read[2]&0xF)<<8) + (data_read[1]) ) * 36;
 
           data_value[0] = current_wind&0xF;
           data_value[1] = (current_wind>>4)&0xF;
           data_value[2] = (current_wind>>8)&0xF;
           data_value[3] = (current_wind>>12)&0xF;
          
           // Get current time from station
           address=0x23B;
           number=6;
          
           if (read_safe(ws2300, address, number, data_read, command) != number)
                      read_error_exit();
          
           data_time[0] = data_read[0]&0xF;
           data_time[1] = data_read[0]>>4;
           data_time[2] = data_read[1]&0xF;
           data_time[3] = data_read[1]>>4;
           data_time[4] = data_read[2]>>4;
           data_time[5] = data_read[3]&0xF;
           data_time[6] = data_read[3]>>4;
           data_time[7] = data_read[4]&0xF;
           data_time[8] = data_read[4]>>4;
           data_time[9] = data_read[5]&0xF;
 
           if (minmax & RESET_MIN) // minimum
           {
                      // Set min value to current value
                      address=0x4EE;
                      number=4;
                     
                      if (write_safe(ws2300, address, number, WRITENIB, data_value, command) != number)
                                 write_error_exit();
 
                      // Set min value timestamp to current time
                      address=0x4F8;
                      number=10;
 
                      if (write_safe(ws2300, address, number, WRITENIB, data_time, command) != number)
                                 write_error_exit();
           }
          
           if (minmax & RESET_MAX) // maximum
           {
                      // Set max value to current value
                      address=0x4F4;
                      number=4;
                     
                      if (write_safe(ws2300, address, number, WRITENIB, data_value, command) != number)
                                 write_error_exit();
 
                      // Set max value timestamp to current time
                      address=0x502;
                      number=10;
 
                      if (write_safe(ws2300, address, number, WRITENIB, data_time, command) != number)
                                 write_error_exit();             
           }
 
           return 1;
}
 
 
/********************************************************************
 * windchill
 * Read wind chill, current value only
 *
 * Input: Handle to weatherstation
 *        temperature_conv flag (integer) controlling
 *            convertion to deg F
 *
 * Returns: wind chill  (deg C if config.temperature_conv is not set)
 *                      (deg F if config.temperature_conv is set)
 *
 * It is recommended to run this right after a wind speed reading
 * to enhance the likelyhood that the wind speed is valid
 *
 ********************************************************************/
double windchill(WEATHERSTATION ws2300, int temperature_conv)
{
           unsigned char data[20];
           unsigned char command[25];       //room for write data also
           int address=0x3A0;
           int bytes=2;
 
           if (read_safe(ws2300, address, bytes, data, command) != bytes)
                      read_error_exit();
 
           if (temperature_conv)
                      return ((((data[1] >> 4) * 10 + (data[1] & 0xF) +
                                (data[0] >> 4) / 10.0 + (data[0] & 0xF) / 100.0) -
                                30.0) * 9 / 5 + 32);
           else
                      return ((((data[1] >> 4) * 10 + (data[1] & 0xF) +
                                (data[0] >> 4) / 10.0 + (data[0] & 0xF) / 100.0) - 30.0));
}
 
 
/********************************************************************
 * windchill_minmax
 * Read wind chill min/max with timestamps
 *
 * Input: Handle to weatherstation
 *        temperature_conv flag (integer) controlling
 *            convertion to deg F
 *
 * Output: Windchill wc_min and wc_max
 *                (deg C if config.temperature_conv is not set)
 *                (deg F if config.temperature_conv is set)
 *         Timestamps for wc_min and wc_max in pointers to
 *                timestamp structures for time_min and time_max
 *
 * Returns: Nothing
 *
 ********************************************************************/
void windchill_minmax(WEATHERSTATION ws2300,
                      int temperature_conv,
                      double *wc_min,
                      double *wc_max,
                      struct timestamp *time_min,
                      struct timestamp *time_max)
{
           unsigned char data[20];
           unsigned char command[25];       //room for write data also
           int address=0x3A5;
           int bytes=15;
          
           if (read_safe(ws2300, address, bytes, data, command) != bytes)
                      read_error_exit();
          
           *wc_min = ( (data[1]>>4)*10 + (data[1]&0xF) + (data[0]>>4)/10.0 +
                       (data[0]&0xF)/100.0 ) - 30.0;
          
           *wc_max = ( (data[4]&0xF)*10 + (data[3]>>4) + (data[3]&0xF)/10.0 +
                       (data[2]>>4)/100.0 ) - 30.0;
 
           if (temperature_conv)
           {
                      *wc_min = *wc_min * 9/5 + 32;
                      *wc_max = *wc_max * 9/5 + 32;
           }
 
           time_min->minute = ((data[5] & 0xF) * 10) + (data[4] >> 4);
           time_min->hour = ((data[6] & 0xF) * 10) + (data[5] >> 4);
           time_min->day = ((data[7] & 0xF) * 10) + (data[6] >> 4);
           time_min->month = ((data[8] & 0xF) * 10) + (data[7] >> 4);
           time_min->year = 2000 + ((data[9] & 0xF) * 10) + (data[8] >> 4);
          
           time_max->minute = ((data[10] & 0xF) * 10) + (data[9] >> 4);
           time_max->hour = ((data[11] & 0xF) * 10) + (data[10] >> 4);
           time_max->day = ((data[12] & 0xF) * 10) + (data[11] >> 4);
           time_max->month = ((data[13] & 0xF) * 10) + (data[12] >> 4);
           time_max->year = 2000 + ((data[14] & 0xF) * 10) + (data[13] >> 4);
          
           return;
}
 
 
/********************************************************************/
/* windchill_reset
 * Reset min/max windchill with timestamps
 *
 * Input: Handle to weatherstation
 *        minmax - char (8 bit integer) that controls if minimum,
 *                 maximum or both are reset
 * Output: None
 *
 * Returns: 1 if success
 *
 ********************************************************************/
int windchill_reset(WEATHERSTATION ws2300, char minmax)
{
           unsigned char data_read[20];
           unsigned char data_value[20];
           unsigned char data_time[20];
           unsigned char command[25];       //room for write data also
           int address;
           int number;
 
           // First read current windchill into data_value
           address=0x3A0;
           number=2;
          
           if (read_safe(ws2300, address, number, data_read, command) != number)
                      read_error_exit();
          
           data_value[0] = data_read[0]&0xF;
           data_value[1] = data_read[0]>>4;
           data_value[2] = data_read[1]&0xF;
           data_value[3] = data_read[1]>>4;
          
           // Get current time from station
           address=0x23B;
           number=6;
          
           if (read_safe(ws2300, address, number, data_read, command) != number)
                      read_error_exit();
                     
           data_time[0] = data_read[0]&0xF;
           data_time[1] = data_read[0]>>4;
           data_time[2] = data_read[1]&0xF;
           data_time[3] = data_read[1]>>4;
           data_time[4] = data_read[2]>>4;
           data_time[5] = data_read[3]&0xF;
           data_time[6] = data_read[3]>>4;
           data_time[7] = data_read[4]&0xF;
           data_time[8] = data_read[4]>>4;
           data_time[9] = data_read[5]&0xF;
 
           if (minmax & RESET_MIN) // minimum
           {
                      // Set min value to current value
                      address=0x3A5;
                      number=4;
                     
                      if (write_safe(ws2300, address, number, WRITENIB, data_value, command) != number)
                                 write_error_exit();
 
                      // Set min value timestamp to current time
                      address=0x3AE;
                      number=10;
 
                      if (write_safe(ws2300, address, number, WRITENIB, data_time, command) != number)
                                 write_error_exit();
           }
          
           if (minmax & RESET_MAX) // maximum
           {
                      // Set max value to current value
                      address=0x3AA;
                      number=4;
                     
                      if (write_safe(ws2300, address, number, WRITENIB, data_value, command) != number)
                                 write_error_exit();
 
                      // Set max value timestamp to current time
                      address=0x3B8;
                      number=10;
 
                      if (write_safe(ws2300, address, number, WRITENIB, data_time, command) != number)
                                 write_error_exit();
           }
 
           return 1;
}
 
 
/********************************************************************
 * rain_1h
 * Read rain last 1 hour, current value only
 *
 * Input: Handle to weatherstation
 *        rain_conv_factor controlling convertion to other
 *             units than mm
 *
 * Returns: rain (double) converted to unit given in config
 *
 ********************************************************************/
double rain_1h(WEATHERSTATION ws2300, double rain_conv_factor)
{
           unsigned char data[20];
           unsigned char command[25];       //room for write data also
           int address=0x4B4;
           int bytes=3;
 
           if (read_safe(ws2300, address, bytes, data, command) != bytes)
                      read_error_exit();
 
           return ( ((data[2] >> 4) * 1000 + (data[2] & 0xF) * 100 +
                     (data[1] >> 4) * 10 + (data[1] & 0xF) + (data[0] >> 4) / 10.0 +
                     (data[0] & 0xF) / 100.0 ) / rain_conv_factor);
}
 
/********************************************************************
 * rain_1h_all
 * Read rain last 1 hourand maximum with timestamp
 *
 * Input: Handle to weatherstation
 *        rain_conv_factor controlling convertion to other
 *             units than mm
 *
 * Output: Rain maximum in rain_max (double)
 *                unit defined by config conversion factor
 *         Timestamps for rain_max in pointers to
 *                timestamp structures for time_min and time_max
 *
 * Returns: rain (double) converted to unit given in config
 *
 ********************************************************************/
double rain_1h_all(WEATHERSTATION ws2300,
                   double rain_conv_factor,
                   double *rain_max,
                   struct timestamp *time_max)
{
           unsigned char data[20];
           unsigned char command[25];       //room for write data also
           int address=0x4B4;
           int bytes=11;
 
           if (read_safe(ws2300, address, bytes, data, command) != bytes)
                      read_error_exit();
                     
           *rain_max = ((data[5] >> 4) * 1000 + (data[5] & 0xF) * 100 +
                        (data[4] >> 4) * 10 + (data[4] & 0xF) + (data[3]>>4)/10.0 +
                        (data[3] & 0xF) / 100.0) / rain_conv_factor;
                       
           time_max->minute = ((data[6] >> 4) * 10) + (data[6] & 0xF);
           time_max->hour = ((data[7] >> 4) * 10) + (data[7] & 0xF);
           time_max->day = ((data[8] >> 4) * 10) + (data[8] & 0xF);
           time_max->month = ((data[9] >> 4) * 10) + (data[9] & 0xF);
           time_max->year = 2000 + ((data[10] >> 4) * 10) + (data[10] & 0xF);
 
           return (((data[2] >> 4) * 1000 + (data[2] & 0xF) * 100 +
                    (data[1] >> 4) * 10 + (data[1] & 0xF) + (data[0] >> 4) / 10.0 +
                    (data[0] & 0xF) / 100.0) / rain_conv_factor);
}
 
 
/********************************************************************/
/* rain_1h_max_reset
 * Reset max rain 1h with timestamps
 *
 * Input: Handle to weatherstation
 *        minmax - char (8 bit integer) that controls if minimum,
 *                 maximum or both are reset
 * Output: None
 *
 * Returns: 1 if success
 *
 ********************************************************************/
int rain_1h_max_reset(WEATHERSTATION ws2300)
{
           unsigned char data_read[20];
           unsigned char data_value[20];
           unsigned char data_time[20];
           unsigned char command[25];       //room for write data also
           int address;
           int number;
 
           // First read current rain 1h into data_value
           address=0x4B4;
           number=3;
          
           if (read_safe(ws2300, address, number, data_read, command) != number)
                      read_error_exit();
          
           data_value[0] = data_read[0]&0xF;
           data_value[1] = data_read[0]>>4;
           data_value[2] = data_read[1]&0xF;
           data_value[3] = data_read[1]>>4;
           data_value[4] = data_read[2]&0xF;
           data_value[5] = data_read[2]>>4;
          
           // Get current time from station
           address=0x23B;
           number=6;
          
           if (read_safe(ws2300, address, number, data_read, command) != number)
                      read_error_exit();
          
           data_time[0] = data_read[0]&0xF;
           data_time[1] = data_read[0]>>4;
           data_time[2] = data_read[1]&0xF;
           data_time[3] = data_read[1]>>4;
           data_time[4] = data_read[2]>>4;
           data_time[5] = data_read[3]&0xF;
           data_time[6] = data_read[3]>>4;
           data_time[7] = data_read[4]&0xF;
           data_time[8] = data_read[4]>>4;
           data_time[9] = data_read[5]&0xF;
 
           // Set max value to current value
           address=0x4BA;
           number=6;
          
           if (write_safe(ws2300, address, number, WRITENIB, data_value, command) != number)
                      write_error_exit();
 
           // Set max value timestamp to current time
           address=0x4C0;
           number=10;
 
           if (write_safe(ws2300, address, number, WRITENIB, data_time, command) != number)
                      write_error_exit();
 
           return 1;
}
 
/********************************************************************/
/* rain_1h_reset
 * Reset current rain 1h
 *
 * Input: Handle to weatherstation
 *        minmax - char (8 bit integer) that controls if minimum,
 *                 maximum or both are reset
 * Output: None
 *
 * Returns: 1 if success
 *
 ********************************************************************/
int rain_1h_reset(WEATHERSTATION ws2300)
{
           unsigned char data[50];
           unsigned char command[60];       //room for write data also
           int address;
           int number;
 
           // First overwrite the 1h rain history with zeros
           address=0x479;
           number=30;
           memset(&data, 0, sizeof(data));
          
           if (write_safe(ws2300, address, number, WRITENIB, data, command) != number)
                      write_error_exit();
          
           // Set value to zero
           address=0x4B4;
           number=6;
          
           if (write_safe(ws2300, address, number, WRITENIB, data, command) != number)
                      write_error_exit();
 
           return 1;
}
 
 
/********************************************************************
 * rain_24h
 * Read rain last 24 hours, current value only
 *
 * Input: Handle to weatherstation
 *        rain_conv_factor controlling convertion to other
 *             units than mm
 *
 * Returns: rain (double) converted to unit given in config
 *
 ********************************************************************/
double rain_24h(WEATHERSTATION ws2300, double rain_conv_factor)
{
           unsigned char data[20];
           unsigned char command[25];       //room for write data also
           int address=0x497;
           int bytes=3;
          
           if (read_safe(ws2300, address, bytes, data, command) != bytes)
                      read_error_exit();
 
           return (((data[2] >> 4) * 1000 + (data[2] & 0xF) * 100 +
                    (data[1] >> 4) * 10 + (data[1] & 0xF) + (data[0] >> 4) / 10.0 +
                    (data[0] & 0xF) / 100.0) / rain_conv_factor);
}
 
 
/********************************************************************
 * rain_24h_all
 * Read rain last 24 hours and maximum with timestamp
 *
 * Input: Handle to weatherstation
 *        rain_conv_factor controlling convertion to other
 *             units than mm
 *
 * Output: Rain maximum in rain_max (double)
 *                unit defined by config conversion factor
 *         Timestamp for rain_max in pointers to
 *                timestamp structures for time_min and time_max
 *
 * Returns: rain (double) converted to unit given in config
 *
 ********************************************************************/
double rain_24h_all(WEATHERSTATION ws2300,
                   double rain_conv_factor,
                   double *rain_max,
                   struct timestamp *time_max)
{
           unsigned char data[20];
           unsigned char command[25];       //room for write data also
           int address=0x497;
           int bytes=11;
 
           if (read_safe(ws2300, address, bytes, data, command) != bytes)
                      read_error_exit();
          
           *rain_max = ((data[5] >> 4) * 1000 + (data[5] & 0xF) * 100 +
                        (data[4] >> 4) * 10 + (data[4] & 0xF) + (data[3]>>4)/10.0 +
                        (data[3] & 0xF) / 100.0) / rain_conv_factor;
          
           time_max->minute = ((data[6] >> 4) * 10) + (data[6] & 0xF);
           time_max->hour = ((data[7] >> 4) * 10) + (data[7] & 0xF);
           time_max->day = ((data[8] >> 4) * 10) + (data[8] & 0xF);
           time_max->month = ((data[9] >> 4) * 10) + (data[9] & 0xF);
           time_max->year = 2000 + ((data[10] >> 4) * 10) + (data[10] & 0xF);
 
           return (((data[2] >> 4) * 1000 + (data[2] & 0xF) * 100 +
                    (data[1] >> 4) * 10 + (data[1] & 0xF) + (data[0] >> 4) / 10.0 +
                    (data[0] & 0xF) / 100.0) / rain_conv_factor);
}
 
 
/********************************************************************/
/* rain_24h_max_reset
 * Reset max rain 24h with timestamps
 *
 * Input: Handle to weatherstation
 *        minmax - char (8 bit integer) that controls if minimum,
 *                 maximum or both are reset
 * Output: None
 *
 * Returns: 1 if success
 *
 ********************************************************************/
int rain_24h_max_reset(WEATHERSTATION ws2300)
{
           unsigned char data_read[20];
           unsigned char data_value[20];
           unsigned char data_time[20];
           unsigned char command[25];       //room for write data also
           int address;
           int number;
 
           // First read current rain 24h into data_value
           address=0x497;
           number=3;
          
           if (read_safe(ws2300, address, number, data_read, command) != number)
                      read_error_exit();
          
           data_value[0] = data_read[0]&0xF;
           data_value[1] = data_read[0]>>4;
           data_value[2] = data_read[1]&0xF;
           data_value[3] = data_read[1]>>4;
           data_value[4] = data_read[2]&0xF;
           data_value[5] = data_read[2]>>4;
          
           // Get current time from station
           address=0x23B;
           number=6;
          
           if (read_safe(ws2300, address, number, data_read, command) != number)
                      read_error_exit();
          
           data_time[0] = data_read[0]&0xF;
           data_time[1] = data_read[0]>>4;
           data_time[2] = data_read[1]&0xF;
           data_time[3] = data_read[1]>>4;
           data_time[4] = data_read[2]>>4;
           data_time[5] = data_read[3]&0xF;
           data_time[6] = data_read[3]>>4;
           data_time[7] = data_read[4]&0xF;
           data_time[8] = data_read[4]>>4;
           data_time[9] = data_read[5]&0xF;
 
           // Set max value to current value
           address=0x49D;
           number=6;
          
           if (write_safe(ws2300, address, number, WRITENIB, data_value, command) != number)
                      write_error_exit();
 
           // Set max value timestamp to current time
           address=0x4A3;
           number=10;
 
           if (write_safe(ws2300, address, number, WRITENIB, data_time, command) != number)
                      write_error_exit();
 
           return 1;
}
 
 
/********************************************************************/
/* rain_24h_reset
 * Reset current rain 24h
 *
 * Input: Handle to weatherstation
 *        minmax - char (8 bit integer) that controls if minimum,
 *                 maximum or both are reset
 * Output: None
 *
 * Returns: 1 if success
 *
 ********************************************************************/
int rain_24h_reset(WEATHERSTATION ws2300)
{
           unsigned char data[50];
           unsigned char command[60];       //room for write data also
           int address;
           int number;
 
           // First overwrite the 24h rain history with zeros
           address=0x446;
           number=48;
           memset(&data, 0, sizeof(data));
          
           if (write_safe(ws2300, address, number, WRITENIB, data, command) != number)
                      write_error_exit();
          
           // Set value to zero
           address=0x497;
           number=6;
          
           if (write_safe(ws2300, address, number, WRITENIB, data, command) != number)
                      write_error_exit();
 
           return 1;
}
 
 
/********************************************************************
 * rain_total
 * Read rain accumulated total, current value only
 *
 * Input: Handle to weatherstation
 *        rain_conv_factor controlling convertion to other
 *             units than mm
 *
 * Returns: rain (double) converted to unit given in config
 *
 ********************************************************************/
double rain_total(WEATHERSTATION ws2300, double rain_conv_factor)
{
           unsigned char data[20];
           unsigned char command[25];       //room for write data also
           int address=0x4D2;
           int bytes=3;
          
           if (read_safe(ws2300, address, bytes, data, command) != bytes)
                      read_error_exit();
 
           return (((data[2] >> 4) * 1000 + (data[2] & 0xF) * 100 +
                    (data[1] >> 4) * 10 + (data[1] & 0xF) +
                    (data[0] >> 4) / 10.0 + (data[0] & 0xF) / 100.0) /
                    rain_conv_factor);
}
 
 
/********************************************************************
 * rain_total_all
 * Read rain total accumulated with timestamp
 *
 * Input: Handle to weatherstation
 *        rain_conv_factor controlling convertion to other
 *             units than mm
 *
 * Output: Timestamp for rain total in pointers to
 *                timestamp structures for time_since
 *
 * Returns: rain (double) converted to unit given in config
 *
 ********************************************************************/
double rain_total_all(WEATHERSTATION ws2300,
                   double rain_conv_factor,
                   struct timestamp *time_since)
{
           unsigned char data[20];
           unsigned char command[25];       //room for write data also
           int address=0x4D2;
           int bytes=8;
 
           if (read_safe(ws2300, address, bytes, data, command) != bytes)
                      read_error_exit();
 
           time_since->minute = ((data[3] >> 4) * 10) + (data[3] & 0xF);
           time_since->hour = ((data[4] >> 4) * 10) + (data[4] & 0xF);
           time_since->day = ((data[5] >> 4) * 10) + (data[5] & 0xF);
           time_since->month = ((data[6] >> 4) * 10) + (data[6] & 0xF);
           time_since->year = 2000 + ((data[7] >> 4) * 10) + (data[7] & 0xF);
 
           return (((data[2] >> 4) * 1000 + (data[2] & 0xF) * 100 +
                    (data[1] >> 4) * 10 + (data[1] & 0xF) +
                    (data[0] >> 4) / 10.0 + (data[0] & 0xF) / 100.0) /
                    rain_conv_factor);
}
 
 
/********************************************************************/
/* rain_total_reset
 * Reset current total rain
 *
 * Input: Handle to weatherstation
 *        minmax - char (8 bit integer) that controls if minimum,
 *                 maximum or both are reset
 * Output: None
 *
 * Returns: 1 if success
 *
 ********************************************************************/
int rain_total_reset(WEATHERSTATION ws2300)
{
           unsigned char data_read[20];
           unsigned char data_value[20];
           unsigned char data_time[20];
           unsigned char command[25];       //room for write data also
           int address;
           int number;
          
           // Get current time from station
           address=0x23B;
           number=6;
          
           if (read_safe(ws2300, address, number, data_read, command) != number)
                      read_error_exit();
                     
           data_time[0] = data_read[0]&0xF;
           data_time[1] = data_read[0]>>4;
           data_time[2] = data_read[1]&0xF;
           data_time[3] = data_read[1]>>4;
           data_time[4] = data_read[2]>>4;
           data_time[5] = data_read[3]&0xF;
           data_time[6] = data_read[3]>>4;
           data_time[7] = data_read[4]&0xF;
           data_time[8] = data_read[4]>>4;
           data_time[9] = data_read[5]&0xF;
 
           // Set value to zero
           address=0x4D1;
           number=7;
           memset(&data_value, 0, sizeof(data_value));
          
           if (write_safe(ws2300, address, number, WRITENIB, data_value, command) != number)
                      write_error_exit();
 
           // Set max value timestamp to current time
           address=0x4D8;
           number=10;
 
           if (write_safe(ws2300, address, number, WRITENIB, data_time, command) != number)
                      write_error_exit();
 
           return 1;
}
 
 
/********************************************************************
 * rel_pressure
 * Read relaive air pressure, current value only
 *
 * Input: Handle to weatherstation
 *        pressure_conv_factor controlling convertion to other
 *             units than hPa
 *
 * Returns: pressure (double) converted to unit given in config
 *
 ********************************************************************/
double rel_pressure(WEATHERSTATION ws2300, double pressure_conv_factor)
{
           unsigned char data[20];
           unsigned char command[25];
           int address=0x5E2;
           int bytes=3;
          
           if (read_safe(ws2300, address, bytes, data, command) != bytes)
                      read_error_exit();
 
 
           return (((data[2] & 0xF) * 1000 + (data[1] >> 4) * 100 +
                    (data[1] & 0xF) * 10 + (data[0] >> 4) +
                    (data[0] & 0xF) / 10.0) / pressure_conv_factor);
}
 
 
/********************************************************************
 * rel_pressure_minmax
 * Read relative pressure min/max with timestamps
 *
 * Input: Handle to weatherstation
 *        pressure_conv_factor controlling convertion to other
 *             units than hPa
 *
 * Output: Pressure pres_min and pres_max (double)
 *                unit defined by config conversion factor
 *         Timestamps for pres_min and pres_max in pointers to
 *                timestamp structures for time_min and time_max
 *
 * Returns: nothing
 *
 ********************************************************************/
void rel_pressure_minmax(WEATHERSTATION ws2300,
                         double pressure_conv_factor,
                         double *pres_min,
                         double *pres_max,
                         struct timestamp *time_min,
                         struct timestamp *time_max)
{
           unsigned char data[20];
           unsigned char command[25];
           int address=0x600;
           int bytes=13;
          
           if (read_safe(ws2300, address, bytes, data, command) != bytes)
                      read_error_exit();
          
           *pres_min = ((data[2]&0xF)*1000 + (data[1]>>4)*100 +
                       (data[1]&0xF)*10 + (data[0]>>4) +
                       (data[0]&0xF)/10.0) / pressure_conv_factor;
          
           *pres_max = ((data[12]&0xF)*1000 + (data[11]>>4)*100 +
                       (data[11]&0xF)*10 + (data[10]>>4) +
                       (data[10]&0xF)/10.0) / pressure_conv_factor;
                     
           address=0x61E; //Relative pressure time and date for min/max
           bytes=10;
          
           if (read_safe(ws2300, address, bytes, data, command)!=bytes)    
                      read_error_exit();
 
           time_min->minute = ((data[0] >> 4) * 10) + (data[0] & 0xF);
           time_min->hour = ((data[1] >> 4) * 10) + (data[1] & 0xF);
           time_min->day = ((data[2] >> 4) * 10) + (data[2] & 0xF);
           time_min->month = ((data[3] >> 4) * 10) + (data[3] & 0xF);
           time_min->year = 2000 + ((data[4] >> 4) * 10) + (data[4] & 0xF);
          
           time_max->minute = ((data[5] >> 4) * 10) + (data[5] & 0xF);
           time_max->hour = ((data[6] >> 4) * 10) + (data[6] & 0xF);
           time_max->day = ((data[7] >> 4) * 10) + (data[7] & 0xF);
           time_max->month = ((data[8] >> 4) * 10) + (data[8] & 0xF);
           time_max->year = 2000 + ((data[9] >> 4) * 10) + (data[9] & 0xF);
          
           return;
}
 
 
/********************************************************************
 * abs_pressure
 * Read absolute air pressure, current value only
 *
 * Input: Handle to weatherstation
 *        pressure_conv_factor controlling convertion to other
 *             units than hPa
 *
 * Returns: pressure (double) converted to unit given in config
 *
 ********************************************************************/
double abs_pressure(WEATHERSTATION ws2300, double pressure_conv_factor)
{
           unsigned char data[20];
           unsigned char command[25];
           int address=0x5D8;
           int bytes=3;
          
           if (read_safe(ws2300, address, bytes, data, command) != bytes)
                      read_error_exit();
 
 
           return (((data[2] & 0xF) * 1000 + (data[1] >> 4) * 100 +
                    (data[1] & 0xF) * 10 + (data[0] >> 4) +
                    (data[0] & 0xF) / 10.0) / pressure_conv_factor);
}
 
 
/********************************************************************
 * abs_pressure_minmax
 * Read absolute pressure min/max with timestamps
 *
 * Input: Handle to weatherstation
 *        pressure_conv_factor controlling convertion to other
 *             units than hPa
 *
 * Output: Pressure pres_min and pres_max (double)
 *                unit defined by config conversion factor
 *         Timestamps for pres_min and pres_max in pointers to
 *                timestamp structures for time_min and time_max
 *
 * Returns: nothing
 *
 ********************************************************************/
void abs_pressure_minmax(WEATHERSTATION ws2300,
                         double pressure_conv_factor,
                         double *pres_min,
                         double *pres_max,
                         struct timestamp *time_min,
                         struct timestamp *time_max)
{
           unsigned char data[20];
           unsigned char command[25];
           int address=0x5F6;
           int bytes=13;
          
           if (read_safe(ws2300, address, bytes, data, command) != bytes)
                      read_error_exit();
          
           *pres_min = ((data[2]&0xF)*1000 + (data[1]>>4)*100 +
                       (data[1]&0xF)*10 + (data[0]>>4) +
                       (data[0]&0xF)/10.0) / pressure_conv_factor;
          
           *pres_max = ((data[12]&0xF)*1000 + (data[11]>>4)*100 +
                       (data[11]&0xF)*10 + (data[10]>>4) +
                       (data[10]&0xF)/10.0) / pressure_conv_factor;
                     
           address=0x61E; //Relative pressure time and date for min/max
           bytes=10;
          
           if (read_safe(ws2300, address, bytes, data, command)!=bytes)    
                      read_error_exit();
 
           time_min->minute = ((data[0] >> 4) * 10) + (data[0] & 0xF);
           time_min->hour = ((data[1] >> 4) * 10) + (data[1] & 0xF);
           time_min->day = ((data[2] >> 4) * 10) + (data[2] & 0xF);
           time_min->month = ((data[3] >> 4) * 10) + (data[3] & 0xF);
           time_min->year = 2000 + ((data[4] >> 4) * 10) + (data[4] & 0xF);
          
           time_max->minute = ((data[5] >> 4) * 10) + (data[5] & 0xF);
           time_max->hour = ((data[6] >> 4) * 10) + (data[6] & 0xF);
           time_max->day = ((data[7] >> 4) * 10) + (data[7] & 0xF);
           time_max->month = ((data[8] >> 4) * 10) + (data[8] & 0xF);
           time_max->year = 2000 + ((data[9] >> 4) * 10) + (data[9] & 0xF);
          
           return;
}
 
 
 
/********************************************************************/
/* pressure_reset
 * Reset min/max pressure (relative and absolute) with timestamps
 *
 * Input: Handle to weatherstation
 *        minmax - char (8 bit integer) that controls if minimum,
 *                 maximum or both are reset
 * Output: None
 *
 * Returns: 1 if success
 *
 ********************************************************************/
int pressure_reset(WEATHERSTATION ws2300, char minmax)
{
           unsigned char data_read[20];
           unsigned char data_value_abs[20];
           unsigned char data_value_rel[20];
           unsigned char data_time[20];
           unsigned char command[25];       //room for write data also
           int address;
           int number;
 
           // First read current abs/rel pressure into data_value_abs/rel
           address=0x5D8;
           number=8;
          
           if (read_safe(ws2300, address, number, data_read, command) != number)
                      read_error_exit();
                     
           data_value_abs[0] = data_read[0]&0xF;
           data_value_abs[1] = data_read[0]>>4;
           data_value_abs[2] = data_read[1]&0xF;
           data_value_abs[3] = data_read[1]>>4;
           data_value_abs[4] = data_read[2]&0xF;
          
           data_value_rel[0] = data_read[5]&0xF;
           data_value_rel[1] = data_read[5]>>4;
           data_value_rel[2] = data_read[6]&0xF;
           data_value_rel[3] = data_read[6]>>4;
           data_value_rel[4] = data_read[7]&0xF;
          
           // Get current time from station
           address=0x23B;
           number=6;
          
           if (read_safe(ws2300, address, number, data_read, command) != number)
                      read_error_exit();
                     
           data_time[0] = data_read[0]&0xF;
           data_time[1] = data_read[0]>>4;
           data_time[2] = data_read[1]&0xF;
           data_time[3] = data_read[1]>>4;
           data_time[4] = data_read[2]>>4;
           data_time[5] = data_read[3]&0xF;
           data_time[6] = data_read[3]>>4;
           data_time[7] = data_read[4]&0xF;
           data_time[8] = data_read[4]>>4;
           data_time[9] = data_read[5]&0xF;
 
           if (minmax & RESET_MIN) // minimum
           {
                      // Set min abs value to current abs value
                      address=0x5F6;
                      number=5;
                     
                      if (write_safe(ws2300, address, number, WRITENIB, data_value_abs, command) != number)
                                 write_error_exit();
                                
                      // Set min rel value to current rel value
                      address=0x600;
                      number=5;
                     
                      if (write_safe(ws2300, address, number, WRITENIB, data_value_rel, command) != number)
                                 write_error_exit();
 
                      // Set min value timestamp to current time
                      address=0x61E;
                      number=10;
 
                      if (write_safe(ws2300, address, number, WRITENIB, data_time, command) != number)
                                 write_error_exit();
           }
          
           if (minmax & RESET_MAX) // maximum
           {
                      // Set max abs value to current abs value
                      address=0x60A;
                      number=5;
                     
                      if (write_safe(ws2300, address, number, WRITENIB, data_value_abs, command) != number)
                                 write_error_exit();
                                
                      // Set max rel value to current rel value
                      address=0x614;
                      number=5;
                     
                      if (write_safe(ws2300, address, number, WRITENIB, data_value_rel, command) != number)
                                 write_error_exit();
 
                      // Set max value timestamp to current time
                      address=0x628;
                      number=10;
 
                      if (write_safe(ws2300, address, number, WRITENIB, data_time, command) != number)
                                 write_error_exit();             
           }
 
           return 1;
}
 
 
/********************************************************************
 * pressure_correction
 * Read the correction from absolute to relaive air pressure
 *
 * Input: Handle to weatherstation
 *        pressure_conv_factor controlling convertion to other
 *             units than hPa
 *
 * Returns: pressure (double) converted to unit given in conv factor
 *
 ********************************************************************/
double pressure_correction(WEATHERSTATION ws2300, double pressure_conv_factor)
{
           unsigned char data[20];
           unsigned char command[25];
           int address=0x5EC;
           int bytes=3;
          
           if (read_safe(ws2300, address, bytes, data, command) != bytes)
                      read_error_exit();
 
 
           return ((data[2] & 0xF) * 1000 +
                   (data[1] >> 4) * 100 +
                   (data[1] & 0xF) * 10 +
                   (data[0] >> 4) +
                   (data[0] & 0xF) / 10.0 -
                   1000
                  ) / pressure_conv_factor;
}
 
 
/********************************************************************
 * tendency_forecast
 * Read Tendency and Forecast
 *
 * Input: Handle to weatherstation
 *
 * Output: tendency - string Steady, Rising or Falling
 *         forecast - string Rainy, Cloudy or Sunny
 *
 * Returns: nothing
 *
 ********************************************************************/
void tendency_forecast(WEATHERSTATION ws2300, char *tendency, char *forecast)
{
           unsigned char data[20];
           unsigned char command[25];
           int address=0x26B;
           int bytes=1;
           const char *tendency_values[] = { "Steady", "Rising", "Falling" };
           const char *forecast_values[] = { "Rainy", "Cloudy", "Sunny" };
 
           if (read_safe(ws2300, address, bytes, data, command) != bytes)
               read_error_exit();
 
           strcpy(tendency, tendency_values[data[0] >> 4]);
           strcpy(forecast, forecast_values[data[0] & 0xF]);
 
           return;
}
 
 
/********************************************************************
 * read_history_info
 * Read the history information like interval, countdown, time
 * of last record, pointer to last record.
 *
 * Input:  Handle to weatherstation
 *       
 * Output: interval - Current interval in minutes (integer)
 *         countdown - Countdown to next measurement (integer)
 *         timelast - Time/Date for last measurement (timestamp struct)
 *         no_records - number of valid records (integer)
 *
 * Returns: interger pointing to last written record. [0x00-0xAE]
 *
 ********************************************************************/
int read_history_info(WEATHERSTATION ws2300, int *interval, int *countdown,
                 struct timestamp *time_last, int *no_records)
{
           unsigned char data[20];
           unsigned char command[25];
           int address=0x6B2;
           int bytes=10;
 
           if (read_safe(ws2300, address, bytes, data, command) != bytes)
               read_error_exit();
          
           *interval = (data[1] & 0xF)*256 + data[0] + 1;
           *countdown = data[2]*16 + (data[1] >> 4) + 1;
           time_last->minute = ((data[3] >> 4) * 10) + (data[3] & 0xF);
           time_last->hour = ((data[4] >> 4) * 10) + (data[4] & 0xF);
           time_last->day = ((data[5] >> 4) * 10) + (data[5] & 0xF);
           time_last->month = ((data[6] >> 4) * 10) + (data[6] & 0xF);
           time_last->year = 2000 + ((data[7] >> 4) * 10) + (data[7] & 0xF);
           *no_records = data[9];
 
           return data[8];
 
}
 
 
/********************************************************************
 * read_history_record
 * Read the history information like interval, countdown, time
 * of last record, pointer to last record.
 *
 * Input:  Handle to weatherstation
 *         config structure with conversion factors
 *         record - record index number to be read [0x00-0xAE]
 *       
 * Output: temperature_indoor (double)
 *         temperature_indoor (double)
 *         pressure (double)
 *         humidity_indoor (integer)
 *         humidity_outdoor (integer)
 *         raincount (double)
 *         windspeed (double)
 *         windir_degrees (double)
 *         dewpoint (double) - calculated
 *         windchill (double) - calculated, new post 2001 formula
 *
 * Returns: interger index number pointing to next record
 *
 ********************************************************************/
int read_history_record(WEATHERSTATION ws2300,
                        int record,
                        struct config_type *config,
                        double *temperature_indoor,
                        double *temperature_outdoor,
                        double *pressure,
                        int *humidity_indoor,
                        int *humidity_outdoor,
                        double *raincount,
                        double *windspeed,
                        double *winddir_degrees,
                        double *dewpoint,
                        double *windchill)
{
           unsigned char data[20];
           unsigned char command[25];
           int address;
           int bytes=10;
           long int tempint;
           double A, B, C; // Intermediate values used for dewpoint calculation
           double wind_kmph;
 
           address = 0x6C6 + record*19;
 
           if (read_safe(ws2300, address, bytes, data, command) != bytes)
               read_error_exit();
          
           tempint = (data[4]<<12) + (data[3]<<4) + (data[2] >> 4);
          
           *pressure = 1000 + (tempint % 10000)/10.0;
          
           if (*pressure >= 1502.2)
                      *pressure = *pressure - 1000;
                     
           *pressure = *pressure / config->pressure_conv_factor;
          
           *humidity_indoor = (tempint - (tempint % 10000)) / 10000.0;
 
           *humidity_outdoor = (data[5]>>4)*10 + (data[5]&0xF);
          
           *raincount = ((data[7]&0xF)*256 + data[6]) * 0.518 / config->rain_conv_factor;
          
           *windspeed = (data[8]*16 + (data[7]>>4))/ 10.0; //Need metric for WC
          
           *winddir_degrees = (data[9]&0xF)*22.5;
          
           // Temperatures       in Celcius. Cannot convert until WC is calculated
           tempint = ((data[2] & 0xF)<<16) + (data[1]<<8) + data[0];
           *temperature_indoor = (tempint % 1000)/10.0 - 30.0;
           *temperature_outdoor = (tempint - (tempint % 1000))/10000.0 - 30.0;
          
           // Calculate windchill using new post 2001 USA/Canadian formula
           // Twc = 13.112 + 0.6215*Ta -11.37*V^0.16 + 0.3965*Ta*V^0.16 [Celcius and km/h]
          
           wind_kmph = 3.6 * *windspeed;
           if (wind_kmph > 4.8)
           {
                      *windchill = 13.112 + 0.6215 * *temperature_outdoor -
                                   11.37 * pow(wind_kmph, 0.16) +
                                   0.3965 * *temperature_outdoor * pow(wind_kmph, 0.16);
           }
           else
           {
                      *windchill = *temperature_outdoor;
           }
          
           // Calculate dewpoint
           // REF http://www.faqs.org/faqs/meteorology/temp-dewpoint/             
           A = 17.2694;
           B = (*temperature_outdoor > 0) ? 237.3 : 265.5;
           C = (A * *temperature_outdoor)/(B + *temperature_outdoor) + log((double)*humidity_outdoor/100);
           *dewpoint = B * C / (A - C);
 
           // Now that WC/DP is calculated we can convert all temperatures and winds
           if (config->temperature_conv)
           {
                      *temperature_indoor = *temperature_indoor * 9/5 + 32;
                      *temperature_outdoor = *temperature_outdoor * 9/5 + 32;
                      *windchill = *windchill * 9/5 + 32;
                      *dewpoint = *dewpoint * 9/5 + 32;
           }
          
           *windspeed *= config->wind_speed_conv_factor;
          
           return (++record)%0xAF;
}
 
 
/********************************************************************
 * light
 * Turns display light on and off
 *
 * Input: control - integer -   0 = off, Anything else = on
 *
 * Returns: Nothing
 *
 ********************************************************************/
void light(WEATHERSTATION ws2300, int control)
{
           unsigned char data;
           unsigned char command[25];  //Data returned is just ignored
           int address=0x016;
           int number=1;
           unsigned char encode_constant;
          
           data = 0;
           encode_constant = UNSETBIT;
           if (control != 0)
                      encode_constant = SETBIT;
                     
           if (write_safe(ws2300, address, number, encode_constant, &data, command)!=number)
                      write_error_exit();
          
           return;   
}
 
 
/********************************************************************
 * read_error_exit
 * exit location for all calls to read_safe for error exit.
 * includes error reporting.
 *
 ********************************************************************/
void read_error_exit(void)
{
           perror("read_safe() error");
           exit(EXIT_FAILURE);
}
 
/********************************************************************
 * write_error_exit
 * exit location for all calls to write_safe for error exit.
 * includes error reporting.
 *
 ********************************************************************/
void write_error_exit(void)
{
           perror("write_safe() error");
           exit(EXIT_FAILURE);
}
 
 
/********************************************************************
 * get_configuration()
 *
 * read setup parameters from ws2300.conf
 * It searches in this sequence:
 * 1. Path to config file including filename given as parameter
 * 2. ./open2300.conf
 * 3. /usr/local/etc/open2300.conf
 * 4. /etc/open2300.conf
 *
 * See file open2300.conf-dist for the format and option names/values
 *
 * input:    config file name with full path - pointer to string
 *
 * output:   struct config populated with valid settings either
 *           from config file or defaults
 *
 * returns:  0 = OK
 *          -1 = no config file or file open error
 *
 ********************************************************************/
int get_configuration(struct config_type *config, char *path)
{
           FILE *fptr;
           char inputline[1000] = "";
           char token[100] = "";
           char val[100] = "";
           char val2[100] = "";
          
           // First we set everything to defaults - faster than many if statements
           strcpy(config->serial_device_name, DEFAULT_SERIAL_DEVICE);  // Name of serial device
           strcpy(config->citizen_weather_id, "CW0000");               // Citizen Weather ID
           strcpy(config->citizen_weather_latitude, "5540.12N");       // latitude default Glostrup, DK
           strcpy(config->citizen_weather_longitude, "01224.60E");     // longitude default, Glostrup, DK
           strcpy(config->aprs_host[0].name, "rotate.aprs.net");       // host1 name
           config->aprs_host[0].port = 14580;                          // host1 port
           strcpy(config->aprs_host[1].name, "first.aprs.net");        // host2 name
           config->aprs_host[1].port = 14580;                          // host2 port
           strcpy(config->aprs_host[2].name, "second.aprs.net");       // host2 name
           config->aprs_host[2].port = 14580;                          // host2 port
           config->num_hosts = 0;                                      // will not count yet
           strcpy(config->weather_underground_id, "WUID");             // Weather Underground ID
           strcpy(config->weather_underground_password, "WUPassword"); // Weather Underground Password
           strcpy(config->timezone, "1");                              // Timezone, default CET
           config->wind_speed_conv_factor = 1.0;                   // Speed dimention, m/s is default
           config->temperature_conv = 0;                           // Temperature in Celcius
           config->rain_conv_factor = 1.0;                         // Rain in mm
           config->pressure_conv_factor = 1.0;                     // Pressure in hPa (same as millibar)
           strcpy(config->mysql_host, "localhost");            // localhost, IP or domainname of server
           strcpy(config->mysql_user, "open2300");             // MySQL database user name
           strcpy(config->mysql_passwd, "mysql2300");          // Password for MySQL database user
           strcpy(config->mysql_database, "open2300");         // Name of MySQL database
           config->mysql_port = 0;                             // MySQL port. 0 means default port/socket
           strcpy(config->pgsql_connect, "hostaddr='127.0.0.1'dbname='open2300'user='postgres'"); // connection string
           strcpy(config->pgsql_table, "weather");             // PgSQL table name
           strcpy(config->pgsql_station, "open2300");          // Unique station id
 
           // open the config file
 
           fptr = NULL;
           if (path != NULL)
                      fptr = fopen(path, "r");       //first try the parameter given
           if (fptr == NULL)                  //then try default search
           {
                      if ((fptr = fopen("open2300.conf", "r")) == NULL)
                      {
                                 if ((fptr = fopen("/usr/local/etc/open2300.conf", "r")) == NULL)
                                 {
                                            if ((fptr = fopen("/etc/open2300.conf", "r")) == NULL)
                                            {
                                                      //Give up and use defaults
                                                      return(-1);
                                            }
                                 }
                      }
           }
 
           while (fscanf(fptr, "%[^\n]\n", inputline) != EOF)
           {
                      sscanf(inputline, "%[^= \t]%*[ \t=]%s%*[, \t]%s%*[^\n]", token, val, val2);
 
                      if (token[0] == '#')  // comment
                                 continue;
 
                      if ((strcmp(token,"SERIAL_DEVICE")==0) && (strlen(val) != 0))
                      {
                                 strcpy(config->serial_device_name,val);
                                 continue;
                      }
 
                      if ((strcmp(token,"CITIZEN_WEATHER_ID")==0) && (strlen(val) != 0))
                      {
                                 strcpy(config->citizen_weather_id, val);
                                 continue;
                      }
                     
                      if ((strcmp(token,"CITIZEN_WEATHER_LATITUDE")==0) && (strlen(val)!=0))
                      {
                                 strcpy(config->citizen_weather_latitude, val);
                                 continue;
                      }
 
                      if ((strcmp(token,"CITIZEN_WEATHER_LONGITUDE")==0) && (strlen(val)!=0))
                      {
                                 strcpy(config->citizen_weather_longitude, val);
                                 continue;
                      }
                     
                      if ((strcmp(token,"APRS_SERVER")==0) && (strlen(val)!=0) && (strlen(val2)!=0))
                      {
                                 if ( config->num_hosts >= MAX_APRS_HOSTS)
                                            continue;           // ignore host definitions over the defined max
                                 strcpy(config->aprs_host[config->num_hosts].name, val);
                                 config->aprs_host[config->num_hosts].port = atoi(val2);
                                 config->num_hosts++;    // increment for next
                                 continue;
                      }
 
                      if ((strcmp(token,"WEATHER_UNDERGROUND_ID")==0) && (strlen(val)!=0))
                      {
                                 strcpy(config->weather_underground_id, val);
                                 continue;
                      }
 
                      if ((strcmp(token,"WEATHER_UNDERGROUND_PASSWORD")==0)&&(strlen(val)!=0))
                      {
                                 strcpy(config->weather_underground_password, val);
                                 continue;
                      }
 
                      if ((strcmp(token,"TIMEZONE")==0) && (strlen(val) != 0))
                      {
                                 strcpy(config->timezone, val);
                                 continue;
                      }
 
                      if ((strcmp(token,"WIND_SPEED") == 0) && (strlen(val) != 0))
                      {
                                 if (strcmp(val, "m/s") == 0)
                                            config->wind_speed_conv_factor = METERS_PER_SECOND;
                                 else if (strcmp(val, "km/h") == 0)
                                            config->wind_speed_conv_factor = KILOMETERS_PER_HOUR;
                                 else if (strcmp(val, "MPH") == 0)
                                            config->wind_speed_conv_factor = MILES_PER_HOUR;
                                 continue; //else default remains
                      }
 
                      if ((strcmp(token,"TEMPERATURE") == 0) && (strlen(val) != 0))
                      {
                                 if (strcmp(val, "C") == 0)
                                            config->temperature_conv = CELCIUS;
                                 else if (strcmp(val, "F") == 0)
                                            config->temperature_conv = FAHRENHEIT;
                                 continue; //else default remains
                      }
 
                      if ((strcmp(token,"RAIN") == 0) && (strlen(val) != 0))
                      {
                                 if (strcmp(val, "mm") == 0)
                                            config->rain_conv_factor = MILLIMETERS;
                                 else if (strcmp(val, "IN") == 0)
                                            config->rain_conv_factor = INCHES;
                                 continue; //else default remains
                      }
 
                      if ((strcmp(token,"PRESSURE") == 0) && (strlen(val) != 0))
                      {
                                 if ( (strcmp(val, "hPa") == 0) || (strcmp(val, "mb") == 0))
                                            config->pressure_conv_factor = HECTOPASCAL;
                                 else if (strcmp(val, "INHG") == 0)
                                            config->pressure_conv_factor = INCHES_HG;
                                 continue; //else default remains
                      }
 
                      if ((strcmp(token,"MYSQL_HOST") == 0) && (strlen(val) != 0))
                      {
                                 strcpy(config->mysql_host, val);
                                 continue;
                      }
 
                      if ( (strcmp(token,"MYSQL_USERNAME") == 0) && (strlen(val) != 0) )
                      {
                                 strcpy(config->mysql_user, val);
                                 continue;
                      }
 
                      if ( (strcmp(token,"MYSQL_PASSWORD") == 0) && (strlen(val) != 0) )
                      {
                                 strcpy(config->mysql_passwd, val);
                                 continue;
                      }
 
                      if ( (strcmp(token,"MYSQL_DATABASE") == 0) && (strlen(val) != 0) )
                      {
                                 strcpy(config->mysql_database, val);
                                 continue;
                      }
                     
                      if ( (strcmp(token,"MYSQL_PORT") == 0) && (strlen(val) != 0) )
                      {
                                 config->mysql_port = atoi(val);
                                 continue;
                      }
 
                      if ( (strcmp(token,"PGSQL_CONNECT") == 0) && (strlen(val) != 0) )
                      {
                                 strcpy(config->pgsql_connect, val);
                                 continue;
                      }
                     
                      if ( (strcmp(token,"PGSQL_TABLE") == 0) && (strlen(val) != 0) )
                      {
                                 strcpy(config->pgsql_table, val);
                                 continue;
                      }
                     
                      if ( (strcmp(token,"PGSQL_STATION") == 0) && (strlen(val) != 0) )
                      {
                                 strcpy(config->pgsql_station, val);
                                 continue;
                      }
                     
           }
          
           // Expose the default host names if no configuration file was found or
           // one was supplied but it didn't contain any APRS_SERVER entries.
           if (0 == config->num_hosts) {
                      config->num_hosts = 3;
           }
 
           return (0);
}
 
 
 /********************************************************************
 * address_encoder converts an 16 bit address to the form needed
 * by the WS-2300 when sending commands.
 *
 * Input:   address_in (interger - 16 bit)
 *
 * Output:  address_out - Pointer to an unsigned character array.
 *          3 bytes, not zero terminated.
 *
 * Returns: Nothing.
 *
 ********************************************************************/
void address_encoder(int address_in, unsigned char *address_out)
{
           int i = 0;
           int adrbytes = 4;
           unsigned char nibble;
 
           for (i = 0; i < adrbytes; i++)
           {
                      nibble = (address_in >> (4 * (3 - i))) & 0x0F;
                      address_out[i] = (unsigned char) (0x82 + (nibble * 4));
           }
 
           return;
}
 
 
/********************************************************************
 * data_encoder converts up to 15 data bytes to the form needed
 * by the WS-2300 when sending write commands.
 *
 * Input:   number - number of databytes (integer)
 *          encode_constant - unsigned char
 *                            0x12=set bit, 0x32=unset bit, 0x42=write nibble
 *          data_in - char array with up to 15 hex values
 *
 * Output:  address_out - Pointer to an unsigned character array.
 *
 * Returns: Nothing.
 *
 ********************************************************************/
void data_encoder(int number, unsigned char encode_constant,
                  unsigned char *data_in, unsigned char *data_out)
{
           int i = 0;
 
           for (i = 0; i < number; i++)
           {
                      data_out[i] = (unsigned char) (encode_constant + (data_in[i] * 4));
           }
 
           return;
}
 
 
/********************************************************************
 * numberof_encoder converts the number of bytes we want to read
 * to the form needed by the WS-2300 when sending commands.
 *
 * Input:   number interger, max value 15
 *
 * Returns: unsigned char which is the coded number of bytes
 *
 ********************************************************************/
unsigned char numberof_encoder(int number)
{
           int coded_number;
 
           coded_number = (unsigned char) (0xC2 + number * 4);
           if (coded_number > 0xfe)
                      coded_number = 0xfe;
 
           return coded_number;
}
 
 
/********************************************************************
 * command_check0123 calculates the checksum for the first 4
 * commands sent to WS2300.
 *
 * Input:   pointer to char to check
 *          sequence of command - i.e. 0, 1, 2 or 3.
 *
 * Returns: calculated checksum as unsigned char
 *
 ********************************************************************/
unsigned char command_check0123(unsigned char *command, int sequence)
{
           int response;
 
           response = sequence * 16 + ((*command) - 0x82) / 4;
 
           return (unsigned char) response;
}
 
 
/********************************************************************
 * command_check4 calculates the checksum for the last command
 * which is sent just before data is received from WS2300
 *
 * Input: number of bytes requested
 *
 * Returns: expected response from requesting number of bytes
 *
 ********************************************************************/
unsigned char command_check4(int number)
{
           int response;
 
           response = 0x30 + number;
 
           return response;
}
 
 
/********************************************************************
 * data_checksum calculates the checksum for the data bytes received
 * from the WS2300
 *
 * Input:   pointer to array of data to check
 *          number of bytes in array
 *
 * Returns: calculated checksum as unsigned char
 *
 ********************************************************************/
unsigned char data_checksum(unsigned char *data, int number)
{
           int checksum = 0;
           int i;
 
           for (i = 0; i < number; i++)
           {
                      checksum += data[i];
           }
 
           checksum &= 0xFF;
 
           return (unsigned char) checksum;
}
 
 
/********************************************************************
 * initialize resets WS2300 to cold start (rewind and start over)
 *
 * Input:   device number of the already open serial port
 *          
 * Returns: 0 if fail, 1 if success
 *
 ********************************************************************/
int initialize(WEATHERSTATION ws2300)
{
           unsigned char command = 0x06;
           unsigned char answer;
 
           write_device(ws2300, &command, 1);
 
           if (read_device(ws2300, &answer, 1) != 1)
                      return 0;
 
           write_device(ws2300, &command, 1);
           write_device(ws2300, &command, 1);
 
           if (read_device(ws2300, &answer, 1) != 1)
                      return 0;
 
           write_device(ws2300, &command, 1);
 
           if (read_device(ws2300, &answer, 1) != 1)
                      return 0;
 
           write_device(ws2300, &command, 1);
 
           if (read_device(ws2300, &answer, 1) != 1)
                      return 0;
 
           if (answer != 2)
                      return 0;
 
           return 1;
}
 
 
/********************************************************************
 * read_data reads data from the WS2300 based on a given address,
 * number of data read, and a an already open serial port
 *
 * Inputs:  serdevice - device number of the already open serial port
 *          address (interger - 16 bit)
 *          number - number of bytes to read, max value 15
 *
 * Output:  readdata - pointer to an array of chars containing
 *                     the just read data, not zero terminated
 *          commanddata - pointer to an array of chars containing
 *                     the commands that were sent to the station
 *
 * Returns: number of bytes read, -1 if failed
 *
 ********************************************************************/
int read_data(WEATHERSTATION ws2300, int address, int number,
                                   unsigned char *readdata, unsigned char *commanddata)
{
 
           unsigned char answer;
           int i;
 
           // First 4 bytes are populated with converted address range 0000-13B0
           address_encoder(address, commanddata);
           // Last populate the 5th byte with the converted number of bytes
           commanddata[4] = numberof_encoder(number);
 
           for (i = 0; i < 4; i++)
           {
                      usleep( 10000 );
                      if (write_device(ws2300, commanddata + i, 1) != 1)
                                 return -1;
                      usleep( 10000 );
                      if (read_device(ws2300, &answer, 1) != 1)
                                 return -1;
                      usleep( 10000 );
                      if (answer != command_check0123(commanddata + i, i))
                                 return -1;
           }
 
           //Send the final command that asks for 'number' of bytes, check answer
           usleep( 10000 );
           if (write_device(ws2300, commanddata + 4, 1) != 1)
                      return -1;
           usleep( 10000 );
           if (read_device(ws2300, &answer, 1) != 1)
                      return -1;
           usleep( 10000 );
           if (answer != command_check4(number))
                      return -1;
 
           //Read the data bytes
           for (i = 0; i < number; i++)
           {
                      usleep( 10000 );
                      if (read_device(ws2300, readdata + i, 1) != 1)
                                 return -1;
           }
 
           //Read and verify checksum
           usleep( 10000 );
           if (read_device(ws2300, &answer, 1) != 1)
                      return -1;
           usleep( 10000 );
           if (answer != data_checksum(readdata, number))
                      return -1;
                     
           return i;
 
}
 
 
/********************************************************************
 * write_data writes data to the WS2300.
 * It can both write nibbles and set/unset bits
 *
 * Inputs:      ws2300 - device number of the already open serial port
 *              address (interger - 16 bit)
 *              number - number of nibbles to be written/changed
 *                       must 1 for bit modes (SETBIT and UNSETBIT)
 *                       max 80 for nibble mode (WRITENIB)
 *              encode_constant - unsigned char
 *                                (SETBIT, UNSETBIT or WRITENIB)
 *              writedata - pointer to an array of chars containing
 *                          data to write, not zero terminated
 *                          data must be in hex - one digit per byte
 *                          If bit mode value must be 0-3 and only
 *                          the first byte can be used.
 *
 * Output:      commanddata - pointer to an array of chars containing
 *                            the commands that were sent to the station
 *
 * Returns:     number of bytes written, -1 if failed
 *
 ********************************************************************/
int write_data(WEATHERSTATION ws2300, int address, int number,
                                    unsigned char encode_constant, unsigned char *writedata,
                                    unsigned char *commanddata)
{
           unsigned char answer;
           unsigned char encoded_data[80];
           int i = 0;
           unsigned char ack_constant = WRITEACK;
          
           if (encode_constant == SETBIT)
           {
                      ack_constant = SETACK;
           }
           else if (encode_constant == UNSETBIT)
           {
                      ack_constant = UNSETACK;
           }
 
           // First 4 bytes are populated with converted address range 0000-13XX
           address_encoder(address, commanddata);
           // populate the encoded_data array
           data_encoder(number, encode_constant, writedata, encoded_data);
 
           //Write the 4 address bytes
           for (i = 0; i < 4; i++)
           {
                      usleep( 10000 );
                      if (write_device(ws2300, commanddata + i, 1) != 1)
                                 return -1;
                      usleep( 10000 );
                      if (read_device(ws2300, &answer, 1) != 1)
                                 return -1;
                      usleep( 10000 );
                      if (answer != command_check0123(commanddata + i, i))
                                 return -1;
           }
 
           //Write the data nibbles or set/unset the bits
           for (i = 0; i < number; i++)
           {
                      usleep( 10000 );
                      if (write_device(ws2300, encoded_data + i, 1) != 1)
                                 return -1;
                      usleep( 10000 );
                      if (read_device(ws2300, &answer, 1) != 1)
                                 return -1;
                      usleep( 10000 );
                      if (answer != (writedata[i] + ack_constant))
                                 return -1;
                      commanddata[i + 4] = encoded_data[i];
           }
 
           return i;
}
 
 
/********************************************************************
 * read_safe Read data, retry until success or maxretries
 * Reads data from the WS2300 based on a given address,
 * number of data read, and a an already open serial port
 * Uses the read_data function and has same interface
 *
 * Inputs:  ws2300 - device number of the already open serial port
 *          address (interger - 16 bit)
 *          number - number of bytes to read, max value 15
 *
 * Output:  readdata - pointer to an array of chars containing
 *                     the just read data, not zero terminated
 *          commanddata - pointer to an array of chars containing
 *                     the commands that were sent to the station
 *
 * Returns: number of bytes read, -1 if failed
 *
 ********************************************************************/
int read_safe(WEATHERSTATION ws2300, int address, int number,
                                   unsigned char *readdata, unsigned char *commanddata)
{
           int j;
 
           for (j = 0; j < MAXRETRIES; j++)
           {
                      reset_06(ws2300);
                     
                      // Read the data. If expected number of bytes read break out of loop.
                      if (read_data(ws2300, address, number, readdata, commanddata)==number)
                      {
                                 break;
                      }
           }
 
           // If we have tried MAXRETRIES times to read we expect not to
           // have valid data
           if (j == MAXRETRIES)
           {
                      return -1;
           }
 
           return number;
}
 
 
/********************************************************************
 * write_safe Write data, retry until success or maxretries
 * Writes data to the WS2300 based on a given address,
 * number of data to write, and a an already open serial port
 * Uses the write_data function and has same interface
 *
 * Inputs:      serdevice - device number of the already open serial port
 *              address (interger - 16 bit)
 *              number - number of nibbles to be written/changed
 *                       must 1 for bit modes (SETBIT and UNSETBIT)
 *                       unlimited for nibble mode (WRITENIB)
 *              encode_constant - unsigned char
 *                               (SETBIT, UNSETBIT or WRITENIB)
 *              writedata - pointer to an array of chars containing
 *                          data to write, not zero terminated
 *                          data must be in hex - one digit per byte
 *                          If bit mode value must be 0-3 and only
 *                          the first byte can be used.
 *
 * Output:      commanddata - pointer to an array of chars containing
 *                            the commands that were sent to the station
 *
 * Returns: number of bytes written, -1 if failed
 *
 ********************************************************************/
int write_safe(WEATHERSTATION ws2300, int address, int number,
               unsigned char encode_constant, unsigned char *writedata,
               unsigned char *commanddata)
{
           int j;
 
           for (j = 0; j < MAXRETRIES; j++)
           {
                      // printf("Iteration = %d\n",j); // debug
                      reset_06(ws2300);
 
                      // Read the data. If expected number of bytes read break out of loop.
                      if (write_data(ws2300, address, number, encode_constant, writedata,
                          commanddata)==number)
                      {
                                 break;
                      }
           }
 
           // If we have tried MAXRETRIES times to read we expect not to
           // have valid data
           if (j == MAXRETRIES)
           {
                      return -1;
           }
 
           return number;
}

Environment

Open2300 version: 1.10
Shared libraries: mysql, postgresql
Server OS: OpenSuse 13.2
-- TomasJensen - 04 Feb 2015

Follow up

Fix record

BugReportForm edit

TopicTitle Yet one more fix reading and writing via USB->Serial on fast machines
BugStatus New
AssignedBugTo
SubmittedBy WikiGuest
Topic revision: r1 - 04 Feb 2015, TomasJensen
Copyright © 1999-2024 by the contributing authors. All material on this collaboration platform is the property of the contributing authors.
This website only use harmless session cookies. See Cookie Policy for details. By using this website you accept the use of these cookies.