]> sigrok.org Git - libsigrok.git/blame - src/hardware/rdtech-dps/protocol.c
rdtech-dps: adjust header includes (config.h is not a system header)
[libsigrok.git] / src / hardware / rdtech-dps / protocol.c
CommitLineData
0549416e
JC
1/*
2 * This file is part of the libsigrok project.
3 *
4 * Copyright (C) 2018 James Churchill <pelrun@gmail.com>
7c0891b0 5 * Copyright (C) 2019 Frank Stettner <frank-stettner@gmx.net>
d7a4dad8 6 * Copyright (C) 2021 Gerhard Sittig <gerhard.sittig@gmx.net>
0549416e
JC
7 *
8 * This program is free software: you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation, either version 3 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program. If not, see <http://www.gnu.org/licenses/>.
20 */
21
5352598f 22#include "config.h"
d7a4dad8 23
02a4f485 24#include <math.h>
d7a4dad8
GS
25#include <string.h>
26
0549416e
JC
27#include "protocol.h"
28
02a4f485 29/* These are the Modbus RTU registers for the family of rdtech-dps devices. */
d7a4dad8 30enum rdtech_dps_register {
884ae8c0
GS
31 REG_DPS_USET = 0x00, /* Mirror of 0x50 */
32 REG_DPS_ISET = 0x01, /* Mirror of 0x51 */
33 REG_DPS_UOUT = 0x02,
34 REG_DPS_IOUT = 0x03,
35 REG_DPS_POWER = 0x04,
36 REG_DPS_UIN = 0x05,
37 REG_DPS_LOCK = 0x06,
38 REG_DPS_PROTECT = 0x07,
39 REG_DPS_CV_CC = 0x08,
40 REG_DPS_ENABLE = 0x09,
41 REG_DPS_BACKLIGHT = 0x0A, /* Mirror of 0x55 */
42 REG_DPS_MODEL = 0x0B,
43 REG_DPS_VERSION = 0x0C,
44
45 REG_DPS_PRESET = 0x23, /* Loads a preset into preset 0. */
d7a4dad8
GS
46
47 /*
48 * Add (preset * 0x10) to each of the following, for preset 1-9.
49 * Preset 0 regs below are the active output settings.
50 */
884ae8c0
GS
51 PRE_DPS_USET = 0x50,
52 PRE_DPS_ISET = 0x51,
53 PRE_DPS_OVPSET = 0x52,
54 PRE_DPS_OCPSET = 0x53,
55 PRE_DPS_OPPSET = 0x54,
56 PRE_DPS_BACKLIGHT = 0x55,
57 PRE_DPS_DISABLE = 0x56, /* Disable output if 0 is copied here from a preset (1 is no change). */
58 PRE_DPS_BOOT = 0x57, /* Enable output at boot if 1. */
d7a4dad8 59};
884ae8c0 60#define PRE_DPS_STRIDE 0x10
d7a4dad8
GS
61
62enum rdtech_dps_protect_state {
63 STATE_NORMAL = 0,
64 STATE_OVP = 1,
65 STATE_OCP = 2,
66 STATE_OPP = 3,
67};
68
69enum rdtech_dps_regulation_mode {
70 MODE_CV = 0,
71 MODE_CC = 1,
72};
73
02a4f485
MD
74/*
75 * Some registers are specific to a certain device. For example,
76 * REG_RD_RANGE is specific to RD6012P.
77 */
884ae8c0
GS
78enum rdtech_rd_register {
79 REG_RD_MODEL = 0, /* u16 */
80 REG_RD_SERIAL = 1, /* u32 */
81 REG_RD_FIRMWARE = 3, /* u16 */
82 REG_RD_TEMP_INT = 4, /* 2x u16 */
83 REG_RD_TEMP_INT_F = 6, /* 2x u16 */
84 REG_RD_VOLT_TGT = 8, /* u16 */
85 REG_RD_CURR_LIM = 9, /* u16 */
86 REG_RD_VOLTAGE = 10, /* u16 */
87 REG_RD_CURRENT = 11, /* u16 */
88 REG_RD_ENERGY = 12, /* u16 */
89 REG_RD_POWER = 13, /* u16 */
90 REG_RD_VOLT_IN = 14, /* u16 */
91 REG_RD_PROTECT = 16, /* u16 */
92 REG_RD_REGULATION = 17, /* u16 */
93 REG_RD_ENABLE = 18, /* u16 */
02a4f485
MD
94 REG_RD_PRESET = 19, /* u16 */
95 REG_RD_RANGE = 20, /* u16 */
884ae8c0
GS
96 /*
97 * Battery at 32 == 0x20 pp:
98 * Mode, voltage, temperature, capacity, energy.
99 */
100 /*
101 * Date/time at 48 == 0x30 pp:
102 * Year, month, day, hour, minute, second.
103 */
104 /* Backlight at 72 == 0x48. */
105 REG_RD_OVP_THR = 82, /* 0x52 */
106 REG_RD_OCP_THR = 83, /* 0x53 */
107 /* One "live" slot and 9 "memory" positions. */
108 REG_RD_START_MEM = 84, /* 0x54 */
109};
110
d7a4dad8
GS
111/* Retries failed modbus read attempts for improved reliability. */
112static int rdtech_dps_read_holding_registers(struct sr_modbus_dev_inst *modbus,
113 int address, int nb_registers, uint16_t *registers)
aff20941 114{
d7a4dad8
GS
115 size_t retries;
116 int ret;
aff20941 117
d7a4dad8 118 retries = 3;
02a4f485 119 do {
aff20941
FS
120 ret = sr_modbus_read_holding_registers(modbus,
121 address, nb_registers, registers);
d7a4dad8
GS
122 if (ret == SR_OK)
123 return ret;
02a4f485 124 } while (--retries);
aff20941
FS
125
126 return ret;
127}
128
884ae8c0
GS
129/* Set one 16bit register. LE format for DPS devices. */
130static int rdtech_dps_set_reg(const struct sr_dev_inst *sdi,
131 uint16_t address, uint16_t value)
69b05583 132{
7c0891b0
FS
133 struct dev_context *devc;
134 struct sr_modbus_dev_inst *modbus;
69b05583 135 uint16_t registers[1];
7c0891b0 136 int ret;
884ae8c0 137 uint8_t *wrptr;
7c0891b0
FS
138
139 devc = sdi->priv;
140 modbus = sdi->conn;
141
884ae8c0 142 wrptr = (void *)registers;
a7e919a3 143 write_u16be(wrptr, value);
884ae8c0 144
7c0891b0 145 g_mutex_lock(&devc->rw_mutex);
884ae8c0
GS
146 ret = sr_modbus_write_multiple_registers(modbus, address,
147 ARRAY_SIZE(registers), registers);
7c0891b0 148 g_mutex_unlock(&devc->rw_mutex);
d7a4dad8 149
69b05583
JC
150 return ret;
151}
152
884ae8c0
GS
153/* Set one 16bit register. BE format for RD devices. */
154static int rdtech_rd_set_reg(const struct sr_dev_inst *sdi,
d7a4dad8 155 uint16_t address, uint16_t value)
69b05583 156{
7c0891b0
FS
157 struct dev_context *devc;
158 struct sr_modbus_dev_inst *modbus;
69b05583 159 uint16_t registers[1];
7c0891b0 160 int ret;
d7a4dad8 161 uint8_t *wrptr;
7c0891b0
FS
162
163 devc = sdi->priv;
164 modbus = sdi->conn;
165
d7a4dad8 166 wrptr = (void *)registers;
884ae8c0 167 write_u16be(wrptr, value);
d7a4dad8 168
7c0891b0 169 g_mutex_lock(&devc->rw_mutex);
d7a4dad8
GS
170 ret = sr_modbus_write_multiple_registers(modbus, address,
171 ARRAY_SIZE(registers), registers);
7c0891b0 172 g_mutex_unlock(&devc->rw_mutex);
d7a4dad8 173
7c0891b0 174 return ret;
69b05583
JC
175}
176
d7a4dad8 177/* Get DPS model number and firmware version from a connected device. */
69b05583 178SR_PRIV int rdtech_dps_get_model_version(struct sr_modbus_dev_inst *modbus,
884ae8c0
GS
179 enum rdtech_dps_model_type model_type,
180 uint16_t *model, uint16_t *version, uint32_t *serno)
69b05583 181{
884ae8c0 182 uint16_t registers[4];
69b05583 183 int ret;
d7a4dad8
GS
184 const uint8_t *rdptr;
185
7c0891b0 186 /*
884ae8c0
GS
187 * No mutex here because when the routine executes then the
188 * device instance was not created yet (probe phase).
7c0891b0 189 */
884ae8c0
GS
190 switch (model_type) {
191 case MODEL_DPS:
192 /* Get the MODEL and VERSION registers. */
193 ret = rdtech_dps_read_holding_registers(modbus,
194 REG_DPS_MODEL, 2, registers);
195 if (ret != SR_OK)
196 return ret;
197 rdptr = (void *)registers;
a7e919a3
VA
198 *model = read_u16be_inc(&rdptr);
199 *version = read_u16be_inc(&rdptr);
884ae8c0
GS
200 *serno = 0;
201 sr_info("RDTech DPS/DPH model: %u version: %u",
202 *model, *version);
203 return SR_OK;
204 case MODEL_RD:
205 /* Get the MODEL, SERIAL, and FIRMWARE registers. */
206 ret = rdtech_dps_read_holding_registers(modbus,
207 REG_RD_MODEL, 4, registers);
208 if (ret != SR_OK)
209 return ret;
210 rdptr = (void *)registers;
02a4f485 211 *model = read_u16be_inc(&rdptr);
884ae8c0
GS
212 *serno = read_u32be_inc(&rdptr);
213 *version = read_u16be_inc(&rdptr);
214 sr_info("RDTech RD model: %u version: %u, serno %u",
215 *model, *version, *serno);
216 return SR_OK;
217 default:
218 sr_err("Unexpected RDTech PSU device type. Programming error?");
219 return SR_ERR_ARG;
220 }
221 /* UNREACH */
69b05583
JC
222}
223
02a4f485
MD
224SR_PRIV void rdtech_dps_update_multipliers(const struct sr_dev_inst *sdi)
225{
226 struct dev_context *devc;
227 struct rdtech_dps_range *range;
228
229 devc = sdi->priv;
230 range = &devc->model->ranges[devc->curr_range];
231 devc->current_multiplier = pow(10.0, range->current_digits);
232 devc->voltage_multiplier = pow(10.0, range->voltage_digits);
233}
234
235/*
236 * Determine range of connected device. Don't do anything once
237 * acquisition has started (since the range will then be tracked).
238 */
239SR_PRIV int rdtech_dps_update_range(const struct sr_dev_inst *sdi)
240{
241 struct dev_context *devc;
242 uint16_t range;
243 int ret;
244
245 devc = sdi->priv;
246
247 /*
248 * Only update range if there are multiple ranges and data
249 * acquisition hasn't started.
250 */
251 if (devc->model->n_ranges == 1 || devc->acquisition_started)
252 return SR_OK;
253 if (devc->model->model_type != MODEL_RD)
254 return SR_ERR;
255
256 ret = rdtech_dps_read_holding_registers(sdi->conn,
257 REG_RD_RANGE, 1, &range);
258 if (ret != SR_OK)
259 return ret;
260 devc->curr_range = range ? 1 : 0;
261 rdtech_dps_update_multipliers(sdi);
262
263 return SR_OK;
264}
265
d7a4dad8
GS
266/* Send a measured value to the session feed. */
267static int send_value(const struct sr_dev_inst *sdi,
268 struct sr_channel *ch, float value,
269 enum sr_mq mq, enum sr_mqflag mqflags,
270 enum sr_unit unit, int digits)
69b05583
JC
271{
272 struct sr_datafeed_packet packet;
273 struct sr_datafeed_analog analog;
274 struct sr_analog_encoding encoding;
275 struct sr_analog_meaning meaning;
276 struct sr_analog_spec spec;
d7a4dad8 277 int ret;
69b05583
JC
278
279 sr_analog_init(&analog, &encoding, &meaning, &spec, digits);
280 analog.meaning->channels = g_slist_append(NULL, ch);
281 analog.num_samples = 1;
282 analog.data = &value;
283 analog.meaning->mq = mq;
c9b187a6 284 analog.meaning->mqflags = mqflags;
69b05583 285 analog.meaning->unit = unit;
69b05583
JC
286
287 packet.type = SR_DF_ANALOG;
288 packet.payload = &analog;
d7a4dad8
GS
289 ret = sr_session_send(sdi, &packet);
290
69b05583 291 g_slist_free(analog.meaning->channels);
d7a4dad8
GS
292
293 return ret;
294}
295
296/*
297 * Get the device's current state. Exhaustively, relentlessly.
298 * Concentrate all details of communication in the physical transport,
299 * register layout interpretation, and potential model dependency in
300 * this central spot, to simplify maintenance.
301 *
302 * TODO Optionally limit the transfer volume depending on caller's spec
303 * which detail level is desired? Is 10 registers each 16bits an issue
304 * when the UART bitrate is only 9600bps?
305 */
306SR_PRIV int rdtech_dps_get_state(const struct sr_dev_inst *sdi,
7a78fd56 307 struct rdtech_dps_state *state, enum rdtech_dps_state_context reason)
d7a4dad8
GS
308{
309 struct dev_context *devc;
310 struct sr_modbus_dev_inst *modbus;
7a78fd56 311 gboolean get_config, get_init_state, get_curr_meas;
02a4f485 312 uint16_t registers[14];
d7a4dad8
GS
313 int ret;
314 const uint8_t *rdptr;
315 uint16_t uset_raw, iset_raw, uout_raw, iout_raw, power_raw;
316 uint16_t reg_val, reg_state, out_state, ovpset_raw, ocpset_raw;
317 gboolean is_lock, is_out_enabled, is_reg_cc;
318 gboolean uses_ovp, uses_ocp;
02a4f485 319 uint16_t range;
d7a4dad8
GS
320 float volt_target, curr_limit;
321 float ovp_threshold, ocp_threshold;
322 float curr_voltage, curr_current, curr_power;
323
324 if (!sdi || !sdi->priv || !sdi->conn)
325 return SR_ERR_ARG;
326 devc = sdi->priv;
327 modbus = sdi->conn;
328 if (!state)
329 return SR_ERR_ARG;
330
7a78fd56
GS
331 /* Determine the requested level of response detail. */
332 get_config = FALSE;
333 get_init_state = FALSE;
334 get_curr_meas = FALSE;
335 switch (reason) {
336 case ST_CTX_CONFIG:
337 get_config = TRUE;
338 get_init_state = TRUE;
339 get_curr_meas = TRUE;
340 break;
341 case ST_CTX_PRE_ACQ:
342 get_init_state = TRUE;
343 get_curr_meas = TRUE;
344 break;
345 case ST_CTX_IN_ACQ:
346 get_curr_meas = TRUE;
347 break;
348 default:
349 /* EMPTY */
350 break;
351 }
352 /*
353 * TODO Make use of this information to reduce the transfer
354 * volume, especially on low bitrate serial connections. Though
355 * the device firmware's samplerate is probably more limiting
356 * than communication bandwidth is.
357 */
358 (void)get_config;
359 (void)get_init_state;
360 (void)get_curr_meas;
361
02a4f485
MD
362 /*
363 * The model RD6012P has two voltage/current ranges. We set a
364 * default value here such that the compiler doesn't generate
365 * an uninitialized variable warning.
366 */
367 range = 0;
368
884ae8c0
GS
369 switch (devc->model->model_type) {
370 case MODEL_DPS:
371 /*
372 * Transfer a chunk of registers in a single call. It's
373 * unfortunate that the model dependency and the sparse
374 * register map force us to open code addresses, sizes,
375 * and the sequence of the registers and how to interpret
376 * their bit fields. But then this is not too unusual for
377 * a hardware specific device driver ...
884ae8c0
GS
378 */
379 g_mutex_lock(&devc->rw_mutex);
02a4f485
MD
380 ret = rdtech_dps_read_holding_registers(modbus, REG_DPS_USET,
381 REG_DPS_ENABLE - REG_DPS_USET + 1, registers);
884ae8c0
GS
382 g_mutex_unlock(&devc->rw_mutex);
383 if (ret != SR_OK)
384 return ret;
d7a4dad8 385
884ae8c0
GS
386 /* Interpret the registers' values. */
387 rdptr = (const void *)registers;
a7e919a3 388 uset_raw = read_u16be_inc(&rdptr);
884ae8c0 389 volt_target = uset_raw / devc->voltage_multiplier;
a7e919a3 390 iset_raw = read_u16be_inc(&rdptr);
884ae8c0 391 curr_limit = iset_raw / devc->current_multiplier;
a7e919a3 392 uout_raw = read_u16be_inc(&rdptr);
884ae8c0 393 curr_voltage = uout_raw / devc->voltage_multiplier;
a7e919a3 394 iout_raw = read_u16be_inc(&rdptr);
884ae8c0 395 curr_current = iout_raw / devc->current_multiplier;
a7e919a3 396 power_raw = read_u16be_inc(&rdptr);
884ae8c0 397 curr_power = power_raw / 100.0f;
a7e919a3
VA
398 (void)read_u16be_inc(&rdptr); /* UIN */
399 reg_val = read_u16be_inc(&rdptr); /* LOCK */
884ae8c0 400 is_lock = reg_val != 0;
a7e919a3 401 reg_val = read_u16be_inc(&rdptr); /* PROTECT */
884ae8c0
GS
402 uses_ovp = reg_val == STATE_OVP;
403 uses_ocp = reg_val == STATE_OCP;
a7e919a3 404 reg_state = read_u16be_inc(&rdptr); /* CV_CC */
884ae8c0 405 is_reg_cc = reg_state == MODE_CC;
a7e919a3 406 out_state = read_u16be_inc(&rdptr); /* ENABLE */
884ae8c0
GS
407 is_out_enabled = out_state != 0;
408
409 /* Transfer another chunk of registers in a single call. */
410 g_mutex_lock(&devc->rw_mutex);
411 ret = rdtech_dps_read_holding_registers(modbus,
412 PRE_DPS_OVPSET, 2, registers);
413 g_mutex_unlock(&devc->rw_mutex);
414 if (ret != SR_OK)
415 return ret;
d7a4dad8 416
884ae8c0
GS
417 /* Interpret the second registers chunk's values. */
418 rdptr = (const void *)registers;
a7e919a3 419 ovpset_raw = read_u16be_inc(&rdptr); /* PRE OVPSET */
884ae8c0 420 ovp_threshold = ovpset_raw * devc->voltage_multiplier;
a7e919a3 421 ocpset_raw = read_u16be_inc(&rdptr); /* PRE OCPSET */
884ae8c0
GS
422 ocp_threshold = ocpset_raw * devc->current_multiplier;
423
424 break;
425
426 case MODEL_RD:
427 /* Retrieve a set of adjacent registers. */
428 g_mutex_lock(&devc->rw_mutex);
429 ret = rdtech_dps_read_holding_registers(modbus,
02a4f485
MD
430 REG_RD_VOLT_TGT,
431 devc->model->n_ranges > 1
432 ? REG_RD_RANGE - REG_RD_VOLT_TGT + 1
433 : REG_RD_ENABLE - REG_RD_VOLT_TGT + 1,
434 registers);
884ae8c0
GS
435 g_mutex_unlock(&devc->rw_mutex);
436 if (ret != SR_OK)
437 return ret;
438
439 /* Interpret the registers' raw content. */
440 rdptr = (const void *)registers;
441 uset_raw = read_u16be_inc(&rdptr); /* USET */
442 volt_target = uset_raw / devc->voltage_multiplier;
443 iset_raw = read_u16be_inc(&rdptr); /* ISET */
444 curr_limit = iset_raw / devc->current_multiplier;
445 uout_raw = read_u16be_inc(&rdptr); /* UOUT */
446 curr_voltage = uout_raw / devc->voltage_multiplier;
447 iout_raw = read_u16be_inc(&rdptr); /* IOUT */
448 curr_current = iout_raw / devc->current_multiplier;
449 (void)read_u16be_inc(&rdptr); /* ENERGY */
450 power_raw = read_u16be_inc(&rdptr); /* POWER */
451 curr_power = power_raw / 100.0f;
452 (void)read_u16be_inc(&rdptr); /* VOLT_IN */
453 (void)read_u16be_inc(&rdptr);
454 reg_val = read_u16be_inc(&rdptr); /* PROTECT */
455 uses_ovp = reg_val == STATE_OVP;
456 uses_ocp = reg_val == STATE_OCP;
457 reg_state = read_u16be_inc(&rdptr); /* REGULATION */
458 is_reg_cc = reg_state == MODE_CC;
459 out_state = read_u16be_inc(&rdptr); /* ENABLE */
460 is_out_enabled = out_state != 0;
02a4f485
MD
461 if (devc->model->n_ranges > 1) {
462 rdptr += sizeof (uint16_t); /* PRESET */
463 range = read_u16be_inc(&rdptr) ? 1 : 0; /* RANGE */
464 }
884ae8c0
GS
465
466 /* Retrieve a set of adjacent registers. */
467 g_mutex_lock(&devc->rw_mutex);
468 ret = rdtech_dps_read_holding_registers(modbus,
469 REG_RD_OVP_THR, 2, registers);
470 g_mutex_unlock(&devc->rw_mutex);
471 if (ret != SR_OK)
472 return ret;
473
474 /* Interpret the registers' raw content. */
475 rdptr = (const void *)registers;
476 ovpset_raw = read_u16be_inc(&rdptr); /* OVP THR */
477 ovp_threshold = ovpset_raw / devc->voltage_multiplier;
478 ocpset_raw = read_u16be_inc(&rdptr); /* OCP THR */
479 ocp_threshold = ocpset_raw / devc->current_multiplier;
d7a4dad8 480
884ae8c0
GS
481 /* Details which we cannot query from the device. */
482 is_lock = FALSE;
483
484 break;
485
486 default:
487 /* ShouldNotHappen(TM). Probe should have failed. */
488 return SR_ERR_ARG;
489 }
d7a4dad8 490
7a78fd56
GS
491 /*
492 * Store gathered details in the high level container.
493 *
494 * TODO Make use of the caller's context. The register access
495 * code path above need not have gathered every detail in every
496 * invocation.
497 */
d7a4dad8
GS
498 memset(state, 0, sizeof(*state));
499 state->lock = is_lock;
500 state->mask |= STATE_LOCK;
501 state->output_enabled = is_out_enabled;
502 state->mask |= STATE_OUTPUT_ENABLED;
503 state->regulation_cc = is_reg_cc;
504 state->mask |= STATE_REGULATION_CC;
505 state->protect_ovp = uses_ovp;
506 state->mask |= STATE_PROTECT_OVP;
507 state->protect_ocp = uses_ocp;
508 state->mask |= STATE_PROTECT_OCP;
509 state->protect_enabled = TRUE;
510 state->mask |= STATE_PROTECT_ENABLED;
511 state->voltage_target = volt_target;
512 state->mask |= STATE_VOLTAGE_TARGET;
513 state->current_limit = curr_limit;
514 state->mask |= STATE_CURRENT_LIMIT;
515 state->ovp_threshold = ovp_threshold;
516 state->mask |= STATE_OVP_THRESHOLD;
517 state->ocp_threshold = ocp_threshold;
518 state->mask |= STATE_OCP_THRESHOLD;
519 state->voltage = curr_voltage;
520 state->mask |= STATE_VOLTAGE;
521 state->current = curr_current;
522 state->mask |= STATE_CURRENT;
523 state->power = curr_power;
524 state->mask |= STATE_POWER;
02a4f485
MD
525 if (devc->model->n_ranges > 1) {
526 state->range = range;
527 state->mask |= STATE_RANGE;
528 }
d7a4dad8
GS
529
530 return SR_OK;
531}
532
533/* Setup device's parameters. Selectively, from caller specs. */
534SR_PRIV int rdtech_dps_set_state(const struct sr_dev_inst *sdi,
535 struct rdtech_dps_state *state)
536{
537 struct dev_context *devc;
538 uint16_t reg_value;
539 int ret;
540
541 if (!sdi || !sdi->priv || !sdi->conn)
542 return SR_ERR_ARG;
543 devc = sdi->priv;
544 if (!state)
545 return SR_ERR_ARG;
546
547 /* Only a subset of known values is settable. */
548 if (state->mask & STATE_OUTPUT_ENABLED) {
549 reg_value = state->output_enabled ? 1 : 0;
884ae8c0
GS
550 switch (devc->model->model_type) {
551 case MODEL_DPS:
552 ret = rdtech_dps_set_reg(sdi, REG_DPS_ENABLE, reg_value);
553 if (ret != SR_OK)
554 return ret;
555 break;
556 case MODEL_RD:
557 ret = rdtech_rd_set_reg(sdi, REG_RD_ENABLE, reg_value);
558 if (ret != SR_OK)
559 return ret;
560 break;
561 default:
562 return SR_ERR_ARG;
563 }
d7a4dad8
GS
564 }
565 if (state->mask & STATE_VOLTAGE_TARGET) {
566 reg_value = state->voltage_target * devc->voltage_multiplier;
884ae8c0
GS
567 switch (devc->model->model_type) {
568 case MODEL_DPS:
569 ret = rdtech_dps_set_reg(sdi, REG_DPS_USET, reg_value);
570 if (ret != SR_OK)
571 return ret;
572 break;
573 case MODEL_RD:
574 ret = rdtech_rd_set_reg(sdi, REG_RD_VOLT_TGT, reg_value);
575 if (ret != SR_OK)
576 return ret;
577 break;
578 default:
579 return SR_ERR_ARG;
580 }
d7a4dad8
GS
581 }
582 if (state->mask & STATE_CURRENT_LIMIT) {
583 reg_value = state->current_limit * devc->current_multiplier;
884ae8c0
GS
584 switch (devc->model->model_type) {
585 case MODEL_DPS:
586 ret = rdtech_dps_set_reg(sdi, REG_DPS_ISET, reg_value);
587 if (ret != SR_OK)
588 return ret;
589 break;
590 case MODEL_RD:
591 ret = rdtech_rd_set_reg(sdi, REG_RD_CURR_LIM, reg_value);
592 if (ret != SR_OK)
593 return ret;
594 break;
595 default:
596 return SR_ERR_ARG;
597 }
d7a4dad8
GS
598 }
599 if (state->mask & STATE_OVP_THRESHOLD) {
600 reg_value = state->ovp_threshold * devc->voltage_multiplier;
884ae8c0
GS
601 switch (devc->model->model_type) {
602 case MODEL_DPS:
603 ret = rdtech_dps_set_reg(sdi, PRE_DPS_OVPSET, reg_value);
604 if (ret != SR_OK)
605 return ret;
606 break;
607 case MODEL_RD:
608 ret = rdtech_rd_set_reg(sdi, REG_RD_OVP_THR, reg_value);
609 if (ret != SR_OK)
610 return ret;
611 break;
612 default:
613 return SR_ERR_ARG;
614 }
d7a4dad8
GS
615 }
616 if (state->mask & STATE_OCP_THRESHOLD) {
617 reg_value = state->ocp_threshold * devc->current_multiplier;
884ae8c0
GS
618 switch (devc->model->model_type) {
619 case MODEL_DPS:
620 ret = rdtech_dps_set_reg(sdi, PRE_DPS_OCPSET, reg_value);
621 if (ret != SR_OK)
622 return ret;
623 break;
624 case MODEL_RD:
625 ret = rdtech_rd_set_reg(sdi, REG_RD_OCP_THR, reg_value);
626 if (ret != SR_OK)
627 return ret;
628 break;
629 default:
630 return SR_ERR_ARG;
631 }
d7a4dad8
GS
632 }
633 if (state->mask & STATE_LOCK) {
884ae8c0
GS
634 switch (devc->model->model_type) {
635 case MODEL_DPS:
636 reg_value = state->lock ? 1 : 0;
637 ret = rdtech_dps_set_reg(sdi, REG_DPS_LOCK, reg_value);
638 if (ret != SR_OK)
639 return ret;
640 break;
641 case MODEL_RD:
642 /* Do nothing, _and_ silently succeed. */
643 break;
644 default:
645 return SR_ERR_ARG;
646 }
d7a4dad8 647 }
02a4f485
MD
648 if (state->mask & STATE_RANGE) {
649 reg_value = state->range;
650 switch (devc->model->model_type) {
651 case MODEL_DPS:
652 if (reg_value > 0)
653 return SR_ERR_ARG;
654 break;
655 case MODEL_RD:
656 if (devc->model->n_ranges == 1)
657 /* No need to set. */
658 return SR_OK;
659 ret = rdtech_rd_set_reg(sdi, REG_RD_RANGE, reg_value);
660 if (ret != SR_OK)
661 return ret;
662 if (!devc->acquisition_started) {
663 devc->curr_range = reg_value ? 1 : 0;
664 rdtech_dps_update_multipliers(sdi);
665 }
666 /*
667 * We rely on the data acquisition to update
668 * devc->curr_range. If we do it here, there
669 * will be no range meta package.
670 */
671 break;
672 default:
673 return SR_ERR_ARG;
674 }
675 }
d7a4dad8
GS
676
677 return SR_OK;
69b05583
JC
678}
679
d7a4dad8
GS
680/* Get the current state when acquisition starts. */
681SR_PRIV int rdtech_dps_seed_receive(const struct sr_dev_inst *sdi)
682{
683 struct dev_context *devc;
684 struct rdtech_dps_state state;
685 int ret;
686
4efd5462
FS
687 if (!sdi || !sdi->priv)
688 return SR_ERR_ARG;
689 devc = sdi->priv;
02a4f485 690 devc->acquisition_started = TRUE;
4efd5462 691
7a78fd56 692 ret = rdtech_dps_get_state(sdi, &state, ST_CTX_PRE_ACQ);
d7a4dad8
GS
693 if (ret != SR_OK)
694 return ret;
695
696 if (state.mask & STATE_PROTECT_OVP)
697 devc->curr_ovp_state = state.protect_ovp;
698 if (state.mask & STATE_PROTECT_OCP)
699 devc->curr_ocp_state = state.protect_ocp;
700 if (state.mask & STATE_REGULATION_CC)
701 devc->curr_cc_state = state.regulation_cc;
702 if (state.mask & STATE_OUTPUT_ENABLED)
703 devc->curr_out_state = state.output_enabled;
02a4f485
MD
704 if (state.mask & STATE_RANGE) {
705 devc->curr_range = state.range;
706 rdtech_dps_update_multipliers(sdi);
707 }
d7a4dad8
GS
708
709 return SR_OK;
710}
711
712/* Get measurements, track state changes during acquisition. */
0549416e
JC
713SR_PRIV int rdtech_dps_receive_data(int fd, int revents, void *cb_data)
714{
69b05583 715 struct sr_dev_inst *sdi;
0549416e 716 struct dev_context *devc;
d7a4dad8 717 struct rdtech_dps_state state;
7c0891b0 718 int ret;
d7a4dad8
GS
719 struct sr_channel *ch;
720 const char *regulation_text;
0549416e
JC
721
722 (void)fd;
69b05583 723 (void)revents;
0549416e 724
d7a4dad8
GS
725 sdi = cb_data;
726 if (!sdi)
0549416e 727 return TRUE;
69b05583
JC
728 devc = sdi->priv;
729
d7a4dad8 730 /* Get the device's current state. */
7a78fd56 731 ret = rdtech_dps_get_state(sdi, &state, ST_CTX_IN_ACQ);
d7a4dad8
GS
732 if (ret != SR_OK)
733 return ret;
7c0891b0 734
d7a4dad8
GS
735
736 /* Submit measurement data to the session feed. */
737 std_session_send_df_frame_begin(sdi);
738 ch = g_slist_nth_data(sdi->channels, 0);
739 send_value(sdi, ch, state.voltage,
740 SR_MQ_VOLTAGE, SR_MQFLAG_DC, SR_UNIT_VOLT,
02a4f485 741 devc->model->ranges[devc->curr_range].voltage_digits);
d7a4dad8
GS
742 ch = g_slist_nth_data(sdi->channels, 1);
743 send_value(sdi, ch, state.current,
744 SR_MQ_CURRENT, SR_MQFLAG_DC, SR_UNIT_AMPERE,
02a4f485 745 devc->model->ranges[devc->curr_range].current_digits);
d7a4dad8
GS
746 ch = g_slist_nth_data(sdi->channels, 2);
747 send_value(sdi, ch, state.power,
748 SR_MQ_POWER, 0, SR_UNIT_WATT, 2);
749 std_session_send_df_frame_end(sdi);
750
751 /* Check for state changes. */
752 if (devc->curr_ovp_state != state.protect_ovp) {
753 (void)sr_session_send_meta(sdi,
754 SR_CONF_OVER_VOLTAGE_PROTECTION_ACTIVE,
755 g_variant_new_boolean(state.protect_ovp));
756 devc->curr_ovp_state = state.protect_ovp;
757 }
758 if (devc->curr_ocp_state != state.protect_ocp) {
759 (void)sr_session_send_meta(sdi,
760 SR_CONF_OVER_CURRENT_PROTECTION_ACTIVE,
761 g_variant_new_boolean(state.protect_ocp));
762 devc->curr_ocp_state = state.protect_ocp;
763 }
764 if (devc->curr_cc_state != state.regulation_cc) {
765 regulation_text = state.regulation_cc ? "CC" : "CV";
766 (void)sr_session_send_meta(sdi, SR_CONF_REGULATION,
767 g_variant_new_string(regulation_text));
768 devc->curr_cc_state = state.regulation_cc;
769 }
770 if (devc->curr_out_state != state.output_enabled) {
771 (void)sr_session_send_meta(sdi, SR_CONF_ENABLED,
772 g_variant_new_boolean(state.output_enabled));
773 devc->curr_out_state = state.output_enabled;
69b05583 774 }
02a4f485
MD
775 if (devc->curr_range != state.range) {
776 (void)sr_session_send_meta(sdi, SR_CONF_RANGE,
777 g_variant_new_string(
778 devc->model->ranges[state.range].range_str));
779 devc->curr_range = state.range;
780 rdtech_dps_update_multipliers(sdi);
781 }
69b05583 782
d7a4dad8
GS
783 /* Check optional acquisition limits. */
784 sr_sw_limits_update_samples_read(&devc->limits, 1);
69b05583
JC
785 if (sr_sw_limits_check(&devc->limits)) {
786 sr_dev_acquisition_stop(sdi);
787 return TRUE;
0549416e
JC
788 }
789
790 return TRUE;
791}