X-Git-Url: https://sigrok.org/gitweb/?a=blobdiff_plain;f=src%2Fhardware%2Fhantek-4032l%2Fapi.c;h=26a9315e5035024c9559f679a950576a72246b95;hb=deb7615262ac4f9cc0750a08351afa7cbf9c34d5;hp=55b764e1e60eedf4b9ba3cd45624afa621d4816b;hpb=28f2d07fe5c88508b957860044355ee9b284a3ac;p=libsigrok.git diff --git a/src/hardware/hantek-4032l/api.c b/src/hardware/hantek-4032l/api.c index 55b764e1..26a9315e 100644 --- a/src/hardware/hantek-4032l/api.c +++ b/src/hardware/hantek-4032l/api.c @@ -35,11 +35,53 @@ static const uint32_t drvopts[] = { static const uint32_t devopts[] = { SR_CONF_SAMPLERATE | SR_CONF_GET | SR_CONF_SET | SR_CONF_LIST, - SR_CONF_CAPTURE_RATIO | SR_CONF_GET | SR_CONF_SET, - SR_CONF_LIMIT_SAMPLES | SR_CONF_GET | SR_CONF_SET, + SR_CONF_CAPTURE_RATIO | SR_CONF_GET | SR_CONF_SET | SR_CONF_LIST, + SR_CONF_LIMIT_SAMPLES | SR_CONF_GET | SR_CONF_SET | SR_CONF_LIST, SR_CONF_TRIGGER_MATCH | SR_CONF_LIST, SR_CONF_CONN | SR_CONF_GET, - SR_CONF_VOLTAGE_THRESHOLD | SR_CONF_SET | SR_CONF_LIST, + 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, +}; + +static const uint32_t devopts_fpga_zero[] = { + SR_CONF_SAMPLERATE | SR_CONF_GET | SR_CONF_SET | SR_CONF_LIST, + SR_CONF_CAPTURE_RATIO | SR_CONF_GET | SR_CONF_SET | SR_CONF_LIST, + SR_CONF_LIMIT_SAMPLES | SR_CONF_GET | SR_CONF_SET | SR_CONF_LIST, + SR_CONF_TRIGGER_MATCH | SR_CONF_LIST, + SR_CONF_CONN | SR_CONF_GET, +}; + +static const uint32_t devopts_cg[] = { + SR_CONF_VOLTAGE_THRESHOLD | SR_CONF_GET | SR_CONF_SET | SR_CONF_LIST, +}; + +static const char *cg_names[] = { + "A", "B", +}; + +static const char *signal_edges[] = { + [H4032L_CLOCK_EDGE_TYPE_RISE] = "rising", + [H4032L_CLOCK_EDGE_TYPE_FALL] = "falling", + [H4032L_CLOCK_EDGE_TYPE_BOTH] = "both", +}; + +static const char *ext_clock_sources[] = { + [H4032L_EXT_CLOCK_SOURCE_CHANNEL_A] = "ACLK", + [H4032L_EXT_CLOCK_SOURCE_CHANNEL_B] = "BCLK" +}; + +static const uint8_t ext_clock_edges[2][3] = { + { + H4032L_CLOCK_EDGE_TYPE_RISE_A, + H4032L_CLOCK_EDGE_TYPE_FALL_A, + H4032L_CLOCK_EDGE_TYPE_BOTH_A + }, + { + H4032L_CLOCK_EDGE_TYPE_RISE_B, + H4032L_CLOCK_EDGE_TYPE_FALL_B, + H4032L_CLOCK_EDGE_TYPE_BOTH_B + } }; static const int32_t trigger_matches[] = { @@ -125,7 +167,7 @@ static const uint64_t samplerates_hw[] = { SR_MHZ(320), }; -SR_PRIV struct sr_dev_driver hantek_4032l_driver_info; +static struct sr_dev_driver hantek_4032l_driver_info; static GSList *scan(struct sr_dev_driver *di, GSList *options) { @@ -210,16 +252,22 @@ static GSList *scan(struct sr_dev_driver *di, GSList *options) /* Initialize command packet. */ devc->cmd_pkt.magic = H4032L_CMD_PKT_MAGIC; - devc->cmd_pkt.pwm_a = h4032l_voltage2pwm(2.5); - devc->cmd_pkt.pwm_b = h4032l_voltage2pwm(2.5); - devc->cmd_pkt.sample_size = 16384; - devc->cmd_pkt.pre_trigger_size = 1024; + devc->cmd_pkt.sample_size = 16 * 1024; + devc->sample_rate = 0; devc->status = H4032L_STATUS_IDLE; devc->capture_ratio = 5; + devc->external_clock = FALSE; + devc->clock_edge = H4032L_CLOCK_EDGE_TYPE_RISE; - devc->usb_transfer = libusb_alloc_transfer(0); + /* Create array of thresholds from min to max. */ + GVariant *thresholds = std_gvar_min_max_step_thresholds( + H4032L_THR_VOLTAGE_MIN, H4032L_THR_VOLTAGE_MAX, + H4032L_THR_VOLTAGE_STEP); + /* Take default threshold value from array (FP workaround). */ + g_variant_get_child(thresholds, H4032L_THR_VOLTAGE_DEFAULT, + "(dd)", &devc->cur_threshold[0], &devc->cur_threshold[1]); sdi->priv = devc; devices = g_slist_append(devices, sdi); @@ -267,6 +315,10 @@ static int dev_open(struct sr_dev_inst *sdi) return SR_ERR; } + /* Get FPGA version. */ + if ((ret = h4032l_get_fpga_version(sdi)) != SR_OK) + return ret; + return SR_OK; } @@ -293,12 +345,19 @@ static int config_get(uint32_t key, GVariant **data, { struct dev_context *devc = sdi->priv; struct sr_usb_dev_inst *usb; - - (void)cg; + int idx; switch (key) { + case SR_CONF_VOLTAGE_THRESHOLD: + if (!cg) + return SR_ERR_CHANNEL_GROUP; + if ((idx = std_str_idx_s(cg->name, ARRAY_AND_SIZE(cg_names))) < 0) + return SR_ERR_CHANNEL_GROUP; + *data = std_gvar_tuple_double( + devc->cur_threshold[idx], devc->cur_threshold[idx]); + break; case SR_CONF_SAMPLERATE: - *data = g_variant_new_uint64(samplerates_hw[devc->cmd_pkt.sample_rate]); + *data = g_variant_new_uint64(samplerates_hw[devc->sample_rate]); break; case SR_CONF_CAPTURE_RATIO: *data = g_variant_new_uint64(devc->capture_ratio); @@ -306,11 +365,20 @@ static int config_get(uint32_t key, GVariant **data, case SR_CONF_LIMIT_SAMPLES: *data = g_variant_new_uint64(devc->cmd_pkt.sample_size); break; + case SR_CONF_EXTERNAL_CLOCK: + *data = g_variant_new_boolean(devc->external_clock); + break; + case SR_CONF_EXTERNAL_CLOCK_SOURCE: + *data = g_variant_new_string(ext_clock_sources[devc->external_clock_source]); + break; case SR_CONF_CONN: if (!sdi || !(usb = sdi->conn)) return SR_ERR_ARG; *data = g_variant_new_printf("%d.%d", usb->bus, usb->address); break; + case SR_CONF_CLOCK_EDGE: + *data = g_variant_new_string(signal_edges[devc->clock_edge]); + break; default: return SR_ERR_NA; } @@ -321,48 +389,60 @@ static int config_get(uint32_t key, GVariant **data, static int config_set(uint32_t key, GVariant *data, const struct sr_dev_inst *sdi, const struct sr_channel_group *cg) { + int idx; struct dev_context *devc = sdi->priv; struct h4032l_cmd_pkt *cmd_pkt = &devc->cmd_pkt; - - (void)cg; + uint64_t sample_rate, num_samples; + double low, high; switch (key) { - case SR_CONF_SAMPLERATE: { - uint64_t sample_rate = g_variant_get_uint64(data); - uint8_t i = 0; - while (i < ARRAY_SIZE(samplerates_hw) && samplerates_hw[i] != sample_rate) - i++; - - if (i == ARRAY_SIZE(samplerates_hw) || sample_rate == 0) { - sr_err("Invalid sample rate."); - return SR_ERR_SAMPLERATE; - } - cmd_pkt->sample_rate = i; - break; + case SR_CONF_SAMPLERATE: + idx = 0; + sample_rate = g_variant_get_uint64(data); + while (idx < (int)ARRAY_SIZE(samplerates_hw) && samplerates_hw[idx] != sample_rate) + idx++; + if (idx == ARRAY_SIZE(samplerates_hw) || sample_rate == 0) { + sr_err("Invalid sample rate."); + return SR_ERR_SAMPLERATE; } + devc->sample_rate = idx; + break; case SR_CONF_CAPTURE_RATIO: devc->capture_ratio = g_variant_get_uint64(data); break; - case SR_CONF_LIMIT_SAMPLES: { - uint64_t number_samples = g_variant_get_uint64(data); - number_samples += 511; - number_samples &= 0xfffffe00; - if (number_samples < 2048 || - number_samples > 64 * 1024 * 1024) { - sr_err("Invalid sample range 2k...64M: %" - PRIu64 ".", number_samples); - return SR_ERR; - } - cmd_pkt->sample_size = number_samples; - break; - } - case SR_CONF_VOLTAGE_THRESHOLD: { - double d1, d2; - g_variant_get(data, "(dd)", &d1, &d2); - devc->cmd_pkt.pwm_a = h4032l_voltage2pwm(d1); - devc->cmd_pkt.pwm_b = h4032l_voltage2pwm(d2); - break; + case SR_CONF_LIMIT_SAMPLES: + num_samples = g_variant_get_uint64(data); + num_samples += 511; + num_samples &= 0xfffffe00; + if (num_samples < H4043L_NUM_SAMPLES_MIN || + num_samples > H4032L_NUM_SAMPLES_MAX) { + sr_err("Invalid sample range 2k...64M: %" + PRIu64 ".", num_samples); + return SR_ERR; } + cmd_pkt->sample_size = num_samples; + break; + case SR_CONF_VOLTAGE_THRESHOLD: + if (!cg) + return SR_ERR_CHANNEL_GROUP; + if ((idx = std_str_idx_s(cg->name, ARRAY_AND_SIZE(cg_names))) < 0) + return SR_ERR_CHANNEL_GROUP; + g_variant_get(data, "(dd)", &low, &high); + devc->cur_threshold[idx] = (low + high) / 2.0; + break; + case SR_CONF_EXTERNAL_CLOCK: + devc->external_clock = g_variant_get_boolean(data); + break; + case SR_CONF_EXTERNAL_CLOCK_SOURCE: + if ((idx = std_str_idx(data, ARRAY_AND_SIZE(ext_clock_sources))) < 0) + return SR_ERR_ARG; + devc->external_clock_source = idx; + break; + case SR_CONF_CLOCK_EDGE: + if ((idx = std_str_idx(data, ARRAY_AND_SIZE(signal_edges))) < 0) + return SR_ERR_ARG; + devc->clock_edge = idx; + break; default: return SR_ERR_NA; } @@ -373,9 +453,18 @@ 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 = (sdi) ? sdi->priv : NULL; + switch (key) { case SR_CONF_SCAN_OPTIONS: case SR_CONF_DEVICE_OPTIONS: + if (cg) { + *data = std_gvar_array_u32(ARRAY_AND_SIZE(devopts_cg)); + break; + } + /* Disable external clock and edges for FPGA version 0. */ + if (devc && (!devc->fpga_version)) + return STD_CONFIG_LIST(key, data, sdi, cg, scanopts, drvopts, devopts_fpga_zero); return STD_CONFIG_LIST(key, data, sdi, cg, scanopts, drvopts, devopts); case SR_CONF_SAMPLERATE: *data = std_gvar_samplerates(ARRAY_AND_SIZE(samplerates)); @@ -384,7 +473,17 @@ static int config_list(uint32_t key, GVariant **data, *data = std_gvar_array_i32(ARRAY_AND_SIZE(trigger_matches)); break; case SR_CONF_VOLTAGE_THRESHOLD: - *data = std_gvar_tuple_double(2.5, 2.5); + *data = std_gvar_min_max_step_thresholds(H4032L_THR_VOLTAGE_MIN, + H4032L_THR_VOLTAGE_MAX, H4032L_THR_VOLTAGE_STEP); + break; + case SR_CONF_LIMIT_SAMPLES: + *data = std_gvar_tuple_u64(H4043L_NUM_SAMPLES_MIN, H4032L_NUM_SAMPLES_MAX); + break; + case SR_CONF_CLOCK_EDGE: + *data = g_variant_new_strv(ARRAY_AND_SIZE(signal_edges)); + break; + case SR_CONF_EXTERNAL_CLOCK_SOURCE: + *data = g_variant_new_strv(ARRAY_AND_SIZE(ext_clock_sources)); break; default: return SR_ERR_NA; @@ -403,9 +502,22 @@ static int dev_acquisition_start(const struct sr_dev_inst *sdi) /* Initialize variables. */ devc->acq_aborted = FALSE; + devc->submitted_transfers = 0; + devc->sent_samples = 0; /* Calculate packet ratio. */ cmd_pkt->pre_trigger_size = (cmd_pkt->sample_size * devc->capture_ratio) / 100; + devc->trigger_pos = cmd_pkt->pre_trigger_size; + + /* Set clock edge, when external clock is enabled. */ + if (devc->external_clock) + cmd_pkt->sample_rate = ext_clock_edges[devc->external_clock_source][devc->clock_edge]; + else + cmd_pkt->sample_rate = devc->sample_rate; + + /* Set PWM channel values. */ + devc->cmd_pkt.pwm_a = h4032l_voltage2pwm(devc->cur_threshold[0]); + devc->cmd_pkt.pwm_b = h4032l_voltage2pwm(devc->cur_threshold[1]); cmd_pkt->trig_flags.enable_trigger1 = 0; cmd_pkt->trig_flags.enable_trigger2 = 0; @@ -475,25 +587,9 @@ static int dev_acquisition_start(const struct sr_dev_inst *sdi) channel = channel->next; } - /* Compress range mask value and apply range settings. */ - if (range_mask) { - cmd_pkt->trigger[0].flags.data_range_enabled = 1; - cmd_pkt->trigger[0].data_range_mask |= (range_mask); - - uint32_t new_range_value = 0; - uint32_t bit_mask = 1; - while (range_mask) { - if ((range_mask & 1) != 0) { - new_range_value <<= 1; - if ((range_value & 1) != 0) - new_range_value |= bit_mask; - bit_mask <<= 1; - } - range_mask >>= 1; - range_value >>= 1; - } - cmd_pkt->trigger[0].data_range_max |= range_value; - } + cmd_pkt->trigger[0].flags.data_range_enabled = 1; + cmd_pkt->trigger[0].data_range_mask |= range_mask; + cmd_pkt->trigger[0].data_range_max = range_value; } usb_source_add(sdi->session, drvc->sr_ctx, 1000, @@ -505,18 +601,11 @@ static int dev_acquisition_start(const struct sr_dev_inst *sdi) static int dev_acquisition_stop(struct sr_dev_inst *sdi) { - struct dev_context *devc = sdi->priv; - - devc->acq_aborted = TRUE; - if (devc->usb_transfer) - libusb_cancel_transfer(devc->usb_transfer); - - devc->status = H4032L_STATUS_IDLE; - - return SR_OK; + /* Stop capturing. */ + return h4032l_stop(sdi); } -SR_PRIV struct sr_dev_driver hantek_4032l_driver_info = { +static struct sr_dev_driver hantek_4032l_driver_info = { .name = "hantek-4032l", .longname = "Hantek 4032L", .api_version = 1,