X-Git-Url: https://sigrok.org/gitweb/?p=libsigrok.git;a=blobdiff_plain;f=src%2Fhardware%2Frdtech-dps%2Fprotocol.c;h=83090d86ac7c2253c6662a305b7beab10015df67;hp=9ce2eb66e3a855337dc63f0bed452ba165f511f1;hb=HEAD;hpb=713a3f352496f928b9911bfdc7e87a67134113df diff --git a/src/hardware/rdtech-dps/protocol.c b/src/hardware/rdtech-dps/protocol.c index 9ce2eb66..dfcffbb1 100644 --- a/src/hardware/rdtech-dps/protocol.c +++ b/src/hardware/rdtech-dps/protocol.c @@ -19,12 +19,14 @@ * along with this program. If not, see . */ -#include +#include "config.h" +#include #include #include "protocol.h" +/* These are the Modbus RTU registers for the DPS family of devices. */ enum rdtech_dps_register { REG_DPS_USET = 0x00, /* Mirror of 0x50 */ REG_DPS_ISET = 0x01, /* Mirror of 0x51 */ @@ -69,6 +71,11 @@ enum rdtech_dps_regulation_mode { MODE_CC = 1, }; +/* + * These are the Modbus RTU registers for the RD family of devices. + * Some registers are device specific, like REG_RD_RANGE of RD6012P + * which could be battery related in other devices. + */ enum rdtech_rd_register { REG_RD_MODEL = 0, /* u16 */ REG_RD_SERIAL = 1, /* u32 */ @@ -85,6 +92,8 @@ enum rdtech_rd_register { REG_RD_PROTECT = 16, /* u16 */ REG_RD_REGULATION = 17, /* u16 */ REG_RD_ENABLE = 18, /* u16 */ + REG_RD_PRESET = 19, /* u16 */ + REG_RD_RANGE = 20, /* u16 */ /* * Battery at 32 == 0x20 pp: * Mode, voltage, temperature, capacity, energy. @@ -132,7 +141,7 @@ static int rdtech_dps_set_reg(const struct sr_dev_inst *sdi, modbus = sdi->conn; wrptr = (void *)registers; - write_u16le(wrptr, value); + write_u16be(wrptr, value); g_mutex_lock(&devc->rw_mutex); ret = sr_modbus_write_multiple_registers(modbus, address, @@ -187,8 +196,8 @@ SR_PRIV int rdtech_dps_get_model_version(struct sr_modbus_dev_inst *modbus, if (ret != SR_OK) return ret; rdptr = (void *)registers; - *model = read_u16le_inc(&rdptr); - *version = read_u16le_inc(&rdptr); + *model = read_u16be_inc(&rdptr); + *version = read_u16be_inc(&rdptr); *serno = 0; sr_info("RDTech DPS/DPH model: %u version: %u", *model, *version); @@ -200,7 +209,7 @@ SR_PRIV int rdtech_dps_get_model_version(struct sr_modbus_dev_inst *modbus, if (ret != SR_OK) return ret; rdptr = (void *)registers; - *model = read_u16be_inc(&rdptr) / 10; + *model = read_u16be_inc(&rdptr); *serno = read_u32be_inc(&rdptr); *version = read_u16be_inc(&rdptr); sr_info("RDTech RD model: %u version: %u, serno %u", @@ -213,6 +222,49 @@ SR_PRIV int rdtech_dps_get_model_version(struct sr_modbus_dev_inst *modbus, /* UNREACH */ } +SR_PRIV void rdtech_dps_update_multipliers(const struct sr_dev_inst *sdi) +{ + struct dev_context *devc; + const struct rdtech_dps_range *range; + + devc = sdi->priv; + range = &devc->model->ranges[devc->curr_range]; + devc->current_multiplier = pow(10.0, range->current_digits); + devc->voltage_multiplier = pow(10.0, range->voltage_digits); +} + +/* + * Determine range of connected device. Don't do anything once + * acquisition has started (since the range will then be tracked). + */ +SR_PRIV int rdtech_dps_update_range(const struct sr_dev_inst *sdi) +{ + struct dev_context *devc; + uint16_t range; + int ret; + + devc = sdi->priv; + + /* + * Only update range if there are multiple ranges and data + * acquisition hasn't started. + */ + if (devc->model->n_ranges <= 1 || devc->acquisition_started) + return SR_OK; + if (devc->model->model_type != MODEL_RD) + return SR_ERR; + + ret = rdtech_dps_read_holding_registers(sdi->conn, + REG_RD_RANGE, 1, &range); + if (ret != SR_OK) + return ret; + range = range ? 1 : 0; + devc->curr_range = range; + rdtech_dps_update_multipliers(sdi); + + return SR_OK; +} + /* Send a measured value to the session feed. */ static int send_value(const struct sr_dev_inst *sdi, struct sr_channel *ch, float value, @@ -259,13 +311,15 @@ SR_PRIV int rdtech_dps_get_state(const struct sr_dev_inst *sdi, struct dev_context *devc; struct sr_modbus_dev_inst *modbus; gboolean get_config, get_init_state, get_curr_meas; - uint16_t registers[12]; + uint16_t registers[14]; int ret; const uint8_t *rdptr; uint16_t uset_raw, iset_raw, uout_raw, iout_raw, power_raw; uint16_t reg_val, reg_state, out_state, ovpset_raw, ocpset_raw; gboolean is_lock, is_out_enabled, is_reg_cc; gboolean uses_ovp, uses_ocp; + gboolean have_range; + uint16_t range; float volt_target, curr_limit; float ovp_threshold, ocp_threshold; float curr_voltage, curr_current, curr_power; @@ -308,6 +362,10 @@ SR_PRIV int rdtech_dps_get_state(const struct sr_dev_inst *sdi, (void)get_init_state; (void)get_curr_meas; + have_range = devc->model->n_ranges > 1; + if (!have_range) + range = 0; + switch (devc->model->model_type) { case MODEL_DPS: /* @@ -320,32 +378,33 @@ SR_PRIV int rdtech_dps_get_state(const struct sr_dev_inst *sdi, */ g_mutex_lock(&devc->rw_mutex); ret = rdtech_dps_read_holding_registers(modbus, - REG_DPS_USET, 10, registers); + REG_DPS_USET, REG_DPS_ENABLE - REG_DPS_USET + 1, + registers); g_mutex_unlock(&devc->rw_mutex); if (ret != SR_OK) return ret; /* Interpret the registers' values. */ rdptr = (const void *)registers; - uset_raw = read_u16le_inc(&rdptr); + uset_raw = read_u16be_inc(&rdptr); volt_target = uset_raw / devc->voltage_multiplier; - iset_raw = read_u16le_inc(&rdptr); + iset_raw = read_u16be_inc(&rdptr); curr_limit = iset_raw / devc->current_multiplier; - uout_raw = read_u16le_inc(&rdptr); + uout_raw = read_u16be_inc(&rdptr); curr_voltage = uout_raw / devc->voltage_multiplier; - iout_raw = read_u16le_inc(&rdptr); + iout_raw = read_u16be_inc(&rdptr); curr_current = iout_raw / devc->current_multiplier; - power_raw = read_u16le_inc(&rdptr); + power_raw = read_u16be_inc(&rdptr); curr_power = power_raw / 100.0f; - (void)read_u16le_inc(&rdptr); /* UIN */ - reg_val = read_u16le_inc(&rdptr); /* LOCK */ + (void)read_u16be_inc(&rdptr); /* UIN */ + reg_val = read_u16be_inc(&rdptr); /* LOCK */ is_lock = reg_val != 0; - reg_val = read_u16le_inc(&rdptr); /* PROTECT */ + reg_val = read_u16be_inc(&rdptr); /* PROTECT */ uses_ovp = reg_val == STATE_OVP; uses_ocp = reg_val == STATE_OCP; - reg_state = read_u16le_inc(&rdptr); /* CV_CC */ + reg_state = read_u16be_inc(&rdptr); /* CV_CC */ is_reg_cc = reg_state == MODE_CC; - out_state = read_u16le_inc(&rdptr); /* ENABLE */ + out_state = read_u16be_inc(&rdptr); /* ENABLE */ is_out_enabled = out_state != 0; /* Transfer another chunk of registers in a single call. */ @@ -358,9 +417,9 @@ SR_PRIV int rdtech_dps_get_state(const struct sr_dev_inst *sdi, /* Interpret the second registers chunk's values. */ rdptr = (const void *)registers; - ovpset_raw = read_u16le_inc(&rdptr); /* PRE OVPSET */ + ovpset_raw = read_u16be_inc(&rdptr); /* PRE OVPSET */ ovp_threshold = ovpset_raw * devc->voltage_multiplier; - ocpset_raw = read_u16le_inc(&rdptr); /* PRE OCPSET */ + ocpset_raw = read_u16be_inc(&rdptr); /* PRE OCPSET */ ocp_threshold = ocpset_raw * devc->current_multiplier; break; @@ -369,7 +428,11 @@ SR_PRIV int rdtech_dps_get_state(const struct sr_dev_inst *sdi, /* Retrieve a set of adjacent registers. */ g_mutex_lock(&devc->rw_mutex); ret = rdtech_dps_read_holding_registers(modbus, - REG_RD_VOLT_TGT, 11, registers); + REG_RD_VOLT_TGT, + devc->model->n_ranges > 1 + ? REG_RD_RANGE - REG_RD_VOLT_TGT + 1 + : REG_RD_ENABLE - REG_RD_VOLT_TGT + 1, + registers); g_mutex_unlock(&devc->rw_mutex); if (ret != SR_OK) return ret; @@ -396,6 +459,10 @@ SR_PRIV int rdtech_dps_get_state(const struct sr_dev_inst *sdi, is_reg_cc = reg_state == MODE_CC; out_state = read_u16be_inc(&rdptr); /* ENABLE */ is_out_enabled = out_state != 0; + if (have_range) { + (void)read_u16be_inc(&rdptr); /* PRESET */ + range = read_u16be_inc(&rdptr) ? 1 : 0; /* RANGE */ + } /* Retrieve a set of adjacent registers. */ g_mutex_lock(&devc->rw_mutex); @@ -456,6 +523,10 @@ SR_PRIV int rdtech_dps_get_state(const struct sr_dev_inst *sdi, state->mask |= STATE_CURRENT; state->power = curr_power; state->mask |= STATE_POWER; + if (have_range) { + state->range = range; + state->mask |= STATE_RANGE; + } return SR_OK; } @@ -575,6 +646,42 @@ SR_PRIV int rdtech_dps_set_state(const struct sr_dev_inst *sdi, return SR_ERR_ARG; } } + if (state->mask & STATE_RANGE) { + reg_value = state->range; + switch (devc->model->model_type) { + case MODEL_DPS: + /* DPS models don't support current ranges at all. */ + if (reg_value > 0) + return SR_ERR_ARG; + break; + case MODEL_RD: + /* + * Reject unsupported range indices. + * Need not set the range when the device only + * supports a single fixed range. + */ + if (reg_value >= devc->model->n_ranges) + return SR_ERR_NA; + if (devc->model->n_ranges <= 1) + return SR_OK; + ret = rdtech_rd_set_reg(sdi, REG_RD_RANGE, reg_value); + if (ret != SR_OK) + return ret; + /* + * Immediately update internal state outside of + * an acquisition. Assume that in-acquisition + * activity will update internal state. This is + * essential for meta package emission. + */ + if (!devc->acquisition_started) { + devc->curr_range = reg_value; + rdtech_dps_update_multipliers(sdi); + } + break; + default: + return SR_ERR_ARG; + } + } return SR_OK; } @@ -602,6 +709,10 @@ SR_PRIV int rdtech_dps_seed_receive(const struct sr_dev_inst *sdi) devc->curr_cc_state = state.regulation_cc; if (state.mask & STATE_OUTPUT_ENABLED) devc->curr_out_state = state.output_enabled; + if (state.mask & STATE_RANGE) { + devc->curr_range = state.range; + rdtech_dps_update_multipliers(sdi); + } return SR_OK; } @@ -614,7 +725,7 @@ SR_PRIV int rdtech_dps_receive_data(int fd, int revents, void *cb_data) struct rdtech_dps_state state; int ret; struct sr_channel *ch; - const char *regulation_text; + const char *regulation_text, *range_text; (void)fd; (void)revents; @@ -635,11 +746,11 @@ SR_PRIV int rdtech_dps_receive_data(int fd, int revents, void *cb_data) ch = g_slist_nth_data(sdi->channels, 0); send_value(sdi, ch, state.voltage, SR_MQ_VOLTAGE, SR_MQFLAG_DC, SR_UNIT_VOLT, - devc->model->voltage_digits); + devc->model->ranges[devc->curr_range].voltage_digits); ch = g_slist_nth_data(sdi->channels, 1); send_value(sdi, ch, state.current, SR_MQ_CURRENT, SR_MQFLAG_DC, SR_UNIT_AMPERE, - devc->model->current_digits); + devc->model->ranges[devc->curr_range].current_digits); ch = g_slist_nth_data(sdi->channels, 2); send_value(sdi, ch, state.power, SR_MQ_POWER, 0, SR_UNIT_WATT, 2); @@ -669,6 +780,13 @@ SR_PRIV int rdtech_dps_receive_data(int fd, int revents, void *cb_data) g_variant_new_boolean(state.output_enabled)); devc->curr_out_state = state.output_enabled; } + if (devc->curr_range != state.range) { + range_text = devc->model->ranges[state.range].range_str; + (void)sr_session_send_meta(sdi, SR_CONF_RANGE, + g_variant_new_string(range_text)); + devc->curr_range = state.range; + rdtech_dps_update_multipliers(sdi); + } /* Check optional acquisition limits. */ sr_sw_limits_update_samples_read(&devc->limits, 1);