summaryrefslogtreecommitdiffstats
path: root/weatherstation.c
diff options
context:
space:
mode:
Diffstat (limited to 'weatherstation.c')
-rw-r--r--weatherstation.c152
1 files changed, 152 insertions, 0 deletions
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);
+}