X-Git-Url: https://sigrok.org/gitweb/?p=libsigrok.git;a=blobdiff_plain;f=src%2Fhardware%2Frdtech-dps%2Fapi.c;h=dda75896140cbd0efaed57d9b589934ed43bbd51;hp=f719e6c74d483a9d2f906e3e8e1f34a9a441a761;hb=d7a4dad881bf;hpb=69b05583955761d24c86cf1f46c1d1dba8c6176c diff --git a/src/hardware/rdtech-dps/api.c b/src/hardware/rdtech-dps/api.c index f719e6c7..dda75896 100644 --- a/src/hardware/rdtech-dps/api.c +++ b/src/hardware/rdtech-dps/api.c @@ -2,6 +2,8 @@ * This file is part of the libsigrok project. * * Copyright (C) 2018 James Churchill + * Copyright (C) 2019 Frank Stettner + * Copyright (C) 2021 Gerhard Sittig * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -18,6 +20,10 @@ */ #include + +#include +#include + #include "protocol.h" static const uint32_t scanopts[] = { @@ -46,56 +52,60 @@ static const uint32_t devopts[] = { SR_CONF_OVER_CURRENT_PROTECTION_THRESHOLD | SR_CONF_GET | SR_CONF_SET, }; -/* Model ID, model name, max current, max voltage, max power */ +/* Model ID, model name, max current/voltage/power, current/voltage digits. */ static const struct rdtech_dps_model supported_models[] = { - { 3005, "DPS3005", 3, 50, 160 }, - { 5005, "DPS5005", 5, 50, 250 }, - { 5205, "DPH5005", 5, 50, 250 }, - { 5015, "DPS5015", 15, 50, 750 }, - { 5020, "DPS5020", 20, 50, 1000 }, - { 8005, "DPS8005", 5, 80, 408 }, + { 3005, "DPS3005", 5, 30, 160, 3, 2 }, + { 5005, "DPS5005", 5, 50, 250, 3, 2 }, + { 5205, "DPH5005", 5, 50, 250, 3, 2 }, + { 5015, "DPS5015", 15, 50, 750, 2, 2 }, + { 5020, "DPS5020", 20, 50, 1000, 2, 2 }, + { 8005, "DPS8005", 5, 80, 408, 3, 2 }, }; static struct sr_dev_driver rdtech_dps_driver_info; static struct sr_dev_inst *probe_device(struct sr_modbus_dev_inst *modbus) { - const struct rdtech_dps_model *model = NULL; - struct dev_context *devc; - struct sr_dev_inst *sdi; uint16_t id, version; - unsigned int i; + int ret; + const struct rdtech_dps_model *model; + size_t i; + struct sr_dev_inst *sdi; + struct dev_context *devc; - int ret = rdtech_dps_get_model_version(modbus, &id, &version); + ret = rdtech_dps_get_model_version(modbus, &id, &version); if (ret != SR_OK) return NULL; - for (i = 0; i < ARRAY_SIZE(supported_models); i++) + model = NULL; + for (i = 0; i < ARRAY_SIZE(supported_models); i++) { if (id == supported_models[i].id) { model = &supported_models[i]; break; } - if (model == NULL) { - sr_err("Unknown model: %d.", id); + } + if (!model) { + sr_err("Unknown model: %u.", id); return NULL; } - sdi = g_malloc0(sizeof(struct sr_dev_inst)); + sdi = g_malloc0(sizeof(*sdi)); sdi->status = SR_ST_INACTIVE; sdi->vendor = g_strdup("RDTech"); sdi->model = g_strdup(model->name); - sdi->version = g_strdup_printf("v%d", version); + sdi->version = g_strdup_printf("v%u", version); sdi->conn = modbus; sdi->driver = &rdtech_dps_driver_info; sdi->inst_type = SR_INST_MODBUS; sr_channel_new(sdi, 0, SR_CHANNEL_ANALOG, TRUE, "V"); - sr_channel_new(sdi, 0, SR_CHANNEL_ANALOG, TRUE, "I"); - sr_channel_new(sdi, 0, SR_CHANNEL_ANALOG, TRUE, "P"); + sr_channel_new(sdi, 1, SR_CHANNEL_ANALOG, TRUE, "I"); + sr_channel_new(sdi, 2, SR_CHANNEL_ANALOG, TRUE, "P"); - devc = g_malloc0(sizeof(struct dev_context)); + devc = g_malloc0(sizeof(*devc)); sr_sw_limits_init(&devc->limits); devc->model = model; - devc->expecting_registers = 0; + devc->current_multiplier = pow(10.0, model->current_digits); + devc->voltage_multiplier = pow(10.0, model->voltage_digits); sdi->priv = devc; @@ -118,8 +128,9 @@ static GSList *scan(struct sr_dev_driver *di, GSList *options) .key = SR_CONF_MODBUSADDR, .data = g_variant_new_uint64(1), }; - GSList *opts = options, *devices; + GSList *opts, *devices; + opts = options; if (!g_slist_find_custom(options, &default_serialcomm, config_compare)) opts = g_slist_prepend(opts, &default_serialcomm); if (!g_slist_find_custom(options, &default_modbusaddr, config_compare)) @@ -137,36 +148,37 @@ static GSList *scan(struct sr_dev_driver *di, GSList *options) static int dev_open(struct sr_dev_inst *sdi) { - struct sr_modbus_dev_inst *modbus = sdi->conn; + struct sr_modbus_dev_inst *modbus; + struct rdtech_dps_state state; + int ret; + modbus = sdi->conn; if (sr_modbus_open(modbus) < 0) return SR_ERR; - rdtech_dps_set_reg(modbus, REG_LOCK, 1); + memset(&state, 0, sizeof(state)); + state.lock = TRUE; + state.mask |= STATE_LOCK; + ret = rdtech_dps_set_state(sdi, &state); + if (ret != SR_OK) + return ret; return SR_OK; } static int dev_close(struct sr_dev_inst *sdi) { - struct dev_context *devc; struct sr_modbus_dev_inst *modbus; + struct rdtech_dps_state state; modbus = sdi->conn; - if (!modbus) return SR_ERR_BUG; - devc = sdi->priv; - - if (devc->expecting_registers) { - /* Wait for the last data that was requested from the device. */ - uint16_t registers[devc->expecting_registers]; - sr_modbus_read_holding_registers(modbus, -1, - devc->expecting_registers, registers); - } - - rdtech_dps_set_reg(modbus, REG_LOCK, 0); + memset(&state, 0, sizeof(state)); + state.lock = FALSE; + state.mask |= STATE_LOCK; + (void)rdtech_dps_set_state(sdi, &state); return sr_modbus_close(modbus); } @@ -175,13 +187,12 @@ 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; - struct sr_modbus_dev_inst *modbus; + struct rdtech_dps_state state; int ret; - uint16_t ivalue; + const char *cc_text; (void)cg; - modbus = sdi->conn; devc = sdi->priv; ret = SR_OK; @@ -191,54 +202,101 @@ static int config_get(uint32_t key, GVariant **data, ret = sr_sw_limits_config_get(&devc->limits, key, data); break; case SR_CONF_ENABLED: - if ((ret = rdtech_dps_get_reg(modbus, REG_ENABLE, &ivalue)) == SR_OK) - *data = g_variant_new_boolean(ivalue); + ret = rdtech_dps_get_state(sdi, &state); + if (ret != SR_OK) + return ret; + if (!(state.mask & STATE_OUTPUT_ENABLED)) + return SR_ERR_DATA; + *data = g_variant_new_boolean(state.output_enabled); break; case SR_CONF_REGULATION: - if ((ret = rdtech_dps_get_reg(modbus, REG_CV_CC, &ivalue)) != SR_OK) - break; - if (ivalue == MODE_CC) - *data = g_variant_new_string("CC"); - else - *data = g_variant_new_string("CV"); + ret = rdtech_dps_get_state(sdi, &state); + if (ret != SR_OK) + return ret; + if (!(state.mask & STATE_REGULATION_CC)) + return SR_ERR_DATA; + cc_text = state.regulation_cc ? "CC" : "CV"; + *data = g_variant_new_string(cc_text); break; case SR_CONF_VOLTAGE: - if ((ret = rdtech_dps_get_reg(modbus, REG_UOUT, &ivalue)) == SR_OK) - *data = g_variant_new_double((float)ivalue / 100.0f); + ret = rdtech_dps_get_state(sdi, &state); + if (ret != SR_OK) + return ret; + if (!(state.mask & STATE_VOLTAGE)) + return SR_ERR_DATA; + *data = g_variant_new_double(state.voltage); break; case SR_CONF_VOLTAGE_TARGET: - if ((ret = rdtech_dps_get_reg(modbus, REG_USET, &ivalue)) == SR_OK) - *data = g_variant_new_double((float)ivalue / 100.0f); + ret = rdtech_dps_get_state(sdi, &state); + if (ret != SR_OK) + return ret; + if (!(state.mask & STATE_VOLTAGE_TARGET)) + return SR_ERR_DATA; + *data = g_variant_new_double(state.voltage_target); break; case SR_CONF_CURRENT: - if ((ret = rdtech_dps_get_reg(modbus, REG_IOUT, &ivalue)) == SR_OK) - *data = g_variant_new_double((float)ivalue / 100.0f); + ret = rdtech_dps_get_state(sdi, &state); + if (ret != SR_OK) + return ret; + if (!(state.mask & STATE_CURRENT)) + return SR_ERR_DATA; + *data = g_variant_new_double(state.current); break; case SR_CONF_CURRENT_LIMIT: - if ((ret = rdtech_dps_get_reg(modbus, REG_ISET, &ivalue)) == SR_OK) - *data = g_variant_new_double((float)ivalue / 1000.0f); + ret = rdtech_dps_get_state(sdi, &state); + if (ret != SR_OK) + return ret; + if (!(state.mask & STATE_CURRENT_LIMIT)) + return SR_ERR_DATA; + *data = g_variant_new_double(state.current_limit); break; case SR_CONF_OVER_VOLTAGE_PROTECTION_ENABLED: - *data = g_variant_new_boolean(TRUE); + ret = rdtech_dps_get_state(sdi, &state); + if (ret != SR_OK) + return ret; + if (!(state.mask & STATE_PROTECT_ENABLED)) + return SR_ERR_DATA; + *data = g_variant_new_boolean(state.protect_enabled); break; case SR_CONF_OVER_VOLTAGE_PROTECTION_ACTIVE: - if ((ret = rdtech_dps_get_reg(modbus, REG_PROTECT, &ivalue)) == SR_OK) - *data = g_variant_new_boolean(ivalue == STATE_OVP); + ret = rdtech_dps_get_state(sdi, &state); + if (ret != SR_OK) + return ret; + if (!(state.mask & STATE_PROTECT_OVP)) + return SR_ERR_DATA; + *data = g_variant_new_boolean(state.protect_ovp); break; case SR_CONF_OVER_VOLTAGE_PROTECTION_THRESHOLD: - if ((ret = rdtech_dps_get_reg(modbus, PRE_OVPSET, &ivalue)) == SR_OK) - *data = g_variant_new_double((float)ivalue / 100.0f); + ret = rdtech_dps_get_state(sdi, &state); + if (ret != SR_OK) + return ret; + if (!(state.mask & STATE_OUTPUT_ENABLED)) + return SR_ERR_DATA; + *data = g_variant_new_double(state.ovp_threshold); break; case SR_CONF_OVER_CURRENT_PROTECTION_ENABLED: - *data = g_variant_new_boolean(TRUE); + ret = rdtech_dps_get_state(sdi, &state); + if (ret != SR_OK) + return ret; + if (!(state.mask & STATE_PROTECT_ENABLED)) + return SR_ERR_DATA; + *data = g_variant_new_boolean(state.protect_enabled); break; case SR_CONF_OVER_CURRENT_PROTECTION_ACTIVE: - if ((ret = rdtech_dps_get_reg(modbus, REG_PROTECT, &ivalue)) == SR_OK) - *data = g_variant_new_boolean(ivalue == STATE_OCP); + ret = rdtech_dps_get_state(sdi, &state); + if (ret != SR_OK) + return ret; + if (!(state.mask & STATE_PROTECT_OCP)) + return SR_ERR_DATA; + *data = g_variant_new_boolean(state.protect_ocp); break; case SR_CONF_OVER_CURRENT_PROTECTION_THRESHOLD: - if ((ret = rdtech_dps_get_reg(modbus, PRE_OCPSET, &ivalue)) == SR_OK) - *data = g_variant_new_double((float)ivalue / 1000.0f); + ret = rdtech_dps_get_state(sdi, &state); + if (ret != SR_OK) + return ret; + if (!(state.mask & STATE_OCP_THRESHOLD)) + return SR_ERR_DATA; + *data = g_variant_new_double(state.ocp_threshold); break; default: return SR_ERR_NA; @@ -251,27 +309,37 @@ 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; - struct sr_modbus_dev_inst *modbus; + struct rdtech_dps_state state; (void)cg; - modbus = sdi->conn; devc = sdi->priv; + memset(&state, 0, sizeof(state)); switch (key) { case SR_CONF_LIMIT_SAMPLES: case SR_CONF_LIMIT_MSEC: return sr_sw_limits_config_set(&devc->limits, key, data); case SR_CONF_ENABLED: - return rdtech_dps_set_reg(modbus, REG_ENABLE, g_variant_get_boolean(data)); + state.output_enabled = g_variant_get_boolean(data); + state.mask |= STATE_OUTPUT_ENABLED; + return rdtech_dps_set_state(sdi, &state); case SR_CONF_VOLTAGE_TARGET: - return rdtech_dps_set_reg(modbus, REG_USET, g_variant_get_double(data) * 100); + state.voltage_target = g_variant_get_double(data); + state.mask |= STATE_VOLTAGE_TARGET; + return rdtech_dps_set_state(sdi, &state); case SR_CONF_CURRENT_LIMIT: - return rdtech_dps_set_reg(modbus, REG_ISET, g_variant_get_double(data) * 1000); + state.current_limit = g_variant_get_double(data); + state.mask |= STATE_CURRENT_LIMIT; + return rdtech_dps_set_state(sdi, &state); case SR_CONF_OVER_VOLTAGE_PROTECTION_THRESHOLD: - return rdtech_dps_set_reg(modbus, PRE_OVPSET, g_variant_get_double(data) * 100); + state.ovp_threshold = g_variant_get_double(data); + state.mask |= STATE_OVP_THRESHOLD; + return rdtech_dps_set_state(sdi, &state); case SR_CONF_OVER_CURRENT_PROTECTION_THRESHOLD: - return rdtech_dps_set_reg(modbus, PRE_OCPSET, g_variant_get_double(data) * 1000); + state.ocp_threshold = g_variant_get_double(data); + state.mask |= STATE_OCP_THRESHOLD; + return rdtech_dps_set_state(sdi, &state); default: return SR_ERR_NA; } @@ -291,10 +359,12 @@ static int config_list(uint32_t key, GVariant **data, case SR_CONF_DEVICE_OPTIONS: return STD_CONFIG_LIST(key, data, sdi, cg, scanopts, drvopts, devopts); case SR_CONF_VOLTAGE_TARGET: - *data = std_gvar_min_max_step(0.0, devc->model->max_voltage, 0.001); + *data = std_gvar_min_max_step(0.0, devc->model->max_voltage, + 1 / devc->voltage_multiplier); break; case SR_CONF_CURRENT_LIMIT: - *data = std_gvar_min_max_step(0.0, devc->model->max_current, 0.0001); + *data = std_gvar_min_max_step(0.0, devc->model->max_current, + 1 / devc->current_multiplier); break; default: return SR_ERR_NA; @@ -312,14 +382,21 @@ static int dev_acquisition_start(const struct sr_dev_inst *sdi) modbus = sdi->conn; devc = sdi->priv; - if ((ret = sr_modbus_source_add(sdi->session, modbus, G_IO_IN, 10, - rdtech_dps_receive_data, (void *)sdi)) != SR_OK) + /* Seed internal state from current data. */ + ret = rdtech_dps_seed_receive(sdi); + if (ret != SR_OK) + return ret; + + /* Register the periodic data reception callback. */ + ret = sr_modbus_source_add(sdi->session, modbus, G_IO_IN, 10, + rdtech_dps_receive_data, (void *)sdi); + if (ret != SR_OK) return ret; sr_sw_limits_acquisition_start(&devc->limits); std_session_send_df_header(sdi); - return rdtech_dps_capture_start(sdi); + return SR_OK; } static int dev_acquisition_stop(struct sr_dev_inst *sdi)