X-Git-Url: https://sigrok.org/gitweb/?p=libsigrok.git;a=blobdiff_plain;f=src%2Fhardware%2Fasix-sigma%2Fapi.c;h=388148725d852eeb1e142c6b9acf98d3c8041445;hp=77e989a934e9a04a0414922dde14bfbafb361eb5;hb=5e78a56481769db6ffe9b9fd392d71be3fcf0319;hpb=c01bf34ca264b268fee2e71ab918c71d28dc3018 diff --git a/src/hardware/asix-sigma/api.c b/src/hardware/asix-sigma/api.c index 77e989a9..38814872 100644 --- a/src/hardware/asix-sigma/api.c +++ b/src/hardware/asix-sigma/api.c @@ -19,15 +19,9 @@ * along with this program. If not, see . */ -/* - * ASIX SIGMA/SIGMA2 logic analyzer driver - */ - #include #include "protocol.h" -SR_PRIV struct sr_dev_driver asix_sigma_driver_info; - /* * Channel numbers seem to go from 1-16, according to this image: * http://tools.asix.net/img/sigma_sigmacab_pins_720.jpg @@ -38,132 +32,248 @@ static const char *channel_names[] = { "9", "10", "11", "12", "13", "14", "15", "16", }; +static const uint32_t scanopts[] = { + SR_CONF_CONN, +}; + static const uint32_t drvopts[] = { SR_CONF_LOGIC_ANALYZER, }; static const uint32_t devopts[] = { SR_CONF_LIMIT_MSEC | SR_CONF_GET | SR_CONF_SET, - SR_CONF_LIMIT_SAMPLES | SR_CONF_SET, + SR_CONF_LIMIT_SAMPLES | SR_CONF_GET | SR_CONF_SET, + SR_CONF_CONN | SR_CONF_GET, SR_CONF_SAMPLERATE | SR_CONF_GET | SR_CONF_SET | SR_CONF_LIST, +#if ASIX_SIGMA_WITH_TRIGGER SR_CONF_TRIGGER_MATCH | SR_CONF_LIST, SR_CONF_CAPTURE_RATIO | SR_CONF_GET | SR_CONF_SET, +#endif }; +#if ASIX_SIGMA_WITH_TRIGGER static const int32_t trigger_matches[] = { SR_TRIGGER_ZERO, SR_TRIGGER_ONE, SR_TRIGGER_RISING, SR_TRIGGER_FALLING, }; +#endif +static void clear_helper(struct dev_context *devc) +{ + ftdi_deinit(&devc->ftdic); +} static int dev_clear(const struct sr_dev_driver *di) { - return std_dev_clear(di, sigma_clear_helper); + return std_dev_clear_with_callback(di, (std_dev_clear_callback)clear_helper); } -static int init(struct sr_dev_driver *di, struct sr_context *sr_ctx) +static gboolean bus_addr_in_devices(int bus, int addr, GSList *devs) { - return std_init(sr_ctx, di, LOG_PREFIX); + struct sr_usb_dev_inst *usb; + + for (/* EMPTY */; devs; devs = devs->next) { + usb = devs->data; + if (usb->bus == bus && usb->address == addr) + return TRUE; + } + + return FALSE; +} + +static gboolean known_vid_pid(const struct libusb_device_descriptor *des) +{ + if (des->idVendor != USB_VENDOR_ASIX) + return FALSE; + if (des->idProduct != USB_PRODUCT_SIGMA && des->idProduct != USB_PRODUCT_OMEGA) + return FALSE; + return TRUE; } static GSList *scan(struct sr_dev_driver *di, GSList *options) { - struct sr_dev_inst *sdi; struct drv_context *drvc; - struct dev_context *devc; + libusb_context *usbctx; + const char *conn; + GSList *l, *conn_devices; + struct sr_config *src; GSList *devices; - struct ftdi_device_list *devlist; - char serial_txt[10]; - uint32_t serial; + libusb_device **devlist, *devitem; + int bus, addr; + struct libusb_device_descriptor des; + struct libusb_device_handle *hdl; int ret; - unsigned int i; - - (void)options; + char conn_id[20]; + char serno_txt[16]; + char *end; + long serno_num, serno_pre; + enum asix_device_type dev_type; + const char *dev_text; + struct sr_dev_inst *sdi; + struct dev_context *devc; + size_t devidx, chidx; drvc = di->context; + usbctx = drvc->sr_ctx->libusb_ctx; + + /* Find all devices which match an (optional) conn= spec. */ + conn = NULL; + for (l = options; l; l = l->next) { + src = l->data; + switch (src->key) { + case SR_CONF_CONN: + conn = g_variant_get_string(src->data, NULL); + break; + } + } + conn_devices = NULL; + if (conn) + conn_devices = sr_usb_find(usbctx, conn); + if (conn && !conn_devices) + return NULL; + /* Find all ASIX logic analyzers (which match the connection spec). */ devices = NULL; + libusb_get_device_list(usbctx, &devlist); + for (devidx = 0; devlist[devidx]; devidx++) { + devitem = devlist[devidx]; - devc = g_malloc0(sizeof(struct dev_context)); - - ftdi_init(&devc->ftdic); + /* Check for connection match if a user spec was given. */ + bus = libusb_get_bus_number(devitem); + addr = libusb_get_device_address(devitem); + if (conn && !bus_addr_in_devices(bus, addr, conn_devices)) + continue; + snprintf(conn_id, sizeof(conn_id), "%d.%d", bus, addr); - /* Look for SIGMAs. */ - - if ((ret = ftdi_usb_find_all(&devc->ftdic, &devlist, - USB_VENDOR, USB_PRODUCT)) <= 0) { - if (ret < 0) - sr_err("ftdi_usb_find_all(): %d", ret); - goto free; - } - - /* Make sure it's a version 1 or 2 SIGMA. */ - ftdi_usb_get_strings(&devc->ftdic, devlist->dev, NULL, 0, NULL, 0, - serial_txt, sizeof(serial_txt)); - sscanf(serial_txt, "%x", &serial); + /* + * Check for known VID:PID pairs. Get the serial number, + * to then derive the device type from it. + */ + libusb_get_device_descriptor(devitem, &des); + if (!known_vid_pid(&des)) + continue; + if (!des.iSerialNumber) { + sr_warn("Cannot get serial number (index 0)."); + continue; + } + ret = libusb_open(devitem, &hdl); + if (ret < 0) { + sr_warn("Cannot open USB device %04x.%04x: %s.", + des.idVendor, des.idProduct, + libusb_error_name(ret)); + continue; + } + ret = libusb_get_string_descriptor_ascii(hdl, + des.iSerialNumber, + (unsigned char *)serno_txt, sizeof(serno_txt)); + if (ret < 0) { + sr_warn("Cannot get serial number (%s).", + libusb_error_name(ret)); + libusb_close(hdl); + continue; + } + libusb_close(hdl); - if (serial < 0xa6010000 || serial > 0xa602ffff) { - sr_err("Only SIGMA and SIGMA2 are supported " - "in this version of libsigrok."); - goto free; + /* + * All ASIX logic analyzers have a serial number, which + * reads as a hex number, and tells the device type. + */ + ret = sr_atol_base(serno_txt, &serno_num, &end, 16); + if (ret != SR_OK || !end || *end) { + sr_warn("Cannot interpret serial number %s.", serno_txt); + continue; + } + dev_type = ASIX_TYPE_NONE; + dev_text = NULL; + serno_pre = serno_num >> 16; + switch (serno_pre) { + case 0xa601: + dev_type = ASIX_TYPE_SIGMA; + dev_text = "SIGMA"; + sr_info("Found SIGMA, serno %s.", serno_txt); + break; + case 0xa602: + dev_type = ASIX_TYPE_SIGMA; + dev_text = "SIGMA2"; + sr_info("Found SIGMA2, serno %s.", serno_txt); + break; + case 0xa603: + dev_type = ASIX_TYPE_OMEGA; + dev_text = "OMEGA"; + sr_info("Found OMEGA, serno %s.", serno_txt); + if (!ASIX_WITH_OMEGA) { + sr_warn("OMEGA support is not implemented yet."); + continue; + } + break; + default: + sr_warn("Unknown serno %s, skipping.", serno_txt); + continue; + } + + /* Create a device instance, add it to the result set. */ + + sdi = g_malloc0(sizeof(*sdi)); + devices = g_slist_append(devices, sdi); + sdi->status = SR_ST_INITIALIZING; + sdi->vendor = g_strdup("ASIX"); + sdi->model = g_strdup(dev_text); + sdi->serial_num = g_strdup(serno_txt); + sdi->connection_id = g_strdup(conn_id); + for (chidx = 0; chidx < ARRAY_SIZE(channel_names); chidx++) + sr_channel_new(sdi, chidx, SR_CHANNEL_LOGIC, + TRUE, channel_names[chidx]); + + devc = g_malloc0(sizeof(*devc)); + sdi->priv = devc; + devc->id.vid = des.idVendor; + devc->id.pid = des.idProduct; + devc->id.serno = serno_num; + devc->id.prefix = serno_pre; + devc->id.type = dev_type; + devc->samplerate = samplerates[0]; + sr_sw_limits_init(&devc->cfg_limits); + devc->cur_firmware = -1; + devc->capture_ratio = 50; + devc->use_triggers = 0; } + libusb_free_device_list(devlist, 1); + g_slist_free_full(conn_devices, (GDestroyNotify)sr_usb_dev_inst_free); - sr_info("Found ASIX SIGMA - Serial: %s", serial_txt); - - devc->cur_samplerate = samplerates[0]; - devc->period_ps = 0; - devc->limit_msec = 0; - devc->cur_firmware = -1; - devc->num_channels = 0; - devc->samples_per_event = 0; - devc->capture_ratio = 50; - devc->use_triggers = 0; - - /* Register SIGMA device. */ - sdi = g_malloc0(sizeof(struct sr_dev_inst)); - sdi->status = SR_ST_INITIALIZING; - sdi->vendor = g_strdup(USB_VENDOR_NAME); - sdi->model = g_strdup(USB_MODEL_NAME); - sdi->driver = di; - - for (i = 0; i < ARRAY_SIZE(channel_names); i++) - sr_channel_new(sdi, i, SR_CHANNEL_LOGIC, TRUE, channel_names[i]); - - devices = g_slist_append(devices, sdi); - drvc->instances = g_slist_append(drvc->instances, sdi); - sdi->priv = devc; - - /* We will open the device again when we need it. */ - ftdi_list_free(&devlist); - - return devices; - -free: - ftdi_deinit(&devc->ftdic); - g_free(devc); - return NULL; + return std_scan_complete(di, devices); } static int dev_open(struct sr_dev_inst *sdi) { struct dev_context *devc; + long vid, pid; + const char *serno; int ret; devc = sdi->priv; - /* Make sure it's an ASIX SIGMA. */ - if ((ret = ftdi_usb_open_desc(&devc->ftdic, - USB_VENDOR, USB_PRODUCT, USB_DESCRIPTION, NULL)) < 0) { - - sr_err("ftdi_usb_open failed: %s", - ftdi_get_error_string(&devc->ftdic)); - - return 0; + if (devc->id.type == ASIX_TYPE_OMEGA && !ASIX_WITH_OMEGA) { + sr_err("OMEGA support is not implemented yet."); + return SR_ERR_NA; + } + vid = devc->id.vid; + pid = devc->id.pid; + serno = sdi->serial_num; + + ret = ftdi_init(&devc->ftdic); + if (ret < 0) { + sr_err("Cannot initialize FTDI context (%d): %s.", + ret, ftdi_get_error_string(&devc->ftdic)); + return SR_ERR_IO; + } + ret = ftdi_usb_open_desc_index(&devc->ftdic, vid, pid, NULL, serno, 0); + if (ret < 0) { + sr_err("Cannot open device (%d): %s.", + ret, ftdi_get_error_string(&devc->ftdic)); + return SR_ERR_IO; } - - sdi->status = SR_ST_ACTIVE; return SR_OK; } @@ -171,20 +281,18 @@ static int dev_open(struct sr_dev_inst *sdi) static int dev_close(struct sr_dev_inst *sdi) { struct dev_context *devc; + int ret; devc = sdi->priv; - /* TODO */ - if (sdi->status == SR_ST_ACTIVE) - ftdi_usb_close(&devc->ftdic); - - sdi->status = SR_ST_INACTIVE; + ret = ftdi_usb_close(&devc->ftdic); + ftdi_deinit(&devc->ftdic); - return SR_OK; + return (ret == 0) ? SR_OK : SR_ERR; } -static int config_get(uint32_t key, GVariant **data, const struct sr_dev_inst *sdi, - const struct sr_channel_group *cg) +static int config_get(uint32_t key, GVariant **data, + const struct sr_dev_inst *sdi, const struct sr_channel_group *cg) { struct dev_context *devc; @@ -195,15 +303,20 @@ static int config_get(uint32_t key, GVariant **data, const struct sr_dev_inst *s devc = sdi->priv; switch (key) { + case SR_CONF_CONN: + *data = g_variant_new_string(sdi->connection_id); + break; case SR_CONF_SAMPLERATE: - *data = g_variant_new_uint64(devc->cur_samplerate); + *data = g_variant_new_uint64(devc->samplerate); break; case SR_CONF_LIMIT_MSEC: - *data = g_variant_new_uint64(devc->limit_msec); - break; + case SR_CONF_LIMIT_SAMPLES: + return sr_sw_limits_config_get(&devc->cfg_limits, key, data); +#if ASIX_SIGMA_WITH_TRIGGER case SR_CONF_CAPTURE_RATIO: *data = g_variant_new_uint64(devc->capture_ratio); break; +#endif default: return SR_ERR_NA; } @@ -211,79 +324,66 @@ static int config_get(uint32_t key, GVariant **data, const struct sr_dev_inst *s return SR_OK; } -static int config_set(uint32_t key, GVariant *data, const struct sr_dev_inst *sdi, - const struct sr_channel_group *cg) +static int config_set(uint32_t key, GVariant *data, + const struct sr_dev_inst *sdi, const struct sr_channel_group *cg) { struct dev_context *devc; - uint64_t tmp; int ret; + uint64_t want_rate, have_rate; (void)cg; - if (sdi->status != SR_ST_ACTIVE) - return SR_ERR_DEV_CLOSED; - devc = sdi->priv; - ret = SR_OK; switch (key) { case SR_CONF_SAMPLERATE: - ret = sigma_set_samplerate(sdi, g_variant_get_uint64(data)); + want_rate = g_variant_get_uint64(data); + ret = sigma_normalize_samplerate(want_rate, &have_rate); + if (ret != SR_OK) + return ret; + if (have_rate != want_rate) { + char *text_want, *text_have; + text_want = sr_samplerate_string(want_rate); + text_have = sr_samplerate_string(have_rate); + sr_info("Adjusted samplerate %s to %s.", + text_want, text_have); + g_free(text_want); + g_free(text_have); + } + devc->samplerate = have_rate; break; case SR_CONF_LIMIT_MSEC: - tmp = g_variant_get_uint64(data); - if (tmp > 0) - devc->limit_msec = g_variant_get_uint64(data); - else - ret = SR_ERR; - break; case SR_CONF_LIMIT_SAMPLES: - tmp = g_variant_get_uint64(data); - devc->limit_msec = tmp * 1000 / devc->cur_samplerate; - break; + return sr_sw_limits_config_set(&devc->cfg_limits, key, data); +#if ASIX_SIGMA_WITH_TRIGGER case SR_CONF_CAPTURE_RATIO: - tmp = g_variant_get_uint64(data); - if (tmp <= 100) - devc->capture_ratio = tmp; - else - ret = SR_ERR; + devc->capture_ratio = g_variant_get_uint64(data); break; +#endif default: - ret = SR_ERR_NA; + return SR_ERR_NA; } - return ret; + return SR_OK; } -static int config_list(uint32_t key, GVariant **data, const struct sr_dev_inst *sdi, - const struct sr_channel_group *cg) +static int config_list(uint32_t key, GVariant **data, + const struct sr_dev_inst *sdi, const struct sr_channel_group *cg) { - GVariant *gvar; - GVariantBuilder gvb; - - (void)cg; - switch (key) { + case SR_CONF_SCAN_OPTIONS: case SR_CONF_DEVICE_OPTIONS: - if (!sdi) - *data = g_variant_new_fixed_array(G_VARIANT_TYPE_UINT32, - drvopts, ARRAY_SIZE(drvopts), sizeof(uint32_t)); - else - *data = g_variant_new_fixed_array(G_VARIANT_TYPE_UINT32, - devopts, ARRAY_SIZE(devopts), sizeof(uint32_t)); - break; + if (cg) + return SR_ERR_NA; + return STD_CONFIG_LIST(key, data, sdi, cg, scanopts, drvopts, devopts); case SR_CONF_SAMPLERATE: - g_variant_builder_init(&gvb, G_VARIANT_TYPE("a{sv}")); - gvar = g_variant_new_fixed_array(G_VARIANT_TYPE("t"), samplerates, - SAMPLERATES_COUNT, sizeof(uint64_t)); - g_variant_builder_add(&gvb, "{sv}", "samplerates", gvar); - *data = g_variant_builder_end(&gvb); + *data = std_gvar_samplerates(samplerates, samplerates_count); break; +#if ASIX_SIGMA_WITH_TRIGGER case SR_CONF_TRIGGER_MATCH: - *data = g_variant_new_fixed_array(G_VARIANT_TYPE_INT32, - trigger_matches, ARRAY_SIZE(trigger_matches), - sizeof(int32_t)); + *data = std_gvar_array_i32(ARRAY_AND_SIZE(trigger_matches)); break; +#endif default: return SR_ERR_NA; } @@ -295,33 +395,44 @@ static int dev_acquisition_start(const struct sr_dev_inst *sdi) { struct dev_context *devc; struct clockselect_50 clockselect; - int frac, triggerpin, ret; - uint8_t triggerselect = 0; + int triggerpin, ret; + uint8_t triggerselect; struct triggerinout triggerinout_conf; struct triggerlut lut; - - if (sdi->status != SR_ST_ACTIVE) - return SR_ERR_DEV_CLOSED; + uint8_t regval; + uint8_t clock_bytes[sizeof(clockselect)]; + size_t clock_idx; devc = sdi->priv; + /* + * Setup the device's samplerate from the value which up to now + * just got checked and stored. As a byproduct this can pick and + * send firmware to the device, reduce the number of available + * logic channels, etc. + * + * Determine an acquisition timeout from optionally configured + * sample count or time limits. Which depends on the samplerate. + */ + ret = sigma_set_samplerate(sdi); + if (ret != SR_OK) + return ret; + ret = sigma_set_acquire_timeout(devc); + if (ret != SR_OK) + return ret; + if (sigma_convert_trigger(sdi) != SR_OK) { sr_err("Failed to configure triggers."); return SR_ERR; } - /* If the samplerate has not been set, default to 200 kHz. */ - if (devc->cur_firmware == -1) { - if ((ret = sigma_set_samplerate(sdi, SR_KHZ(200))) != SR_OK) - return ret; - } - /* Enter trigger programming mode. */ - sigma_set_register(WRITE_TRIGGER_SELECT1, 0x20, devc); + sigma_set_register(WRITE_TRIGGER_SELECT2, 0x20, devc); - /* 100 and 200 MHz mode. */ - if (devc->cur_samplerate >= SR_MHZ(100)) { - sigma_set_register(WRITE_TRIGGER_SELECT1, 0x81, devc); + triggerselect = 0; + if (devc->samplerate >= SR_MHZ(100)) { + /* 100 and 200 MHz mode. */ + sigma_set_register(WRITE_TRIGGER_SELECT2, 0x81, devc); /* Find which pin to trigger on from mask. */ for (triggerpin = 0; triggerpin < 8; triggerpin++) @@ -336,8 +447,8 @@ static int dev_acquisition_start(const struct sr_dev_inst *sdi) if (devc->trigger.fallingmask) triggerselect |= 1 << 3; - /* All other modes. */ - } else if (devc->cur_samplerate <= SR_MHZ(50)) { + } else if (devc->samplerate <= SR_MHZ(50)) { + /* All other modes. */ sigma_build_basic_trigger(&lut, devc); sigma_write_trigger_lut(&lut, devc); @@ -355,40 +466,47 @@ static int dev_acquisition_start(const struct sr_dev_inst *sdi) sizeof(struct triggerinout), devc); /* Go back to normal mode. */ - sigma_set_register(WRITE_TRIGGER_SELECT1, triggerselect, devc); + sigma_set_register(WRITE_TRIGGER_SELECT2, triggerselect, devc); /* Set clock select register. */ - if (devc->cur_samplerate == SR_MHZ(200)) + clockselect.async = 0; + clockselect.fraction = 1 - 1; /* Divider 1. */ + clockselect.disabled_channels = 0x0000; /* All channels enabled. */ + if (devc->samplerate == SR_MHZ(200)) { /* Enable 4 channels. */ - sigma_set_register(WRITE_CLOCK_SELECT, 0xf0, devc); - else if (devc->cur_samplerate == SR_MHZ(100)) + clockselect.disabled_channels = 0xf0ff; + } else if (devc->samplerate == SR_MHZ(100)) { /* Enable 8 channels. */ - sigma_set_register(WRITE_CLOCK_SELECT, 0x00, devc); - else { + clockselect.disabled_channels = 0x00ff; + } else { /* - * 50 MHz mode (or fraction thereof). Any fraction down to - * 50 MHz / 256 can be used, but is not supported by sigrok API. + * 50 MHz mode, or fraction thereof. The 50MHz reference + * can get divided by any integer in the range 1 to 256. + * Divider minus 1 gets written to the hardware. + * (The driver lists a discrete set of sample rates, but + * all of them fit the above description.) */ - frac = SR_MHZ(50) / devc->cur_samplerate - 1; - - clockselect.async = 0; - clockselect.fraction = frac; - clockselect.disabled_channels = 0; - - sigma_write_register(WRITE_CLOCK_SELECT, - (uint8_t *) &clockselect, - sizeof(clockselect), devc); + clockselect.fraction = SR_MHZ(50) / devc->samplerate - 1; } + clock_idx = 0; + clock_bytes[clock_idx++] = clockselect.async; + clock_bytes[clock_idx++] = clockselect.fraction; + clock_bytes[clock_idx++] = clockselect.disabled_channels & 0xff; + clock_bytes[clock_idx++] = clockselect.disabled_channels >> 8; + sigma_write_register(WRITE_CLOCK_SELECT, clock_bytes, clock_idx, devc); /* Setup maximum post trigger time. */ sigma_set_register(WRITE_POST_TRIGGER, (devc->capture_ratio * 255) / 100, devc); /* Start acqusition. */ - gettimeofday(&devc->start_tv, 0); - sigma_set_register(WRITE_MODE, 0x0d, devc); + regval = WMR_TRGRES | WMR_SDRAMWRITEEN; +#if ASIX_SIGMA_WITH_TRIGGER + regval |= WMR_TRGEN; +#endif + sigma_set_register(WRITE_MODE, regval, devc); - std_session_send_df_header(sdi, LOG_PREFIX); + std_session_send_df_header(sdi); /* Add capture source. */ sr_session_source_add(sdi->session, -1, 0, 10, sigma_receive_data, (void *)sdi); @@ -403,18 +521,29 @@ static int dev_acquisition_stop(struct sr_dev_inst *sdi) struct dev_context *devc; devc = sdi->priv; - devc->state.state = SIGMA_IDLE; - sr_session_source_remove(sdi->session, -1); + /* + * When acquisition is currently running, keep the receive + * routine registered and have it stop the acquisition upon the + * next invocation. Else unregister the receive routine here + * already. The detour is required to have sample data retrieved + * for forced acquisition stops. + */ + if (devc->state.state == SIGMA_CAPTURE) { + devc->state.state = SIGMA_STOPPING; + } else { + devc->state.state = SIGMA_IDLE; + sr_session_source_remove(sdi->session, -1); + } return SR_OK; } -SR_PRIV struct sr_dev_driver asix_sigma_driver_info = { +static struct sr_dev_driver asix_sigma_driver_info = { .name = "asix-sigma", .longname = "ASIX SIGMA/SIGMA2", .api_version = 1, - .init = init, + .init = std_init, .cleanup = std_cleanup, .scan = scan, .dev_list = std_dev_list, @@ -428,3 +557,4 @@ SR_PRIV struct sr_dev_driver asix_sigma_driver_info = { .dev_acquisition_stop = dev_acquisition_stop, .context = NULL, }; +SR_REGISTER_DEV_DRIVER(asix_sigma_driver_info);