#include <stdio.h>
#include <getopt.h>
#include <stdbool.h>
+#include <ctype.h>
#include <libubox/blobmsg_json.h>
#include <libubox/avl.h>
static const char *config_file = DEFAULT_CONFIG;
static struct blob_buf conf;
-static struct blob_attr **messages;
-static int n_messages;
+char **messages = NULL;
+int *message_len;
+int n_messages = 0;
static struct avl_tree devices;
-static struct libusb_context *usb;
+struct libusb_context *usb;
static struct libusb_device **usbdevs;
static int n_usbdevs;
+static int hex2num(char c)
+{
+ if (c >= '0' && c <= '9')
+ return c - '0';
+
+ c = toupper(c);
+ if (c >= 'A' && c <= 'F')
+ return c - 'A' + 10;
+
+ return -1;
+}
+
+static int hex2byte(const char *hex)
+{
+ int a, b;
+
+ a = hex2num(*hex++);
+ if (a < 0)
+ return -1;
+
+ b = hex2num(*hex++);
+ if (b < 0)
+ return -1;
+
+ return (a << 4) | b;
+}
+
+static int hexstr2bin(const char *hex, char *buffer, int len)
+{
+ const char *ipos = hex;
+ char *opos = buffer;
+ int i, a;
+
+ for (i = 0; i < len; i++) {
+ a = hex2byte(ipos);
+ if (a < 0)
+ return -1;
+
+ *opos++ = a;
+ ipos += 2;
+ }
+
+ return 0;
+}
+
+static int convert_message(struct blob_attr *attr)
+{
+ char *data;
+ int len;
+
+ data = blobmsg_data(attr);
+ len = strlen(data);
+ if (len % 2)
+ return -1;
+
+ if (hexstr2bin(data, data, len / 2))
+ return -1;
+
+ return len / 2;
+}
+
static int parse_config(void)
{
enum {
n_messages++;
messages = calloc(n_messages, sizeof(*messages));
+ message_len = calloc(n_messages, sizeof(*message_len));
n_messages = 0;
- blobmsg_for_each_attr(cur, tb[CONF_MESSAGES], rem)
- messages[n_messages++] = cur;
+ blobmsg_for_each_attr(cur, tb[CONF_MESSAGES], rem) {
+ int len = convert_message(cur);
+
+ if (len < 0) {
+ fprintf(stderr, "Invalid data in message %d\n", n_messages);
+ return -1;
+ }
+
+ message_len[n_messages] = len;
+ messages[n_messages++] = blobmsg_data(cur);
+ }
blobmsg_for_each_attr(cur, tb[CONF_DEVICES], rem) {
dev = calloc(1, sizeof(*dev));
return NULL;
}
+static void
+parse_interface_config(libusb_device *dev, struct usbdev_data *data)
+{
+ struct libusb_config_descriptor *config;
+ const struct libusb_interface *iface;
+ const struct libusb_interface_descriptor *alt;
+ int i;
+
+ data->interface = -1;
+ if (libusb_get_config_descriptor(dev, 0, &config))
+ return;
+
+ data->config = config;
+ if (!config->bNumInterfaces)
+ return;
+
+ iface = &config->interface[0];
+ if (!iface->num_altsetting)
+ return;
+
+ alt = &iface->altsetting[0];
+ data->interface = alt->bInterfaceNumber;
+ data->dev_class = alt->bInterfaceClass;
+
+ for (i = 0; i < alt->bNumEndpoints; i++) {
+ const struct libusb_endpoint_descriptor *ep = &alt->endpoint[i];
+ bool out = false;
+
+ if (data->msg_endpoint && data->response_endpoint)
+ break;
+
+ if ((ep->bmAttributes & LIBUSB_TRANSFER_TYPE_MASK) !=
+ LIBUSB_TRANSFER_TYPE_BULK)
+ continue;
+
+ out = (ep->bEndpointAddress & LIBUSB_ENDPOINT_DIR_MASK) ==
+ LIBUSB_ENDPOINT_OUT;
+
+ if (!data->msg_endpoint && out)
+ data->msg_endpoint = ep->bEndpointAddress;
+ if (!data->response_endpoint && !out)
+ data->response_endpoint = ep->bEndpointAddress;
+ }
+}
+
static void iterate_devs(cmd_cb_t cb)
{
struct usbdev_data data;
if (libusb_open(usbdevs[i], &data.devh))
continue;
+ data.dev = usbdevs[i];
+
libusb_get_string_descriptor_ascii(
data.devh, data.desc.iManufacturer,
(void *) data.mfg, sizeof(data.mfg));
data.devh, data.desc.iSerialNumber,
(void *) data.serial, sizeof(data.serial));
+ parse_interface_config(usbdevs[i], &data);
+
data.info = find_dev_data(&data, dev);
if (data.info)
cb(&data);
- libusb_close(data.devh);
+
+ if (data.config)
+ libusb_free_config_descriptor(data.config);
+
+ if (data.devh)
+ libusb_close(data.devh);
}
}