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 --- weatherstation.c | 152 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 152 insertions(+) create mode 100644 weatherstation.c (limited to 'weatherstation.c') 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); +} -- cgit v1.2.3