X-Git-Url: http://sigrok.org/gitweb/?a=blobdiff_plain;f=hardware%2Fgenericdmm%2Fapi.c;h=e83bce16ea967b18da4ca37c0f9bced91fba107c;hb=19b0cce3125f08f961886fb312219c7c6f496ffc;hp=5c868a4db137a68b42ee4d536972f8fc8ef3fd26;hpb=301a5e4c4ade2f640eeb532195e6e84dee81783c;p=libsigrok.git diff --git a/hardware/genericdmm/api.c b/hardware/genericdmm/api.c index 5c868a4d..e83bce16 100644 --- a/hardware/genericdmm/api.c +++ b/hardware/genericdmm/api.c @@ -28,17 +28,18 @@ extern SR_PRIV struct dmmchip dmmchip_fs9922; +extern SR_PRIV struct dmmchip dmmchip_victor70c; 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, - DMM_TRANSPORT_USBHID, victor_70c_vidpid + { "victor-70c", "Victor", "70C", &dmmchip_victor70c, + DMM_TRANSPORT_USBHID, 1000, victor_70c_vidpid }, - { "mastech-va18b", "Mastech", "VA18B", NULL, DMM_TRANSPORT_SERIAL, NULL}, - { NULL, NULL, NULL, NULL, 0, NULL } + { "mastech-va18b", "Mastech", "VA18B", NULL, DMM_TRANSPORT_SERIAL, 0, NULL}, + { NULL, NULL, NULL, NULL, 0, 0, NULL } }; static const int hwopts[] = { @@ -64,7 +65,9 @@ static const char *probe_names[] = { 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 libusb_context *genericdmm_usb_context = NULL; +static int hw_dev_acquisition_stop(const struct sr_dev_inst *sdi, + void *cb_data); static GSList *connect_usb(const char *conn) @@ -72,6 +75,7 @@ static GSList *connect_usb(const char *conn) struct sr_dev_inst *sdi; struct drv_context *drvc; struct dev_context *devc; + struct sr_probe *probe; libusb_device **devlist; struct libusb_device_descriptor des; GSList *devices; @@ -152,12 +156,15 @@ static GSList *connect_usb(const char *conn) } devcnt = g_slist_length(drvc->instances); - if (!(sdi = sr_dev_inst_new(devcnt, SR_ST_ACTIVE, + if (!(sdi = sr_dev_inst_new(devcnt, SR_ST_INACTIVE, NULL, NULL, NULL))) { sr_err("genericdmm: sr_dev_inst_new returned NULL."); return NULL; } sdi->priv = devc; + if (!(probe = sr_probe_new(0, SR_PROBE_ANALOG, TRUE, "P1"))) + return NULL; + sdi->probes = g_slist_append(sdi->probes, probe); devc->usb = sr_usb_dev_inst_new( libusb_get_bus_number(devlist[i]), libusb_get_device_address(devlist[i]), NULL); @@ -219,6 +226,97 @@ static GSList *default_scan(GSList *options) return devices; } +static int open_usb(struct sr_dev_inst *sdi) +{ + libusb_device **devlist; + struct libusb_device_descriptor des; + struct dev_context *devc; + int ret, tmp, cnt, i; + + devc = sdi->priv; + + if (sdi->status == SR_ST_ACTIVE) + /* already in use */ + return SR_ERR; + + cnt = libusb_get_device_list(genericdmm_usb_context, &devlist); + if (cnt < 0) { + sr_err("genericdmm: Failed to retrieve device list (%d)", cnt); + return SR_ERR; + } + + ret = SR_ERR; + for (i = 0; i < cnt; i++) { + if ((tmp = libusb_get_device_descriptor(devlist[i], &des))) { + sr_err("genericdmm: Failed to get device descriptor: %d.", tmp); + continue; + } + + if (libusb_get_bus_number(devlist[i]) != devc->usb->bus + || libusb_get_device_address(devlist[i]) != devc->usb->address) + /* this is not the one */ + continue; + + if ((tmp = libusb_open(devlist[i], &devc->usb->devhdl))) { + sr_err("genericdmm: Failed to open device: %d.", tmp); + break; + } + + sr_info("genericdmm: Opened device %s on %d.%d ", devc->profile->modelid, + devc->usb->bus, devc->usb->address); + ret = SR_OK; + break; + } + libusb_free_device_list(devlist, 1); + + return ret; +} + +static int clear_instances(void) +{ + GSList *l; + struct sr_dev_inst *sdi; + struct dev_context *devc; + struct drv_context *drvc; + + if (!(drvc = gdi->priv)) + return SR_OK; + + /* Properly close and free all devices. */ + for (l = drvc->instances; l; l = l->next) { + if (!(sdi = l->data)) { + /* Log error, but continue cleaning up the rest. */ + sr_err("genericdmm: sdi was NULL, continuing."); + continue; + } + if (!(devc = sdi->priv)) { + /* Log error, but continue cleaning up the rest. */ + sr_err("genericdmm: sdi->priv was NULL, continuing."); + continue; + } + + if (devc->profile) { + switch (devc->profile->transport) { + case DMM_TRANSPORT_USBHID: + sr_usb_dev_inst_free(devc->usb); + break; + case DMM_TRANSPORT_SERIAL: + if (devc->serial && devc->serial->fd != -1) + serial_close(devc->serial->fd); + sr_serial_dev_inst_free(devc->serial); + break; + } + } + + sr_dev_inst_free(sdi); + } + + g_slist_free(drvc->instances); + drvc->instances = NULL; + + return SR_OK; +} + static int hw_init(void) { struct drv_context *drvc; @@ -245,6 +343,7 @@ static GSList *hw_scan(GSList *options) struct dev_profile *pr, *profile; struct sr_dev_inst *sdi; struct drv_context *drvc; + struct dev_context *devc; const char *model; drvc = gdi->priv; @@ -325,6 +424,8 @@ static GSList *hw_scan(GSList *options) * or model. Do that now. */ sdi = l->data; + devc = sdi->priv; + devc->profile = profile; sdi->driver = gdi; if (!sdi->vendor) sdi->vendor = g_strdup(profile->vendor); @@ -338,36 +439,46 @@ static GSList *hw_scan(GSList *options) return devices; } +static GSList *hw_dev_list(void) +{ + struct drv_context *drvc; + + drvc = gdi->priv; + + return drvc->instances; +} + static int hw_dev_open(struct sr_dev_inst *sdi) { struct dev_context *devc; + int ret; if (!(devc = sdi->priv)) { sr_err("genericdmm: sdi->priv was NULL."); return SR_ERR_BUG; } - sr_dbg("genericdmm: Opening serial port '%s'.", devc->serial->port); - + ret = SR_OK; switch (devc->profile->transport) { case DMM_TRANSPORT_USBHID: - /* TODO */ + ret = open_usb(sdi); break; case DMM_TRANSPORT_SERIAL: - /* TODO: O_NONBLOCK? */ + sr_dbg("genericdmm: Opening serial port '%s'.", devc->serial->port); devc->serial->fd = serial_open(devc->serial->port, O_RDWR | O_NONBLOCK); if (devc->serial->fd == -1) { sr_err("genericdmm: Couldn't open serial port '%s'.", devc->serial->port); - return SR_ERR; + ret = SR_ERR; } // serial_set_params(devc->serial->fd, 2400, 8, 0, 1, 2); break; default: sr_err("No transport set."); + ret = SR_ERR; } - return SR_OK; + return ret; } static int hw_dev_close(struct sr_dev_inst *sdi) @@ -397,45 +508,8 @@ static int hw_dev_close(struct sr_dev_inst *sdi) static int hw_cleanup(void) { - GSList *l; - struct sr_dev_inst *sdi; - struct dev_context *devc; - struct drv_context *drvc; - if (!(drvc = gdi->priv)) - return SR_OK; - - /* Properly close and free all devices. */ - for (l = drvc->instances; l; l = l->next) { - if (!(sdi = l->data)) { - /* Log error, but continue cleaning up the rest. */ - sr_err("genericdmm: sdi was NULL, continuing."); - continue; - } - if (!(devc = sdi->priv)) { - /* Log error, but continue cleaning up the rest. */ - sr_err("genericdmm: sdi->priv was NULL, continuing."); - continue; - } - - if (devc->profile) { - switch (devc->profile->transport) { - case DMM_TRANSPORT_USBHID: - /* TODO */ - break; - case DMM_TRANSPORT_SERIAL: - if (devc->serial && devc->serial->fd != -1) - serial_close(devc->serial->fd); - sr_serial_dev_inst_free(devc->serial); - break; - } - } - - sr_dev_inst_free(sdi); - } - - g_slist_free(drvc->instances); - drvc->instances = NULL; + clear_instances(); if (genericdmm_usb_context) libusb_exit(genericdmm_usb_context); @@ -467,6 +541,7 @@ static int hw_info_get(int info_id, const void **data, case SR_DI_CUR_SAMPLERATE: /* TODO get rid of this */ *data = NULL; + return SR_ERR_ARG; break; default: /* Unknown device info ID. */ @@ -488,17 +563,18 @@ static int hw_dev_config_set(const struct sr_dev_inst *sdi, int hwcap, switch (hwcap) { case SR_HWCAP_LIMIT_MSEC: + /* TODO: not yet implemented */ if (*(const uint64_t *)value == 0) { sr_err("genericdmm: LIMIT_MSEC can't be 0."); return SR_ERR; } devc->limit_msec = *(const uint64_t *)value; - sr_dbg("genericdmm: Setting LIMIT_MSEC to %" PRIu64 ".", + sr_dbg("genericdmm: Setting time limit to %" PRIu64 "ms.", devc->limit_msec); break; case SR_HWCAP_LIMIT_SAMPLES: devc->limit_samples = *(const uint64_t *)value; - sr_dbg("genericdmm: Setting LIMIT_SAMPLES to %" PRIu64 ".", + sr_dbg("genericdmm: Setting sample limit to %" PRIu64 ".", devc->limit_samples); break; default: @@ -515,26 +591,28 @@ static int receive_data(int fd, int revents, void *cb_data) struct sr_dev_inst *sdi; struct dev_context *devc; + (void)revents; + if (!(sdi = cb_data)) - return FALSE; + return TRUE; if (!(devc = sdi->priv)) - return FALSE; - - if (revents != G_IO_IN) { - sr_err("genericdmm: No data?"); - return FALSE; - } + return TRUE; switch (devc->profile->transport) { case DMM_TRANSPORT_USBHID: - /* TODO */ + if (devc->profile->chip->data) + devc->profile->chip->data(sdi); break; case DMM_TRANSPORT_SERIAL: /* TODO */ + fd = fd; break; } + if (devc->num_samples >= devc->limit_samples) + hw_dev_acquisition_stop(sdi, cb_data); + return TRUE; } @@ -573,7 +651,14 @@ static int hw_dev_acquisition_start(const struct sr_dev_inst *sdi, /* Hook up a proxy handler to receive data from the device. */ switch (devc->profile->transport) { case DMM_TRANSPORT_USBHID: - /* TODO libusb FD setup */ + /* Callously using stdin here. This works because no G_IO_* flags + * are set, but will certainly break when any other driver does + * this, and runs at the same time as genericdmm. + * We'll need a timeout-only source when revamping the whole + * driver source system. + */ + sr_source_add(0, 0, devc->profile->poll_timeout, + receive_data, (void *)sdi); break; case DMM_TRANSPORT_SERIAL: /* TODO serial FD setup */ @@ -599,6 +684,8 @@ static int hw_dev_acquisition_stop(const struct sr_dev_inst *sdi, packet.type = SR_DF_END; sr_session_send(cb_data, &packet); + sr_source_remove(0); + return SR_OK; } @@ -609,6 +696,8 @@ SR_PRIV struct sr_dev_driver genericdmm_driver_info = { .init = hw_init, .cleanup = hw_cleanup, .scan = hw_scan, + .dev_list = hw_dev_list, + .dev_clear = clear_instances, .dev_open = hw_dev_open, .dev_close = hw_dev_close, .info_get = hw_info_get,