summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Makefile31
-rw-r--r--demo.vala46
-rw-r--r--libweatherstation.vapi291
-rw-r--r--weatherstation.c152
-rw-r--r--weatherstation.h257
5 files changed, 777 insertions, 0 deletions
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 <sre@ring0.de>
+ *
+ * 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 <sre@ring0.de>
+ *
+ * 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 <sre@ring0.de>
+ *
+ * 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 <usb.h>
+#include <string.h>
+#include <stdio.h>
+#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 <sre@ring0.de>
+ *
+ * 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 <inttypes.h>
+
+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