From 2e82359fa5bf7c34e9cbb3436fe9da0289710399 Mon Sep 17 00:00:00 2001 From: Sebastian Reichel Date: Sun, 26 Feb 2012 19:25:42 +0100 Subject: initial code import --- Makefile | 31 ++++++ demo.vala | 46 ++++++++ libweatherstation.vapi | 291 +++++++++++++++++++++++++++++++++++++++++++++++++ weatherstation.c | 152 ++++++++++++++++++++++++++ weatherstation.h | 257 +++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 777 insertions(+) create mode 100644 Makefile create mode 100644 demo.vala create mode 100644 libweatherstation.vapi create mode 100644 weatherstation.c create mode 100644 weatherstation.h diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..aee11ca --- /dev/null +++ b/Makefile @@ -0,0 +1,31 @@ +VALAC?=valac +SOURCES:=$(wildcard *.c) +OBJECTS:=$(patsubst %.c, %.o, $(SOURCES)) +CFLAGS+=`pkg-config --cflags libusb` +LIBS+=`pkg-config --libs libusb` +NAME:=libweatherstation.so +SONAME=$(NAME).0 +LONGNAME=$(NAME).0.0 + +all: library demo + +library: $(LONGNAME) + @ln -sf $(LONGNAME) $(SONAME) + @ln -sf $(SONAME) $(NAME) + +%.o: %.c + @echo "[CC] $<" + @$(CC) $(CFLAGS) -c -std=c99 -fPIC -o $@ $< + +$(LONGNAME): $(OBJECTS) + @echo "[LD] $^" + @$(CC) -shared -Wl,-soname,$(SONAME) -o $@ $(LIBS) $^ + +demo: demo.vala + @echo "[VALAC] $^" + @$(VALAC) --vapidir=. --Xcc=-I. --Xcc=-L. --Xcc=-lweatherstation --pkg posix --pkg libweatherstation $^ + +clean: + rm -f $(OBJECTS) $(LONGNAME) $(SONAME) $(NAME) demo + +.PHONY: all library clean diff --git a/demo.vala b/demo.vala new file mode 100644 index 0000000..0262edb --- /dev/null +++ b/demo.vala @@ -0,0 +1,46 @@ +/* demo.vala + * Copyright (c) 2012, Sebastian Reichel + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +public static int main(string[] args) { + var station = new Weather.Station(); + + if(station == null) { + stderr.printf("weather station not found!\n"); + return 1; + } + + var header = station.read_header(); + var data = station.read_data(header.history_data_stack); + + /* print some infos from the header */ + stdout.printf("interval: %d\n", header.sampling_interval); + stdout.printf("stack addr: 0x%04x\n", header.history_data_stack); + stdout.printf("stack size: %d\n\n", header.history_data_sets); + + /* print content of the current data set */ + stdout.printf("Valid: %s\n", (data.status & Weather.Status.INVALID_DATA) == 0 ? "yes" : "no"); + stdout.printf("Temperature Indoor: %.1f°C\n", data.temperature_indoor/10.0); + stdout.printf("Humidity Indoor: %d%%\n", data.humidity_indoor); + stdout.printf("Temperature Outdoor: %.1f°C\n", data.temperature_outdoor/10.0); + stdout.printf("Humidity Outdoor: %d%%\n", data.humidity_outdoor); + stdout.printf("Pressure: %.1f hPa\n", data.pressure/10.0); + stdout.printf("Wind Direction: %s\n", data.wind_direction.to_string()); + stdout.printf("Wind Speed: %.1f m/s\n", data.avg_wind_speed/10.0); + stdout.printf("Wind Gust: %.1f m/s\n", data.gust_wind_speed/10.0); + stdout.printf("Total Rain: %.1f mm\n", data.rain*0.3); + + return 0; +} diff --git a/libweatherstation.vapi b/libweatherstation.vapi new file mode 100644 index 0000000..e509ae1 --- /dev/null +++ b/libweatherstation.vapi @@ -0,0 +1,291 @@ +/* libweatherstation.vapi + * Copyright (c) 2012, Sebastian Reichel + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +[CCode (cprefix = "weather_", cheader_filename = "weatherstation.h")] +namespace Weather { + [CCode (cname = "enum weather_wind_direction", cprefix = "")] + public enum WindDirection { + NORTH, + NORTH_EAST_NORTH, + NORTH_EAST, + EAST_NORTH_EAST, + EAST, + EAST_SOUTH_EAST, + SOUTH_EAST, + SOUTH_EAST_SOUTH, + SOUTH, + SOUTH_WEST_SOUTH, + SOUTH_WEST, + WEST_SOUTH_WEST, + WEST, + WEST_NORTH_WEST, + NORTH_WEST, + NORTH_WEST_NORTH; + + [CCode (cname = "weather_wind_direction_to_string")] + public unowned string to_string(); + } + + [Flag] + [CCode (cname = "enum weather_flag_status", cprefix = "WEATHER_STATUS_")] + public enum Status { + INVALID_DATA, + RAIN_OVERFLOW; + } + + [CCode (cname = "struct weather_data")] + public struct Data { + uint8 sample_time; + uint8 humidity_indoor; + uint16 temperature_indoor; + uint8 humidity_outdoor; + uint16 temperature_outdoor; + uint16 pressure; + uint8 avg_wind_speed; + uint8 gust_wind_speed; + uint8 high_nibble_wind_speed; + [CCode (ctype = "uint8_t")] + WindDirection wind_direction; + uint16 rain; + [CCode (ctype = "uint8_t")] + Status status; + } + + [Flag] + [CCode (cname = "enum weather_flag_unit_setting1", cprefix = "WEATHER_UNIT_")] + public enum UnitSetting1 { + IN_TEMP_FAHRENHEIT, + OUT_TEMP_FAHRENHEIT, + RAIN_INCH, + PRESSURE_HPA, + PRESSURE_INHG, + PRESSURE_MMHG; + } + + [Flag] + [CCode (cname = "enum weather_flag_unit_setting2", cprefix = "WEATHER_UNIT_")] + public enum UnitSetting2 { + WIND_SPEED_MS, + WIND_SPEED_KMH, + WIND_SPEED_KNOT, + WIND_SPEED_MH, + WIND_SPEED_BFT; + } + + [Flag] + [CCode (cname = "enum weather_flag_display_format1", cprefix = "WEATHER_DISPLAY_FORMAT_")] + public enum DisplayFormat1 { + PRESSURE_RELATIVE, + WIND_SPEED_GUST, + TIME_12H, + TIME_MMDDYY, + TIME_24H_SCALE, + COMPLETE_DATE, + DATE_WEEK, + ALARM; + } + + [Flag] + [CCode (cname = "enum weather_flag_display_format2", cprefix = "WEATHER_DISPLAY_FORMAT_")] + public enum DisplayFormat2 { + OUT_TEMP, + OUT_WINDCHILL, + OUT_DEW_POINT, + RAIN_1H, + RAIN_24H, + RAIN_WEEK, + RAIN_MONTH, + RAIN_TOTAL; + } + + [Flag] + [CCode (cname = "enum weather_flag_alarm1", cprefix = "WEATHER_ALARM_")] + public enum AlarmFlags1 { + TIME, + WIND_DIRECTION, + IN_HUMIDITY_LOW, + IN_HUMIDITY_HIGH, + OUT_HUMIDITY_LOW, + OUT_HUMIDITY_HIGH; + } + + [Flag] + [CCode (cname = "enum weather_flag_alarm2", cprefix = "WEATHER_ALARM_")] + public enum AlarmFlags2 { + AVERAGE_WIND_SPEED, + GUST_WIND_SPEED, + RAIN_1H, + RAIN_24H, + ABS_PRESSURE_LOW, + ABS_PRESSURE_HIGH, + REL_PRESSURE_LOW, + REL_PRESSURE_HIGH; + } + + [Flag] + [CCode (cname = "enum weather_flag_alarm3", cprefix = "WEATHER_ALARM_")] + public enum AlarmFlags3 { + IN_TEMP_LOW, + IN_TEMP_HIGH, + OUT_TEMP_LOW, + OUT_TEMP_HIGH, + WINDCHILL_LOW, + WINDCHILL_HIGH, + DEW_POINT_LOW, + DRW_POINT_HIGH; + } + + [CCode (cname = "struct weather_header_alarms")] + public struct Alarms { + uint8 in_humidity_high; + uint8 in_humidity_low; + uint16 inemp_high; + uint16 inemp_low; + uint8 out_humidity_high; + uint8 out_humidity_low; + uint16 outemp_high; + uint16 outemp_low; + uint16 wind_chill_high; + uint16 wind_chill_low; + uint16 dew_point_high; + uint16 dew_point_low; + uint16 absolute_pressure_high; + uint16 absolute_pressure_low; + uint16 relative_pressure_high; + uint16 relative_pressure_low; + uint8 average_bft_high; + uint16 average_wsp_high; + uint8 gust_bft_high; + uint16 gust_wsp_high; + uint8 wind_direction; + uint16 rain_1h_high; + uint16 rain_24h_high; + uint8 hour; + uint8 minute; + } + + [CCode (cname = "struct weather_header_records")] + public struct Records { + uint8 in_humidity_max; + uint8 in_humidity_min; + uint8 out_humidity_max; + uint8 out_humidity_min; + uint16 inemp_max; + uint16 inemp_min; + uint16 outemp_max; + uint16 outemp_min; + uint16 windchill_max; + uint16 windchill_min; + uint16 dew_point_max; + uint16 dew_point_min; + uint16 absolute_pressure_max; + uint16 absolute_pressure_min; + uint16 relative_pressure_max; + uint16 relative_pressure_min; + uint16 wsp_average_max; + uint16 wsp_gust_max; + uint16 rain_1h_max; + uint16 rain_24h_max; + uint16 rain_week_max; + uint16 rain_month_max; + uint16 rainotal_max; + uint8 nibble; + } + + [CCode (cname = "struct weather_time")] + public struct Time { + uint8 year; + uint8 month; + uint8 date; + uint8 hour; + uint8 minute; + } + + [CCode (cname = "struct weather_header_timestamps")] + public struct Timestamps { + Time in_humidity_max; + Time in_humidity_min; + Time out_humidity_max; + Time out_humidity_min; + Time in_temp_max; + Time in_temp_min; + Time out_temp_max; + Time out_temp_min; + Time wind_chill_max; + Time wind_chill_min; + Time dew_point_max; + Time dew_point_min; + Time absolute_pressure_max; + Time absolute_pressure_min; + Time relative_pressure_max; + Time relative_pressure_min; + Time wsp_average_max; + Time wsp_gust_max; + Time rain_1h_max; + Time rain_24h_max; + Time rain_week_max; + Time rain_month_max; + Time rain_total_max; + } + + [CCode (cname = "struct weather_header")] + public struct Header { + uint8 sampling_interval; + + [CCode (ctype = "uint8_t")] + UnitSetting1 unit_setting1; + + [CCode (ctype = "uint8_t")] + UnitSetting2 unit_setting2; + + [CCode (ctype = "uint8_t")] + DisplayFormat1 display_format1; + + [CCode (ctype = "uint8_t")] + DisplayFormat2 display_format2; + + [CCode (ctype = "uint8_t")] + AlarmFlags1 alarm_enable1; + + [CCode (ctype = "uint8_t")] + AlarmFlags2 alarm_enable2; + + [CCode (ctype = "uint8_t")] + AlarmFlags3 alarm_enable3; + + uint8 timezone; + + uint16 history_data_sets; + uint16 history_data_stack; + + uint16 relative_pressure; + uint16 absolute_pressure; + + Alarms alarm; + Records record; + Timestamps timestamp; + } + + [Compact] + [CCode (cname = "struct weather_station")] + public class Station { + [CCode (cname = "weather_station_init")] + public Station(); + public Data read_data(uint16 addr); + public Header read_header(); + public void write(uint16 addr, uint8 byte); + } +} diff --git a/weatherstation.c b/weatherstation.c new file mode 100644 index 0000000..c8b6fcf --- /dev/null +++ b/weatherstation.c @@ -0,0 +1,152 @@ +/* weatherstation.c + * Copyright (c) 2012, Sebastian Reichel + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include +#include +#include "weatherstation.h" + +#define WEATHER_CMD_WRITE 0xA0 +#define WEATHER_CMD_READ 0xA1 +#define WEATHER_CMD_WRITE_WORD 0xA2 +#define WEATHER_CMD_END 0x20 + +static struct usb_device* weather_station_find(uint16_t vendor, uint16_t product) { + for(struct usb_bus *bus = usb_get_busses(); bus != NULL; bus = bus->next) + for(struct usb_device *dev = bus->devices; dev != NULL; dev = dev->next) + if(dev->descriptor.idVendor == vendor && dev->descriptor.idProduct == product) + return dev; + return NULL; +} + +char * weather_wind_direction_to_string(enum weather_wind_direction dir) { + static char* translation_table[] = { + "north", "north-east-north", "north-east", "east-north-east", "east", "east-south-east", "south-east", "south-east-south", + "south", "south-west-south", "south-west", "west-south-west", "west", "west-north-west", "north-west", "north-west-north" + }; + + return (dir < 16) ? translation_table[dir] : "invalid"; +} + +struct weather_station* weather_station_init() { + int ret; + + usb_init(); + usb_find_busses(); + usb_find_devices(); + + struct usb_device *dev = weather_station_find(0x1941, 0x8021); + if(dev == NULL) + return NULL; + + struct usb_dev_handle *handle = usb_open(dev); + + #ifdef LIBUSB_HAS_GET_DRIVER_NP + #ifdef LIBUSB_HAS_DETACH_KERNEL_DRIVER_NP + char name[32]; + if(usb_get_driver_np(handle, 0, name, sizeof(name)) == 0) { + fprintf(stderr, "detach kernel driver: %s\n", name); + usb_detach_kernel_driver_np(handle, 0); + } + #endif + #endif + + ret = usb_claim_interface(handle, 0); + if(ret < 0) + return NULL; + + ret = usb_set_altinterface(handle, 0); + if(ret < 0) + return NULL; + + char buffer[256]; + ret = usb_get_descriptor(handle, 1, 0, buffer, 0x12); + if(ret < 0) + return NULL; + + ret = usb_get_descriptor(handle, 2, 0, buffer, 0x09); + if(ret < 0) + return NULL; + + ret = usb_get_descriptor(handle, 2, 0, buffer, 0x22); + if(ret < 0) + return NULL; + + ret = usb_release_interface(handle, 0); + if(ret < 0) + return NULL; + + ret = usb_set_configuration(handle, 1); + if(ret < 0) + return NULL; + + ret = usb_claim_interface(handle, 0); + if(ret < 0) + return NULL; + + ret = usb_set_altinterface(handle, 0); + if(ret < 0) + return NULL; + + ret = usb_control_msg(handle, USB_TYPE_CLASS + USB_RECIP_INTERFACE, 0xa, 0, 0, buffer, 0, 1000); + if(ret < 0) + return NULL; + + ret = usb_get_descriptor(handle, 0x22, 0, buffer, 0x74); + if(ret < 0) + return NULL; + + struct weather_station *this = malloc(sizeof(struct weather_station)); + this->dev = handle; + return this; +} + +void weather_station_free(struct weather_station *self) { + usb_close(self->dev); + free(self); +} + +void weather_station_send(struct weather_station *self, uint8_t data[], uint16_t size) { + usb_control_msg(self->dev, USB_TYPE_CLASS + USB_RECIP_INTERFACE, 9, 0x200, 0, data, size, 1000); +} + +void weather_station_recv(struct weather_station *self, uint8_t data[]) { + usb_interrupt_read(self->dev, 0x81, data, 32, 1000); +} + +void weather_station_read(struct weather_station *self, uint16_t addr, uint8_t *data) { + uint8_t buf[] = { WEATHER_CMD_READ, addr/256, addr%256, WEATHER_CMD_END, WEATHER_CMD_READ, 0x00, 0x00, WEATHER_CMD_END }; + weather_station_send(self, buf, 8); + weather_station_recv(self, data); +} + +void weather_station_read_data(struct weather_station *self, uint16_t addr, struct weather_data *result) { + uint8_t data[32]; + weather_station_read(self, addr, data); + + /* weather_data has the same structure as the raw data */ + memcpy(result, data, 16); +} + +void weather_station_read_header(struct weather_station *self, struct weather_header *result) { + for(int i=0; i<8; i++) + weather_station_read(self, i*32, (uint8_t*) result+i*32); +} + +void weather_station_write(struct weather_station *self, uint16_t addr, uint8_t byte) { + uint8_t buf[] = { WEATHER_CMD_WRITE_WORD, addr/256, addr%256, WEATHER_CMD_END, WEATHER_CMD_WRITE_WORD, byte, 0x00, WEATHER_CMD_END }; + weather_station_send(self, buf, 8); +} diff --git a/weatherstation.h b/weatherstation.h new file mode 100644 index 0000000..16d705c --- /dev/null +++ b/weatherstation.h @@ -0,0 +1,257 @@ +/* weather.h + * Copyright (c) 2012, Sebastian Reichel + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +#ifndef _WEATHER_STATION_H +#define _WEATHER_STATION_H + +#include + +enum weather_wind_direction { + NORTH, + NORTH_EAST_NORTH, + NORTH_EAST, + EAST_NORTH_EAST, + EAST, + EAST_SOUTH_EAST, + SOUTH_EAST, + SOUTH_EAST_SOUTH, + SOUTH, + SOUTH_WEST_SOUTH, + SOUTH_WEST, + WEST_SOUTH_WEST, + WEST, + WEST_NORTH_WEST, + NORTH_WEST, + NORTH_WEST_NORTH +}; + +enum weather_flag_status { + WEATHER_STATUS_INVALID_DATA = 0x40, + WEATHER_STATUS_RAIN_OVERFLOW = 0x80 +}; + +enum weather_flag_unit_setting1 { + WEATHER_UNIT_IN_TEMP_FAHRENHEIT = 0x01, + WEATHER_UNIT_OUT_TEMP_FAHRENHEIT = 0x02, + WEATHER_UNIT_RAIN_INCH = 0x04, + WEATHER_UNIT_PRESSURE_HPA = 0x20, + WEATHER_UNIT_PRESSURE_INHG = 0x40, + WEATHER_UNIT_PRESSURE_MMHG = 0x80 +}; + +enum weather_flag_unit_setting2 { + WEATHER_UNIT_WIND_SPEED_MS = 0x01, + WEATHER_UNIT_WIND_SPEED_KMH = 0x02, + WEATHER_UNIT_WIND_SPEED_KNOT = 0x04, + WEATHER_UNIT_WIND_SPEED_MH = 0x08, + WEATHER_UNIT_WIND_SPEED_BFT = 0x10 +}; + +enum weather_flag_display_format1 { + WEATHER_DISPLAY_FORMAT_PRESSURE_RELATIVE = 0x01, + WEATHER_DISPLAY_FORMAT_WIND_SPEED_GUST = 0x02, + WEATHER_DISPLAY_FORMAT_TIME_12H = 0x04, + WEATHER_DISPLAY_FORMAT_TIME_MMDDYY = 0x08, + WEATHER_DISPLAY_FORMAT_TIME_24H_SCALE = 0x10, + WEATHER_DISPLAY_FORMAT_COMPLETE_DATE = 0x20, + WEATHER_DISPLAY_FORMAT_DATE_WEEK = 0x40, + WEATHER_DISPLAY_FORMAT_ALARM = 0x80 +}; + +enum weather_flag_display_format2 { + WEATHER_DISPLAY_FORMAT_OUT_TEMP = 0x01, + WEATHER_DISPLAY_FORMAT_OUT_WINDCHILL = 0x02, + WEATHER_DISPLAY_FORMAT_OUT_DEW_POINT = 0x04, + WEATHER_DISPLAY_FORMAT_RAIN_1H = 0x08, + WEATHER_DISPLAY_FORMAT_RAIN_24H = 0x10, + WEATHER_DISPLAY_FORMAT_RAIN_WEEK = 0x20, + WEATHER_DISPLAY_FORMAT_RAIN_MONTH = 0x40, + WEATHER_DISPLAY_FORMAT_RAIN_TOTAL = 0x80 +}; + +enum weather_flag_alarm1 { + WEATHER_ALARM_TIME = 0x02, + WEATHER_ALARM_WIND_DIRECTION = 0x04, + WEATHER_ALARM_IN_HUMIDITY_LOW = 0x10, + WEATHER_ALARM_IN_HUMIDITY_HIGH = 0x20, + WEATHER_ALARM_OUT_HUMIDITY_LOW = 0x40, + WEATHER_ALARM_OUT_HUMIDITY_HIGH = 0x80 +}; + +enum weather_flag_alarm2 { + WEATHER_ALARM_AVERAGE_WIND_SPEED = 0x01, + WEATHER_ALARM_GUST_WIND_SPEED = 0x02, + WEATHER_ALARM_RAIN_1H = 0x04, + WEATHER_ALARM_RAIN_24H = 0x08, + WEATHER_ALARM_ABS_PRESSURE_LOW = 0x10, + WEATHER_ALARM_ABS_PRESSURE_HIGH = 0x20, + WEATHER_ALARM_REL_PRESSURE_LOW = 0x40, + WEATHER_ALARM_REL_PRESSURE_HIGH = 0x80 +}; + +enum weather_flag_alarm3 { + WEATHER_ALARM_IN_TEMP_LOW = 0x01, + WEATHER_ALARM_IN_TEMP_HIGH = 0x02, + WEATHER_ALARM_OUT_TEMP_LOW = 0x04, + WEATHER_ALARM_OUT_TEMP_HIGH = 0x08, + WEATHER_ALARM_WINDCHILL_LOW = 0x10, + WEATHER_ALARM_WINDCHILL_HIGH = 0x20, + WEATHER_ALARM_DEW_POINT_LOW = 0x40, + WEATHER_ALARM_DRW_POINT_HIGH = 0x80 +}; + +struct weather_data { + uint8_t sample_time; + uint8_t humidity_indoor; + uint16_t temperature_indoor; + uint8_t humidity_outdoor; + uint16_t temperature_outdoor; + uint16_t pressure; + uint8_t avg_wind_speed; + uint8_t gust_wind_speed; + uint8_t high_nibble_wind_speed; + uint8_t wind_direction; + uint16_t rain; + uint8_t status; +} __attribute__((packed)); + +struct weather_time { + uint8_t year; + uint8_t month; + uint8_t date; + uint8_t hour; + uint8_t minute; +} __attribute__((packed)); + +struct weather_header_timestamps { + struct weather_time in_humidity_max; + struct weather_time in_humidity_min; + struct weather_time out_humidity_max; + struct weather_time out_humidity_min; + struct weather_time in_temp_max; + struct weather_time in_temp_min; + struct weather_time out_temp_max; + struct weather_time out_temp_min; + struct weather_time wind_chill_max; + struct weather_time wind_chill_min; + struct weather_time dew_point_max; + struct weather_time dew_point_min; + struct weather_time absolute_pressure_max; + struct weather_time absolute_pressure_min; + struct weather_time relative_pressure_max; + struct weather_time relative_pressure_min; + struct weather_time wsp_average_max; + struct weather_time wsp_gust_max; + struct weather_time rain_1h_max; + struct weather_time rain_24h_max; + struct weather_time rain_week_max; + struct weather_time rain_month_max; + struct weather_time rain_total_max; +} __attribute__((packed)); + +struct weather_header_alarms { + uint8_t in_humidity_high; + uint8_t in_humidity_low; + uint16_t in_temp_high; + uint16_t in_temp_low; + uint8_t out_humidity_high; + uint8_t out_humidity_low; + uint16_t out_temp_high; + uint16_t out_temp_low; + uint16_t wind_chill_high; + uint16_t wind_chill_low; + uint16_t dew_point_high; + uint16_t dew_point_low; + uint16_t absolute_pressure_high; + uint16_t absolute_pressure_low; + uint16_t relative_pressure_high; + uint16_t relative_pressure_low; + uint8_t average_bft_high; + uint16_t average_wsp_high; + uint8_t gust_bft_high; + uint16_t gust_wsp_high; + uint8_t wind_direction; + uint16_t rain_1h_high; + uint16_t rain_24h_high; + uint8_t hour; + uint8_t minute; +} __attribute__((packed)); + +struct weather_header_records { + uint8_t in_humidity_max; + uint8_t in_humidity_min; + uint8_t out_humidity_max; + uint8_t out_humidity_min; + uint16_t in_temp_max; + uint16_t in_temp_min; + uint16_t out_temp_max; + uint16_t out_temp_min; + uint16_t windchill_max; + uint16_t windchill_min; + uint16_t dew_point_max; + uint16_t dew_point_min; + uint16_t absolute_pressure_max; + uint16_t absolute_pressure_min; + uint16_t relative_pressure_max; + uint16_t relative_pressure_min; + uint16_t wsp_average_max; + uint16_t wsp_gust_max; + uint16_t rain_1h_max; + uint16_t rain_24h_max; + uint16_t rain_week_max; + uint16_t rain_month_max; + uint16_t rain_total_max; + uint8_t nibble; +} __attribute__((packed)); + +struct weather_header { + uint8_t eeprom_init_flag1; + uint8_t eeprom_init_flag2; + uint8_t padding1[14]; + uint8_t sampling_interval; + uint8_t unit_setting1; + uint8_t unit_setting2; + uint8_t display_format1; + uint8_t display_format2; + uint8_t alarm_enable1; + uint8_t alarm_enable2; + uint8_t alarm_enable3; + uint8_t timezone; + uint8_t padding2[1]; + uint8_t data_refreshed; + uint16_t history_data_sets; + uint8_t padding3[1]; + uint16_t history_data_stack; + uint16_t relative_pressure; + uint16_t absolute_pressure; + uint8_t padding4[12]; + struct weather_header_alarms alarm; + uint8_t padding5[9]; + struct weather_header_records record; + struct weather_header_timestamps timestamp; +} __attribute__((packed)); + +struct weather_station { + struct usb_dev_handle *dev; +}; + +struct weather_station* weather_station_init(); +void weather_station_free(struct weather_station *self); +void weather_station_read_data(struct weather_station *self, uint16_t addr, struct weather_data *data); +void weather_station_read_header(struct weather_station *self, struct weather_header *data); +void weather_station_write(struct weather_station *self, uint16_t addr, uint8_t byte); +char * weather_wind_direction_to_string(enum weather_wind_direction dir); + +#endif -- cgit v1.2.3