/* 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. */ #ifdef __linux__ #include #endif #include #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); }