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