--- /dev/null
+/*
+ * Copyright (C) 2014 Timo Kokkonen <timo.t.kokkonen@iki.fi>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA
+ */
+
+#include <libusb.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "contour-next-protocol.h"
+#include "utils.h"
+
+#define OUT_EP (4 | LIBUSB_ENDPOINT_OUT)
+#define IN_EP (3 | LIBUSB_ENDPOINT_IN)
+
+static int send_msg(libusb_device_handle *dev_handle, unsigned char *msg)
+{
+ int ret, actual;
+
+ trace(2, "Sending message ");
+ print_hex(2, msg, MSG_LEN);
+
+ ret = libusb_interrupt_transfer(dev_handle, OUT_EP, msg,
+ MSG_LEN, &actual, 0);
+ if (ret || actual != MSG_LEN) {
+ trace(0, "Error sending msg: %d, actual %d\n", ret, actual);
+ return -1;
+ }
+
+ return 0;
+}
+
+static int read_msg(libusb_device_handle *dev_handle, unsigned char *msg)
+{
+ int ret, actual;
+
+ ret = libusb_interrupt_transfer(dev_handle, IN_EP , msg,
+ MSG_LEN, &actual, 0);
+ if (ret || actual != MSG_LEN) {
+ trace(0, "Error reading message: %d, actual %d\n",
+ ret, actual);
+ return -1;
+ }
+
+ return 0;
+}
+
+static int send_init_msg(libusb_device_handle *dev_handle,
+ unsigned char b0, unsigned char b1, unsigned char b2,
+ int read_msgs)
+{
+ unsigned char msg[MSG_LEN];
+ int ret, i;
+ bzero(msg, sizeof(msg));
+ msg[3] = b0;
+ msg[4] = b1;
+ msg[5] = b2;
+
+ ret = send_msg(dev_handle, msg);
+ if (ret)
+ return ret;
+
+ for (i = 0; i < read_msgs; i++) {
+ ret = read_msg(dev_handle, msg);
+ if (ret)
+ return ret;
+
+ trace(1, "Reading intermediate msg %d of %d\n", i, read_msgs);
+ print_hex(3, msg, sizeof(msg));
+ print_ascii(2, msg, sizeof(msg));
+ }
+
+ return 0;
+}
+
+struct contour_next_init_sequence {
+ unsigned char b0, b1, b2;
+ int response_msgs;
+};
+
+static int send_init_messages(libusb_device_handle *dev_handle,
+ struct contour_next_init_sequence *seq, int messages)
+{
+ int i, ret;
+
+ for (i = 0; i < messages; i++) {
+ if (!trace_level)
+ trace(0, "\rInitializing %d/%d...", i, messages);
+
+ ret = send_init_msg(dev_handle,
+ seq[i].b0, seq[i].b1, seq[i].b2,
+ seq[i].response_msgs);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+static struct contour_next_init_sequence seq[] = {
+ { 0x01, 0x04, 0x00, 6, },
+ { 0x01, 0x06, 0x00, 5, },
+ { 0x01, 0x15, 0x00, 5, },
+ { 0x01, 0x15, 0x00, 5, },
+ { 0x01, 0x15, 0x00, 5, },
+ { 0x01, 0x15, 0x00, 5, },
+ { 0x01, 0x15, 0x00, 5, },
+ { 0x01, 0x15, 0x00, 2, },
+ { 0x01, 0x15, 0x00, 1, },
+ { 0x01, 0x05, 0x00, 1, },
+ { 0x01, 0x04, 0x00, 1, },
+ { 0x01, 0x15, 0x00, 1, },
+ { 0x01, 0x05, 0x00, 1, },
+ { 0x02, 0x52, 0x7C, 1, },
+ { 0x02, 0x41, 0x7C, 2, },
+ { 0x01, 0x04, 0x00, 1, },
+ { 0x01, 0x15, 0x00, 1, },
+ { 0x01, 0x05, 0x00, 1, },
+ { 0x02, 0x52, 0x7C, 1, },
+ { 0x02, 0x43, 0x7C, 2, },
+ { 0x01, 0x04, 0x00, 1, },
+ { 0x01, 0x15, 0x00, 1, },
+ { 0x01, 0x05, 0x00, 1, },
+ { 0x02, 0x52, 0x7C, 1, },
+ { 0x02, 0x44, 0x7C, 2, },
+ { 0x01, 0x04, 0x00, 1, },
+ { 0x01, 0x15, 0x00, 1, },
+ { 0x01, 0x05, 0x00, 1, },
+ { 0x02, 0x52, 0x7C, 1, },
+ { 0x02, 0x47, 0x7C, 2, },
+ { 0x01, 0x04, 0x00, 1, },
+ { 0x01, 0x15, 0x00, 1, },
+ { 0x01, 0x05, 0x00, 1, },
+ { 0x02, 0x52, 0x7C, 1, },
+ { 0x02, 0x49, 0x7C, 1, },
+ { 0x01, 0x04, 0x00, 1, },
+ { 0x01, 0x15, 0x00, 1, },
+ { 0x01, 0x05, 0x00, 1, },
+ { 0x02, 0x52, 0x7C, 1, },
+ { 0x02, 0x4D, 0x7C, 2, },
+ { 0x01, 0x04, 0x00, 1, },
+ { 0x01, 0x15, 0x00, 1, },
+ { 0x01, 0x05, 0x00, 1, },
+ { 0x02, 0x52, 0x7C, 1, },
+ { 0x02, 0x50, 0x7C, 2, },
+ { 0x01, 0x04, 0x00, 1, },
+ { 0x01, 0x15, 0x00, 1, },
+ { 0x01, 0x05, 0x00, 1, },
+ { 0x02, 0x52, 0x7C, 1, },
+ { 0x02, 0x53, 0x7C, 2, },
+ { 0x01, 0x04, 0x00, 1, },
+ { 0x01, 0x15, 0x00, 1, },
+ { 0x01, 0x05, 0x00, 1, },
+ { 0x02, 0x52, 0x7C, 1, },
+ { 0x02, 0x54, 0x7C, 2, },
+ { 0x01, 0x04, 0x00, 1, },
+ { 0x01, 0x15, 0x00, 1, },
+ { 0x01, 0x05, 0x00, 1, },
+ { 0x02, 0x52, 0x7C, 1, },
+ { 0x02, 0x56, 0x7C, 2, },
+ { 0x01, 0x04, 0x00, 1, },
+ { 0x01, 0x15, 0x00, 1, },
+ { 0x01, 0x05, 0x00, 1, },
+ { 0x02, 0x52, 0x7C, 1, },
+ { 0x02, 0x57, 0x7C, 2, },
+ { 0x01, 0x04, 0x00, 1, },
+ { 0x01, 0x15, 0x00, 1, },
+ { 0x01, 0x05, 0x00, 1, },
+ { 0x02, 0x52, 0x7C, 1, },
+ { 0x02, 0x58, 0x7C, 2, },
+ { 0x01, 0x04, 0x00, 1, },
+ { 0x01, 0x15, 0x00, 1, },
+ { 0x01, 0x05, 0x00, 1, },
+ { 0x02, 0x52, 0x7C, 1, },
+ { 0x02, 0x5A, 0x7C, 2, },
+ { 0x01, 0x04, 0x00, 1, },
+ { 0x01, 0x15, 0x00, 1, },
+ { 0x01, 0x05, 0x00, 1, },
+ { 0x01, 0x04, 0x00, 1, },
+ { 0x01, 0x04, 0x00, 6, },
+ { 0x01, 0x06, 0x00, 5, },
+ { 0x01, 0x06, 0x00, 1, },
+};
+
+static libusb_device_handle *dev_handle;
+
+int contour_next_initialize(void)
+{
+ libusb_device **devs;
+ int ret;
+
+ ret = libusb_init(NULL);
+ if (ret) {
+ printf("Failed to init libusb: %d\n", ret);
+ return 1;
+ }
+
+ ret = libusb_get_device_list(NULL, &devs);
+ if (ret < 0) {
+ printf("Failed to get device list: %d\n", ret);
+ return 1;
+ }
+
+ dev_handle = libusb_open_device_with_vid_pid(NULL, 0x1a79, 0x7410);
+ if (dev_handle == NULL) {
+ printf("Failed to open device\n");
+ return 1;
+ }
+
+ ret = libusb_kernel_driver_active(dev_handle, 0);
+ if (ret == 1) {
+ printf("Kernel Driver Active\n");
+
+ ret = libusb_detach_kernel_driver(dev_handle, 0);
+ if (ret == 0)
+ printf("Kernel Driver Detached!\n");
+ }
+
+ ret = libusb_claim_interface(dev_handle, 0);
+ if (ret) {
+ printf("Failed to claim the interface: %d\n", ret);
+ return 1;
+ }
+
+ send_init_messages(dev_handle, seq, sizeof(seq)/sizeof(seq[0]));
+
+ return 0;
+
+ while (1) {
+ unsigned char msg[MSG_LEN];
+
+ bzero(msg, sizeof(msg));
+ msg[3] = 0x01;
+ msg[4] = 0x06;
+ msg[5] = 0x00;
+
+ ret = send_msg(dev_handle, msg);
+ if (ret)
+ return ret;
+
+ ret = read_msg(dev_handle, msg);
+ if (ret)
+ return ret;
+
+ print_ascii(0, msg, sizeof(msg));
+ }
+
+ return 0;
+}
+
+int contour_next_read_entry(unsigned char *msg)
+{
+ int ret;
+ bzero(msg, MSG_LEN);
+ msg[3] = 0x01;
+ msg[4] = 0x06;
+ msg[5] = 0x00;
+
+ ret = send_msg(dev_handle, msg);
+ if (ret)
+ return ret;
+
+ ret = read_msg(dev_handle, msg);
+ if (ret)
+ return ret;
+
+ return datalen(msg);
+}
#include "hiddev.h"
#include "utils.h"
#include "options.h"
-#include "contour-protocol.h"
+#include "contour-next-protocol.h"
static char *token(char **str, char sep)
{
for (cur = start; *cur && (*cur != sep); ++cur);
*cur = 0;
- *str = cur+1;
+ *str = cur + 1;
return start;
}
-static void format_csv(struct user_options *opts, struct msg *msg)
+static void format_csv(struct user_options *opts, unsigned char *msg)
{
- char *tok = (char *) msg->data;
+ char *tok = (char *)msg;
token(&tok, '|'); // unknown
char *seq = token(&tok, '|');
char *type = token(&tok, '|');
token(&tok, '|');// unknown
char *time = token(&tok, '\r');
- unit[strlen(unit)-2] = 0;
+ unit[strlen(unit) - 2] = 0;
fprintf(opts->outf,
"%s,\"%.4s-%.2s-%.2s %.2s:%.2s\",\"%s\",\"%s\",\"%s\","
"%s,%s,%s,%s,%s,%s,%s\n",
);
}
-static int format_message(struct user_options *opts, struct msg *msg, int len)
+static int format_message(struct user_options *opts,
+ unsigned char *msg, int len)
{
switch (opts->output_format)
{
break;
case CLEAN:
- sanitize_ascii(msg->data, len);
- fprintf(opts->outf, "%s\n", msg->data);
+ sanitize_ascii(msg, len);
+ fprintf(opts->outf, "%s\n", msg);
break;
case RAW:
- fprintf(opts->outf, "%s", msg->data);
+ fprintf(opts->outf, "%s", msg);
break;
default:
return 0;
}
-static int dump_entries(struct user_options *opts, int fd, int usage_code)
+static int dump_entries(struct user_options *opts)
{
- struct msg msg;
+ unsigned char msg[64 + 1];
int ret;
int entries = 0;
- int extra_delay = 0;
trace(0, "Reading data ...\n");
if (opts->output_format == CSV)
"Activity,\"Control test\"\n");
while (1) {
- ret = contour_read_entry(fd, usage_code, &msg, extra_delay);
+ ret = contour_next_read_entry(msg);
+ msg[MSG_LEN] = 0;
if (ret < 45)
break;
- ret = format_message(opts, &msg, ret);
+ ret = format_message(opts, msg, ret);
if (ret < 0)
return ret;
entries++;
- /*
- * Add 20ms magic sleep. This is needed especially for
- * meters that have reached the internal limit of 2000
- * glucose readings. We don't want to delay any other
- * reads as it appears to be needed only for every
- * 16th read.
- */
- if (!(entries % 16))
- extra_delay = 20;
- else
- extra_delay = 0;
-
if ((opts->outf != stdout) || !isatty(fileno(stdout))) {
trace(0, "\r%d entries", entries);
fflush(stdout);
int main(int argc, char *argv[])
{
struct user_options opts;
- int fd, usage_code, ret;
+ int ret;
bzero(&opts, sizeof(opts));
opts.output_format = CLEAN;
- if ( read_args(argc, argv, &opts) )
+ if (read_args(argc, argv, &opts))
return -1;
trace_level = opts.trace_level;
opts.outf = stdout;
}
- if (opts.usbdev == NULL)
- fd = wait_for_device(CONTOUR_USB_VENDOR_ID,
- CONTOUR_USB_PRODUCT_ID, &usage_code);
- else
- fd = hiddev_open(opts.usbdev, &usage_code);
- if (fd < 0)
- return 1;
-
trace(0, "Initializing ...\n");
- contour_initialize(fd, usage_code);
+ contour_next_initialize();
- ret = dump_entries(&opts, fd, usage_code);
+ ret = dump_entries(&opts);
return ret ? 1 : 0;
}