X-Git-Url: https://sigrok.org/gitweb/?a=blobdiff_plain;f=src%2Fhardware%2Fkingst-la2016%2Fapi.c;h=d5cb8678e1d2294ae7925032b9c67a3416399b76;hb=331277e05e45e8fe3fde95316c4b572161e68416;hp=0b672eea7ee14226db9ff9a340154bf1cbdc23f8;hpb=d8fbfcd9d6d66bffcb8607e9de7706ce322d42c7;p=libsigrok.git diff --git a/src/hardware/kingst-la2016/api.c b/src/hardware/kingst-la2016/api.c index 0b672eea..d5cb8678 100644 --- a/src/hardware/kingst-la2016/api.c +++ b/src/hardware/kingst-la2016/api.c @@ -39,6 +39,7 @@ static const uint32_t scanopts[] = { static const uint32_t drvopts[] = { SR_CONF_LOGIC_ANALYZER, + SR_CONF_SIGNAL_GENERATOR, }; static const uint32_t devopts[] = { @@ -54,6 +55,12 @@ static const uint32_t devopts[] = { SR_CONF_CAPTURE_RATIO | SR_CONF_GET | SR_CONF_SET, }; +static const uint32_t devopts_cg_pwm[] = { + SR_CONF_ENABLED | SR_CONF_GET | SR_CONF_SET, + SR_CONF_OUTPUT_FREQUENCY | SR_CONF_GET | SR_CONF_SET, + SR_CONF_DUTY_CYCLE | SR_CONF_GET | SR_CONF_SET, +}; + static const int32_t trigger_matches[] = { SR_TRIGGER_ZERO, SR_TRIGGER_ONE, @@ -68,6 +75,10 @@ static const char *channel_names_logic[] = { "CH24", "CH25", "CH26", "CH27", "CH28", "CH29", "CH30", "CH31", }; +static const char *channel_names_pwm[] = { + "PWM1", "PWM2", +}; + /* * The hardware uses a 100/200/500MHz base clock (model dependent) and * a 16bit divider (common across all models). The range from 10kHz to @@ -249,7 +260,17 @@ static int la2016_identify_read(struct sr_dev_inst *sdi, sr_err("Cannot communicate to MCU firmware."); return ret; } + + /* + * Also complete the hardware configuration (FPGA bitstream) + * when MCU firmware communication became operational. Either + * failure is considered fatal when probing for the device. + */ ret = la2016_identify_device(sdi, show_message); + if (ret == SR_OK) { + ret = la2016_init_hardware(sdi); + } + la2016_close_usb(usb); return ret; @@ -398,6 +419,8 @@ static GSList *scan(struct sr_dev_driver *di, GSList *options) char conn_id[64]; int ret; size_t ch_off, ch_max; + struct sr_channel *ch; + struct sr_channel_group *cg; drvc = di->context; ctx = drvc->sr_ctx;; @@ -546,23 +569,55 @@ static GSList *scan(struct sr_dev_driver *di, GSList *options) sdi->model = g_strdup(devc->model->name); ch_off = 0; - /* Create the logic channels. */ + /* Create the "Logic" channel group. */ ch_max = ARRAY_SIZE(channel_names_logic); if (ch_max > devc->model->channel_count) ch_max = devc->model->channel_count; + cg = sr_channel_group_new(sdi, "Logic", NULL); + devc->cg_logic = cg; for (ch_idx = 0; ch_idx < ch_max; ch_idx++) { - sr_channel_new(sdi, ch_off, + ch = sr_channel_new(sdi, ch_off, SR_CHANNEL_LOGIC, TRUE, channel_names_logic[ch_idx]); ch_off++; + cg->channels = g_slist_append(cg->channels, ch); + } + + /* Create the "PWMx" channel groups. */ + ch_max = ARRAY_SIZE(channel_names_pwm); + for (ch_idx = 0; ch_idx < ch_max; ch_idx++) { + const char *name; + name = channel_names_pwm[ch_idx]; + cg = sr_channel_group_new(sdi, name, NULL); + if (!devc->cg_pwm) + devc->cg_pwm = cg; + ch = sr_channel_new(sdi, ch_off, + SR_CHANNEL_ANALOG, FALSE, name); + ch_off++; + cg->channels = g_slist_append(cg->channels, ch); } + /* + * Ideally we'd get the previous configuration from the + * hardware, but this device is write-only. So we have + * to assign a fixed set of initial configuration values. + */ sr_sw_limits_init(&devc->sw_limits); devc->sw_limits.limit_samples = 0; devc->capture_ratio = 50; devc->cur_samplerate = devc->model->samplerate; devc->threshold_voltage_idx = 0; devc->threshold_voltage = logic_threshold_value[devc->threshold_voltage_idx]; + if (ARRAY_SIZE(devc->pwm_setting) >= 1) { + devc->pwm_setting[0].enabled = FALSE; + devc->pwm_setting[0].freq = SR_KHZ(1); + devc->pwm_setting[0].duty = 50; + } + if (ARRAY_SIZE(devc->pwm_setting) >= 2) { + devc->pwm_setting[1].enabled = FALSE; + devc->pwm_setting[1].freq = SR_KHZ(100); + devc->pwm_setting[1].duty = 50; + } sdi->status = SR_ST_INACTIVE; devices = g_slist_append(devices, sdi); @@ -574,7 +629,11 @@ static GSList *scan(struct sr_dev_driver *di, GSList *options) static int dev_open(struct sr_dev_inst *sdi) { + struct dev_context *devc; int ret; + size_t ch; + + devc = sdi->priv; ret = la2016_open_enum(sdi); if (ret != SR_OK) { @@ -582,6 +641,13 @@ static int dev_open(struct sr_dev_inst *sdi) return ret; } + /* Send most recent PWM configuration to the device. */ + for (ch = 0; ch < ARRAY_SIZE(devc->pwm_setting); ch++) { + ret = la2016_write_pwm_config(sdi, ch); + if (ret != SR_OK) + return ret; + } + return SR_OK; } @@ -594,7 +660,7 @@ static int dev_close(struct sr_dev_inst *sdi) if (!usb->devhdl) return SR_ERR_BUG; - la2016_deinit_device(sdi); + la2016_deinit_hardware(sdi); sr_info("Closing device on %d.%d (logical) / %s (physical) interface %d.", usb->bus, usb->address, sdi->connection_id, USB_INTERFACE); @@ -603,20 +669,105 @@ static int dev_close(struct sr_dev_inst *sdi) return SR_OK; } +/* Config API helper. Get type and index of a channel group. */ +static int get_cg_index(const struct sr_dev_inst *sdi, + const struct sr_channel_group *cg, + int *type, size_t *logic, size_t *analog) +{ + struct dev_context *devc; + GSList *l; + size_t idx; + + /* Preset return values. */ + if (type) + *type = 0; + if (logic) + *logic = 0; + if (analog) + *analog = 0; + + /* Start categorizing the received cg. */ + if (!sdi) + return SR_ERR_ARG; + devc = sdi->priv; + if (!cg) + return SR_OK; + l = sdi->channel_groups; + + /* First sdi->channelgroups item is "Logic". */ + if (!l) + return SR_ERR_BUG; + if (cg == l->data) { + if (type) + *type = SR_CHANNEL_LOGIC; + if (logic) + *logic = 0; + return SR_OK; + } + l = l->next; + + /* Next sdi->channelgroups items are "PWMx". */ + idx = 0; + while (l && l->data != cg) { + idx++; + l = l->next; + } + if (l && idx < ARRAY_SIZE(devc->pwm_setting)) { + if (type) + *type = SR_CHANNEL_ANALOG; + if (analog) + *analog = idx; + return SR_OK; + } + + return SR_ERR_ARG; +} + 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; + int ret, cg_type; + size_t logic_idx, analog_idx; + struct pwm_setting *pwm; struct sr_usb_dev_inst *usb; double rounded; const char *label; - (void)cg; - if (!sdi) return SR_ERR_ARG; devc = sdi->priv; + /* Check for types (and index) of channel groups. */ + ret = get_cg_index(sdi, cg, &cg_type, &logic_idx, &analog_idx); + if (cg && ret != SR_OK) + return SR_ERR_ARG; + + /* Handle requests for the "Logic" channel group. */ + if (cg && cg_type == SR_CHANNEL_LOGIC) { + /* TODO */ + return SR_ERR_NA; + } + + /* Handle requests for the "PWMx" channel groups. */ + if (cg && cg_type == SR_CHANNEL_ANALOG) { + pwm = &devc->pwm_setting[analog_idx]; + switch (key) { + case SR_CONF_ENABLED: + *data = g_variant_new_boolean(pwm->enabled); + break; + case SR_CONF_OUTPUT_FREQUENCY: + *data = g_variant_new_double(pwm->freq); + break; + case SR_CONF_DUTY_CYCLE: + *data = g_variant_new_double(pwm->duty); + break; + default: + return SR_ERR_NA; + } + return SR_OK; + } + switch (key) { case SR_CONF_CONN: if (!sdi->conn) @@ -663,13 +814,53 @@ 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; + int ret, cg_type; + size_t logic_idx, analog_idx; + struct pwm_setting *pwm; double low, high; int idx; - (void)cg; - devc = sdi->priv; + /* Check for types (and index) of channel groups. */ + ret = get_cg_index(sdi, cg, &cg_type, &logic_idx, &analog_idx); + if (cg && ret != SR_OK) + return SR_ERR_ARG; + + /* Handle requests for the "Logic" channel group. */ + if (cg && cg_type == SR_CHANNEL_LOGIC) { + /* TODO */ + return SR_ERR_NA; + } + + /* Handle requests for the "PWMx" channel groups. */ + if (cg && cg_type == SR_CHANNEL_ANALOG) { + pwm = &devc->pwm_setting[analog_idx]; + switch (key) { + case SR_CONF_ENABLED: + pwm->enabled = g_variant_get_boolean(data); + ret = la2016_write_pwm_config(sdi, analog_idx); + if (ret != SR_OK) + return ret; + break; + case SR_CONF_OUTPUT_FREQUENCY: + pwm->freq = g_variant_get_double(data); + ret = la2016_write_pwm_config(sdi, analog_idx); + if (ret != SR_OK) + return ret; + break; + case SR_CONF_DUTY_CYCLE: + pwm->duty = g_variant_get_double(data); + ret = la2016_write_pwm_config(sdi, analog_idx); + if (ret != SR_OK) + return ret; + break; + default: + return SR_ERR_NA; + } + return SR_OK; + } + switch (key) { case SR_CONF_SAMPLERATE: devc->cur_samplerate = g_variant_get_uint64(data); @@ -709,9 +900,36 @@ 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; + int ret, cg_type; + size_t logic_idx, analog_idx; devc = sdi ? sdi->priv : NULL; + /* Check for types (and index) of channel groups. */ + ret = get_cg_index(sdi, cg, &cg_type, &logic_idx, &analog_idx); + if (cg && ret != SR_OK) + return SR_ERR_ARG; + + /* Handle requests for the "Logic" channel group. */ + if (cg && cg_type == SR_CHANNEL_LOGIC) { + /* TODO */ + return SR_ERR_NA; + } + + /* Handle requests for the "PWMx" channel groups. */ + if (cg && cg_type == SR_CHANNEL_ANALOG) { + switch (key) { + case SR_CONF_DEVICE_OPTIONS: + *data = g_variant_new_fixed_array(G_VARIANT_TYPE_UINT32, + devopts_cg_pwm, ARRAY_SIZE(devopts_cg_pwm), + sizeof(devopts_cg_pwm[0])); + break; + default: + return SR_ERR_NA; + } + return SR_OK; + } + switch (key) { case SR_CONF_SCAN_OPTIONS: case SR_CONF_DEVICE_OPTIONS: