X-Git-Url: https://git.ao2.it/visomat-utils.git/blobdiff_plain/91d0c4148bdb1fca33062b80b669e3c9e00c8030..e1d3986c78a172b4120056f03d4e2140bba0315b:/src/visomat-data-downloader.c diff --git a/src/visomat-data-downloader.c b/src/visomat-data-downloader.c index a91ee43..b471dc9 100644 --- a/src/visomat-data-downloader.c +++ b/src/visomat-data-downloader.c @@ -20,19 +20,48 @@ */ #include +#include #include +#include #include #include #include -#define STX 0x02 -#define ETX 0x03 +#ifdef DEBUG +#define debug(...) fprintf(stderr, __VA_ARGS__) +static void debug_dump_buffer(const char *filename, uint8_t *buffer, unsigned int len) +{ + FILE *dump_file; + + dump_file = fopen(filename, "wb"); + if (dump_file == NULL) { + fprintf(stderr, "Failed to open %s: %s\n", filename, strerror(errno)); + return; + } + + fwrite(buffer, 1, len, dump_file); + fclose(dump_file); +} +#else +#define debug(...) do {} while(0) +static void debug_dump_buffer(const char *filename, uint8_t *buffer, unsigned int len) +{ + (void)filename; + (void)buffer; + (void)len; +} +#endif -#define DEVICE_VID 0x1247 -#define DEVICE_PID 0x00f8 +#define VISOMAT_DEVICE_VID 0x1247 +#define VISOMAT_DEVICE_PID 0x00f8 +#define VISOMAT_CONFIGURATION 1 +#define VISOMAT_INTERFACE 1 +#define VISOMAT_EP_IN 0x82 +#define VISOMAT_EP_OUT 0x03 +#define VISOMAT_PACKET_SIZE 64 -#define EP_IN 0x82 -#define EP_OUT 0x03 +#define STX 0x02 +#define ETX 0x03 #define BASE_YEAR 2000 @@ -69,7 +98,7 @@ struct pressure { unsigned int pulses; }; -static inline int extract_datetime(unsigned char *buffer, struct datetime *d) +static inline int extract_datetime(uint8_t *buffer, struct datetime *d) { int ret; @@ -117,8 +146,8 @@ static void print_record_csv_compat(struct datetime *d, struct pressure *p) printf("\n"); } -/* TODO separate better decoding data from printing it */ -static int decode_eeprom(unsigned char *buffer, +/* TODO: it would be better to separate decoding data from printing it */ +static int decode_eeprom(uint8_t *buffer, unsigned int len, unsigned int user_mask) { @@ -131,8 +160,15 @@ static int decode_eeprom(unsigned char *buffer, struct datetime d; struct pressure p; - if (buffer[0] != STX || buffer[1] != 'M' || buffer[len - 1] != ETX) + if (buffer[0] != STX || buffer[1] != 'M') { + fprintf(stderr, "Usupported data.\n"); + return -EINVAL; + } + + if (buffer[len - 1] != ETX) { + fprintf(stderr, "Bad terminator in data. Buffer too small?\n"); return -EINVAL; + } /* skip the initial STX */ i = 1; @@ -154,6 +190,13 @@ static int decode_eeprom(unsigned char *buffer, /* user_id and num_records take 3 bytes */ i += 3; + /* + * when there are no records, there is a dummy byte + * which has to be consumed + */ + if (num_records == 0) + i += 1; + for (j = 0; j < num_records; j++) { ret = extract_datetime(buffer + i, &d); if (ret < 0) @@ -187,12 +230,12 @@ static int decode_eeprom(unsigned char *buffer, return 0; } -static int decode_datetime(unsigned char *buffer, unsigned int len) +static int decode_datetime(uint8_t *buffer, unsigned int len) { int ret; - unsigned char code[4] = { 0 }; + uint8_t code[4] = { 0 }; struct datetime d; - unsigned char *pbuffer = buffer; + uint8_t *pbuffer = buffer; if (len != 15) return -EINVAL; @@ -215,7 +258,7 @@ static int send_command(libusb_device_handle *dev, visomat_command cmd) { int ret; int transferred; - unsigned char request[5]; + uint8_t request[5]; request[0] = STX; request[1] = command_codes[cmd][0]; @@ -224,7 +267,7 @@ static int send_command(libusb_device_handle *dev, visomat_command cmd) request[4] = ETX; transferred = 0; - ret = libusb_bulk_transfer(dev, EP_OUT, request, sizeof(request), &transferred, 0); + ret = libusb_bulk_transfer(dev, VISOMAT_EP_OUT, request, sizeof(request), &transferred, 0); if (ret != 0 || transferred != sizeof(request)) { fprintf(stderr, "Error: sending request: %d (%s)\ttransferred: %d (expected %zu)\n", ret, libusb_error_name(ret), transferred, sizeof(request)); @@ -234,12 +277,12 @@ static int send_command(libusb_device_handle *dev, visomat_command cmd) } static int get_response(libusb_device_handle *dev, - unsigned char *buffer, + uint8_t *buffer, unsigned int len) { int ret; int transferred; - unsigned char response[64] = { 0 }; + uint8_t response[VISOMAT_PACKET_SIZE] = { 0 }; unsigned int i; i = 0; @@ -247,7 +290,7 @@ static int get_response(libusb_device_handle *dev, unsigned int j; transferred = 0; - ret = libusb_bulk_transfer(dev, EP_IN, response, sizeof(response), &transferred, 5000); + ret = libusb_bulk_transfer(dev, VISOMAT_EP_IN, response, sizeof(response), &transferred, 5000); if (ret != 0) { fprintf(stderr, "Error getting response: %d (%s)\ttransferred: %d (expected %zu)\n", ret, libusb_error_name(ret), transferred, sizeof(response)); @@ -272,8 +315,8 @@ static int get_response(libusb_device_handle *dev, #define visomat_device libusb_device_handle static int visomat_dump_eeprom(visomat_device *dev, unsigned int user_mask) { - /* Assuming an EEPROM of 1 KiB */ - unsigned char buffer[1024] = { 0 }; + /* Assuming an EEPROM of 4 KiB */ + uint8_t buffer[4096] = { 0 }; int ret; ret = send_command(dev, VISOMAT_CMD_DUMP_EEPROM); @@ -281,6 +324,8 @@ static int visomat_dump_eeprom(visomat_device *dev, unsigned int user_mask) return ret; ret = get_response(dev, buffer, sizeof(buffer)); + debug("buffer size: %d\n", ret); + debug_dump_buffer("eeprom.bin", buffer, sizeof(buffer)); if (ret < 0) return ret; @@ -293,7 +338,7 @@ static int visomat_dump_eeprom(visomat_device *dev, unsigned int user_mask) static int visomat_get_datetime(visomat_device *dev) { - unsigned char buffer[255] = { 0 }; + uint8_t buffer[255] = { 0 }; int ret; ret = send_command(dev, VISOMAT_CMD_GET_DATETIME); @@ -311,34 +356,120 @@ static int visomat_get_datetime(visomat_device *dev) return 0; } -int main(void) +static void usage(const char *name) +{ + printf("usage: %s [OPTIONS]\n\n", name); + printf("OPTIONS:\n"); + printf("\t-D\t\tenable libusb debug output\n"); + printf("\t-h\t\tthis help message\n"); +} + +int main(int argc, char *argv[]) { int ret; + int opt; + bool enable_libusb_debug = false; libusb_device_handle *dev; + int current_configuration; + + while ((opt = getopt(argc, argv, "Dh")) != -1) { + switch (opt) { + case 'D': + enable_libusb_debug = true; + break; + case 'h': + usage(argv[0]); + ret = 0; + goto out; + default: /* '?' */ + usage(argv[0]); + ret = -EINVAL; + goto out; + } + } + + ret = libusb_init(NULL); + if (ret < 0) { + fprintf(stderr, "libusb_init failed: %s\n", + libusb_error_name(ret)); + goto out; + } - libusb_init(NULL); - libusb_set_debug(NULL, LIBUSB_LOG_LEVEL_INFO); + libusb_set_debug(NULL, enable_libusb_debug ? + LIBUSB_LOG_LEVEL_DEBUG : LIBUSB_LOG_LEVEL_INFO); - dev = libusb_open_device_with_vid_pid(NULL, DEVICE_VID, DEVICE_PID); + dev = libusb_open_device_with_vid_pid(NULL, + VISOMAT_DEVICE_VID, + VISOMAT_DEVICE_PID); if (dev == NULL) { - fprintf(stderr, "Couldn't open device.\n"); - ret = -ENODEV; + fprintf(stderr, "libusb_open failed: %s\n", strerror(errno)); + ret = -errno; goto out_libusb_exit; } - libusb_set_configuration(dev, 1); - libusb_detach_kernel_driver(dev, 1); - libusb_claim_interface(dev, 1); + current_configuration = -1; + ret = libusb_get_configuration(dev, ¤t_configuration); + if (ret < 0) { + fprintf(stderr, "libusb_get_configuration failed: %s\n", + libusb_error_name(ret)); + goto out_libusb_close; + } + + if (current_configuration != VISOMAT_CONFIGURATION) { + ret = libusb_set_configuration(dev, VISOMAT_CONFIGURATION); + if (ret < 0) { + fprintf(stderr, "libusb_set_configuration failed: %s\n", + libusb_error_name(ret)); + fprintf(stderr, "Cannot set configuration %d\n", + VISOMAT_CONFIGURATION); + goto out_libusb_close; + } + } + + libusb_set_auto_detach_kernel_driver(dev, 1); + + ret = libusb_claim_interface(dev, VISOMAT_INTERFACE); + if (ret < 0) { + fprintf(stderr, "libusb_claim_interface failed: %s\n", + libusb_error_name(ret)); + fprintf(stderr, "Cannot claim interface %d\n", + VISOMAT_INTERFACE); + goto out_libusb_close; + } + + /* Checking that the configuration has not changed, as suggested in + * http://libusb.sourceforge.net/api-1.0/caveats.html + */ + current_configuration = -1; + ret = libusb_get_configuration(dev, ¤t_configuration); + if (ret < 0) { + fprintf(stderr, "libusb_get_configuration after claim failed: %s\n", + libusb_error_name(ret)); + goto out_libusb_release_interface; + } + + if (current_configuration != VISOMAT_CONFIGURATION) { + fprintf(stderr, "libusb configuration changed (expected: %d, current: %d)\n", + VISOMAT_CONFIGURATION, current_configuration); + ret = -EINVAL; + goto out_libusb_release_interface; + } ret = visomat_get_datetime(dev); if (ret < 0) - goto out; + goto out_libusb_release_interface; ret = visomat_dump_eeprom(dev, 0x01 | 0x02); + if (ret < 0) + goto out_libusb_release_interface; -out: +out_libusb_release_interface: + libusb_release_interface(dev, VISOMAT_INTERFACE); +out_libusb_close: libusb_close(dev); + dev = NULL; out_libusb_exit: libusb_exit(NULL); +out: return ret; }