*/
#include <stdio.h>
+#include <stdbool.h>
#include <stdlib.h>
+#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <libusb.h>
-#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 DATETIME_PACKET_SIZE 15
#define BASE_YEAR 2000
typedef enum {
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;
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)
{
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;
/* 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)
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 }; /* the initial STX + 3 bytes command code */
struct datetime d;
- unsigned char *pbuffer = buffer;
+ uint8_t *pbuffer = buffer;
- if (len != 15)
+ if (len != DATETIME_PACKET_SIZE)
return -EINVAL;
code[0] = buffer[1];
code[1] = buffer[2];
code[2] = buffer[3];
- ret = extract_datetime(pbuffer + 4, &d);
+ ret = extract_datetime(pbuffer + sizeof(code), &d);
if (ret < 0)
return ret;
{
int ret;
int transferred;
- unsigned char request[5];
+ uint8_t request[5];
request[0] = STX;
request[1] = command_codes[cmd][0];
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));
}
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;
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));
} while (buffer[i - 1] != ETX && i < len);
- /* Check the buffer is a valid response packet */
+ /* Check if the buffer contains a valid response packet */
if (buffer[0] != STX || buffer[i - 1] != ETX)
return -EINVAL;
#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);
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;
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);
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;
}