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