]> sigrok.org Git - libsigrok.git/blame - src/hardware/uni-t-ut181a/protocol.c
output/csv: use intermediate time_t var, silence compiler warning
[libsigrok.git] / src / hardware / uni-t-ut181a / protocol.c
CommitLineData
3094e9d8
GS
1/*
2 * This file is part of the libsigrok project.
3 *
ebc51109 4 * Copyright (C) 2019-2020 Gerhard Sittig <gerhard.sittig@gmx.net>
3094e9d8
GS
5 *
6 * This program is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 */
19
ebc51109
GS
20/*
21 * This implementation uses protocol information which was provided by
22 * the MIT licensed ut181a project. See Protocol.md for more details:
23 *
24 * https://github.com/antage/ut181a/blob/master/Protocol.md
25 */
26
3094e9d8 27#include <config.h>
ebc51109
GS
28#include <ctype.h>
29#include <math.h>
30#include <string.h>
31
3094e9d8
GS
32#include "protocol.h"
33
ebc51109
GS
34/*
35 * This driver depends on the user's enabling serial communication in
36 * the multimeter's menu system: SETUP -> Communication -> ON. The BLE
37 * adapter will shutdown within a short period of time when it's not
38 * being communicated to, needs another power cycle to re-connect. The
39 * USB cable does not suffer from such a constraint.
40 *
41 * Developer notes on the UT181A protocol:
42 * - Serial communication over HID or BLE based "cables", UT-D09 or
43 * UT-D07A, bidirectional communication (UT-D04 won't do).
44 * - UART frame format 8n1 at 9600 bps. Variable length DMM packets.
45 * - DMM packet starts with a magic marker, followed by the length,
46 * followed by data bytes and terminated by the checksum field.
47 * The length includes the remainder of the frame. The checksum
48 * includes the length field as well. The checksum value is the
49 * 16bit sum of all preceeding byte values.
50 * - The meter has many features (live readings, saved measurements,
51 * recorded measurement series) with many additional attributes:
52 * relative, min/max/avg, peak, AC+DC, multiple temperature probes,
53 * COMP mode (PASS/FAIL). The protocol reflects this with highly
54 * variable responses, with differing response layouts including
55 * optional field presence.
56 * - Frame field values are communicated in 8/16/32 bit integer as well
57 * as 32bit float formats in little endian presentation. Measurement
58 * values are represented by a combination of a float value and flags
59 * and a precision (digits count) and a text string which encodes the
60 * measured quantity including its flags and another scale factor
61 * (prefix reflecting the current range).
62 * - Response frames often provide a set of values at the same time:
63 * There are multiple displays, like current and min/max/avg values,
64 * relative values including their reference and the absolute value,
65 * differences between probes, etc.
66 * - The meter can hold multiple recordings with user assigned names,
67 * sample interval and duration, including interactive stop of a
68 * currently active recording. These recordings contain samples that
69 * were taken at a user specified interval.
70 * - The meter can store a list of measurements, which get saved upon
71 * user requests, and can span arbitrary modes/functions/layouts per
72 * saved measurement. In contrast to recordings which keep their type
73 * of measurement across the set of samples.
74 *
75 * See https://github.com/antage/ut181a/blob/master/Protocol.md for a
76 * detailled description of the meter's protocol. Some additional notes
77 * in slightly reformatted layout for improved maintainability:
78 * - "Range byte"
79 * 0x00 Auto range
80 * 0x01 60 mV 6 V 600 uA 60 mA 600 R 60 Hz 6 nF
81 * 0x02 600 mV 60 V 6000 uA 600 mA 6 K 600 Hz 60 nF
82 * 0x03 600V (20A is: auto) 60 K 6 KHz 600 nF
83 * 0x04 1000 V 600 K 60 KHz 6 uF
84 * 0x05 6 M 600 KHz 60 uF
85 * 0x06 60 M 6 MHz 600 uF
86 * 0x07 60 MHz 6 mF
87 * 0x08 60 mF
88 * ampere: 20A is auto, not user selectable
89 * continuity: 600 R, not user selectable
90 * conductivity: 60nS, not user selectable
91 * temperature: not user selectable
92 * diode: not user selectable
93 * frequency: all of the above ranges are available
94 * duty cycle, period: 60Hz to 60kHz, not user selectable beyond 60kHz
95 * - DMM response packets in COMP mode (limits check, PASS/FAIL):
96 * - The device supports two limits (upper, lower) and several modes
97 * ("inner", "outer", "below", "above"). The result is boolean for
98 * PASS or FAIL.
99 * - Response packets are NORMAL MEASUREMENTs, with a MAIN value but
100 * without AUX1/AUX2/BAR. Plus some more fields after the bargraph
101 * unit field's position which are specific to COMP mode. Auto range
102 * is off (also in the display).
103 * - Example data for COMP mode responses:
104 * INNER +0mV +3.3mV PASS -- 00 00 03 33 33 53 40 00 00 00 00
105 * INNER +0mV +3.3mV FAIL -- 00 01 03 33 33 53 40 00 00 00 00
106 * INNER +1mV +3.3mV FAIL -- 00 01 03 33 33 53 40 00 00 80 3f
107 * OUTER +0mV +3.3mV PASS -- 01 00 03 33 33 53 40 00 00 00 00
108 * BELOW +30mV PASS -- 02 00 03 00 00 f0 41
109 * - Extra fields:
110 * 1 byte mode, can be 0 to 3 for INNER/OUTER/BELOW/ABOVE
111 * 1 byte test result, bool failure, 0 is PASS, 1 is FAIL
112 * 1 byte digits, *not* shifted as in other precision fields
113 * 4 byte (always) high limit
114 * 4 byte (conditional) low limit, not in all modes
115 *
116 * Implementation notes on this driver version:
117 * - DMM channel assignment for measurement types:
118 * - normal: P1 main, P2 aux1, P3 aux2, P5 bar (as applicable)
119 * - relative: P1 relative, P2 reference, P3 absolute
120 * - min-max: P1 current, P2 maximum, P3 average, P4 minimum
121 * - peak: P2 maximum, P4 minimum
122 * - save/recording: P5 timestamp (in addition to the above)
123 */
124
125/*
126 * TODO:
127 * - General question: How many channels to export? An overlay with ever
128 * changing meanings? Or a multitude where values are sparse?
129 * - Check how the PC side can _set_ the mode and range. Does mode
130 * selection depend on the physical knob? Would assume it does.
131 * The multitude of mode codes (some 70) and the lack of an apparent
132 * formula to them makes this enhancement tedious. Listing too many
133 * items in the "list" query could reduce usability.
134 * - Add support for "COMP mode" (comparison, PASS/FAIL result).
135 * - How to express PASS/FAIL in the data feed submission? There is
136 * SR_UNIT_BOOLEAN but not a good MQ for envelope test results.
137 * - How to communicate limits to the session feed? COMP replies are
138 * normal measurements without aux1 and aux2. Is it appropriate to
139 * re-use DMM channels, or shall we add more of them?
140 * - Communicate timestamps for saved measurements and recordings to the
141 * session feed.
142 * - There is SR_MQ_TIME and SR_MQFLAG_RELATIVE, and SR_UNIT_SECOND.
143 * Absolute time seems appropriate for save, relative (to the start
144 * of the recording) for recordings.
145 * - Unfortunately double data types are not fully operational, so we
146 * use float. Which is limited to 23 bits, thus can only span some
147 * 100 days. But recordings can span longer periods when the sample
148 * interval is large.
149 * - Absolute times suffer from the 23bit limit (epoch time_t values
150 * require 32 bits these days). And they get presented as 1.5Gs,
151 * there seems to be no "date/time" flag or format.
152 * - Dynamically allocate and re-allocate the record name table. There
153 * appears to be no limit of 20 recordings. The manual won't tell, but
154 * it's assumed that a few hundreds or thousands are supported (10K
155 * samples in total? that's a guess though).
156 * - The PC side could initiate to save a live measurement. The command
157 * is there, it's just uncertain which SR_CONF_ key to use, DATALOG
158 * appears to enter/leave a period of recording, not a single shot.
159 * - The PC side could start and stop recordings. But the start command
160 * requires a name, sample interval, and duration, but SR_CONF_DATALOG
161 * is just a boolean. Combining SR_CONF_LIMIT_SAMPLES, _DATALOG, et al
162 * raises the question which order applications will send configure
163 * requests for them.
164 * - How to communicate the LOWPASS condition? PASS/FAIL results for
165 * COMP mode? Timestamps (absolute wall clock times)? High voltage,
166 * lead errors (probe plugs in ampere modes)?
167 */
168
169/*
170 * Development HACK, to see data frame exchange at -l 2 without the
171 * serial spew of -l 5. Also lets you concentrate on some of the code
172 * paths which currently are most interesting during maintenance. :)
173 */
174#if UT181A_WITH_SER_ECHO
175# define FRAME_DUMP_LEVEL SR_LOG_WARN
176# define FRAME_DUMP_CALL sr_warn
177#else
178# define FRAME_DUMP_LEVEL (SR_LOG_SPEW + 1)
179# define sr_nop(...) do { /* EMPTY */ } while (0)
180# define FRAME_DUMP_CALL sr_nop
181#endif
182
183#define FRAME_DUMP_RXDATA 0 /* UART level receive data. */
184#define FRAME_DUMP_CSUM 0 /* Chunking, frame isolation. */
185#define FRAME_DUMP_FRAME 0 /* DMM frames, including envelope. */
186#define FRAME_DUMP_BYTES 0 /* DMM frame's payload data, "DMM packet". */
187#define FRAME_DUMP_PARSE 1 /* Measurement value extraction. */
188#define FRAME_DUMP_REMAIN 1 /* Unprocessed response data. */
189
190/*
191 * TODO Can we collapse several u16 modes in useful ways? Need we keep
192 * them separate for "MQ+flags to mode" lookups, yet mark only some of
193 * them for LIST result sets? Can't filter and need to provide them all
194 * to the user? There are some 70-80 combinations. :-O
195 *
196 * Unfortunately there is no general pattern to these code numbers, or
197 * when there is it's non-obvious. There are _some_ conventions, but also
198 * exceptions, so that programmatic handling fails.
199 *
200 * TODO
201 * - Factor out LOWPASS to a separate mode? At least derive an MQFLAG.
202 */
203static const struct mqopt_item ut181a_mqopts[] = {
204 {
205 SR_MQ_VOLTAGE, SR_MQFLAG_AC, {
206 MODE_V_AC, MODE_V_AC_REL,
207 MODE_mV_AC, MODE_mV_AC_REL,
208 MODE_V_AC_PEAK, MODE_mV_AC_PEAK,
209 MODE_V_AC_LOWPASS, MODE_V_AC_LOWPASS_REL,
210 0,
211 },
212 },
213 {
214 SR_MQ_VOLTAGE, SR_MQFLAG_DC, {
215 MODE_V_DC, MODE_V_DC_REL,
216 MODE_mV_DC, MODE_mV_DC_REL,
217 MODE_V_DC_PEAK, MODE_mV_DC_PEAK,
218 0,
219 },
220 },
221 {
222 SR_MQ_VOLTAGE, SR_MQFLAG_DC | SR_MQFLAG_AC, {
223 MODE_V_DC_ACDC, MODE_V_DC_ACDC_REL,
224 MODE_mV_AC_ACDC, MODE_mV_AC_ACDC_REL,
225 0,
226 },
227 },
228 {
229 SR_MQ_GAIN, 0, {
230 MODE_V_AC_dBV, MODE_V_AC_dBV_REL,
231 MODE_V_AC_dBm, MODE_V_AC_dBm_REL,
232 0,
233 },
234 },
235 {
236 SR_MQ_CURRENT, SR_MQFLAG_AC, {
237 MODE_A_AC, MODE_A_AC_REL,
238 MODE_A_AC_PEAK,
239 MODE_mA_AC, MODE_mA_AC_REL,
240 MODE_mA_AC_PEAK,
241 MODE_uA_AC, MODE_uA_AC_REL,
242 MODE_uA_AC_PEAK,
243 0,
244 },
245 },
246 {
247 SR_MQ_CURRENT, SR_MQFLAG_DC, {
248 MODE_A_DC, MODE_A_DC_REL,
249 MODE_A_DC_PEAK,
250 MODE_mA_DC, MODE_mA_DC_REL,
251 MODE_uA_DC, MODE_uA_DC_REL,
252 MODE_uA_DC_PEAK,
253 0,
254 },
255 },
256 {
257 SR_MQ_CURRENT, SR_MQFLAG_DC | SR_MQFLAG_AC, {
258 MODE_A_DC_ACDC, MODE_A_DC_ACDC_REL,
259 MODE_mA_DC_ACDC, MODE_mA_DC_ACDC_REL,
260 MODE_uA_DC_ACDC, MODE_uA_DC_ACDC_REL,
261 MODE_mA_DC_ACDC_PEAK,
262 0,
263 },
264 },
265 {
266 SR_MQ_RESISTANCE, 0, {
267 MODE_RES, MODE_RES_REL, 0,
268 },
269 },
270 {
271 SR_MQ_CONDUCTANCE, 0, {
272 MODE_COND, MODE_COND_REL, 0,
273 },
274 },
275 {
276 SR_MQ_CONTINUITY, 0, {
277 MODE_CONT_SHORT, MODE_CONT_OPEN, 0,
278 },
279 },
280 {
281 SR_MQ_VOLTAGE, SR_MQFLAG_DIODE | SR_MQFLAG_DC, {
282 MODE_DIODE, MODE_DIODE_ALARM, 0,
283 },
284 },
285 {
286 SR_MQ_CAPACITANCE, 0, {
287 MODE_CAP, MODE_CAP_REL, 0,
288 },
289 },
290 {
291 SR_MQ_FREQUENCY, 0, {
292 MODE_FREQ, MODE_FREQ_REL,
293 MODE_V_AC_Hz, MODE_mV_AC_Hz,
294 MODE_A_AC_Hz, MODE_mA_AC_Hz, MODE_uA_AC_Hz,
295 0,
296 },
297 },
298 {
299 SR_MQ_DUTY_CYCLE, 0, {
300 MODE_DUTY, MODE_DUTY_REL, 0,
301 },
302 },
303 {
304 SR_MQ_PULSE_WIDTH, 0, {
305 MODE_PULSEWIDTH, MODE_PULSEWIDTH_REL, 0,
306 },
307 },
308 {
309 SR_MQ_TEMPERATURE, 0, {
310 MODE_TEMP_C_T1_and_T2, MODE_TEMP_C_T1_and_T2_REL,
311 MODE_TEMP_C_T1_minus_T2, MODE_TEMP_F_T1_and_T2,
312 MODE_TEMP_C_T2_and_T1, MODE_TEMP_C_T2_and_T1_REL,
313 MODE_TEMP_C_T2_minus_T1,
314 MODE_TEMP_F_T1_and_T2_REL, MODE_TEMP_F_T1_minus_T2,
315 MODE_TEMP_F_T2_and_T1, MODE_TEMP_F_T2_and_T1_REL,
316 MODE_TEMP_F_T2_minus_T1,
317 0,
318 },
319 },
320};
321
322SR_PRIV const struct mqopt_item *ut181a_get_mqitem_from_mode(uint16_t mode)
323{
324 size_t mq_idx, mode_idx;
325 const struct mqopt_item *item;
326
327 for (mq_idx = 0; mq_idx < ARRAY_SIZE(ut181a_mqopts); mq_idx++) {
328 item = &ut181a_mqopts[mq_idx];
329 for (mode_idx = 0; mode_idx < ARRAY_SIZE(item->modes); mode_idx++) {
330 if (!item->modes[mode_idx])
331 break;
332 if (item->modes[mode_idx] != mode)
333 continue;
334 /* Found a matching mode. */
335 return item;
336 }
337 }
338 return NULL;
339}
340
341SR_PRIV uint16_t ut181a_get_mode_from_mq_flags(enum sr_mq mq, enum sr_mqflag mqflags)
342{
343 size_t mq_idx;
344 const struct mqopt_item *item;
345
346 for (mq_idx = 0; mq_idx < ARRAY_SIZE(ut181a_mqopts); mq_idx++) {
347 item = &ut181a_mqopts[mq_idx];
348 if (mq != item->mq)
349 continue;
350 /* TODO Need finer checks? Masked? */
351 if (mqflags != item->mqflags)
352 continue;
353 return item->modes[0];
354 }
355 return 0;
356}
357
358SR_PRIV GVariant *ut181a_get_mq_flags_list_item(enum sr_mq mq, enum sr_mqflag mqflag)
359{
360 GVariant *arr[2], *tuple;
361
362 arr[0] = g_variant_new_uint32(mq);
363 arr[1] = g_variant_new_uint64(mqflag);
364 tuple = g_variant_new_tuple(arr, ARRAY_SIZE(arr));
365
366 return tuple;
367}
368
369SR_PRIV GVariant *ut181a_get_mq_flags_list(void)
370{
371 GVariantBuilder gvb;
372 GVariant *tuple, *list;
373 size_t i;
374 const struct mqopt_item *item;
375
376 g_variant_builder_init(&gvb, G_VARIANT_TYPE_ARRAY);
377 for (i = 0; i < ARRAY_SIZE(ut181a_mqopts); i++) {
378 item = &ut181a_mqopts[i];
379 tuple = ut181a_get_mq_flags_list_item(item->mq, item->mqflags);
380 g_variant_builder_add_value(&gvb, tuple);
381 }
382 list = g_variant_builder_end(&gvb);
383
384 return list;
385}
386
387/*
388 * See the Protocol.md document's "Range byte" section. Value 0 is said
389 * to communicate "auto range", while values 1-8 are said to communicate
390 * specific ranges which depend on the meter's current function. Yet
391 * there is another misc flag for auto range.
392 *
393 * From this information, and observed packet content, it is assumed
394 * that the following logic applies:
395 * - Measurements (response packets) carry the "auto" flag, _and_ a
396 * "range" byte, to provide the information that auto ranging was in
397 * effect, and which specific range the automatic detection picked.
398 * - "Set range" requests can request a specific range (values 1-8), or
399 * switch to auto range (value 0).
400 *
401 * This driver implementation returns non-settable string literals for
402 * modes where auto ranging is not user adjustable (high current, diode,
403 * continuity, conductivity, temperature). Setup requests get rejected.
404 * (The local user interface neither responds to RANGE button presses.)
405 */
406static const char *range_auto = "auto";
407static const char *ranges_volt_mv[] = {
408 "60mV", "600mV", NULL,
409};
410static const char *ranges_volt_v[] = {
411 "6V", "60V", "600V", "1000V", NULL,
412};
413static const char *ranges_volt_diode[] = {
414 /* Diode is always auto, not user adjustable. */
415 "3.0V", NULL,
416};
417static const char *ranges_amp_ua[] = {
418 "600uA", "6000uA", NULL,
419};
420static const char *ranges_amp_ma[] = {
421 "60mA", "600mA", NULL,
422};
423static const char *ranges_amp_a[] = {
424 /* The 'A' range is always 20A (in the display, manual says 10A). */
425 "20A", NULL,
426};
427static const char *ranges_ohm_res[] = {
428 /* TODO
429 * Prefer "Ohm" (or "R" for sub-kilo ranges) instead? We try to
430 * keep usability in other places (micro), too, by letting users
431 * type regular non-umlaut text, and avoiding encoding issues.
432 */
433 "600Ω", "6kΩ", "60kΩ", "600kΩ", "6MΩ", "60MΩ", NULL,
434};
435static const char *ranges_ohm_600[] = {
436 /* Continuity is always 600R, not user adjustable. */
437 "600Ω", NULL,
438};
439static const char *ranges_cond[] = {
440 /* Conductivity is always 60nS, not user adjustable. */
441 "60nS", NULL,
442};
443static const char *ranges_capa[] = {
444 "6nF", "60nF", "600nF", "6uF", "60uF", "600uF", "6mF", "600mF", NULL,
445};
446static const char *ranges_freq_full[] = {
447 "60Hz", "600Hz", "6kHz", "60kHz", "600kHz", "6MHz", "60MHz", NULL,
448};
449static const char *ranges_freq_60khz[] = {
450 /* Duty cycle and period only support up to 60kHz. */
451 "60Hz", "600Hz", "6kHz", "60kHz", NULL,
452};
453static const char *ranges_temp_c[] = {
454 /* Temperature always is up to 1000 degree C, not user adjustable. */
455 "1000°C", NULL,
456};
457static const char *ranges_temp_f[] = {
458 /* Temperature always is up to 1832 F, not user adjustable. */
459 "1832F", NULL,
460};
461
462static void ut181a_add_ranges_list(GVariantBuilder *b, const char **l)
463{
464 const char *range;
465
466 while (l && *l && **l) {
467 range = *l++;
468 g_variant_builder_add(b, "s", range);
469 }
470}
471
472SR_PRIV GVariant *ut181a_get_ranges_list(void)
473{
474 GVariantBuilder gvb;
475 GVariant *list;
476
477 /* Also list those ranges which cannot get set? */
478#define WITH_RANGE_LIST_FIXED 1
479
480 g_variant_builder_init(&gvb, G_VARIANT_TYPE_ARRAY);
481 g_variant_builder_add(&gvb, "s", range_auto);
482 ut181a_add_ranges_list(&gvb, ranges_volt_mv);
483 ut181a_add_ranges_list(&gvb, ranges_volt_v);
484 (void)ranges_volt_diode;
485 ut181a_add_ranges_list(&gvb, ranges_amp_ua);
486 ut181a_add_ranges_list(&gvb, ranges_amp_ma);
487#if WITH_RANGE_LIST_FIXED
488 ut181a_add_ranges_list(&gvb, ranges_amp_a);
489#else
490 (void)ranges_amp_a;
491#endif
492 ut181a_add_ranges_list(&gvb, ranges_ohm_res);
493 (void)ranges_ohm_600;
494 ut181a_add_ranges_list(&gvb, ranges_cond);
495 ut181a_add_ranges_list(&gvb, ranges_capa);
496 ut181a_add_ranges_list(&gvb, ranges_freq_full);
497 (void)ranges_freq_60khz;
498#if WITH_RANGE_LIST_FIXED
499 ut181a_add_ranges_list(&gvb, ranges_temp_c);
500 ut181a_add_ranges_list(&gvb, ranges_temp_f);
501#else
502 (void)ranges_temp_c;
503 (void)ranges_temp_f;
504#endif
505 list = g_variant_builder_end(&gvb);
506
507 return list;
508}
509
510SR_PRIV const char *ut181a_get_range_from_packet_bytes(struct dev_context *devc)
511{
512 uint16_t mode;
513 uint8_t range;
514 gboolean is_auto;
515 const char **ranges;
516
517 if (!devc)
518 return NULL;
519 mode = devc->info.meas_head.mode;
520 range = devc->info.meas_head.range;
521 is_auto = devc->info.meas_head.is_auto_range;
522
523 /* Handle the simple cases of "auto" and out of (absolute) limits. */
524 if (is_auto)
525 return range_auto;
526 if (!mode)
527 return NULL;
528 if (!range)
529 return range_auto;
530 if (range > MAX_RANGE_INDEX)
531 return NULL;
532
533 /* Lookup the list of ranges which depend on the meter's current mode. */
534 switch (mode) {
535
536 case MODE_V_AC:
537 case MODE_V_AC_REL:
538 case MODE_V_AC_Hz:
539 case MODE_V_AC_PEAK:
540 case MODE_V_AC_LOWPASS:
541 case MODE_V_AC_LOWPASS_REL:
542 case MODE_V_AC_dBV:
543 case MODE_V_AC_dBV_REL:
544 case MODE_V_AC_dBm:
545 case MODE_V_AC_dBm_REL:
546 case MODE_V_DC:
547 case MODE_V_DC_REL:
548 case MODE_V_DC_ACDC:
549 case MODE_V_DC_ACDC_REL:
550 case MODE_V_DC_PEAK:
551 ranges = ranges_volt_v;
552 break;
553 case MODE_mV_AC:
554 case MODE_mV_AC_REL:
555 case MODE_mV_AC_Hz:
556 case MODE_mV_AC_PEAK:
557 case MODE_mV_AC_ACDC:
558 case MODE_mV_AC_ACDC_REL:
559 case MODE_mV_DC:
560 case MODE_mV_DC_REL:
561 case MODE_mV_DC_PEAK:
562 ranges = ranges_volt_mv;
563 break;
564 case MODE_RES:
565 case MODE_RES_REL:
566 ranges = ranges_ohm_res;
567 break;
568 case MODE_CONT_SHORT:
569 case MODE_CONT_OPEN:
570 ranges = ranges_ohm_600;
571 break;
572 case MODE_COND:
573 case MODE_COND_REL:
574 ranges = ranges_cond;
575 break;
576 case MODE_CAP:
577 case MODE_CAP_REL:
578 ranges = ranges_capa;
579 break;
580 case MODE_FREQ:
581 case MODE_FREQ_REL:
582 ranges = ranges_freq_full;
583 break;
584 case MODE_DUTY:
585 case MODE_DUTY_REL:
586 case MODE_PULSEWIDTH:
587 case MODE_PULSEWIDTH_REL:
588 ranges = ranges_freq_60khz;
589 break;
590 case MODE_uA_DC:
591 case MODE_uA_DC_REL:
592 case MODE_uA_DC_ACDC:
593 case MODE_uA_DC_ACDC_REL:
594 case MODE_uA_DC_PEAK:
595 case MODE_uA_AC:
596 case MODE_uA_AC_REL:
597 case MODE_uA_AC_Hz:
598 case MODE_uA_AC_PEAK:
599 ranges = ranges_amp_ua;
600 break;
601 case MODE_mA_DC:
602 case MODE_mA_DC_REL:
603 case MODE_mA_DC_ACDC:
604 case MODE_mA_DC_ACDC_REL:
605 case MODE_mA_DC_ACDC_PEAK:
606 case MODE_mA_AC:
607 case MODE_mA_AC_REL:
608 case MODE_mA_AC_Hz:
609 case MODE_mA_AC_PEAK:
610 ranges = ranges_amp_ma;
611 break;
612
613 /* Some modes are neither flexible nor adjustable. */
614 case MODE_TEMP_C_T1_and_T2:
615 case MODE_TEMP_C_T1_and_T2_REL:
616 case MODE_TEMP_C_T2_and_T1:
617 case MODE_TEMP_C_T2_and_T1_REL:
618 case MODE_TEMP_C_T1_minus_T2:
619 case MODE_TEMP_C_T2_minus_T1:
620 ranges = ranges_temp_c;
621 break;
622 case MODE_TEMP_F_T1_and_T2:
623 case MODE_TEMP_F_T1_and_T2_REL:
624 case MODE_TEMP_F_T2_and_T1:
625 case MODE_TEMP_F_T2_and_T1_REL:
626 case MODE_TEMP_F_T1_minus_T2:
627 case MODE_TEMP_F_T2_minus_T1:
628 ranges = ranges_temp_f;
629 break;
630 /* Diode, always 3V. */
631 case MODE_DIODE:
632 case MODE_DIODE_ALARM:
633 ranges = ranges_volt_diode;
634 break;
635 /* High current (A range). Always 20A. */
636 case MODE_A_DC:
637 case MODE_A_DC_REL:
638 case MODE_A_DC_ACDC:
639 case MODE_A_DC_ACDC_REL:
640 case MODE_A_DC_PEAK:
641 case MODE_A_AC:
642 case MODE_A_AC_REL:
643 case MODE_A_AC_Hz:
644 case MODE_A_AC_PEAK:
645 ranges = ranges_amp_a;
646 break;
647
648 /* Unknown mode? Programming error? */
649 default:
650 return NULL;
651 }
652
653 /* Lookup the range in the list of the mode's ranges. */
654 while (ranges && *ranges && **ranges && --range > 0) {
655 ranges++;
656 }
657 if (!ranges || !*ranges || !**ranges)
658 return NULL;
659 return *ranges;
660}
661
662SR_PRIV int ut181a_set_range_from_text(const struct sr_dev_inst *sdi, const char *text)
663{
664 struct dev_context *devc;
665 uint16_t mode;
666 const char **ranges;
667 uint8_t range;
668
669 /* We must have determined the meter's current mode first. */
670 if (!sdi)
671 return SR_ERR_ARG;
672 if (!text || !*text)
673 return SR_ERR_ARG;
674 devc = sdi->priv;
675 if (!devc)
676 return SR_ERR_ARG;
677 mode = devc->info.meas_head.mode;
678 if (!mode)
679 return SR_ERR_ARG;
680
681 /* Handle the simple case of "auto" caller spec. */
682 if (strcmp(text, range_auto) == 0) {
683 range = 0;
684 return ut181a_send_cmd_setmode(sdi->conn, range);
685 }
686
687 /* Lookup the list of ranges which depend on the meter's current mode. */
688 switch (mode) {
689
690 /* Map "user servicable" modes to their respective ranges list. */
691 case MODE_V_AC:
692 case MODE_V_AC_REL:
693 case MODE_V_AC_Hz:
694 case MODE_V_AC_PEAK:
695 case MODE_V_AC_LOWPASS:
696 case MODE_V_AC_LOWPASS_REL:
697 case MODE_V_AC_dBV:
698 case MODE_V_AC_dBV_REL:
699 case MODE_V_AC_dBm:
700 case MODE_V_AC_dBm_REL:
701 case MODE_V_DC:
702 case MODE_V_DC_REL:
703 case MODE_V_DC_ACDC:
704 case MODE_V_DC_ACDC_REL:
705 case MODE_V_DC_PEAK:
706 ranges = ranges_volt_v;
707 break;
708 case MODE_mV_AC:
709 case MODE_mV_AC_REL:
710 case MODE_mV_AC_Hz:
711 case MODE_mV_AC_PEAK:
712 case MODE_mV_AC_ACDC:
713 case MODE_mV_AC_ACDC_REL:
714 case MODE_mV_DC:
715 case MODE_mV_DC_REL:
716 case MODE_mV_DC_PEAK:
717 ranges = ranges_volt_mv;
718 break;
719 case MODE_RES:
720 case MODE_RES_REL:
721 ranges = ranges_ohm_res;
722 break;
723 case MODE_CAP:
724 case MODE_CAP_REL:
725 ranges = ranges_capa;
726 break;
727 case MODE_FREQ:
728 case MODE_FREQ_REL:
729 ranges = ranges_freq_full;
730 break;
731 case MODE_DUTY:
732 case MODE_DUTY_REL:
733 case MODE_PULSEWIDTH:
734 case MODE_PULSEWIDTH_REL:
735 ranges = ranges_freq_60khz;
736 break;
737 case MODE_uA_DC:
738 case MODE_uA_DC_REL:
739 case MODE_uA_DC_ACDC:
740 case MODE_uA_DC_ACDC_REL:
741 case MODE_uA_DC_PEAK:
742 case MODE_uA_AC:
743 case MODE_uA_AC_REL:
744 case MODE_uA_AC_Hz:
745 case MODE_uA_AC_PEAK:
746 ranges = ranges_amp_ua;
747 break;
748 case MODE_mA_DC:
749 case MODE_mA_DC_REL:
750 case MODE_mA_DC_ACDC:
751 case MODE_mA_DC_ACDC_REL:
752 case MODE_mA_DC_ACDC_PEAK:
753 case MODE_mA_AC:
754 case MODE_mA_AC_REL:
755 case MODE_mA_AC_Hz:
756 case MODE_mA_AC_PEAK:
757 ranges = ranges_amp_ma;
758 break;
759
760 /*
761 * Some modes use fixed ranges. Accept their specs or refuse to
762 * set a specific range? The meter's UI refuses MANUAL mode and
763 * remains in AUTO mode. So do we here.
764 */
765 case MODE_CONT_SHORT:
766 case MODE_CONT_OPEN:
767 return SR_ERR_NA;
768 ranges = ranges_ohm_600;
769 break;
770 case MODE_COND:
771 case MODE_COND_REL:
772 return SR_ERR_NA;
773 ranges = ranges_cond;
774 break;
775 case MODE_TEMP_C_T1_and_T2:
776 case MODE_TEMP_C_T1_and_T2_REL:
777 case MODE_TEMP_C_T2_and_T1:
778 case MODE_TEMP_C_T2_and_T1_REL:
779 case MODE_TEMP_C_T1_minus_T2:
780 case MODE_TEMP_C_T2_minus_T1:
781 return SR_ERR_NA;
782 ranges = ranges_temp_c;
783 break;
784 case MODE_TEMP_F_T1_and_T2:
785 case MODE_TEMP_F_T1_and_T2_REL:
786 case MODE_TEMP_F_T2_and_T1:
787 case MODE_TEMP_F_T2_and_T1_REL:
788 case MODE_TEMP_F_T1_minus_T2:
789 case MODE_TEMP_F_T2_minus_T1:
790 return SR_ERR_NA;
791 ranges = ranges_temp_f;
792 break;
793 /* Diode, always 3V. */
794 case MODE_DIODE:
795 case MODE_DIODE_ALARM:
796 return SR_ERR_NA;
797 ranges = ranges_volt_diode;
798 break;
799 /* High current (A range). Always 20A. */
800 case MODE_A_DC:
801 case MODE_A_DC_REL:
802 case MODE_A_DC_ACDC:
803 case MODE_A_DC_ACDC_REL:
804 case MODE_A_DC_PEAK:
805 case MODE_A_AC:
806 case MODE_A_AC_REL:
807 case MODE_A_AC_Hz:
808 case MODE_A_AC_PEAK:
809 return SR_ERR_NA;
810 ranges = ranges_amp_a;
811 break;
812
813 /* Unknown mode? Programming error? */
814 default:
815 return SR_ERR_BUG;
816 }
817
818 /* Lookup the range in the list of the mode's ranges. */
819 range = 1;
820 while (ranges && *ranges && **ranges) {
821 if (strcmp(*ranges, text) != 0) {
822 range++;
823 ranges++;
824 continue;
825 }
826 return ut181a_send_cmd_setrange(sdi->conn, range);
827 }
828 return SR_ERR_ARG;
829}
830
831/**
832 * Parse a unit text into scale factor, MQ and flags, and unit.
833 *
834 * @param[out] mqs The scale/MQ/unit details to fill in.
835 * @param[in] text The DMM's "unit text" (string label).
836 *
837 * @returns SR_OK upon success, SR_ERR_* upon error.
838 *
839 * UT181A unit text strings encode several details: They start with an
840 * optional prefix (which communicates a scale factor), specify the unit
841 * of the measured value (which hints towards the measured quantity),
842 * and carry optional attributes (which MQ flags can get derived from).
843 *
844 * See unit.rs for the list of known input strings. Though there are
845 * unexpected differences:
846 * - \u{FFFD}C/F instead of 0xb0 for degree (local platform conversion?)
847 * - 'u' seems to be used for micro, good (no 'micro' umlaut involved)
848 * - '~' (tilde, 0x7e) for Ohm
849 *
850 * Prefixes: p n u m '' k M G
851 *
852 * Units:
853 * - F Farad (m u n)
854 * - dBV, dBm (no prefix)
855 * - ~ (tilde, Ohm) (- k M)
856 * - S Siemens (n)
857 * - % percent (no prefix)
858 * - s seconds (m)
859 * - Hz Hertz (- k M)
860 * - xC, xF degree (no prefix)
861 *
862 * Units with Flags:
863 * - Aac+dc ampere AC+DC (- m u)
864 * - AAC ampere AC (- m u)
865 * - ADC ampere DC (- m u)
866 * - Vac+dc volt AC+DC (- m)
867 * - VAC volt AC (- m)
868 * - VDC volt DC (- m)
869 */
870static int ut181a_get_mq_details_from_text(struct mq_scale_params *mqs, const char *text)
871{
872 char scale_char;
873 int scale;
874 enum sr_mq mq;
875 enum sr_mqflag mqflags;
876 enum sr_unit unit;
877
878 if (!mqs)
879 return SR_ERR_ARG;
880 memset(mqs, 0, sizeof(*mqs));
881
882 /* Start from unknown state, no modifiers. */
883 scale = 0;
884 unit = 0;
885 mq = 0;
886 mqflags = 0;
887
888 /* Derive the scale factor from the optional prefix. */
889 scale_char = *text++;
890 if (scale_char == 'p')
891 scale = -12;
892 else if (scale_char == 'n')
893 scale = -9;
894 else if (scale_char == 'u')
895 scale = -6;
896 else if (scale_char == 'm')
897 scale = -3;
898 else if (scale_char == 'k')
899 scale = +3;
900 else if (scale_char == 'M')
901 scale = +6;
902 else if (scale_char == 'G')
903 scale = +9;
904 else
905 text--;
906
907 /* Guess the MQ (and flags) from the unit text. */
908 if (g_str_has_prefix(text, "F")) {
909 text += strlen("F");
910 unit = SR_UNIT_FARAD;
911 if (!mq)
912 mq = SR_MQ_CAPACITANCE;
913 } else if (g_str_has_prefix(text, "dBV")) {
914 text += strlen("dBV");
915 unit = SR_UNIT_DECIBEL_VOLT;
916 if (!mq)
917 mq = SR_MQ_GAIN;
918 } else if (g_str_has_prefix(text, "dBm")) {
919 text += strlen("dBm");
920 unit = SR_UNIT_DECIBEL_MW;
921 if (!mq)
922 mq = SR_MQ_GAIN;
923 } else if (g_str_has_prefix(text, "~")) {
924 text += strlen("~");
925 unit = SR_UNIT_OHM;
926 if (!mq)
927 mq = SR_MQ_RESISTANCE;
928 } else if (g_str_has_prefix(text, "S")) {
929 text += strlen("S");
930 unit = SR_UNIT_SIEMENS;
931 if (!mq)
932 mq = SR_MQ_CONDUCTANCE;
933 } else if (g_str_has_prefix(text, "%")) {
934 text += strlen("%");
935 unit = SR_UNIT_PERCENTAGE;
936 if (!mq)
937 mq = SR_MQ_DUTY_CYCLE;
938 } else if (g_str_has_prefix(text, "s")) {
939 text += strlen("s");
940 unit = SR_UNIT_SECOND;
941 if (!mq)
942 mq = SR_MQ_PULSE_WIDTH;
943 } else if (g_str_has_prefix(text, "Hz")) {
944 text += strlen("Hz");
945 unit = SR_UNIT_HERTZ;
946 if (!mq)
947 mq = SR_MQ_FREQUENCY;
948 } else if (g_str_has_prefix(text, "\xb0" "C")) {
949 text += strlen("\xb0" "C");
950 unit = SR_UNIT_CELSIUS;
951 if (!mq)
952 mq = SR_MQ_TEMPERATURE;
953 } else if (g_str_has_prefix(text, "\xb0" "F")) {
954 text += strlen("\xb0" "F");
955 unit = SR_UNIT_FAHRENHEIT;
956 if (!mq)
957 mq = SR_MQ_TEMPERATURE;
958 } else if (g_str_has_prefix(text, "A")) {
959 text += strlen("A");
960 unit = SR_UNIT_AMPERE;
961 if (!mq)
962 mq = SR_MQ_CURRENT;
963 } else if (g_str_has_prefix(text, "V")) {
964 text += strlen("V");
965 unit = SR_UNIT_VOLT;
966 if (!mq)
967 mq = SR_MQ_VOLTAGE;
968 } else if (g_str_has_prefix(text, "timestamp")) {
969 /*
970 * The meter never provides this "timestamp" label,
971 * but the driver re-uses common logic here to have
972 * the MQ details filled in for save/record stamps.
973 */
974 text += strlen("timestamp");
975 unit = SR_UNIT_SECOND;
976 if (!mq)
977 mq = SR_MQ_TIME;
978 }
979
980 /* Amend MQ flags from an optional suffix. */
981 if (g_str_has_prefix(text, "ac+dc")) {
982 text += strlen("ac+dc");
983 mqflags |= SR_MQFLAG_AC | SR_MQFLAG_DC;
984 } else if (g_str_has_prefix(text, "AC")) {
985 text += strlen("AC");
986 mqflags |= SR_MQFLAG_AC;
987 } else if (g_str_has_prefix(text, "DC")) {
988 text += strlen("DC");
989 mqflags |= SR_MQFLAG_DC;
990 }
991
992 /* Put all previously determined details into the container. */
993 mqs->scale = scale;
994 mqs->mq = mq;
995 mqs->mqflags = mqflags;
996 mqs->unit = unit;
997
998 return SR_OK;
999}
1000
1001/*
1002 * Break down a packed 32bit timestamp presentation, and create an epoch
1003 * value from it. The UT181A protocol encodes timestamps in a 32bit value:
1004 *
1005 * [5:0] year - 2000
1006 * [9:6] month
1007 * [14:10] mday
1008 * [19:15] hour
1009 * [25:20] min
1010 * [31:26] sec
1011 *
1012 * TODO Find a portable and correct conversion helper. The mktime() API
1013 * is said to involve timezone details, and modify the environment. Is
1014 * strftime("%s") a better approach? Until then mktime() might be good
1015 * enough an approach, assuming that the meter will be set to the user's
1016 * local time.
1017 */
1018static time_t ut181a_get_epoch_for_timestamp(uint32_t ts)
1019{
1020 struct tm t;
1021
1022 memset(&t, 0, sizeof(t));
1023 t.tm_year = ((ts >> 0) & 0x3f) + 2000 - 1900;
1024 t.tm_mon = ((ts >> 6) & 0x0f) - 1;
1025 t.tm_mday = ((ts >> 10) & 0x1f);
1026 t.tm_hour = ((ts >> 15) & 0x1f);
1027 t.tm_min = ((ts >> 20) & 0x3f);
1028 t.tm_sec = ((ts >> 26) & 0x3f);
1029 t.tm_isdst = -1;
1030
1031 return mktime(&t);
1032}
1033
1034/**
1035 * Calculate UT181A specific checksum for serial data frame.
1036 *
1037 * @param[in] data The payload bytes to calculate the checksum for.
1038 * @param[in] dlen The number of payload bytes.
1039 *
1040 * @returns The checksum value.
1041 *
1042 * On the wire the checksum covers all fields after the magic and before
1043 * the checksum. In other words the checksum covers the length field and
1044 * the payload bytes.
1045 */
1046static uint16_t ut181a_checksum(const uint8_t *data, size_t dlen)
1047{
1048 uint16_t cs;
1049
1050 cs = 0;
1051 while (dlen-- > 0)
1052 cs += *data++;
1053
1054 return cs;
1055}
1056
1057/**
1058 * Send payload bytes via serial comm, add frame envelope and transmit.
1059 *
1060 * @param[in] serial Serial port.
1061 * @param[in] data Payload bytes.
1062 * @param[in] dlen Payload length.
1063 *
1064 * @returns >= 0 upon success, negative upon failure (SR_ERR codes)
1065 */
1066static int ut181a_send_frame(struct sr_serial_dev_inst *serial,
1067 const uint8_t *data, size_t dlen)
1068{
1069 uint8_t frame_buff[SEND_BUFF_SIZE];
1070 size_t frame_off;
1071 const uint8_t *cs_data;
1072 size_t cs_dlen;
1073 uint16_t cs_value;
1074 int ret;
1075
1076 if (FRAME_DUMP_BYTES && sr_log_loglevel_get() >= FRAME_DUMP_LEVEL) {
1077 GString *spew;
1078 spew = sr_hexdump_new(data, dlen);
1079 FRAME_DUMP_CALL("TX payload, %zu bytes: %s", dlen, spew->str);
1080 sr_hexdump_free(spew);
1081 }
1082
1083 /*
1084 * The frame buffer must hold the magic and length and payload
1085 * bytes and checksum. Check for the available space.
1086 */
1087 if (dlen > sizeof(frame_buff) - 3 * sizeof(uint16_t)) {
1088 return SR_ERR_ARG;
1089 }
1090
1091 /*
1092 * Create a frame for the payload bytes. The length field's value
1093 * also includes the checksum field (spans the remainder of the
1094 * frame). The checksum covers everything between the magic and
1095 * the checksum field.
1096 */
1097 frame_off = 0;
1098 WL16(&frame_buff[frame_off], FRAME_MAGIC);
1099 frame_off += sizeof(uint16_t);
1100 WL16(&frame_buff[frame_off], dlen + sizeof(uint16_t));
1101 frame_off += sizeof(uint16_t);
1102 memcpy(&frame_buff[frame_off], data, dlen);
1103 frame_off += dlen;
1104 cs_data = &frame_buff[sizeof(uint16_t)];
1105 cs_dlen = frame_off - sizeof(uint16_t);
1106 cs_value = ut181a_checksum(cs_data, cs_dlen);
1107 WL16(&frame_buff[frame_off], cs_value);
1108 frame_off += sizeof(uint16_t);
1109
1110 if (FRAME_DUMP_FRAME && sr_log_loglevel_get() >= FRAME_DUMP_LEVEL) {
1111 GString *spew;
1112 spew = sr_hexdump_new(frame_buff, frame_off);
1113 FRAME_DUMP_CALL("TX frame, %zu bytes: %s", frame_off, spew->str);
1114 sr_hexdump_free(spew);
1115 }
1116
1117 ret = serial_write_blocking(serial, frame_buff, frame_off, SEND_TO_MS);
1118 if (ret < 0)
1119 return ret;
1120
1121 return SR_OK;
1122}
1123
1124/* Construct and transmit "set mode" command. */
1125SR_PRIV int ut181a_send_cmd_setmode(struct sr_serial_dev_inst *serial, uint16_t mode)
1126{
1127 uint8_t cmd[sizeof(uint8_t) + sizeof(uint16_t)];
1128 size_t cmd_off;
1129
1130 cmd_off = 0;
1131 cmd[cmd_off++] = CMD_CODE_SET_MODE;
1132 WL16(&cmd[cmd_off], mode);
1133 cmd_off += sizeof(uint16_t);
1134
1135 return ut181a_send_frame(serial, cmd, cmd_off);
1136}
1137
1138/* Construct and transmit "set range" command. */
1139SR_PRIV int ut181a_send_cmd_setrange(struct sr_serial_dev_inst *serial, uint8_t range)
1140{
1141 uint8_t cmd[sizeof(uint8_t) + sizeof(uint8_t)];
1142 size_t cmd_off;
1143
1144 cmd_off = 0;
1145 cmd[cmd_off++] = CMD_CODE_SET_RANGE;
1146 cmd[cmd_off++] = range;
1147
1148 return ut181a_send_frame(serial, cmd, cmd_off);
1149}
1150
1151/* Construct and transmit "monitor on/off" command. */
1152SR_PRIV int ut181a_send_cmd_monitor(struct sr_serial_dev_inst *serial, gboolean on)
1153{
1154 uint8_t cmd[sizeof(uint8_t) + sizeof(uint8_t)];
1155 size_t cmd_off;
1156
1157 cmd_off = 0;
1158 cmd[cmd_off++] = CMD_CODE_SET_MONITOR;
1159 cmd[cmd_off++] = on ? 1 : 0;
1160
1161 return ut181a_send_frame(serial, cmd, cmd_off);
1162}
1163
1164/* Construct and transmit "get saved measurements count" command. */
1165SR_PRIV int ut181a_send_cmd_get_save_count(struct sr_serial_dev_inst *serial)
1166{
1167 uint8_t cmd;
1168
1169 cmd = CMD_CODE_GET_SAVED_COUNT;
1170 return ut181a_send_frame(serial, &cmd, sizeof(cmd));
1171}
1172
1173/*
1174 * Construct and transmit "get saved measurement value" command.
1175 * Important: Callers use 0-based index, protocol needs 1-based index.
1176 */
1177SR_PRIV int ut181a_send_cmd_get_saved_value(struct sr_serial_dev_inst *serial, size_t idx)
1178{
1179 uint8_t cmd[sizeof(uint8_t) + sizeof(uint16_t)];
1180 size_t cmd_off;
1181
1182 cmd_off = 0;
1183 cmd[cmd_off++] = CMD_CODE_GET_SAVED_MEAS;
1184 WL16(&cmd[cmd_off], idx + 1);
1185 cmd_off += sizeof(uint16_t);
1186
1187 return ut181a_send_frame(serial, cmd, sizeof(cmd));
1188}
1189
1190/* Construct and transmit "get recordings count" command. */
1191SR_PRIV int ut181a_send_cmd_get_recs_count(struct sr_serial_dev_inst *serial)
1192{
1193 uint8_t cmd;
1194
1195 cmd = CMD_CODE_GET_RECS_COUNT;
1196 return ut181a_send_frame(serial, &cmd, sizeof(cmd));
1197}
1198
1199/*
1200 * Construct and transmit "get recording information" command.
1201 * Important: Callers use 0-based index, protocol needs 1-based index.
1202 */
1203SR_PRIV int ut181a_send_cmd_get_rec_info(struct sr_serial_dev_inst *serial, size_t idx)
1204{
1205 uint8_t cmd[sizeof(uint8_t) + sizeof(uint16_t)];
1206 size_t cmd_off;
1207
1208 cmd_off = 0;
1209 cmd[cmd_off++] = CMD_CODE_GET_REC_INFO;
1210 WL16(&cmd[cmd_off], idx + 1);
1211 cmd_off += sizeof(uint16_t);
1212
1213 return ut181a_send_frame(serial, cmd, sizeof(cmd));
1214}
1215
1216/*
1217 * Construct and transmit "get recording samples" command.
1218 * Important: Callers use 0-based index, protocol needs 1-based index.
1219 */
1220SR_PRIV int ut181a_send_cmd_get_rec_samples(struct sr_serial_dev_inst *serial, size_t idx, size_t off)
1221{
1222 uint8_t cmd[sizeof(uint8_t) + sizeof(uint16_t) + sizeof(uint32_t)];
1223 size_t cmd_off;
1224
1225 cmd_off = 0;
1226 cmd[cmd_off++] = CMD_CODE_GET_REC_SAMPLES;
1227 WL16(&cmd[cmd_off], idx + 1);
1228 cmd_off += sizeof(uint16_t);
1229 WL32(&cmd[cmd_off], off + 1);
1230 cmd_off += sizeof(uint32_t);
1231
1232 return ut181a_send_frame(serial, cmd, sizeof(cmd));
1233}
1234
1235/* TODO
1236 * Construct and transmit "record on/off" command. Requires a caption,
1237 * an interval, and a duration to start a recording. Recordings can get
1238 * stopped upon request, or end when the requested duration has passed.
1239 */
1240
1241/**
1242 * Specify which kind of response to wait for.
1243 *
1244 * @param[in] devc The device context.
1245 * @param[in] want_code Reply code wanted, boolean.
1246 * @param[in] want_data Reply data wanted, boolean.
1247 * @param[in] want_rsp_type Special response type wanted.
1248 * @param[in] want_measure Measurement wanted, boolean.
1249 * @param[in] want_rec_count Records count wanted, boolean.
1250 * @param[in] want_save_count Saved count wanted, boolean.
1251 * @param[in] want_sample_count Samples count wanted, boolean.
1252 */
1253SR_PRIV int ut181a_configure_waitfor(struct dev_context *devc,
1254 gboolean want_code, enum ut181_cmd_code want_data,
1255 enum ut181_rsp_type want_rsp_type,
1256 gboolean want_measure, gboolean want_rec_count,
1257 gboolean want_save_count, gboolean want_sample_count)
1258{
1259
1260 if (want_rec_count)
1261 want_data = CMD_CODE_GET_RECS_COUNT;
1262 if (want_save_count)
1263 want_data = CMD_CODE_GET_SAVED_COUNT;
1264 if (want_sample_count)
1265 want_data = CMD_CODE_GET_REC_SAMPLES;
1266
1267 memset(&devc->wait_state, 0, sizeof(devc->wait_state));
1268 devc->wait_state.want_code = want_code;
1269 devc->wait_state.want_data = want_data;
1270 devc->wait_state.want_rsp_type = want_rsp_type;
1271 devc->wait_state.want_measure = want_measure;
1272 memset(&devc->last_data, 0, sizeof(devc->last_data));
1273
1274 return SR_OK;
1275}
1276
1277/**
1278 * Wait for a response (or timeout) after a command was sent.
1279 *
1280 * @param[in] sdi The device instance.
1281 * @param[in] timeout_ms The timeout in milliseconds.
1282 *
1283 * @returns SR_OK upon success, SR_ERR_* upon error.
1284 *
1285 * This routine waits for the complete reception of a response (any kind)
1286 * after a command was previously sent by the caller, or terminates when
1287 * the timeout has expired without reception of a response. Callers need
1288 * to check the kind of response (data values, or status, or error codes).
1289 */
1290SR_PRIV int ut181a_waitfor_response(const struct sr_dev_inst *sdi, int timeout_ms)
3094e9d8 1291{
ebc51109
GS
1292 struct dev_context *devc;
1293 gint64 deadline, delay;
1294 struct wait_state *state;
1295
1296 devc = sdi->priv;
1297 state = &devc->wait_state;
1298 state->response_count = 0;
1299
1300 deadline = g_get_monotonic_time();
1301 deadline += timeout_ms * 1000;
1302 delay = 0;
1303 while (1) {
1304 gboolean got_wanted;
1305 if (g_get_monotonic_time() >= deadline)
1306 return SR_ERR_DATA;
1307 if (delay)
1308 g_usleep(delay);
1309 delay = 100;
1310 ut181a_handle_events(-1, G_IO_IN, (void *)sdi);
1311 got_wanted = FALSE;
1312 if (state->want_code && state->got_code)
1313 got_wanted = TRUE;
1314 if (state->want_data && state->got_data)
1315 got_wanted = TRUE;
1316 if (state->want_rsp_type && state->got_rsp_type)
1317 got_wanted = TRUE;
1318 if (state->want_measure && state->got_measure)
1319 got_wanted = TRUE;
1320 if (state->want_data == CMD_CODE_GET_RECS_COUNT && state->got_rec_count)
1321 got_wanted = TRUE;
1322 if (state->want_data == CMD_CODE_GET_SAVED_COUNT && state->got_save_count)
1323 got_wanted = TRUE;
1324 if (state->want_data == CMD_CODE_GET_REC_INFO && state->got_sample_count)
1325 got_wanted = TRUE;
1326 if (got_wanted)
1327 return SR_OK;
1328 }
1329}
1330
1331/**
1332 * Get measurement value and precision details from protocol's raw bytes.
1333 */
1334static int ut181a_get_value_params(struct value_params *params, float value, uint8_t prec)
1335{
1336
1337 if (!params)
1338 return SR_ERR_ARG;
1339
1340 memset(params, 0, sizeof(*params));
1341 params->value = value;
1342 params->digits = (prec >> 4) & 0x0f;
1343 params->ol_neg = (prec & (1 << 1)) ? 1 : 0;
1344 params->ol_pos = (prec & (1 << 0)) ? 1 : 0;
1345
1346 return SR_OK;
1347}
1348
1349static void ut181a_cond_stop_acquisition(struct sr_dev_inst *sdi)
1350{
1351 struct dev_context *devc;
1352
1353 if (!sdi)
1354 return;
1355 devc = sdi->priv;
1356 if (!devc)
1357 return;
1358
1359 if (sdi->status == SR_ST_ACTIVE)
1360 sr_dev_acquisition_stop(sdi);
1361}
1362
1363/**
1364 * Send meta packet with samplerate to the session feed.
1365 *
1366 * @param[in] sdi The device instance.
1367 * @param[in] interval The sample interval in seconds.
1368 *
1369 * @returns SR_OK upon success, SR_ERR_* upon error.
1370 *
1371 * The DMM records data at intervals which are multiples of seconds.
1372 * The @ref SR_CONF_SAMPLERATE key cannot express the rate values which
1373 * are below 1Hz. Instead the @ref SR_CONF_SAMPLE_INTERVAL key is sent,
1374 * which applications may or may not support.
1375 */
1376static int ut181a_feed_send_rate(struct sr_dev_inst *sdi, int interval)
1377{
1378#if 1
1379 return sr_session_send_meta(sdi,
1380 SR_CONF_SAMPLE_INTERVAL, g_variant_new_uint64(interval));
1381#else
1382 uint64_t rate;
1383
1384 /*
1385 * In theory we know the sample interval, and could provide a
1386 * corresponding sample rate. In practice the interval has a
1387 * resolution of seconds, which translates to rates below 1Hz,
1388 * which we cannot express. So let's keep the routine here for
1389 * awareness, and send a rate of 0.
1390 */
1391 (void)interval;
1392 rate = 0;
1393
1394 return sr_session_send_meta(sdi,
1395 SR_CONF_SAMPLERATE, g_variant_new_uint64(rate));
1396#endif
1397}
1398
1399/**
1400 * Initialize session feed buffer before submission of values.
1401 */
1402static int ut181a_feedbuff_initialize(struct feed_buffer *buff)
1403{
1404
1405 memset(buff, 0, sizeof(*buff));
1406
1407 /*
1408 * NOTE: The 'digits' fields get updated later from sample data.
1409 * As do the MQ and unit fields and the channel list.
1410 */
1411 memset(&buff->packet, 0, sizeof(buff->packet));
1412 sr_analog_init(&buff->analog, &buff->encoding, &buff->meaning, &buff->spec, 0);
1413 buff->analog.meaning->mq = 0;
1414 buff->analog.meaning->mqflags = 0;
1415 buff->analog.meaning->unit = 0;
1416 buff->analog.meaning->channels = NULL;
1417 buff->analog.encoding->unitsize = sizeof(buff->main_value);
1418 buff->analog.encoding->digits = 0;
1419 buff->analog.spec->spec_digits = 0;
1420 buff->analog.num_samples = 1;
1421 buff->analog.data = &buff->main_value;
1422 buff->packet.type = SR_DF_ANALOG;
1423 buff->packet.payload = &buff->analog;
1424
1425 return SR_OK;
1426}
1427
1428/**
1429 * Setup feed buffer's MQ, MQ flags, and unit before submission of values.
1430 */
1431static int ut181a_feedbuff_setup_unit(struct feed_buffer *buff, const char *text)
1432{
1433 int ret;
1434 struct mq_scale_params scale;
1435
1436 /* Derive MQ, flags, unit, and scale from caller's unit text. */
1437 ret = ut181a_get_mq_details_from_text(&scale, text);
1438 if (ret < 0)
1439 return ret;
1440 buff->scale = scale.scale;
1441 buff->analog.meaning->mq = scale.mq;
1442 buff->analog.meaning->mqflags = scale.mqflags;
1443 buff->analog.meaning->unit = scale.unit;
1444
1445 return SR_OK;
1446}
1447
1448/**
1449 * Setup feed buffer's measurement value details before submission of values.
1450 */
1451static int ut181a_feedbuff_setup_value(struct feed_buffer *buff,
1452 struct value_params *value)
1453{
1454
1455 if (!buff || !value)
1456 return SR_ERR_ARG;
1457
1458 if (buff->scale) {
1459 value->value *= pow(10, buff->scale);
1460 value->digits += -buff->scale;
1461 }
1462 if (value->ol_neg)
1463 value->value = -INFINITY;
1464 if (value->ol_pos)
1465 value->value = +INFINITY;
1466
1467 buff->main_value = value->value;
1468 buff->analog.encoding->digits = value->digits;
1469 buff->analog.spec->spec_digits = value->digits;
1470
1471 return SR_OK;
1472}
1473
1474/**
1475 * Setup feed buffer's channel before submission of values.
1476 */
1477static int ut181a_feedbuff_setup_channel(struct feed_buffer *buff,
1478 enum ut181a_channel_idx ch, struct sr_dev_inst *sdi)
1479{
1480
1481 if (!buff || !sdi)
1482 return SR_ERR_ARG;
1483 if (!buff->analog.meaning)
1484 return SR_ERR_ARG;
1485
1486 g_slist_free(buff->analog.meaning->channels);
1487 buff->analog.meaning->channels = g_slist_append(NULL,
1488 g_slist_nth_data(sdi->channels, ch));
1489
1490 return SR_OK;
1491}
1492
1493/**
1494 * Send previously configured feed buffer's content to the session.
1495 */
1496static int ut181a_feedbuff_send_feed(struct feed_buffer *buff,
1497 struct sr_dev_inst *sdi, size_t count)
1498{
1499 int ret;
1500 struct dev_context *devc;
1501
1502 if (!buff || !sdi)
1503 return SR_ERR_ARG;
1504
1505 if (sdi->status != SR_ST_ACTIVE)
1506 return SR_OK;
1507 devc = sdi->priv;
1508 if (!devc || devc->disable_feed)
1509 return SR_OK;
1510
1511 ret = sr_session_send(sdi, &buff->packet);
1512 if (ret == SR_OK && count && sdi->priv) {
1513 sr_sw_limits_update_samples_read(&devc->limits, count);
1514 if (sr_sw_limits_check(&devc->limits))
1515 ut181a_cond_stop_acquisition(sdi);
1516 }
1517
1518 return ret;
1519}
1520
1521/**
1522 * Release previously allocated resources in the feed buffer.
1523 */
1524static int ut181a_feedbuff_cleanup(struct feed_buffer *buff)
1525{
1526 if (!buff)
1527 return SR_ERR_ARG;
1528
1529 if (buff->analog.meaning)
1530 g_slist_free(buff->analog.meaning->channels);
1531
1532 return SR_OK;
1533}
1534
1535static int ut181a_feedbuff_start_frame(struct sr_dev_inst *sdi)
1536{
1537 struct dev_context *devc;
1538 int ret;
1539
1540 devc = sdi->priv;
1541 if (devc->disable_feed)
1542 return SR_OK;
1543 if (devc->frame_started)
1544 return SR_OK;
1545
1546 ret = std_session_send_df_frame_begin(sdi);
1547 if (ret == SR_OK)
1548 devc->frame_started = TRUE;
1549
1550 return ret;
1551}
1552
1553static int ut181a_feedbuff_count_frame(struct sr_dev_inst *sdi)
1554{
1555 struct dev_context *devc;
1556 int ret;
1557
1558 devc = sdi->priv;
1559 if (devc->disable_feed)
1560 return SR_OK;
1561 if (!devc->frame_started)
1562 return SR_OK;
1563
1564 ret = std_session_send_df_frame_end(sdi);
1565 if (ret != SR_OK)
1566 return ret;
1567 devc->frame_started = FALSE;
1568
1569 sr_sw_limits_update_frames_read(&devc->limits, 1);
1570 if (sr_sw_limits_check(&devc->limits))
1571 ut181a_cond_stop_acquisition(sdi);
1572
1573 return SR_OK;
1574}
1575
1576/* Deserializing helpers which also advance the read pointer. */
1577
1578static int check_len(size_t *got, size_t want)
1579{
1580
1581 if (!got)
1582 return SR_ERR_ARG;
1583 if (want > *got)
1584 return SR_ERR_DATA;
1585
1586 return SR_OK;
1587}
1588
1589static void advance_len(const uint8_t **p, size_t *l, size_t sz)
1590{
1591
1592 if (p)
1593 *p += sz;
1594 if (l)
1595 *l -= sz;
1596}
1597
1598static int consume_u8(uint8_t *v, const uint8_t **p, size_t *l)
1599{
1600 size_t sz;
1601 int ret;
1602
1603 if (v)
1604 *v = 0;
1605
1606 sz = sizeof(uint8_t);
1607 ret = check_len(l, sz);
1608 if (ret != SR_OK)
1609 return ret;
1610
1611 if (v)
1612 *v = R8(*p);
1613 advance_len(p, l, sz);
1614
1615 return SR_OK;
1616}
1617
1618static int consume_u16(uint16_t *v, const uint8_t **p, size_t *l)
1619{
1620 size_t sz;
1621 int ret;
1622
1623 if (v)
1624 *v = 0;
1625
1626 sz = sizeof(uint16_t);
1627 ret = check_len(l, sz);
1628 if (ret != SR_OK)
1629 return ret;
1630
1631 if (v)
1632 *v = RL16(*p);
1633 advance_len(p, l, sz);
1634
1635 return SR_OK;
1636}
1637
1638static int consume_u32(uint32_t *v, const uint8_t **p, size_t *l)
1639{
1640 size_t sz;
1641 int ret;
1642
1643 if (v)
1644 *v = 0;
1645
1646 sz = sizeof(uint32_t);
1647 ret = check_len(l, sz);
1648 if (ret != SR_OK)
1649 return ret;
1650
1651 if (v)
1652 *v = RL32(*p);
1653 advance_len(p, l, sz);
1654
1655 return SR_OK;
1656}
1657
1658static int consume_flt(float *v, const uint8_t **p, size_t *l)
1659{
1660 size_t sz;
1661 int ret;
1662
1663 if (v)
1664 *v = 0;
1665
1666 sz = sizeof(float);
1667 ret = check_len(l, sz);
1668 if (ret != SR_OK)
1669 return ret;
1670
1671 if (v)
1672 *v = RLFL(*p);
1673 advance_len(p, l, sz);
1674
1675 return SR_OK;
1676}
1677
1678/*
1679 * Fills the caller's text buffer from input data. Also trims and NUL
1680 * terminates the buffer content so that callers don't have to.
1681 */
1682static int consume_str(char *buff, size_t sz, const uint8_t **p, size_t *l)
1683{
1684 int ret;
1685 const char *v;
1686
1687 if (buff)
1688 *buff = '\0';
1689
1690 ret = check_len(l, sz);
1691 if (ret != SR_OK)
1692 return ret;
1693
1694 /*
1695 * Quickly grab current position. Immediate bailout if there is
1696 * no caller buffer to fill in. Simpilifies the remaining logic.
1697 */
1698 v = (const char *)*p;
1699 advance_len(p, l, sz);
1700 if (!buff)
1701 return SR_OK;
1702
1703 /*
1704 * Trim leading space off the input text. Then copy the remaining
1705 * input data to the caller's buffer. This operation is bounded,
1706 * and adds the NUL termination. Then trim trailing space.
1707 *
1708 * The resulting buffer content is known to be NUL terminated.
1709 * It has at most the requested size (modulo the termination).
1710 * The content may be empty, which can be acceptable to callers.
1711 * So these need to check for and handle that condition.
1712 */
1713 memset(buff, 0, sz);
1714 while (sz && isspace(*v)) {
1715 v++;
1716 sz--;
1717 }
1718 if (sz)
1719 snprintf(buff, sz, "%s", v);
1720 buff[sz] = '\0';
1721 sz = strlen(buff);
1722 while (sz && isspace(buff[sz - 1])) {
1723 buff[--sz] = '\0';
1724 }
1725
1726 return SR_OK;
1727}
1728
1729/* Process a DMM packet (a frame in the serial protocol). */
1730static int process_packet(struct sr_dev_inst *sdi, uint8_t *pkt, size_t len)
1731{
1732 struct dev_context *devc;
1733 struct wait_state *state;
1734 struct ut181a_info *info;
1735 uint16_t got_magic, got_length, got_cs, want_cs;
1736 const uint8_t *cs_data, *payload;
1737 size_t cs_dlen, pl_dlen;
1738 uint8_t rsp_type;
1739 enum sr_mqflag add_mqflags;
1740 char unit_buff[8], rec_name_buff[11];
1741 const char *unit_text, *rec_name;
1742 struct feed_buffer feedbuff;
1743 struct value_params value;
1744 const struct mqopt_item *mqitem;
1745 int ret;
1746 uint8_t v8; uint16_t v16; uint32_t v32; float vf;
1747
1748 /*
1749 * Cope with different calling contexts. The packet parser can
1750 * get invoked outside of data acquisition, during preparation
1751 * or in shutdown paths.
1752 */
1753 devc = sdi ? sdi->priv : NULL;
1754 state = devc ? &devc->wait_state : NULL;
1755 info = devc ? &devc->info : NULL;
1756 if (FRAME_DUMP_FRAME && sr_log_loglevel_get() >= FRAME_DUMP_LEVEL) {
1757 GString *spew;
1758 spew = sr_hexdump_new(pkt, len);
1759 FRAME_DUMP_CALL("RX frame, %zu bytes: %s", len, spew->str);
1760 sr_hexdump_free(spew);
1761 }
1762
1763 /*
1764 * Check the frame envelope. Redundancy with common reception
1765 * logic is perfectly fine. Several code paths end up here, we
1766 * need to gracefully deal with incomplete or incorrect data.
1767 *
1768 * This stage uses random access to arbitrary positions in the
1769 * packet which surround the payload. Before the then available
1770 * payload gets consumed in a strict serial manner.
1771 */
1772 if (len < 3 * sizeof(uint16_t)) {
1773 /* Need at least magic, length, checksum. */
1774 if (FRAME_DUMP_CSUM) {
1775 FRAME_DUMP_CALL("Insufficient frame data, need %zu, got %zu.",
1776 3 * sizeof(uint16_t), len);
1777 }
1778 return SR_ERR_DATA;
1779 }
1780
1781 got_magic = RL16(&pkt[0]);
1782 if (got_magic != FRAME_MAGIC) {
1783 if (FRAME_DUMP_CSUM) {
1784 FRAME_DUMP_CALL("Frame magic mismatch, want 0x%04x, got 0x%04x.",
1785 (unsigned int)FRAME_MAGIC, (unsigned int)got_magic);
1786 }
1787 return SR_ERR_DATA;
1788 }
1789
1790 got_length = RL16(&pkt[sizeof(uint16_t)]);
1791 if (got_length != len - 2 * sizeof(uint16_t)) {
1792 if (FRAME_DUMP_CSUM) {
1793 FRAME_DUMP_CALL("Frame length mismatch, want %zu, got %u.",
1794 len - 2 * sizeof(uint16_t), got_length);
1795 }
1796 return SR_ERR_DATA;
1797 }
1798
1799 payload = &pkt[2 * sizeof(uint16_t)];
1800 pl_dlen = got_length - sizeof(uint16_t);
1801
1802 cs_data = &pkt[sizeof(uint16_t)];
1803 cs_dlen = len - 2 * sizeof(uint16_t);
1804 want_cs = ut181a_checksum(cs_data, cs_dlen);
1805 got_cs = RL16(&pkt[len - sizeof(uint16_t)]);
1806 if (got_cs != want_cs) {
1807 if (FRAME_DUMP_CSUM) {
1808 FRAME_DUMP_CALL("Frame checksum mismatch, want 0x%04x, got 0x%04x.",
1809 (unsigned int)want_cs, (unsigned int)got_cs);
1810 }
1811 return SR_ERR_DATA;
1812 }
1813 if (state)
1814 state->response_count++;
1815 if (FRAME_DUMP_BYTES && sr_log_loglevel_get() >= FRAME_DUMP_LEVEL) {
1816 GString *spew;
1817 spew = sr_hexdump_new(payload, pl_dlen);
1818 FRAME_DUMP_CALL("RX payload, %zu bytes: %s", pl_dlen, spew->str);
1819 sr_hexdump_free(spew);
1820 }
1821
1822 /*
1823 * Interpret the frame's payload data. The first byte contains
1824 * a packet type which specifies how to interpret the remainder.
1825 */
1826 ret = consume_u8(&v8, &payload, &pl_dlen);
1827 if (ret != SR_OK) {
1828 sr_err("Insufficient payload data, need packet type.");
1829 return ret;
1830 }
1831 rsp_type = v8;
1832 if (info)
1833 info->rsp_head.rsp_type = rsp_type;
1834
1835 add_mqflags = 0;
1836 switch (rsp_type) {
1837 case RSP_TYPE_REPLY_CODE:
1838 /*
1839 * Reply code: One 16bit item with either 'OK' or 'ER'
1840 * "string literals" to communicate boolean state.
1841 */
1842 ret = consume_u16(&v16, &payload, &pl_dlen);
1843 if (ret != SR_OK)
1844 return SR_ERR_DATA;
1845 if (info) {
1846 info->reply_code.code = v16;
1847 info->reply_code.ok = v16 == REPLY_CODE_OK;
1848 }
1849 if (state && state->want_code) {
1850 state->got_code = TRUE;
1851 state->code_ok = v16 == REPLY_CODE_OK;
1852 }
1853 break;
1854 case RSP_TYPE_SAVE:
1855 /*
1856 * Saved measurement: A 32bit timestamp, followed by a
1857 * measurement (FALLTHROUGH).
1858 */
1859 ret = consume_u32(&v32, &payload, &pl_dlen);
1860 if (ret != SR_OK)
1861 return SR_ERR_DATA;
1862 if (info)
1863 info->save_time.stamp = v32;
1864 v32 = ut181a_get_epoch_for_timestamp(v32);
1865 if (info)
1866 info->save_time.epoch = v32;
1867
1868#if UT181A_WITH_TIMESTAMP
1869 if (devc) {
1870 ret = ut181a_feedbuff_start_frame(sdi);
1871 if (ret != SR_OK)
1872 return SR_ERR_DATA;
1873 ret = SR_OK;
1874 ret |= ut181a_feedbuff_initialize(&feedbuff);
1875 ret |= ut181a_feedbuff_setup_channel(&feedbuff, UT181A_CH_TIME, sdi);
1876 ret |= ut181a_feedbuff_setup_unit(&feedbuff, "timestamp");
1877 ret |= ut181a_get_value_params(&value, v32, 0x00);
1878 ret |= ut181a_feedbuff_setup_value(&feedbuff, &value);
1879 ret |= ut181a_feedbuff_send_feed(&feedbuff, sdi, 0);
1880 ret |= ut181a_feedbuff_cleanup(&feedbuff);
1881 if (ret != SR_OK)
1882 return SR_ERR_DATA;
1883 }
1884#endif
1885 if (info)
1886 info->save_info.save_idx++;
1887
1888 /* FALLTHROUGH */
1889 case RSP_TYPE_MEASUREMENT:
1890 /*
1891 * A measurement. Starts with a common header, which
1892 * specifies the layout of the remainder (variants, with
1893 * optional fields, depending on preceeding fields).
1894 *
1895 * Only useful to process when 'info' (and thus 'devc')
1896 * are available.
1897 */
1898 if (!info)
1899 return SR_ERR_NA;
1900
1901 /*
1902 * Get the header fields (misc1, misc2, mode, and range),
1903 * derive local packet type details and flags from them.
1904 */
1905 ret = consume_u8(&v8, &payload, &pl_dlen);
1906 if (ret != SR_OK)
1907 return SR_ERR_DATA;
1908 info->meas_head.misc1 = v8;
1909 info->meas_head.has_hold = (v8 & 0x80) ? 1 : 0;
1910 info->meas_head.is_type = (v8 & 0x70) >> 4;
1911 info->meas_head.is_norm = (info->meas_head.is_type == 0) ? 1 : 0;
1912 info->meas_head.is_rel = (info->meas_head.is_type == 1) ? 1 : 0;
1913 info->meas_head.is_minmax = (info->meas_head.is_type == 2) ? 1 : 0;
1914 info->meas_head.is_peak = (info->meas_head.is_type == 4) ? 1 : 0;
1915 info->meas_head.has_bar = (v8 & 0x8) ? 1 : 0;
1916 info->meas_head.has_aux2 = (v8 & 0x4) ? 1 : 0;
1917 info->meas_head.has_aux1 = (v8 & 0x2) ? 1 : 0;
1918
1919 ret = consume_u8(&v8, &payload, &pl_dlen);
1920 if (ret != SR_OK)
1921 return SR_ERR_DATA;
1922 info->meas_head.misc2 = v8;
1923 info->meas_head.is_rec = (v8 & 0x20) ? 1 : 0;
1924 if (devc)
1925 devc->is_recording = info->meas_head.is_rec;
1926 info->meas_head.is_comp = (v8 & 0x10) ? 1 : 0;
1927 info->meas_head.has_lead_err = (v8 & 0x8) ? 1 : 0;
1928 info->meas_head.has_high_volt = (v8 & 0x2) ? 1 : 0;
1929 info->meas_head.is_auto_range = (v8 & 0x1) ? 1 : 0;
1930
1931 ret = consume_u16(&v16, &payload, &pl_dlen);
1932 if (ret != SR_OK)
1933 return SR_ERR_DATA;
1934 info->meas_head.mode = v16;
1935 mqitem = ut181a_get_mqitem_from_mode(v16);
1936 if (!mqitem || !mqitem->mq)
1937 return SR_ERR_DATA;
1938 add_mqflags |= mqitem->mqflags;
1939 if (info->meas_head.has_hold)
1940 add_mqflags |= SR_MQFLAG_HOLD;
1941 if (info->meas_head.is_auto_range)
1942 add_mqflags |= SR_MQFLAG_AUTORANGE;
1943 if (add_mqflags & SR_MQFLAG_DIODE)
1944 add_mqflags |= SR_MQFLAG_DC;
1945
1946 ret = consume_u8(&v8, &payload, &pl_dlen);
1947 if (ret != SR_OK)
1948 return SR_ERR_DATA;
1949 info->meas_head.range = v8;
1950
1951 if (state && state->want_measure)
1952 state->got_measure = TRUE;
1953
1954 ret = ut181a_feedbuff_start_frame(sdi);
1955 if (ret != SR_OK)
1956 return SR_ERR_DATA;
1957
1958 /*
1959 * The remaining measurement's layout depends on type.
1960 * - Normal measurement:
1961 * - Main value (4/1/8 value/precision/unit).
1962 * - Aux1 value (4/1/8 value/precision/unit) when AUX1
1963 * flag active.
1964 * - Aux2 value (4/1/8 value/precision/unit) when AUX2
1965 * flag active.
1966 * - Bargraph (4/8 value/unit) when BAR flag active.
1967 * - COMP result when COMP flag active.
1968 * - Always 1/1/1/4 mode/flags/digits/limit: type
1969 * of check, PASS/FAIL verdict, limit values'
1970 * precision, upper or only limit.
1971 * - Conditional 4 limit: Lower limit for checks
1972 * which involve two limit values.
1973 * - Relative measurement:
1974 * - Relative value (4/1/8 value/precision/unit).
1975 * - Reference value (4/1/8 value/precision/unit),
1976 * when AUX1 active (practically always).
1977 * - Absolute value (4/1/8 value/precision/unit),
1978 * when AUX2 active (practically always).
1979 * - Bargraph (4/8 value/unit) when BAR flag active.
1980 * - Min/Max measurement:
1981 * - All fields always present, no conditions.
1982 * - One common unit spec at the end which applies to
1983 * all curr/max/avg/min values.
1984 * - Current value (4/1 value/precision).
1985 * - Maximum value (4/1/4 value/precision/time).
1986 * - Average value (4/1/4 value/precision/time).
1987 * - Minimum value (4/1/4 value/precision/time).
1988 * - Common unit text (8).
1989 * - Peak measurement:
1990 * - All fields always present.
1991 * - Maximum value (4/1/8 value/precision/unit).
1992 * - Minimum value (4/1/8 value/precision/unit).
1993 */
1994 ret = ut181a_feedbuff_initialize(&feedbuff);
1995 if (info->meas_head.is_norm) {
1996 /* Main value, unconditional. Get details. */
1997 ret = consume_flt(&vf, &payload, &pl_dlen);
1998 if (ret != SR_OK)
1999 return SR_ERR_DATA;
2000 info->meas_data.norm.main_value = vf;
2001 ret = consume_u8(&v8, &payload, &pl_dlen);
2002 if (ret != SR_OK)
2003 return SR_ERR_DATA;
2004 info->meas_data.norm.main_prec = v8;
2005 ret = consume_str(&unit_buff[0], 8, &payload, &pl_dlen);
2006 unit_text = &unit_buff[0];
2007 if (ret != SR_OK)
2008 return SR_ERR_DATA;
2009 snprintf(info->meas_data.norm.main_unit,
2010 sizeof(info->meas_data.norm.main_unit),
2011 "%s", unit_text);
2012 unit_text = info->meas_data.norm.main_unit;
2013
2014 /* Submit main value to session feed. */
2015 ret = SR_OK;
2016 ret |= ut181a_feedbuff_setup_channel(&feedbuff, UT181A_CH_MAIN, sdi);
2017 ret |= ut181a_feedbuff_setup_unit(&feedbuff, unit_text);
2018 feedbuff.analog.meaning->mqflags |= add_mqflags;
2019 ret |= ut181a_get_value_params(&value, vf, v8);
2020 ret |= ut181a_feedbuff_setup_value(&feedbuff, &value);
2021 ret |= ut181a_feedbuff_send_feed(&feedbuff, sdi, 1);
2022 if (ret != SR_OK)
2023 return SR_ERR_DATA;
2024 }
2025 if (info->meas_head.is_norm && info->meas_head.has_aux1) {
2026 /* Aux1 value, optional. Get details. */
2027 ret = consume_flt(&vf, &payload, &pl_dlen);
2028 if (ret != SR_OK)
2029 return SR_ERR_DATA;
2030 info->meas_data.norm.aux1_value = vf;
2031 ret = consume_u8(&v8, &payload, &pl_dlen);
2032 if (ret != SR_OK)
2033 return SR_ERR_DATA;
2034 info->meas_data.norm.aux1_prec = v8;
2035 ret = consume_str(&unit_buff[0], 8, &payload, &pl_dlen);
2036 unit_text = &unit_buff[0];
2037 if (ret != SR_OK)
2038 return SR_ERR_DATA;
2039 snprintf(info->meas_data.norm.aux1_unit,
2040 sizeof(info->meas_data.norm.aux1_unit),
2041 "%s", unit_text);
2042 unit_text = info->meas_data.norm.aux1_unit;
2043
2044 /* Submit aux1 value to session feed. */
2045 ret = SR_OK;
2046 ret |= ut181a_feedbuff_setup_channel(&feedbuff, UT181A_CH_AUX1, sdi);
2047 ret |= ut181a_feedbuff_setup_unit(&feedbuff, unit_text);
2048 ret |= ut181a_get_value_params(&value, vf, v8);
2049 ret |= ut181a_feedbuff_setup_value(&feedbuff, &value);
2050 ret |= ut181a_feedbuff_send_feed(&feedbuff, sdi, 0);
2051 if (ret != SR_OK)
2052 return SR_ERR_DATA;
2053 }
2054 if (info->meas_head.is_norm && info->meas_head.has_aux2) {
2055 /* Aux2 value, optional. Get details. */
2056 ret = consume_flt(&vf, &payload, &pl_dlen);
2057 if (ret != SR_OK)
2058 return SR_ERR_DATA;
2059 info->meas_data.norm.aux2_value = vf;
2060 ret = consume_u8(&v8, &payload, &pl_dlen);
2061 if (ret != SR_OK)
2062 return SR_ERR_DATA;
2063 info->meas_data.norm.aux2_prec = v8;
2064 ret = consume_str(&unit_buff[0], 8, &payload, &pl_dlen);
2065 unit_text = &unit_buff[0];
2066 if (ret != SR_OK)
2067 return SR_ERR_DATA;
2068 snprintf(info->meas_data.norm.aux2_unit,
2069 sizeof(info->meas_data.norm.aux2_unit),
2070 "%s", unit_text);
2071 unit_text = info->meas_data.norm.aux2_unit;
2072
2073 /* Submit aux2 value to session feed. */
2074 ret = SR_OK;
2075 ret |= ut181a_feedbuff_setup_channel(&feedbuff, UT181A_CH_AUX2, sdi);
2076 ret |= ut181a_feedbuff_setup_unit(&feedbuff, unit_text);
2077 ret |= ut181a_get_value_params(&value, vf, v8);
2078 ret |= ut181a_feedbuff_setup_value(&feedbuff, &value);
2079 ret |= ut181a_feedbuff_send_feed(&feedbuff, sdi, 0);
2080 if (ret != SR_OK)
2081 return SR_ERR_DATA;
2082 }
2083 if (info->meas_head.is_norm && info->meas_head.has_bar) {
2084 /* Bargraph value, optional. */
2085 ret = consume_flt(&vf, &payload, &pl_dlen);
2086 if (ret != SR_OK)
2087 return SR_ERR_DATA;
2088 info->meas_data.norm.bar_value = vf;
2089 ret = consume_str(&unit_buff[0], 8, &payload, &pl_dlen);
2090 unit_text = &unit_buff[0];
2091 if (ret != SR_OK)
2092 return SR_ERR_DATA;
2093 snprintf(info->meas_data.norm.bar_unit,
2094 sizeof(info->meas_data.norm.bar_unit),
2095 "%s", unit_text);
2096 unit_text = info->meas_data.norm.bar_unit;
2097
2098 /* Submit bargraph value to session feed. */
2099 ret = 0;
2100 ret |= ut181a_feedbuff_setup_channel(&feedbuff, UT181A_CH_BAR, sdi);
2101 ret |= ut181a_feedbuff_setup_unit(&feedbuff, unit_text);
2102 ret |= ut181a_get_value_params(&value, vf, 0x00);
2103 ret |= ut181a_feedbuff_setup_value(&feedbuff, &value);
2104 ret |= ut181a_feedbuff_send_feed(&feedbuff, sdi, 0);
2105 if (ret != SR_OK)
2106 return SR_ERR_DATA;
2107 }
2108 if (info->meas_head.is_norm && info->meas_head.is_comp) {
2109 /* COMP result, optional. Get details. */
2110 ret = consume_u8(&v8, &payload, &pl_dlen);
2111 if (ret != SR_OK)
2112 return SR_ERR_DATA;
2113 if (v8 > COMP_MODE_ABOVE)
2114 return SR_ERR_DATA;
2115 info->meas_data.comp.mode = v8;
2116 ret = consume_u8(&v8, &payload, &pl_dlen);
2117 if (ret != SR_OK)
2118 return SR_ERR_DATA;
2119 info->meas_data.comp.fail = v8 ? TRUE : FALSE;
2120 ret = consume_u8(&v8, &payload, &pl_dlen);
2121 if (ret != SR_OK)
2122 return SR_ERR_DATA;
2123 info->meas_data.comp.digits = v8 & 0x0f;
2124 ret = consume_flt(&vf, &payload, &pl_dlen);
2125 if (ret != SR_OK)
2126 return SR_ERR_DATA;
2127 info->meas_data.comp.limit_high = vf;
2128 if (info->meas_data.comp.mode <= COMP_MODE_OUTER) {
2129 ret = consume_flt(&vf, &payload, &pl_dlen);
2130 if (ret != SR_OK)
2131 return SR_ERR_DATA;
2132 info->meas_data.comp.limit_low = vf;
2133 }
2134
2135 /* TODO
2136 * How to present this result to the feed? This
2137 * implementation extracts and interprets the
2138 * fields, but does not pass the values to the
2139 * session. Which MQ to use for PASS/FAIL checks?
2140 */
2141 static const char *mode_text[] = {
2142 [COMP_MODE_INNER] = "INNER",
2143 [COMP_MODE_OUTER] = "OUTER",
2144 [COMP_MODE_BELOW] = "BELOW",
2145 [COMP_MODE_ABOVE] = "ABOVE",
2146 };
2147
2148 if (info->meas_data.comp.mode <= COMP_MODE_OUTER) {
2149 sr_dbg("Unprocessed COMP result:"
2150 " mode %s, %s, digits %d, low %f, high %f",
2151 mode_text[info->meas_data.comp.mode],
2152 info->meas_data.comp.fail ? "FAIL" : "PASS",
2153 info->meas_data.comp.digits,
2154 info->meas_data.comp.limit_low,
2155 info->meas_data.comp.limit_high);
2156 } else {
2157 sr_dbg("Unprocessed COMP result:"
2158 " mode %s, %s, digits %d, limit %f",
2159 mode_text[info->meas_data.comp.mode],
2160 info->meas_data.comp.fail ? "FAIL" : "PASS",
2161 info->meas_data.comp.digits,
2162 info->meas_data.comp.limit_high);
2163 }
2164 }
2165 if (info->meas_head.is_norm) {
2166 /* Normal measurement code path done. */
2167 ret = ut181a_feedbuff_cleanup(&feedbuff);
2168 ret = ut181a_feedbuff_count_frame(sdi);
2169 if (ret != SR_OK)
2170 return SR_ERR_DATA;
2171 break;
2172 }
2173
2174 if (info->meas_head.is_rel) {
2175 /* Relative value, unconditional. Get details. */
2176 ret = consume_flt(&vf, &payload, &pl_dlen);
2177 if (ret != SR_OK)
2178 return SR_ERR_DATA;
2179 info->meas_data.rel.rel_value = vf;
2180 ret = consume_u8(&v8, &payload, &pl_dlen);
2181 if (ret != SR_OK)
2182 return SR_ERR_DATA;
2183 info->meas_data.rel.rel_prec = v8;
2184 ret = consume_str(&unit_buff[0], 8, &payload, &pl_dlen);
2185 unit_text = &unit_buff[0];
2186 if (ret != SR_OK)
2187 return SR_ERR_DATA;
2188 snprintf(info->meas_data.rel.rel_unit,
2189 sizeof(info->meas_data.rel.rel_unit),
2190 "%s", unit_text);
2191 unit_text = info->meas_data.rel.rel_unit;
2192
2193 /* Submit relative value to session feed. */
2194 ret = SR_OK;
2195 ret |= ut181a_feedbuff_setup_channel(&feedbuff, UT181A_CH_MAIN, sdi);
2196 ret |= ut181a_feedbuff_setup_unit(&feedbuff, unit_text);
2197 feedbuff.analog.meaning->mqflags |= add_mqflags;
2198 feedbuff.analog.meaning->mqflags |= SR_MQFLAG_RELATIVE;
2199 ret |= ut181a_get_value_params(&value, vf, v8);
2200 ret |= ut181a_feedbuff_setup_value(&feedbuff, &value);
2201 ret |= ut181a_feedbuff_send_feed(&feedbuff, sdi, 1);
2202 if (ret != SR_OK)
2203 return SR_ERR_DATA;
2204 }
2205 if (info->meas_head.is_rel && info->meas_head.has_aux1) {
2206 /* Reference value, "conditional" in theory. */
2207 ret = consume_flt(&vf, &payload, &pl_dlen);
2208 if (ret != SR_OK)
2209 return SR_ERR_DATA;
2210 info->meas_data.rel.ref_value = vf;
2211 ret = consume_u8(&v8, &payload, &pl_dlen);
2212 if (ret != SR_OK)
2213 return SR_ERR_DATA;
2214 info->meas_data.rel.ref_prec = v8;
2215 ret = consume_str(&unit_buff[0], 8, &payload, &pl_dlen);
2216 unit_text = &unit_buff[0];
2217 if (ret != SR_OK)
2218 return SR_ERR_DATA;
2219 snprintf(info->meas_data.rel.ref_unit,
2220 sizeof(info->meas_data.rel.ref_unit),
2221 "%s", unit_text);
2222 unit_text = info->meas_data.rel.ref_unit;
2223
2224 /* Submit reference value to session feed. */
2225 ret = SR_OK;
2226 ret |= ut181a_feedbuff_setup_channel(&feedbuff, UT181A_CH_AUX1, sdi);
2227 ret |= ut181a_feedbuff_setup_unit(&feedbuff, unit_text);
2228 feedbuff.analog.meaning->mqflags |= SR_MQFLAG_REFERENCE;
2229 ret |= ut181a_get_value_params(&value, vf, v8);
2230 ret |= ut181a_feedbuff_setup_value(&feedbuff, &value);
2231 ret |= ut181a_feedbuff_send_feed(&feedbuff, sdi, 0);
2232 if (ret != SR_OK)
2233 return SR_ERR_DATA;
2234 }
2235 if (info->meas_head.is_rel && info->meas_head.has_aux2) {
2236 /* Absolute value, "conditional" in theory. */
2237 ret = consume_flt(&vf, &payload, &pl_dlen);
2238 if (ret != SR_OK)
2239 return SR_ERR_DATA;
2240 info->meas_data.rel.abs_value = vf;
2241 ret = consume_u8(&v8, &payload, &pl_dlen);
2242 if (ret != SR_OK)
2243 return SR_ERR_DATA;
2244 info->meas_data.rel.abs_prec = v8;
2245 ret = consume_str(&unit_buff[0], 8, &payload, &pl_dlen);
2246 unit_text = &unit_buff[0];
2247 if (ret != SR_OK)
2248 return SR_ERR_DATA;
2249 snprintf(info->meas_data.rel.abs_unit,
2250 sizeof(info->meas_data.rel.abs_unit),
2251 "%s", unit_text);
2252 unit_text = info->meas_data.rel.abs_unit;
2253
2254 /* Submit absolute value to session feed. */
2255 ret = SR_OK;
2256 ret |= ut181a_feedbuff_setup_channel(&feedbuff, UT181A_CH_AUX2, sdi);
2257 ret |= ut181a_feedbuff_setup_unit(&feedbuff, unit_text);
2258 ret |= ut181a_get_value_params(&value, vf, v8);
2259 ret |= ut181a_feedbuff_setup_value(&feedbuff, &value);
2260 ret |= ut181a_feedbuff_send_feed(&feedbuff, sdi, 0);
2261 if (ret != SR_OK)
2262 return SR_ERR_DATA;
2263 }
2264 if (info->meas_head.is_rel && info->meas_head.has_bar) {
2265 /* Bargraph value, conditional. */
2266 ret = consume_flt(&vf, &payload, &pl_dlen);
2267 if (ret != SR_OK)
2268 return SR_ERR_DATA;
2269 info->meas_data.rel.bar_value = vf;
2270 ret = consume_str(&unit_buff[0], 8, &payload, &pl_dlen);
2271 unit_text = &unit_buff[0];
2272 if (ret != SR_OK)
2273 return SR_ERR_DATA;
2274 snprintf(info->meas_data.rel.bar_unit,
2275 sizeof(info->meas_data.rel.bar_unit),
2276 "%s", unit_text);
2277 unit_text = info->meas_data.rel.bar_unit;
2278
2279 /* Submit bargraph value to session feed. */
2280 ret = SR_OK;
2281 ret |= ut181a_feedbuff_setup_channel(&feedbuff, UT181A_CH_BAR, sdi);
2282 ret |= ut181a_feedbuff_setup_unit(&feedbuff, unit_text);
2283 ret |= ut181a_get_value_params(&value, vf, 0x00);
2284 ret |= ut181a_feedbuff_setup_value(&feedbuff, &value);
2285 ret |= ut181a_feedbuff_send_feed(&feedbuff, sdi, 0);
2286 if (ret != SR_OK)
2287 return SR_ERR_DATA;
2288 }
2289 if (info->meas_head.is_rel) {
2290 /* Relative measurement code path done. */
2291 ret = ut181a_feedbuff_cleanup(&feedbuff);
2292 ret = ut181a_feedbuff_count_frame(sdi);
2293 if (ret != SR_OK)
2294 return SR_ERR_DATA;
2295 break;
2296 }
2297
2298 if (info->meas_head.is_minmax) {
2299 /*
2300 * Min/max measurement values, none of them are
2301 * conditional in practice (all are present).
2302 * This is special in that all of curr, max, avg,
2303 * and min values share the same unit text which
2304 * is only at the end of the data fields.
2305 */
2306 ret = SR_OK;
2307 ret |= consume_flt(&info->meas_data.minmax.curr_value, &payload, &pl_dlen);
2308 ret |= consume_u8(&info->meas_data.minmax.curr_prec, &payload, &pl_dlen);
2309 ret |= consume_flt(&info->meas_data.minmax.max_value, &payload, &pl_dlen);
2310 ret |= consume_u8(&info->meas_data.minmax.max_prec, &payload, &pl_dlen);
2311 ret |= consume_u32(&info->meas_data.minmax.max_stamp, &payload, &pl_dlen);
2312 ret |= consume_flt(&info->meas_data.minmax.avg_value, &payload, &pl_dlen);
2313 ret |= consume_u8(&info->meas_data.minmax.avg_prec, &payload, &pl_dlen);
2314 ret |= consume_u32(&info->meas_data.minmax.avg_stamp, &payload, &pl_dlen);
2315 ret |= consume_flt(&info->meas_data.minmax.min_value, &payload, &pl_dlen);
2316 ret |= consume_u8(&info->meas_data.minmax.min_prec, &payload, &pl_dlen);
2317 ret |= consume_u32(&info->meas_data.minmax.min_stamp, &payload, &pl_dlen);
2318 ret |= consume_str(&unit_buff[0], 8, &payload, &pl_dlen);
2319 unit_text = &unit_buff[0];
2320 if (ret != SR_OK)
2321 return SR_ERR_DATA;
2322 snprintf(info->meas_data.minmax.all_unit,
2323 sizeof(info->meas_data.minmax.all_unit),
2324 "%s", unit_text);
2325 unit_text = info->meas_data.minmax.all_unit;
2326
2327 /* Submit the current value. */
2328 vf = info->meas_data.minmax.curr_value;
2329 v8 = info->meas_data.minmax.curr_prec;
2330 ret = SR_OK;
2331 ret |= ut181a_feedbuff_setup_channel(&feedbuff, UT181A_CH_MAIN, sdi);
2332 ret |= ut181a_feedbuff_setup_unit(&feedbuff, unit_text);
2333 feedbuff.analog.meaning->mqflags |= add_mqflags;
2334 ret |= ut181a_get_value_params(&value, vf, v8);
2335 ret |= ut181a_feedbuff_setup_value(&feedbuff, &value);
2336 ret |= ut181a_feedbuff_send_feed(&feedbuff, sdi, 1);
2337 if (ret != SR_OK)
2338 return SR_ERR_DATA;
2339
2340 /* Submit the maximum value. */
2341 vf = info->meas_data.minmax.max_value;
2342 v8 = info->meas_data.minmax.max_prec;
2343 ret = SR_OK;
2344 ret |= ut181a_feedbuff_setup_channel(&feedbuff, UT181A_CH_AUX1, sdi);
2345 ret |= ut181a_feedbuff_setup_unit(&feedbuff, unit_text);
2346 feedbuff.analog.meaning->mqflags |= SR_MQFLAG_MAX;
2347 ret |= ut181a_get_value_params(&value, vf, v8);
2348 ret |= ut181a_feedbuff_setup_value(&feedbuff, &value);
2349 ret |= ut181a_feedbuff_send_feed(&feedbuff, sdi, 0);
2350 if (ret != SR_OK)
2351 return SR_ERR_DATA;
2352
2353 /* Submit the average value. */
2354 vf = info->meas_data.minmax.avg_value;
2355 v8 = info->meas_data.minmax.avg_prec;
2356 ret = SR_OK;
2357 ret |= ut181a_feedbuff_setup_channel(&feedbuff, UT181A_CH_AUX2, sdi);
2358 ret |= ut181a_feedbuff_setup_unit(&feedbuff, unit_text);
2359 feedbuff.analog.meaning->mqflags |= SR_MQFLAG_AVG;
2360 ret |= ut181a_get_value_params(&value, vf, v8);
2361 ret |= ut181a_feedbuff_setup_value(&feedbuff, &value);
2362 ret |= ut181a_feedbuff_send_feed(&feedbuff, sdi, 0);
2363 if (ret != SR_OK)
2364 return SR_ERR_DATA;
2365
2366 /* Submit the minimum value. */
2367 vf = info->meas_data.minmax.min_value;
2368 v8 = info->meas_data.minmax.min_prec;
2369 ret = SR_OK;
2370 ret |= ut181a_feedbuff_setup_channel(&feedbuff, UT181A_CH_AUX3, sdi);
2371 ret |= ut181a_feedbuff_setup_unit(&feedbuff, unit_text);
2372 feedbuff.analog.meaning->mqflags |= SR_MQFLAG_MIN;
2373 ret |= ut181a_get_value_params(&value, vf, v8);
2374 ret |= ut181a_feedbuff_setup_value(&feedbuff, &value);
2375 ret |= ut181a_feedbuff_send_feed(&feedbuff, sdi, 0);
2376 if (ret != SR_OK)
2377 return SR_ERR_DATA;
2378 }
2379 if (info->meas_head.is_minmax) {
2380 /* Min/max measurement code path done. */
2381 ret = ut181a_feedbuff_cleanup(&feedbuff);
2382 ret = ut181a_feedbuff_count_frame(sdi);
2383 if (ret != SR_OK)
2384 return SR_ERR_DATA;
2385 break;
2386 }
2387
2388 if (info->meas_head.is_peak) {
2389 /* Maximum value, unconditional. Get details. */
2390 ret = consume_flt(&vf, &payload, &pl_dlen);
2391 if (ret != SR_OK)
2392 return SR_ERR_DATA;
2393 info->meas_data.peak.max_value = vf;
2394 ret = consume_u8(&v8, &payload, &pl_dlen);
2395 if (ret != SR_OK)
2396 return SR_ERR_DATA;
2397 info->meas_data.peak.max_prec = v8;
2398 ret = consume_str(&unit_buff[0], 8, &payload, &pl_dlen);
2399 unit_text = &unit_buff[0];
2400 if (ret != SR_OK)
2401 return SR_ERR_DATA;
2402 snprintf(info->meas_data.peak.max_unit,
2403 sizeof(info->meas_data.peak.max_unit),
2404 "%s", unit_text);
2405 unit_text = info->meas_data.peak.max_unit;
2406
2407 /* Submit max value to session feed. */
2408 ret = SR_OK;
2409 ret |= ut181a_feedbuff_setup_channel(&feedbuff, UT181A_CH_AUX1, sdi);
2410 ret |= ut181a_feedbuff_setup_unit(&feedbuff, unit_text);
2411 feedbuff.analog.meaning->mqflags |= add_mqflags; /* ??? */
2412 feedbuff.analog.meaning->mqflags |= SR_MQFLAG_MAX;
2413 ret |= ut181a_get_value_params(&value, vf, v8);
2414 ret |= ut181a_feedbuff_setup_value(&feedbuff, &value);
2415 ret |= ut181a_feedbuff_send_feed(&feedbuff, sdi, 1);
2416 if (ret != SR_OK)
2417 return SR_ERR_DATA;
2418
2419 /* Minimum value, unconditional. Get details. */
2420 ret = consume_flt(&vf, &payload, &pl_dlen);
2421 if (ret != SR_OK)
2422 return SR_ERR_DATA;
2423 info->meas_data.peak.min_value = vf;
2424 ret = consume_u8(&v8, &payload, &pl_dlen);
2425 if (ret != SR_OK)
2426 return SR_ERR_DATA;
2427 info->meas_data.peak.min_prec = v8;
2428 ret = consume_str(&unit_buff[0], 8, &payload, &pl_dlen);
2429 unit_text = &unit_buff[0];
2430 if (ret != SR_OK)
2431 return SR_ERR_DATA;
2432 snprintf(info->meas_data.peak.min_unit,
2433 sizeof(info->meas_data.peak.min_unit),
2434 "%s", unit_text);
2435 unit_text = info->meas_data.peak.min_unit;
2436
2437 /* Submit min value to session feed. */
2438 ret = SR_OK;
2439 ret |= ut181a_feedbuff_setup_channel(&feedbuff, UT181A_CH_AUX3, sdi);
2440 ret |= ut181a_feedbuff_setup_unit(&feedbuff, unit_text);
2441 feedbuff.analog.meaning->mqflags |= SR_MQFLAG_MIN;
2442 ret |= ut181a_get_value_params(&value, vf, v8);
2443 ret |= ut181a_feedbuff_setup_value(&feedbuff, &value);
2444 ret |= ut181a_feedbuff_send_feed(&feedbuff, sdi, 0);
2445 if (ret != SR_OK)
2446 return SR_ERR_DATA;
2447 }
2448 if (info->meas_head.is_peak) {
2449 /* Relative measurement code path done. */
2450 ret = ut181a_feedbuff_cleanup(&feedbuff);
2451 ret = ut181a_feedbuff_count_frame(sdi);
2452 if (ret != SR_OK)
2453 return SR_ERR_DATA;
2454 break;
2455 }
2456
2457 /* ShouldNeverHappen(TM) */
2458 sr_dbg("Unhandled measurement type.");
2459 return SR_ERR_DATA;
2460
2461 case RSP_TYPE_REC_INFO:
2462 /*
2463 * Not useful to process without 'devc' or 'info'.
2464 * The caller provided the recording's index (the
2465 * protocol won't in the response).
2466 */
2467 if (!devc || !info)
2468 return SR_ERR_ARG;
2469
2470 /*
2471 * Record information:
2472 * - User specified recording's name (11 ASCIIZ chars).
2473 * - Unit text (8).
2474 * - Interval, duration, sample count (2/4/4).
2475 * - Max/avg/min values and precision (4+1/4+1/4+1).
2476 * - Time when recording started (4).
2477 *
2478 * Notice that the recording name needs to get trimmed
2479 * due to limited text editing capabilities of the DMM
2480 * UI. The name need not be unique, and typically isn't
2481 * (again: because of limited editing, potential numbers
2482 * in names are not auto incremented in the firmware).
2483 */
2484 ret = consume_str(&rec_name_buff[0], 11, &payload, &pl_dlen);
2485 rec_name = &rec_name_buff[0];
2486 if (ret != SR_OK)
2487 return SR_ERR_DATA;
2488 if (!*rec_name)
2489 return SR_ERR_DATA;
2490 snprintf(devc->record_names[info->rec_info.rec_idx],
2491 sizeof(devc->record_names[info->rec_info.rec_idx]),
2492 "%s", rec_name);
2493 snprintf(info->rec_info.name, sizeof(info->rec_info.name),
2494 "%s", rec_name);
2495 ret = consume_str(&unit_buff[0], 8, &payload, &pl_dlen);
2496 unit_text = &unit_buff[0];
2497 if (ret != SR_OK)
2498 return SR_ERR_DATA;
2499 snprintf(info->rec_info.unit,
2500 sizeof(info->rec_info.unit),
2501 "%s", unit_text);
2502 unit_text = info->rec_info.unit;
2503 ret = SR_OK;
2504 ret |= consume_u16(&info->rec_info.interval, &payload, &pl_dlen);
2505 ret |= consume_u32(&info->rec_info.duration, &payload, &pl_dlen);
2506 ret |= consume_u32(&info->rec_info.samples, &payload, &pl_dlen);
2507 ret |= consume_flt(&info->rec_info.max_value, &payload, &pl_dlen);
2508 ret |= consume_u8(&info->rec_info.max_prec, &payload, &pl_dlen);
2509 ret |= consume_flt(&info->rec_info.avg_value, &payload, &pl_dlen);
2510 ret |= consume_u8(&info->rec_info.avg_prec, &payload, &pl_dlen);
2511 ret |= consume_flt(&info->rec_info.min_value, &payload, &pl_dlen);
2512 ret |= consume_u8(&info->rec_info.min_prec, &payload, &pl_dlen);
2513 ret |= consume_u32(&v32, &payload, &pl_dlen);
2514 if (ret != SR_OK)
2515 return SR_ERR_DATA;
2516 info->rec_info.start_stamp = ut181a_get_epoch_for_timestamp(v32);
2517
2518 /*
2519 * Cheat, provide sample count as if it was reply data.
2520 * Some api.c code paths assume to find this detail there.
2521 * Keep the last unit text at hand, subsequent reception
2522 * of record data will reference it.
2523 */
2524 if (state && state->want_data == CMD_CODE_GET_REC_INFO) {
2525 state->got_sample_count = TRUE;
2526 state->data_value = info->rec_info.samples;
2527 }
2528 snprintf(devc->last_data.unit_text,
2529 sizeof(devc->last_data.unit_text),
2530 "%s", unit_text);
2531
2532 /*
2533 * Optionally automatically forward the sample interval
2534 * to the session feed, before record data is sent.
2535 */
2536 if (devc->info.rec_info.auto_feed) {
2537 ret = ut181a_feed_send_rate(sdi, info->rec_info.interval);
2538 }
2539
2540 break;
2541
2542 case RSP_TYPE_REC_DATA:
2543 /*
2544 * We expect record data only during acquisitions from
2545 * that data source, and depend on being able to feed
2546 * data to the session.
2547 */
2548 if (sdi->status != SR_ST_ACTIVE)
2549 break;
2550 if (!devc || devc->disable_feed || !info)
2551 break;
2552 ret = ut181a_feedbuff_initialize(&feedbuff);
2553 ret = ut181a_feedbuff_setup_channel(&feedbuff, UT181A_CH_MAIN, sdi);
2554 ret = ut181a_feedbuff_setup_unit(&feedbuff, devc->last_data.unit_text);
2555
2556 /*
2557 * Record data:
2558 * - u8 sample count for this data chunk, then the
2559 * corresponding number of samples, each is 9 bytes:
2560 * - f32 value
2561 * - u8 precision
2562 * - u32 timestamp
2563 */
2564 ret = consume_u8(&info->rec_data.samples_chunk, &payload, &pl_dlen);
2565 if (ret != SR_OK)
2566 return SR_ERR_DATA;
2567 info->rec_data.samples_curr += info->rec_data.samples_chunk;
2568 while (info->rec_data.samples_chunk--) {
2569 /*
2570 * Implementation detail: Consume all received
2571 * data, yet skip processing when a limit was
2572 * reached and previously terminated acquisition.
2573 */
2574 ret = SR_OK;
2575 ret |= consume_flt(&vf, &payload, &pl_dlen);
2576 ret |= consume_u8(&v8, &payload, &pl_dlen);
2577 ret |= consume_u32(&v32, &payload, &pl_dlen);
2578 if (ret != SR_OK)
2579 return SR_ERR_DATA;
2580
2581 if (sdi->status != SR_ST_ACTIVE)
2582 continue;
2583
2584 ret = ut181a_feedbuff_start_frame(sdi);
2585 if (ret != SR_OK)
2586 return SR_ERR_DATA;
2587
2588 ret = SR_OK;
2589 ret |= ut181a_get_value_params(&value, vf, v8);
2590 ret |= ut181a_feedbuff_setup_value(&feedbuff, &value);
2591 ret |= ut181a_feedbuff_send_feed(&feedbuff, sdi, 1);
2592 if (ret != SR_OK)
2593 return SR_ERR_DATA;
2594
2595 ret = ut181a_feedbuff_count_frame(sdi);
2596 if (ret != SR_OK)
2597 return SR_ERR_DATA;
2598 }
2599 ret = ut181a_feedbuff_cleanup(&feedbuff);
2600 break;
2601
2602 case RSP_TYPE_REPLY_DATA:
2603 /*
2604 * Reply data. Generic 16bit value preceeded by 8bit
2605 * request code.
2606 */
2607 ret = SR_OK;
2608 ret |= consume_u8(&v8, &payload, &pl_dlen);
2609 ret |= consume_u16(&v16, &payload, &pl_dlen);
2610 if (ret != SR_OK)
2611 return SR_ERR_DATA;
2612 if (info) {
2613 info->reply_data.code = v8;
2614 info->reply_data.data = v16;
2615 }
2616 if (state && state->want_data && state->want_data == v8) {
2617 state->got_data = TRUE;
2618 state->data_value = v16;
2619 if (v8 == CMD_CODE_GET_RECS_COUNT)
2620 state->got_rec_count = TRUE;
2621 if (v8 == CMD_CODE_GET_SAVED_COUNT)
2622 state->got_save_count = TRUE;
2623 if (v8 == CMD_CODE_GET_REC_INFO)
2624 state->got_sample_count = TRUE;
2625 }
2626 break;
2627
2628 default:
2629 if (FRAME_DUMP_PARSE)
2630 FRAME_DUMP_CALL("Unhandled response type 0x%02x", rsp_type);
2631 return SR_ERR_NA;
2632 }
2633 if (state && state->want_rsp_type == rsp_type)
2634 state->got_rsp_type = TRUE;
2635 if (FRAME_DUMP_REMAIN && pl_dlen) {
2636 GString *txt;
2637 txt = sr_hexdump_new(payload, pl_dlen);
2638 FRAME_DUMP_CALL("Unprocessed response data: %s", txt->str);
2639 sr_hexdump_free(txt);
2640 }
2641
2642 /* Unconditionally check, we may have hit a time limit. */
2643 if (sr_sw_limits_check(&devc->limits)) {
2644 ut181a_cond_stop_acquisition(sdi);
2645 return SR_OK;
2646 }
2647
2648 /*
2649 * Only emit next requests for chunked downloads after successful
2650 * reception and consumption of the currently received item(s).
2651 */
2652 if (devc) {
2653 struct sr_serial_dev_inst *serial;
2654 serial = sdi->conn;
2655
2656 switch (rsp_type) {
2657 case RSP_TYPE_SAVE:
2658 if (!info)
2659 break;
2660 /* Sample count was incremented during reception above. */
2661 if (info->save_info.save_idx >= info->save_info.save_count) {
2662 ut181a_cond_stop_acquisition(sdi);
2663 break;
2664 }
2665 ret = ut181a_send_cmd_get_saved_value(serial, info->save_info.save_idx);
2666 if (ret < 0)
2667 ut181a_cond_stop_acquisition(sdi);
2668 break;
2669 case RSP_TYPE_REC_DATA:
2670 if (!info)
2671 break;
2672 /*
2673 * The sample count was incremented above during
2674 * reception, because of variable length chunks
2675 * of sample data.
2676 */
2677 if (info->rec_data.samples_curr >= info->rec_data.samples_total) {
2678 ut181a_cond_stop_acquisition(sdi);
2679 break;
2680 }
2681 ret = ut181a_send_cmd_get_rec_samples(serial,
2682 info->rec_data.rec_idx, info->rec_data.samples_curr);
2683 if (ret < 0)
2684 ut181a_cond_stop_acquisition(sdi);
2685 break;
2686 default:
2687 /* EMPTY */
2688 break;
2689 }
2690 }
2691
2692 return SR_OK;
2693}
2694
2695/* Process a previously received RX buffer. May find none or several packets. */
2696static int process_buffer(struct sr_dev_inst *sdi)
2697{
2698 struct dev_context *devc;
2699 uint8_t *pkt;
2700 uint16_t v16;
2701 size_t pkt_len, remain, idx;
2702 int ret;
2703
2704 devc = sdi->priv;
2705
2706 /*
2707 * Specifically do not insist on finding the packet boundary at
2708 * the edge of the most recently received data chunk. Serial ports
2709 * might involve hardware buffers (FIFO). We want to sync as fast
2710 * as possible.
2711 *
2712 * Handle the synchronized situation first. Process complete and
2713 * valid packets that reside at the start of the buffer. Continue
2714 * reception when partially valid data was received but does not
2715 * yet span a complete frame. Break out if data was received that
2716 * failed verification. Assume temporary failure and try to sync
2717 * to the input stream again.
2718 *
2719 * This logic is a little more complex than the typical DMM parser
2720 * because of the variable frame length of the UT181A protocol. A
2721 * frame always contains a magic (u16) and a length (u16), then a
2722 * number of bytes according to length. The frame ends there, the
2723 * checksum field is covered by the length value. packet processing
2724 * will verify the checksum.
2725 */
2726 pkt = &devc->recv_buff[0];
2727 do {
2728 /* Search for (the start of) a valid packet. */
2729 if (devc->recv_count < 2 * sizeof(uint16_t)) {
2730 /* Need more RX data for magic and length. */
2731 return SR_OK;
2732 }
2733 v16 = RL16(&pkt[0]);
2734 if (v16 != FRAME_MAGIC) {
2735 /* Not the expected magic marker. */
2736 if (FRAME_DUMP_CSUM) {
2737 FRAME_DUMP_CALL("Not a frame marker -> re-sync");
2738 }
2739 break;
2740 }
2741 v16 = RL16(&pkt[sizeof(uint16_t)]);
2742 if (v16 < sizeof(uint16_t)) {
2743 /* Insufficient length value, need at least checksum. */
2744 if (FRAME_DUMP_CSUM) {
2745 FRAME_DUMP_CALL("Too small a length -> re-sync");
2746 }
2747 break;
2748 }
2749 /* TODO Can we expect a maximum length value? */
2750 pkt_len = 2 * sizeof(uint16_t) + v16;
2751 if (pkt_len >= sizeof(devc->recv_buff)) {
2752 /* Frame will never fit in RX buffer. Invalid RX data? */
2753 if (FRAME_DUMP_CSUM) {
2754 FRAME_DUMP_CALL("Excessive length -> re-sync");
2755 }
2756 break;
2757 }
2758 if (pkt_len > devc->recv_count) {
2759 /* Need more RX data to complete the frame. */
2760 return SR_OK;
2761 }
2762
2763 /* Process the packet which completed reception. */
2764 if (FRAME_DUMP_CSUM && sr_log_loglevel_get() >= FRAME_DUMP_LEVEL) {
2765 GString *spew;
2766 spew = sr_hexdump_new(pkt, pkt_len);
2767 FRAME_DUMP_CALL("Found RX frame, %zu bytes: %s", pkt_len, spew->str);
2768 sr_hexdump_free(spew);
2769 }
2770 ret = process_packet(sdi, pkt, pkt_len);
2771 if (ret == SR_ERR_DATA) {
2772 /* Verification failed, might be invalid RX data. */
2773 if (FRAME_DUMP_CSUM) {
2774 FRAME_DUMP_CALL("RX frame processing failed -> re-sync");
2775 }
2776 break;
2777 }
2778 remain = devc->recv_count - pkt_len;
2779 if (remain)
2780 memmove(&pkt[0], &pkt[pkt_len], remain);
2781 devc->recv_count -= pkt_len;
2782 } while (1);
2783 if (devc->recv_count < 2 * sizeof(uint16_t)) {
2784 /* Assume incomplete reception. Re-check later. */
2785 return SR_OK;
2786 }
2787
2788 /*
2789 * Data was received but failed the test for a valid frame. Try to
2790 * synchronize to the next frame marker. Make sure to skip the
2791 * current position which might have been a marker yet the frame
2792 * check failed.
2793 */
2794 if (FRAME_DUMP_CSUM) {
2795 FRAME_DUMP_CALL("Trying to re-sync on RX frame");
2796 }
2797 for (idx = 1; idx < devc->recv_count; idx++) {
2798 if (devc->recv_count - idx < sizeof(uint16_t)) {
2799 /* Nothing found. Drop all but the last byte here. */
2800 pkt[0] = pkt[idx];
2801 devc->recv_count = 1;
2802 if (FRAME_DUMP_CSUM) {
2803 FRAME_DUMP_CALL("Dropping %zu bytes, still not in sync", idx);
2804 }
2805 return SR_OK;
2806 }
2807 v16 = RL16(&pkt[idx]);
2808 if (v16 != FRAME_MAGIC)
2809 continue;
2810 /*
2811 * Found a frame marker at offset 'idx'. Discard data
2812 * before the marker. Next receive starts another attempt
2813 * to interpret the frame, and may search the next marker
2814 * upon failure.
2815 */
2816 if (FRAME_DUMP_CSUM) {
2817 FRAME_DUMP_CALL("Dropping %zu bytes, next marker found", idx);
2818 }
2819 remain = devc->recv_count - idx;
2820 if (remain)
2821 memmove(&pkt[0], &pkt[idx], remain);
2822 devc->recv_count -= idx;
2823 break;
2824 }
2825
2826 return SR_OK;
2827}
2828
2829/* Gets invoked when RX data is available. */
2830static int ut181a_receive_data(struct sr_dev_inst *sdi)
2831{
2832 struct dev_context *devc;
2833 struct sr_serial_dev_inst *serial;
2834 size_t len;
2835 uint8_t *data;
2836 ssize_t slen;
2837 GString *spew;
2838
2839 devc = sdi->priv;
2840 serial = sdi->conn;
2841
2842 /*
2843 * Discard receive data when the buffer is exhausted. This shall
2844 * allow to (re-)synchronize to the data stream when we find it
2845 * in an arbitrary state. (Takes a while to exhaust the buffer.
2846 * Data is seriously unusable when we get here.)
2847 */
2848 if (devc->recv_count == sizeof(devc->recv_buff)) {
2849 if (FRAME_DUMP_RXDATA)
2850 FRAME_DUMP_CALL("Discarding RX buffer (space exhausted)");
2851 (void)process_packet(sdi, &devc->recv_buff[0], devc->recv_count);
2852 devc->recv_count = 0;
2853 }
2854
2855 /*
2856 * Drain more data from the serial port, and check the receive
2857 * buffer for packets. Process what was found to be complete.
2858 */
2859 len = sizeof(devc->recv_buff) - devc->recv_count;
2860 data = &devc->recv_buff[devc->recv_count];
2861 slen = serial_read_nonblocking(serial, data, len);
2862 if (slen < 0) {
2863 if (FRAME_DUMP_RXDATA)
2864 FRAME_DUMP_CALL("UART RX failed, rc %zd", slen);
2865 return 0;
2866 }
2867 len = slen;
2868 if (FRAME_DUMP_RXDATA && sr_log_loglevel_get() >= FRAME_DUMP_LEVEL) {
2869 spew = sr_hexdump_new(data, len);
2870 FRAME_DUMP_CALL("UART RX, %zu bytes: %s", len, spew->str);
2871 sr_hexdump_free(spew);
2872 }
2873 devc->recv_count += len;
2874 process_buffer(sdi);
2875
2876 return 0;
2877}
2878
2879SR_PRIV int ut181a_handle_events(int fd, int revents, void *cb_data)
2880{
2881 struct sr_dev_inst *sdi;
2882 struct sr_serial_dev_inst *serial;
3094e9d8
GS
2883 struct dev_context *devc;
2884
2885 (void)fd;
2886
ebc51109
GS
2887 sdi = cb_data;
2888 if (!sdi)
3094e9d8 2889 return TRUE;
ebc51109
GS
2890 serial = sdi->conn;
2891 if (!serial)
3094e9d8 2892 return TRUE;
ebc51109
GS
2893 devc = sdi->priv;
2894
2895 if (revents & G_IO_IN)
2896 (void)ut181a_receive_data(sdi);
3094e9d8 2897
ebc51109
GS
2898 if (sdi->status == SR_ST_STOPPING) {
2899 if (devc->data_source == DATA_SOURCE_LIVE) {
2900 sdi->status = SR_ST_INACTIVE;
2901 (void)ut181a_send_cmd_monitor(serial, FALSE);
2902 (void)ut181a_waitfor_response(sdi, 100);
2903 }
2904 serial_source_remove(sdi->session, serial);
2905 std_session_send_df_end(sdi);
3094e9d8
GS
2906 }
2907
2908 return TRUE;
2909}