X-Git-Url: https://sigrok.org/gitweb/?p=libsigrok.git;a=blobdiff_plain;f=src%2Fhardware%2Fasix-sigma%2Fapi.c;h=dcccb4240669dd37b60b0dfea58dc5bbfc838839;hp=88cb795cb41478ebda9716eb0f35455cf49c04f3;hb=HEAD;hpb=5c231fc466fac5da4b24f79a29af7a3fa0a10f76 diff --git a/src/hardware/asix-sigma/api.c b/src/hardware/asix-sigma/api.c index 88cb795c..f1b96bb7 100644 --- a/src/hardware/asix-sigma/api.c +++ b/src/hardware/asix-sigma/api.c @@ -24,9 +24,9 @@ #include "protocol.h" /* - * Channel numbers seem to go from 1-16, according to this image: - * http://tools.asix.net/img/sigma_sigmacab_pins_720.jpg - * (the cable has two additional GND pins, and a TI and TO pin) + * Channels are labelled 1-16, see this vendor's image of the cable: + * http://tools.asix.net/img/sigma_sigmacab_pins_720.jpg (TI/TO are + * additional trigger in/out signals). */ static const char *channel_names[] = { "1", "2", "3", "4", "5", "6", "7", "8", @@ -35,6 +35,7 @@ static const char *channel_names[] = { static const uint32_t scanopts[] = { SR_CONF_CONN, + SR_CONF_PROBE_NAMES, }; static const uint32_t drvopts[] = { @@ -46,24 +47,30 @@ static const uint32_t devopts[] = { 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_EXTERNAL_CLOCK | SR_CONF_GET | SR_CONF_SET, + SR_CONF_EXTERNAL_CLOCK_SOURCE | SR_CONF_GET | SR_CONF_SET | SR_CONF_LIST, + SR_CONF_CLOCK_EDGE | SR_CONF_GET | SR_CONF_SET | SR_CONF_LIST, SR_CONF_TRIGGER_MATCH | SR_CONF_LIST, SR_CONF_CAPTURE_RATIO | SR_CONF_GET | SR_CONF_SET, -#endif + /* Consider SR_CONF_TRIGGER_PATTERN (SR_T_STRING, GET/SET) support. */ +}; + +static const char *ext_clock_edges[] = { + [SIGMA_CLOCK_EDGE_RISING] = "rising", + [SIGMA_CLOCK_EDGE_FALLING] = "falling", + [SIGMA_CLOCK_EDGE_EITHER] = "either", }; -#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); + (void)sigma_force_close(devc); } static int dev_clear(const struct sr_dev_driver *di) @@ -103,6 +110,7 @@ static GSList *scan(struct sr_dev_driver *di, GSList *options) struct drv_context *drvc; libusb_context *usbctx; const char *conn; + const char *probe_names; GSList *l, *conn_devices; struct sr_config *src; GSList *devices; @@ -114,24 +122,29 @@ static GSList *scan(struct sr_dev_driver *di, GSList *options) char conn_id[20]; char serno_txt[16]; char *end; - long serno_num, serno_pre; + unsigned 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; + size_t count; drvc = di->context; usbctx = drvc->sr_ctx->libusb_ctx; /* Find all devices which match an (optional) conn= spec. */ conn = NULL; + probe_names = 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; + case SR_CONF_PROBE_NAMES: + probe_names = g_variant_get_string(src->data, NULL); + break; } } conn_devices = NULL; @@ -186,7 +199,7 @@ static GSList *scan(struct sr_dev_driver *di, GSList *options) * 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); + ret = sr_atoul_base(serno_txt, &serno_num, &end, 16); if (ret != SR_OK || !end || *end) { sr_warn("Cannot interpret serial number %s.", serno_txt); continue; @@ -228,22 +241,25 @@ static GSList *scan(struct sr_dev_driver *di, GSList *options) 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->channel_names = sr_parse_probe_names(probe_names, + channel_names, ARRAY_SIZE(channel_names), + ARRAY_SIZE(channel_names), &count); + for (chidx = 0; chidx < count; chidx++) + sr_channel_new(sdi, chidx, SR_CHANNEL_LOGIC, + TRUE, devc->channel_names[chidx]); 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->firmware_idx = SIGMA_FW_NONE; + sr_sw_limits_init(&devc->limit.config); devc->capture_ratio = 50; - devc->use_triggers = 0; + devc->use_triggers = FALSE; + + /* Get current hardware configuration (or use defaults). */ + (void)sigma_fetch_hw_config(sdi); } libusb_free_device_list(devlist, 1); g_slist_free_full(conn_devices, (GDestroyNotify)sr_usb_dev_inst_free); @@ -254,9 +270,6 @@ static GSList *scan(struct sr_dev_driver *di, GSList *options) static int dev_open(struct sr_dev_inst *sdi) { struct dev_context *devc; - long vid, pid; - const char *serno; - int ret; devc = sdi->priv; @@ -264,43 +277,24 @@ static int dev_open(struct sr_dev_inst *sdi) 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; - } - return SR_OK; + return sigma_force_open(sdi); } static int dev_close(struct sr_dev_inst *sdi) { struct dev_context *devc; - int ret; devc = sdi->priv; - ret = ftdi_usb_close(&devc->ftdic); - ftdi_deinit(&devc->ftdic); - - return (ret == 0) ? SR_OK : SR_ERR; + return sigma_force_close(devc); } 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; + const char *clock_text; (void)cg; @@ -313,16 +307,25 @@ static int config_get(uint32_t key, GVariant **data, *data = g_variant_new_string(sdi->connection_id); break; case SR_CONF_SAMPLERATE: - *data = g_variant_new_uint64(devc->samplerate); + *data = g_variant_new_uint64(devc->clock.samplerate); + break; + case SR_CONF_EXTERNAL_CLOCK: + *data = g_variant_new_boolean(devc->clock.use_ext_clock); + break; + case SR_CONF_EXTERNAL_CLOCK_SOURCE: + clock_text = devc->channel_names[devc->clock.clock_pin]; + *data = g_variant_new_string(clock_text); + break; + case SR_CONF_CLOCK_EDGE: + clock_text = ext_clock_edges[devc->clock.clock_edge]; + *data = g_variant_new_string(clock_text); break; case SR_CONF_LIMIT_MSEC: case SR_CONF_LIMIT_SAMPLES: - return sr_sw_limits_config_get(&devc->cfg_limits, key, data); -#if ASIX_SIGMA_WITH_TRIGGER + return sr_sw_limits_config_get(&devc->limit.config, key, data); case SR_CONF_CAPTURE_RATIO: *data = g_variant_new_uint64(devc->capture_ratio); break; -#endif default: return SR_ERR_NA; } @@ -336,6 +339,9 @@ static int config_set(uint32_t key, GVariant *data, struct dev_context *devc; int ret; uint64_t want_rate, have_rate; + const char **names; + size_t count; + int idx; (void)cg; @@ -356,16 +362,31 @@ static int config_set(uint32_t key, GVariant *data, g_free(text_want); g_free(text_have); } - devc->samplerate = have_rate; + devc->clock.samplerate = have_rate; + break; + case SR_CONF_EXTERNAL_CLOCK: + devc->clock.use_ext_clock = g_variant_get_boolean(data); + break; + case SR_CONF_EXTERNAL_CLOCK_SOURCE: + names = (const char **)devc->channel_names; + count = g_strv_length(devc->channel_names); + idx = std_str_idx(data, names, count); + if (idx < 0) + return SR_ERR_ARG; + devc->clock.clock_pin = idx; + break; + case SR_CONF_CLOCK_EDGE: + idx = std_str_idx(data, ARRAY_AND_SIZE(ext_clock_edges)); + if (idx < 0) + return SR_ERR_ARG; + devc->clock.clock_edge = idx; break; case SR_CONF_LIMIT_MSEC: case SR_CONF_LIMIT_SAMPLES: - return sr_sw_limits_config_set(&devc->cfg_limits, key, data); -#if ASIX_SIGMA_WITH_TRIGGER + return sr_sw_limits_config_set(&devc->limit.config, key, data); case SR_CONF_CAPTURE_RATIO: devc->capture_ratio = g_variant_get_uint64(data); break; -#endif default: return SR_ERR_NA; } @@ -376,6 +397,11 @@ static int config_set(uint32_t key, GVariant *data, static int config_list(uint32_t key, GVariant **data, const struct sr_dev_inst *sdi, const struct sr_channel_group *cg) { + struct dev_context *devc; + const char **names; + size_t count; + + devc = sdi ? sdi->priv : NULL; switch (key) { case SR_CONF_SCAN_OPTIONS: case SR_CONF_DEVICE_OPTIONS: @@ -384,13 +410,21 @@ static int config_list(uint32_t key, GVariant **data, return STD_CONFIG_LIST(key, data, sdi, cg, scanopts, drvopts, devopts); case SR_CONF_SAMPLERATE: - *data = std_gvar_samplerates(samplerates, samplerates_count); + *data = sigma_get_samplerates_list(); + break; + case SR_CONF_EXTERNAL_CLOCK_SOURCE: + if (!devc) + return SR_ERR_ARG; + names = (const char **)devc->channel_names; + count = g_strv_length(devc->channel_names); + *data = g_variant_new_strv(names, count); + break; + case SR_CONF_CLOCK_EDGE: + *data = g_variant_new_strv(ARRAY_AND_SIZE(ext_clock_edges)); break; -#if ASIX_SIGMA_WITH_TRIGGER case SR_CONF_TRIGGER_MATCH: *data = std_gvar_array_i32(ARRAY_AND_SIZE(trigger_matches)); break; -#endif default: return SR_ERR_NA; } @@ -401,16 +435,24 @@ static int config_list(uint32_t key, GVariant **data, static int dev_acquisition_start(const struct sr_dev_inst *sdi) { struct dev_context *devc; - struct clockselect_50 clockselect; - int triggerpin, ret; - uint8_t triggerselect; + uint16_t pindis_mask; + uint8_t async, div; + int ret; + size_t triggerpin; + uint8_t trigsel2; struct triggerinout triggerinout_conf; struct triggerlut lut; - uint8_t regval, trgconf_bytes[2], clock_bytes[4], *wrptr; - size_t count; + uint8_t regval, cmd_bytes[4], *wrptr; devc = sdi->priv; + /* Convert caller's trigger spec to driver's internal format. */ + ret = sigma_convert_trigger(sdi); + if (ret != SR_OK) { + sr_err("Could not configure triggers."); + return ret; + } + /* * Setup the device's samplerate from the value which up to now * just got checked and stored. As a byproduct this can pick and @@ -419,7 +461,13 @@ static int dev_acquisition_start(const struct sr_dev_inst *sdi) * * Determine an acquisition timeout from optionally configured * sample count or time limits. Which depends on the samplerate. + * Force 50MHz samplerate when external clock is in use. */ + if (devc->clock.use_ext_clock) { + if (devc->clock.samplerate != SR_MHZ(50)) + sr_info("External clock, forcing 50MHz samplerate."); + devc->clock.samplerate = SR_MHZ(50); + } ret = sigma_set_samplerate(sdi); if (ret != SR_OK) return ret; @@ -427,47 +475,57 @@ static int dev_acquisition_start(const struct sr_dev_inst *sdi) if (ret != SR_OK) return ret; - if (sigma_convert_trigger(sdi) != SR_OK) { - sr_err("Failed to configure triggers."); - return SR_ERR; - } - /* Enter trigger programming mode. */ - sigma_set_register(devc, WRITE_TRIGGER_SELECT2, 0x20); + trigsel2 = TRGSEL2_RESET; + ret = sigma_set_register(devc, WRITE_TRIGGER_SELECT2, trigsel2); + if (ret != SR_OK) + return ret; - triggerselect = 0; - if (devc->samplerate >= SR_MHZ(100)) { + trigsel2 = 0; + if (devc->clock.samplerate >= SR_MHZ(100)) { /* 100 and 200 MHz mode. */ - sigma_set_register(devc, WRITE_TRIGGER_SELECT2, 0x81); + /* TODO Decipher the 0x81 magic number's purpose. */ + ret = sigma_set_register(devc, WRITE_TRIGGER_SELECT2, 0x81); + if (ret != SR_OK) + return ret; /* Find which pin to trigger on from mask. */ for (triggerpin = 0; triggerpin < 8; triggerpin++) { - if (devc->trigger.risingmask & (1 << triggerpin)) + if (devc->trigger.risingmask & BIT(triggerpin)) break; - if (devc->trigger.fallingmask & (1 << triggerpin)) + if (devc->trigger.fallingmask & BIT(triggerpin)) break; } /* Set trigger pin and light LED on trigger. */ - triggerselect = TRGSEL2_LEDSEL1 | (triggerpin & 0x7); + trigsel2 = triggerpin & TRGSEL2_PINS_MASK; + trigsel2 |= TRGSEL2_LEDSEL1; /* Default rising edge. */ + /* TODO Documentation disagrees, bit set means _rising_ edge. */ if (devc->trigger.fallingmask) - triggerselect |= 1 << 3; + trigsel2 |= TRGSEL2_PINPOL_RISE; - } else if (devc->samplerate <= SR_MHZ(50)) { - /* All other modes. */ - sigma_build_basic_trigger(devc, &lut); + } else if (devc->clock.samplerate <= SR_MHZ(50)) { + /* 50MHz firmware modes. */ - sigma_write_trigger_lut(devc, &lut); + /* Translate application specs to hardware perspective. */ + ret = sigma_build_basic_trigger(devc, &lut); + if (ret != SR_OK) + return ret; + + /* Communicate resulting register values to the device. */ + ret = sigma_write_trigger_lut(devc, &lut); + if (ret != SR_OK) + return ret; - triggerselect = TRGSEL2_LEDSEL1 | TRGSEL2_LEDSEL0; + trigsel2 = TRGSEL2_LEDSEL1 | TRGSEL2_LEDSEL0; } /* Setup trigger in and out pins to default values. */ memset(&triggerinout_conf, 0, sizeof(triggerinout_conf)); - triggerinout_conf.trgout_bytrigger = 1; - triggerinout_conf.trgout_enable = 1; + triggerinout_conf.trgout_bytrigger = TRUE; + triggerinout_conf.trgout_enable = TRUE; /* TODO * Verify the correctness of this implementation. The previous * version used to assign to a C language struct with bit fields @@ -477,7 +535,7 @@ static int dev_acquisition_start(const struct sr_dev_inst *sdi) * Which means that I could not verify "on paper" either. Let's * re-visit this code later during research for trigger support. */ - wrptr = trgconf_bytes; + wrptr = cmd_bytes; regval = 0; if (triggerinout_conf.trgout_bytrigger) regval |= TRGOPT_TRGOOUTEN; @@ -486,57 +544,85 @@ static int dev_acquisition_start(const struct sr_dev_inst *sdi) if (triggerinout_conf.trgout_enable) regval |= TRGOPT_TRGOEN; write_u8_inc(&wrptr, regval); - count = wrptr - trgconf_bytes; - sigma_write_register(devc, WRITE_TRIGGER_OPTION, trgconf_bytes, count); + ret = sigma_write_register(devc, WRITE_TRIGGER_OPTION, + cmd_bytes, wrptr - cmd_bytes); + if (ret != SR_OK) + return ret; /* Leave trigger programming mode. */ - sigma_set_register(devc, WRITE_TRIGGER_SELECT2, triggerselect); - - /* Set clock select register. */ - clockselect.async = 0; - clockselect.fraction = 1; /* Divider 1. */ - clockselect.disabled_channels = 0x0000; /* All channels enabled. */ - if (devc->samplerate == SR_MHZ(200)) { - /* Enable 4 channels. */ - clockselect.disabled_channels = 0xfff0; - } else if (devc->samplerate == SR_MHZ(100)) { - /* Enable 8 channels. */ - clockselect.disabled_channels = 0xff00; + ret = sigma_set_register(devc, WRITE_TRIGGER_SELECT2, trigsel2); + if (ret != SR_OK) + return ret; + + /* + * Samplerate dependent clock and channels configuration. Some + * channels by design are not available at higher clock rates. + * Register layout differs between firmware variants (depth 1 + * with LSB channel mask above 50MHz, depth 4 with more details + * up to 50MHz). + * + * Derive a mask where bits are set for unavailable channels. + * Either send the single byte, or the full byte sequence. + */ + pindis_mask = ~BITS_MASK(devc->interp.num_channels); + if (devc->clock.samplerate > SR_MHZ(50)) { + ret = sigma_set_register(devc, WRITE_CLOCK_SELECT, + pindis_mask & 0xff); } else { - /* - * 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.) - */ - clockselect.fraction = SR_MHZ(50) / devc->samplerate; + wrptr = cmd_bytes; + /* Select 50MHz base clock, and divider. */ + async = 0; + div = SR_MHZ(50) / devc->clock.samplerate - 1; + if (devc->clock.use_ext_clock) { + async = CLKSEL_CLKSEL8; + div = devc->clock.clock_pin + 1; + switch (devc->clock.clock_edge) { + case SIGMA_CLOCK_EDGE_RISING: + div |= CLKSEL_RISING; + break; + case SIGMA_CLOCK_EDGE_FALLING: + div |= CLKSEL_FALLING; + break; + case SIGMA_CLOCK_EDGE_EITHER: + div |= CLKSEL_RISING; + div |= CLKSEL_FALLING; + break; + } + } + write_u8_inc(&wrptr, async); + write_u8_inc(&wrptr, div); + write_u16be_inc(&wrptr, pindis_mask); + ret = sigma_write_register(devc, WRITE_CLOCK_SELECT, + cmd_bytes, wrptr - cmd_bytes); } - wrptr = clock_bytes; - write_u8_inc(&wrptr, clockselect.async); - write_u8_inc(&wrptr, clockselect.fraction - 1); - write_u16be_inc(&wrptr, clockselect.disabled_channels); - count = wrptr - clock_bytes; - sigma_write_register(devc, WRITE_CLOCK_SELECT, clock_bytes, count); + if (ret != SR_OK) + return ret; /* Setup maximum post trigger time. */ - sigma_set_register(devc, WRITE_POST_TRIGGER, + ret = sigma_set_register(devc, WRITE_POST_TRIGGER, (devc->capture_ratio * 255) / 100); + if (ret != SR_OK) + return ret; /* Start acqusition. */ regval = WMR_TRGRES | WMR_SDRAMWRITEEN; -#if ASIX_SIGMA_WITH_TRIGGER - regval |= WMR_TRGEN; -#endif - sigma_set_register(devc, WRITE_MODE, regval); + if (devc->use_triggers) + regval |= WMR_TRGEN; + ret = sigma_set_register(devc, WRITE_MODE, regval); + if (ret != SR_OK) + return ret; - std_session_send_df_header(sdi); + ret = std_session_send_df_header(sdi); + if (ret != SR_OK) + return ret; /* Add capture source. */ - sr_session_source_add(sdi->session, -1, 0, 10, + ret = sr_session_source_add(sdi->session, -1, 0, 10, sigma_receive_data, (void *)sdi); + if (ret != SR_OK) + return ret; - devc->state.state = SIGMA_CAPTURE; + devc->state = SIGMA_CAPTURE; return SR_OK; } @@ -554,11 +640,11 @@ static int dev_acquisition_stop(struct sr_dev_inst *sdi) * 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; + if (devc->state == SIGMA_CAPTURE) { + devc->state = SIGMA_STOPPING; } else { - devc->state.state = SIGMA_IDLE; - sr_session_source_remove(sdi->session, -1); + devc->state = SIGMA_IDLE; + (void)sr_session_source_remove(sdi->session, -1); } return SR_OK;