X-Git-Url: https://sigrok.org/gitweb/?a=blobdiff_plain;f=hardware%2Fgenericdmm%2Fapi.c;h=2dab4b876a89be44787f0621c83dc95640217348;hb=f8c617cf4c6b649d3456f1ca7082f6cfb6dac76d;hp=be05fb29282158a8e0013b751bf891da492f4a4d;hpb=ca3d84cca1d2f7427f8c5266717cb787d2346e16;p=libsigrok.git diff --git a/hardware/genericdmm/api.c b/hardware/genericdmm/api.c index be05fb29..2dab4b87 100644 --- a/hardware/genericdmm/api.c +++ b/hardware/genericdmm/api.c @@ -22,17 +22,30 @@ #include #include #include -#include "sigrok.h" -#include "sigrok-internal.h" +#include "libsigrok.h" +#include "libsigrok-internal.h" #include "genericdmm.h" extern SR_PRIV struct dmmchip dmmchip_fs9922; +static struct sr_hwopt victor_70c_vidpid[] = { + { SR_HWOPT_CONN, "1244.d237" }, + { 0, NULL } +}; static struct dev_profile dev_profiles[] = { { "victor-70c", "Victor", "70C", &dmmchip_fs9922, - 0x1244, 0xd237, DMM_TRANSPORT_USBHID }, - { "mastech-va18b", "Mastech", "VA18B", NULL, 0, 0, DMM_TRANSPORT_SERIAL}, + DMM_TRANSPORT_USBHID, victor_70c_vidpid + }, + { "mastech-va18b", "Mastech", "VA18B", NULL, DMM_TRANSPORT_SERIAL, NULL}, + { NULL, NULL, NULL, NULL, 0, NULL } +}; + +static const int hwopts[] = { + SR_HWOPT_MODEL, + SR_HWOPT_CONN, + SR_HWOPT_SERIALCOMM, + 0, }; static const int hwcaps[] = { @@ -40,9 +53,6 @@ static const int hwcaps[] = { SR_HWCAP_LIMIT_SAMPLES, SR_HWCAP_LIMIT_MSEC, SR_HWCAP_CONTINUOUS, - SR_HWCAP_MODEL, - SR_HWCAP_CONN, - SR_HWCAP_SERIALCOMM, 0, }; @@ -51,41 +61,268 @@ static const char *probe_names[] = { NULL, }; -/* TODO need a way to keep these local to the static library */ -SR_PRIV GSList *genericdmm_dev_insts = NULL; +SR_PRIV struct sr_dev_driver genericdmm_driver_info; +static struct sr_dev_driver *gdi = &genericdmm_driver_info; +/* TODO need a way to keep this local to the static library */ SR_PRIV libusb_context *genericdmm_usb_context = NULL; -static int hw_init(const char *devinfo) +static GSList *connect_usb(const char *conn) { struct sr_dev_inst *sdi; struct context *ctx; - int devcnt = 0; + libusb_device **devlist; + struct libusb_device_descriptor des; + GSList *devices; + GRegex *reg; + GMatchInfo *match; + int vid, pid, bus, addr, devcnt, err, i; + char *mstr; - /* Avoid compiler warnings. */ - (void)devinfo; + vid = pid = bus = addr = 0; + reg = g_regex_new(DMM_CONN_USB_VIDPID, 0, 0, NULL); + if (g_regex_match(reg, conn, 0, &match)) { + /* Extract VID. */ + if ((mstr = g_match_info_fetch(match, 1))) + vid = strtoul(mstr, NULL, 16); + g_free(mstr); + + /* Extract PID. */ + if ((mstr = g_match_info_fetch(match, 2))) + pid = strtoul(mstr, NULL, 16); + g_free(mstr); + } else { + g_match_info_unref(match); + g_regex_unref(reg); + reg = g_regex_new(DMM_CONN_USB_BUSADDR, 0, 0, NULL); + if (g_regex_match(reg, conn, 0, &match)) { + /* Extract bus. */ + if ((mstr = g_match_info_fetch(match, 0))) + bus = strtoul(mstr, NULL, 16); + g_free(mstr); + + /* Extract address. */ + if ((mstr = g_match_info_fetch(match, 0))) + addr = strtoul(mstr, NULL, 16); + g_free(mstr); + } + } + g_match_info_unref(match); + g_regex_unref(reg); + + if (vid + pid + bus + addr == 0) + return NULL; + + if (bus > 64) { + sr_err("invalid bus"); + return NULL; + } + + if (addr > 127) { + sr_err("invalid address"); + return NULL; + } + + /* Looks like a valid USB device specification, but is it connected? */ + devices = NULL; + libusb_get_device_list(genericdmm_usb_context, &devlist); + for (i = 0; devlist[i]; i++) { + if ((err = libusb_get_device_descriptor(devlist[i], &des))) { + sr_err("genericdmm: failed to get device descriptor: %d", err); + continue; + } + + if (vid + pid && (des.idVendor != vid || des.idProduct != pid)) + /* VID/PID specified, but no match. */ + continue; + + if (bus + addr && ( + libusb_get_bus_number(devlist[i]) != bus + || libusb_get_device_address(devlist[i]) != addr)) + /* Bus/address specified, but no match. */ + continue; + + /* Found one. */ + if (!(ctx = g_try_malloc0(sizeof(struct context)))) { + sr_err("genericdmm: ctx malloc failed."); + return 0; + } + + devcnt = g_slist_length(gdi->instances); + if (!(sdi = sr_dev_inst_new(devcnt, SR_ST_ACTIVE, + NULL, NULL, NULL))) { + sr_err("genericdmm: sr_dev_inst_new returned NULL."); + return NULL; + } + sdi->priv = ctx; + ctx->usb = sr_usb_dev_inst_new( + libusb_get_bus_number(devlist[i]), + libusb_get_device_address(devlist[i]), NULL); + devices = g_slist_append(devices, sdi); + } + libusb_free_device_list(devlist, 1); + + return devices; +} + +static GSList *connect_serial(const char *conn, const char *serialcomm) +{ + GSList *devices; + + devices = NULL; + + /* TODO */ + sr_dbg("not yet implemented"); + + return devices; +} + +GSList *genericdmm_connect(const char *conn, const char *serialcomm) +{ + GSList *devices; + + if (serialcomm) + /* Must be a serial port. */ + return connect_serial(conn, serialcomm); + + if ((devices = connect_usb(conn))) + return devices; + + return NULL; +} + +static GSList *default_scan(GSList *options) +{ + GSList *l, *devices; + struct sr_hwopt *opt; + const char *conn, *serialcomm; + + devices = NULL; + conn = serialcomm = NULL; + for (l = options; l; l = l->next) { + opt = l->data; + switch (opt->hwopt) { + case SR_HWOPT_CONN: + conn = opt->value; + break; + case SR_HWOPT_SERIALCOMM: + serialcomm = opt->value; + break; + } + } + if (conn) + devices = genericdmm_connect(conn, serialcomm); + + return devices; +} + +static int hw_init(void) +{ if (libusb_init(&genericdmm_usb_context) != 0) { sr_err("genericdmm: Failed to initialize USB."); - return 0; + return SR_ERR; } - if (!(ctx = g_try_malloc0(sizeof(struct context)))) { - sr_err("genericdmm: ctx malloc failed."); - return 0; + + return SR_OK; +} + +static GSList *hw_scan(GSList *options) +{ + GSList *l, *ldef, *defopts, *newopts, *devices; + struct sr_hwopt *opt, *defopt; + struct dev_profile *pr, *profile; + struct sr_dev_inst *sdi; + const char *model; + + /* Separate model from the options list. */ + model = NULL; + newopts = NULL; + for (l = options; l; l = l->next) { + opt = l->data; + if (opt->hwopt == SR_HWOPT_MODEL) + model = opt->value; + else + /* New list with references to the original data. */ + newopts = g_slist_append(newopts, opt); + } + if (!model) { + /* This driver only works when a model is specified. */ + return NULL; } - devcnt = g_slist_length(genericdmm_dev_insts); - if (!(sdi = sr_dev_inst_new(devcnt, SR_ST_ACTIVE, "Generic DMM", - NULL, NULL))) { - sr_err("genericdmm: sr_dev_inst_new returned NULL."); - return 0; + /* Find a profile with this model name. */ + profile = NULL; + for (pr = dev_profiles; pr->modelid; pr++) { + if (!strcmp(pr->modelid, model)) { + profile = pr; + break; + } + } + if (!profile) { + sr_err("Unknown model %s.", model); + return NULL; + } + + /* Initialize the DMM chip driver. */ + if (profile->chip->init) + profile->chip->init(); + + /* Convert the profile's default options list to a GSList. */ + defopts = NULL; + for (opt = profile->defaults_opts; opt->hwopt; opt++) { + /* New list with references to const data in the profile. */ + defopts = g_slist_append(defopts, opt); + } + + /* Options given as argument to this function override the + * profile's default options. + */ + for (ldef = defopts; ldef; ldef = ldef->next) { + defopt = ldef->data; + for (l = newopts; l; l = l->next) { + opt = l->data; + if (opt->hwopt == defopt->hwopt) { + /* Override the default, and drop it from the + * options list. + */ + ldef->data = l->data; + newopts = g_slist_remove(newopts, opt); + break; + } + } + } + /* Whatever is left in newopts wasn't in the default options. */ + defopts = g_slist_concat(defopts, newopts); + g_slist_free(newopts); + + if (profile->chip->scan) + /* The DMM chip driver wants to do its own scanning. */ + devices = profile->chip->scan(defopts); + else + devices = default_scan(defopts); + g_slist_free(defopts); + + if (devices) { + /* TODO: need to fix up sdi->index fields */ + for (l = devices; l; l = l->next) { + /* The default connection-based scanner doesn't really + * know about profiles, so it never filled in the vendor + * or model. Do that now. + */ + sdi = l->data; + sdi->driver = gdi; + if (!sdi->vendor) + sdi->vendor = g_strdup(profile->vendor); + if (!sdi->model) + sdi->model = g_strdup(profile->model); + /* Add a copy of these new devices to the driver instances. */ + gdi->instances = g_slist_append(gdi->instances, l->data); + } } - sdi->priv = ctx; - genericdmm_dev_insts = g_slist_append(genericdmm_dev_insts, sdi); - /* Always initialized just one device instance. */ - return 0; + return devices; } static int hw_dev_open(int dev_index) @@ -93,7 +330,7 @@ static int hw_dev_open(int dev_index) struct sr_dev_inst *sdi; struct context *ctx; - if (!(sdi = sr_dev_inst_get(genericdmm_dev_insts, dev_index))) { + if (!(sdi = sr_dev_inst_get(gdi->instances, dev_index))) { sr_err("genericdmm: sdi was NULL."); return SR_ERR_BUG; } @@ -131,7 +368,7 @@ static int hw_dev_close(int dev_index) struct sr_dev_inst *sdi; struct context *ctx; - if (!(sdi = sr_dev_inst_get(genericdmm_dev_insts, dev_index))) { + if (!(sdi = sr_dev_inst_get(gdi->instances, dev_index))) { sr_err("genericdmm: %s: sdi was NULL.", __func__); return SR_ERR_BUG; } @@ -166,7 +403,7 @@ static int hw_cleanup(void) struct context *ctx; /* Properly close and free all devices. */ - for (l = genericdmm_dev_insts; l; l = l->next) { + for (l = gdi->instances; l; l = l->next) { if (!(sdi = l->data)) { /* Log error, but continue cleaning up the rest. */ sr_err("genericdmm: sdi was NULL, continuing."); @@ -194,8 +431,8 @@ static int hw_cleanup(void) sr_dev_inst_free(sdi); } - g_slist_free(genericdmm_dev_insts); - genericdmm_dev_insts = NULL; + g_slist_free(gdi->instances); + gdi->instances = NULL; if (genericdmm_usb_context) libusb_exit(genericdmm_usb_context); @@ -203,58 +440,45 @@ static int hw_cleanup(void) return SR_OK; } -static const void *hw_dev_info_get(int dev_index, int dev_info_id) +static int hw_info_get(int dev_info_id, const void **data, + const struct sr_dev_inst *sdi) { - struct sr_dev_inst *sdi; struct context *ctx; - const void *info; - - if (!(sdi = sr_dev_inst_get(genericdmm_dev_insts, dev_index))) { - sr_err("genericdmm: sdi was NULL."); - return NULL; - } - - if (!(ctx = sdi->priv)) { - sr_err("genericdmm: sdi->priv was NULL."); - return NULL; - } - - sr_spew("genericdmm: dev_index %d, dev_info_id %d.", - dev_index, dev_info_id); switch (dev_info_id) { case SR_DI_INST: - info = sdi; + *data = sdi; sr_spew("genericdmm: Returning sdi."); break; + case SR_DI_HWOPTS: + *data = hwopts; + break; + case SR_DI_HWCAPS: + *data = hwcaps; + break; case SR_DI_NUM_PROBES: - info = GINT_TO_POINTER(1); - sr_spew("genericdmm: Returning number of probes: 1."); + *data = GINT_TO_POINTER(1); break; case SR_DI_PROBE_NAMES: - info = probe_names; - sr_spew("genericdmm: Returning probenames."); + *data = probe_names; break; case SR_DI_CUR_SAMPLERATE: /* TODO get rid of this */ - info = NULL; - sr_spew("genericdmm: Returning samplerate: 0."); + *data = NULL; break; default: /* Unknown device info ID. */ - sr_err("genericdmm: Unknown device info ID: %d.", dev_info_id); - info = NULL; - break; + return SR_ERR_ARG; } - return info; + return SR_OK; } static int hw_dev_status_get(int dev_index) { struct sr_dev_inst *sdi; - if (!(sdi = sr_dev_inst_get(genericdmm_dev_insts, dev_index))) { + if (!(sdi = sr_dev_inst_get(gdi->instances, dev_index))) { sr_err("genericdmm: sdi was NULL, device not found."); return SR_ST_NOT_FOUND; } @@ -264,188 +488,12 @@ static int hw_dev_status_get(int dev_index) return sdi->status; } -static const int *hw_hwcap_get_all(void) -{ - sr_spew("genericdmm: Returning list of device capabilities."); - - return hwcaps; -} - -static int parse_conn_vidpid(struct sr_dev_inst *sdi, const char *conn) -{ - struct context *ctx; - libusb_device **devlist; - struct libusb_device_descriptor des; - GRegex *reg; - GMatchInfo *match; - int vid, pid, found, err, i; - char *vidstr, *pidstr; - - found = FALSE; - - reg = g_regex_new(DMM_CONN_USB_VIDPID, 0, 0, NULL); - if (g_regex_match(reg, conn, 0, &match)) { - /* Extract VID. */ - if (!(vidstr = g_match_info_fetch(match, 0))) { - sr_err("failed to fetch VID from regex"); - goto err; - } - vid = strtoul(vidstr, NULL, 16); - g_free(vidstr); - if (vid > 0xffff) { - sr_err("invalid VID"); - goto err; - } - - /* Extract PID. */ - if (!(pidstr = g_match_info_fetch(match, 0))) { - sr_err("failed to fetch PID from regex"); - goto err; - } - pid = strtoul(pidstr, NULL, 16); - g_free(pidstr); - if (pid > 0xffff) { - sr_err("invalid PID"); - goto err; - } - - /* Looks like a valid VID:PID, but is it connected? */ - libusb_get_device_list(genericdmm_usb_context, &devlist); - for (i = 0; devlist[i]; i++) { - if ((err = libusb_get_device_descriptor(devlist[i], &des))) { - sr_err("genericdmm: failed to get device descriptor: %d", err); - goto err; - } - - if (des.idVendor == vid && des.idProduct == pid) { - ctx = sdi->priv; - ctx->usb = sr_usb_dev_inst_new( - libusb_get_bus_number(devlist[i]), - libusb_get_device_address(devlist[i]), NULL); - found = TRUE; - break; - } - } - libusb_free_device_list(devlist, 1); - } - -err: - if (match) - g_match_info_unref(match); - g_regex_unref(reg); - - return found; -} - -static int parse_conn_busaddr(struct sr_dev_inst *sdi, const char *conn) -{ - struct context *ctx; - libusb_device **devlist; - struct libusb_device_descriptor des; - GRegex *reg; - GMatchInfo *match; - int bus, addr, found, err, i; - char *busstr, *addrstr; - - found = FALSE; - - reg = g_regex_new(DMM_CONN_USB_BUSADDR, 0, 0, NULL); - if (g_regex_match(reg, conn, 0, &match)) { - /* Extract bus. */ - if (!(busstr = g_match_info_fetch(match, 0))) { - sr_err("failed to fetch bus from regex"); - goto err; - } - bus = strtoul(busstr, NULL, 16); - g_free(busstr); - if (bus > 64) { - sr_err("invalid bus"); - goto err; - } - - /* Extract address. */ - if (!(addrstr = g_match_info_fetch(match, 0))) { - sr_err("failed to fetch address from regex"); - goto err; - } - addr = strtoul(addrstr, NULL, 16); - g_free(addrstr); - if (addr > 127) { - sr_err("invalid address"); - goto err; - } - - /* Looks like a valid bus/address, but is it connected? */ - libusb_get_device_list(genericdmm_usb_context, &devlist); - for (i = 0; devlist[i]; i++) { - if ((err = libusb_get_device_descriptor(devlist[i], &des))) { - sr_err("genericdmm: failed to get device descriptor: %d", err); - goto err; - } - - if (libusb_get_bus_number(devlist[i]) == bus - && libusb_get_device_address(devlist[i]) == addr) { - ctx = sdi->priv; - ctx->usb = sr_usb_dev_inst_new(bus, addr, NULL); - found = TRUE; - break; - } - } - libusb_free_device_list(devlist, 1); - } - -err: - if (match) - g_match_info_unref(match); - g_regex_unref(reg); - - return found; -} - -static int parse_conn_serial(struct sr_dev_inst *sdi, const char *conn) -{ - int found; - - found = FALSE; - - /* TODO */ - - return found; -} - -static int parse_conn(struct sr_dev_inst *sdi, const char *conn) -{ - - if (parse_conn_vidpid(sdi, conn)) - return SR_OK; - - if (parse_conn_busaddr(sdi, conn)) - return SR_OK; - - if (parse_conn_serial(sdi, conn)) - return SR_OK; - - sr_err("Invalid connection specification"); - - return SR_ERR; -} - -static int parse_serialcomm(struct sr_dev_inst *sdi, const char *conn) -{ - - /* TODO */ - /* set ctx->serial_* */ - - return SR_OK; -} - static int hw_dev_config_set(int dev_index, int hwcap, const void *value) { struct sr_dev_inst *sdi; struct context *ctx; - int i; - if (!(sdi = sr_dev_inst_get(genericdmm_dev_insts, dev_index))) { + if (!(sdi = sr_dev_inst_get(gdi->instances, dev_index))) { sr_err("genericdmm: sdi was NULL."); return SR_ERR_BUG; } @@ -472,36 +520,6 @@ static int hw_dev_config_set(int dev_index, int hwcap, const void *value) sr_dbg("genericdmm: Setting LIMIT_SAMPLES to %" PRIu64 ".", ctx->limit_samples); break; - case SR_HWCAP_MODEL: - for (i = 0; dev_profiles[i].model; i++) { - if (!strcasecmp(dev_profiles[i].model, value)) { - ctx->profile = &dev_profiles[i]; - /* Frontends access these fields directly, so we - * need to copy them over. */ - sdi->vendor = g_strdup(dev_profiles[i].vendor); - sdi->model = g_strdup(dev_profiles[i].model); - /* This is the first time we actually know which - * DMM chip we're talking to, so let's init - * anything specific to it now */ - if (ctx->profile->chip->init) - if (ctx->profile->chip->init(ctx) != SR_OK) - return SR_ERR; - break; - } - } - if (!ctx->profile) { - sr_err("unknown model %s", value); - return SR_ERR; - } - break; - case SR_HWCAP_CONN: - if (parse_conn(sdi, value) != SR_OK) - return SR_ERR_ARG; - break; - case SR_HWCAP_SERIALCOMM: - if (parse_serialcomm(sdi, value) != SR_OK) - return SR_ERR_ARG; - break; default: sr_err("genericdmm: Unknown capability: %d.", hwcap); return SR_ERR; @@ -547,7 +565,7 @@ static int hw_dev_acquisition_start(int dev_index, void *cb_data) struct sr_dev_inst *sdi; struct context *ctx; - if (!(sdi = sr_dev_inst_get(genericdmm_dev_insts, dev_index))) { + if (!(sdi = sr_dev_inst_get(gdi->instances, dev_index))) { sr_err("genericdmm: sdi was NULL."); return SR_ERR_BUG; } @@ -613,12 +631,13 @@ SR_PRIV struct sr_dev_driver genericdmm_driver_info = { .api_version = 1, .init = hw_init, .cleanup = hw_cleanup, + .scan = hw_scan, .dev_open = hw_dev_open, .dev_close = hw_dev_close, - .dev_info_get = hw_dev_info_get, + .info_get = hw_info_get, .dev_status_get = hw_dev_status_get, - .hwcap_get_all = hw_hwcap_get_all, .dev_config_set = hw_dev_config_set, .dev_acquisition_start = hw_dev_acquisition_start, .dev_acquisition_stop = hw_dev_acquisition_stop, + .instances = NULL, };