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);