diff options
Diffstat (limited to 'Radio/HW/BladeRF/src/devinfo.c')
-rw-r--r-- | Radio/HW/BladeRF/src/devinfo.c | 420 |
1 files changed, 420 insertions, 0 deletions
diff --git a/Radio/HW/BladeRF/src/devinfo.c b/Radio/HW/BladeRF/src/devinfo.c new file mode 100644 index 0000000..cce70f8 --- /dev/null +++ b/Radio/HW/BladeRF/src/devinfo.c @@ -0,0 +1,420 @@ +/* + * This file is part of the bladeRF project: + * http://www.github.com/nuand/bladeRF + * + * Copyright (C) 2013 Nuand LLC + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include <string.h> +#include <ctype.h> +#include <limits.h> + +#include "libbladeRF.h" + +#include "rel_assert.h" + +#include "devinfo.h" +#include "conversions.h" +#include "log.h" + +/******************************************************************************/ +/* Device List Probe */ +/******************************************************************************/ + +int probe(backend_probe_target target_device, struct bladerf_devinfo **devices) +{ + int ret; + size_t num_devices; + struct bladerf_devinfo *devices_local; + int status; + + status = backend_probe(target_device, &devices_local, &num_devices); + + if (status < 0) { + ret = status; + } else { + assert(num_devices <= INT_MAX); + ret = (int)num_devices; + *devices = devices_local; + } + + return ret; +} + +int bladerf_get_device_list(struct bladerf_devinfo **devices) +{ + return probe(BACKEND_PROBE_BLADERF, devices); +} + +void bladerf_free_device_list(struct bladerf_devinfo *devices) +{ + /* Admittedly, we could just have the user call free() directly, + * but this creates a 1:1 pair of calls, and this gives us a spot + * to do any additional cleanup here, if ever needed in the future */ + free(devices); +} + +/******************************************************************************/ +/* Device Information Helpers */ +/******************************************************************************/ + +bool bladerf_instance_matches(const struct bladerf_devinfo *a, + const struct bladerf_devinfo *b) +{ + return a->instance == DEVINFO_INST_ANY || + b->instance == DEVINFO_INST_ANY || + a->instance == b->instance; +} + +bool bladerf_serial_matches(const struct bladerf_devinfo *a, + const struct bladerf_devinfo *b) +{ + /* User specified a "Any serial number" so just report a match */ + const bool wildcard_match = !strcmp(a->serial, DEVINFO_SERIAL_ANY) || + !strcmp(b->serial, DEVINFO_SERIAL_ANY); + + if (wildcard_match) { + return true; + } else { + /* The user-supplied serial number matches the a subset of the + * entire serial number, starting at the beginning. + * + * i.e., "abc01234" can be used to match "abc0123456789def..." + */ + bool subset_match = (strstr(a->serial, b->serial) == a->serial) || + (strstr(b->serial, a->serial) == b->serial); + + return subset_match; + } +} + +bool bladerf_bus_addr_matches(const struct bladerf_devinfo *a, + const struct bladerf_devinfo *b) +{ + bool bus_match, addr_match; + + bus_match = a->usb_bus == DEVINFO_BUS_ANY || + b->usb_bus == DEVINFO_BUS_ANY || + a->usb_bus == b->usb_bus; + + addr_match = a->usb_addr == DEVINFO_BUS_ANY || + b->usb_addr == DEVINFO_BUS_ANY || + a->usb_addr == b->usb_addr; + + return bus_match && addr_match; +} + +int bladerf_devinfo_list_init(struct bladerf_devinfo_list *list) +{ + int status = 0; + + list->num_elt = 0; + list->backing_size = 5; + + list->elt = malloc(list->backing_size * sizeof(struct bladerf_devinfo)); + + if (!list->elt) { + status = BLADERF_ERR_MEM; + } + + return status; +} + +int bladerf_devinfo_list_add(struct bladerf_devinfo_list *list, + struct bladerf_devinfo *info) +{ + int status = 0; + struct bladerf_devinfo *info_tmp; + + if (list->num_elt >= list->backing_size) { + info_tmp = realloc(list->elt, list->backing_size * 2 * sizeof(*list->elt)); + if (!info_tmp) { + status = BLADERF_ERR_MEM; + } else { + list->elt = info_tmp; + list->backing_size = list->backing_size * 2; + } + } + + if (status == 0) { + memcpy(&list->elt[list->num_elt], info, sizeof(*info)); + list->num_elt++; + } + + return status; +} + +void bladerf_init_devinfo(struct bladerf_devinfo *info) +{ + info->backend = BLADERF_BACKEND_ANY; + + memset(info->serial, 0, BLADERF_SERIAL_LENGTH); + strncpy(info->serial, DEVINFO_SERIAL_ANY, BLADERF_SERIAL_LENGTH - 1); + + info->usb_bus = DEVINFO_BUS_ANY; + info->usb_addr = DEVINFO_ADDR_ANY; + info->instance = DEVINFO_INST_ANY; + + memset(info->manufacturer, 0, BLADERF_DESCRIPTION_LENGTH); + strncpy(info->manufacturer, "<unknown>", BLADERF_DESCRIPTION_LENGTH - 1); + + memset(info->product, 0, BLADERF_DESCRIPTION_LENGTH); + strncpy(info->product, "<unknown>", BLADERF_DESCRIPTION_LENGTH - 1); +} + +bool bladerf_devinfo_matches(const struct bladerf_devinfo *a, + const struct bladerf_devinfo *b) +{ + return bladerf_instance_matches(a, b) && + bladerf_serial_matches(a, b) && + bladerf_bus_addr_matches(a ,b); +} + +bool bladerf_devstr_matches(const char *dev_str, + struct bladerf_devinfo *info) +{ + int status; + bool ret; + struct bladerf_devinfo from_str; + + status = str2devinfo(dev_str, &from_str); + if (status < 0) { + ret = false; + log_debug("Failed to parse device string: %s\n", + bladerf_strerror(status)); + } else { + ret = bladerf_devinfo_matches(&from_str, info); + } + + return ret; +} + +int bladerf_get_devinfo_from_str(const char *devstr, + struct bladerf_devinfo *info) +{ + return str2devinfo(devstr, info); +} + +/******************************************************************************/ +/* str2devinfo */ +/******************************************************************************/ + +#define DELIM_SPACE " \t\r\n\v\f" + +static int handle_backend(char *str, struct bladerf_devinfo *d) +{ + char *str_end; + + if (!str || strlen(str) == 0) { + return BLADERF_ERR_INVAL; + } + + /* Gobble up any leading whitespace */ + while (*str && isspace((unsigned char) *str)) { + str++; + }; + + /* Likewise for trailing whitespace */ + str_end = str + strlen(str) - 1; + while (str_end > str && isspace((unsigned char) *str_end)) { str_end--; }; + str_end[1] = '\0'; + + return str2backend(str, &d->backend); +} + +static int handle_device(struct bladerf_devinfo *d, char *value) +{ + int status = BLADERF_ERR_INVAL; + bool bus_ok, addr_ok; + char *bus = value; + char *addr = strchr(value, ':'); + + if (addr && addr[1] != '\0') { + /* Null-terminate bus and set addr to start of addr text */ + *addr = '\0'; + addr++; + + d->usb_bus = str2uint(bus, 0, DEVINFO_BUS_ANY - 1, &bus_ok); + d->usb_addr = str2uint(addr, 0, DEVINFO_ADDR_ANY - 1, &addr_ok); + + if (bus_ok && addr_ok) { + status = 0; + log_debug("Device: %d:%d\n", d->usb_bus, d->usb_addr); + } else { + log_debug("Bad bus (%s) or address (%s)\n", bus, addr); + } + } + + return status; +} + +static int handle_instance(struct bladerf_devinfo *d, char *value) +{ + bool ok; + + if (value == NULL) { + return BLADERF_ERR_INVAL; + } + + d->instance = str2uint(value, 0, DEVINFO_INST_ANY - 1, &ok); + if (!ok) { + log_debug("Bad instance: %s\n", value); + return BLADERF_ERR_INVAL; + } else { + log_debug("Instance: %u\n", d->instance); + return 0; + } +} + +static int handle_serial(struct bladerf_devinfo *d, char *value) +{ + char c; + size_t i; + size_t len; + + if (value == NULL) { + return BLADERF_ERR_INVAL; + } + + len = strlen(value); + if (len > (BLADERF_SERIAL_LENGTH - 1)) { + log_debug("Provided serial # string too long: %"PRIu64"\n", + (uint64_t) len); + + return BLADERF_ERR_INVAL; + } + + for (i = 0; i < len; i++) { + c = value[i]; + if (c >= 'A' && c <='F') { + value[i] = tolower((unsigned char) c); + } + + if ((c < 'a' || c > 'f') && (c < '0' || c > '9')) { + log_debug("Bad serial: %s\n", value); + return BLADERF_ERR_INVAL; + } + } + + strncpy(d->serial, value, sizeof(d->serial)); + d->serial[sizeof(d->serial) - 1] = '\0'; + + if (len == (BLADERF_SERIAL_LENGTH - 1)) { + log_verbose("Requested serial number: %s\n", d->serial); + } else { + log_verbose("Requested serial number subset: %s\n", d->serial); + } + return 0; +} + +/* Returns: 1 on arg and value populated + * 0 on no args left + * BLADERF_ERR_INVAL on bad format + */ + +static int next_arg(char **saveptr, char **arg, char **value) +{ + char *saveptr_local; + char *token = strtok_r(NULL, DELIM_SPACE, saveptr); + + /* No arguments left */ + if (!token) { + return 0; + } + + /* Argument name */ + *arg = strtok_r(token, "=", &saveptr_local); + + if (!*arg) { + *value = NULL; + return BLADERF_ERR_INVAL; + } + + /* Argument value - gobble up the rest of the line*/ + *value = strtok_r(NULL, "", &saveptr_local); + + if (!*value) { + return BLADERF_ERR_INVAL; + } + + return 1; +} + +int str2devinfo(const char *dev_id_const, struct bladerf_devinfo *d) +{ + char *dev_id = NULL; + char *token = NULL; + char *arg = NULL; + char *val = NULL; + char *saveptr = NULL; + int status = BLADERF_ERR_UNEXPECTED; + int arg_status = BLADERF_ERR_UNEXPECTED; + + assert(d); + + /* Prep our device info before we begin manpulating it, defaulting to + * a "wildcard" device indentification */ + bladerf_init_devinfo(d); + + /* No device indentifier -- pick anything we can find */ + if (dev_id_const == NULL || strlen(dev_id_const) == 0) { + return 0; + } + + /* Copy the string so we can butcher it a bit while parsing */ + dev_id = strdup(dev_id_const); + if (!dev_id) { + return BLADERF_ERR_MEM; + } + + /* Extract backend */ + token = strtok_r(dev_id, ":", &saveptr); + + /* We require a valid backend -- args only is not supported */ + if (token) { + status = handle_backend(token, d); + + /* Loop over remainder of string, gathering up args */ + arg_status = 1; + while (arg_status == 1 && status == 0) { + arg_status = next_arg(&saveptr, &arg, &val); + if (arg_status == 1) { + + /* Handle argument if we can */ + if (!strcasecmp("device", arg)) { + status = handle_device(d, val); + } else if (!strcasecmp("instance", arg)) { + status = handle_instance(d, val); + } else if (!strcasecmp("serial", arg)) { + status = handle_serial(d, val); + } else { + arg_status = BLADERF_ERR_INVAL; + } + } + }; + + if (arg_status < 0) { + status = arg_status; + } + + } else { + status = BLADERF_ERR_INVAL; + } + + free(dev_id); + return status; +} |