]> sigrok.org Git - libsigrok.git/blame - src/dmm/eev121gw.c
Doxygen: Properly mark a few symbols as private.
[libsigrok.git] / src / dmm / eev121gw.c
CommitLineData
1c3098aa
GS
1/*
2 * This file is part of the libsigrok project.
3 *
4 * Copyright (C) 2018 Gerhard Sittig <gerhard.sittig@gmx.net>
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 2 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
20/**
21 * @file
22 *
23 * EEVblog 121GW 19-bytes binary protocol parser.
24 *
1c3098aa
GS
25 * Note that this protocol is different from other meters. We need not
26 * decode the LCD presentation (segments a-g and dot of seven segment
27 * displays). Neither need we decode a textual presentation consisting
28 * of number strings with decimals, and scale/quantity suffixes. Instead
29 * a binary packet is received which contains an unsigned mantissa for
30 * the value, and a number of boolean flags as well as bitfields for modes
31 * and ranges.
32 *
33 * But the protocol is also similar to the four-display variant of the
34 * metex14 protocol. A single DMM packet contains information for two
35 * displays and a bargraph, as well as several flags corresponding to
36 * display indicators and global device state. The vendor's documentation
37 * refers to these sections as "main", "sub", "bar", and "icon".
38 *
39 * It's essential to understand that the serial-dmm API is only able to
40 * communicate a single float value (including its precision and quantity
41 * details) in a single parse call. Which is why we keep a channel index
42 * in the 'info' structure, and run the parse routine several times upon
43 * reception of a single packet. This approach is shared with the metex14
44 * parser.
45 *
46 * The parse routine here differs from other DMM parsers which typically
47 * are split into routines which parse a value (get a number and exponent),
48 * parse flags, and handle flags which were parsed before. The 121GW
49 * meter's packets don't fit this separation naturally, getting the value
50 * and related flags heavily depends on which display shall get inspected,
51 * thus should be done at the same time. Filling in an 'info' structure
52 * from packet content first, and mapping this 'info' to the 'analog'
53 * details then still is very useful for maintainability.
54 *
55 * TODO:
56 * - The meter is feature packed. This implementation does support basic
57 * operation (voltage, current, power, resistance, continuity, diode,
58 * capacitance, temperature). Support for remaining modes, previously
59 * untested ranges, and advanced features (DC+AC, VA power, dB gain,
60 * burden voltage) may be missing or incomplete. Ranges support and
61 * value scaling should be considered "under development" in general
62 * until test coverage was increased. Some flags are not evaluated
63 * correctly yet, or not at all (min/max/avg, memory).
64 * - Test previously untested modes: current, power, gain, sub display
65 * modes. Test untested ranges (voltage above 30V, temperature above
66 * 30deg (into the hundreds), negative temperatures, large resistors,
67 * large capacitors). Test untested features (min/max/avg, 1ms peak,
68 * log memory).
69 * - It's assumed that a continuous data stream was arranged for. This
70 * implementation does not support the "packet request" API. Also I
71 * was to understand that once the request was sent (write 0300 to
72 * handle 9, after connecting) no further request is needed. Only
73 * the loss of communication may need recovery, which we leave as an
74 * option for later improvement, or as a feature of an external helper
75 * which feeds the COM port from Bluetooth communication data, or
76 * abstracts away the BLE communication.
77 *
78 * Implementation notes:
79 * - Yes some ranges seem duplicate but that's fine. The meter's packets
80 * do provide multiple range indices for some of the modes which do
81 * communicate values in the same range of values.
82 * - Some of the packet's bits don't match the available documentation.
83 * Some of the meter's features are not available to the PC side by
84 * means of inspecting packets.
85 * - Bit 5 of "bar value" was seen with value 1 in FREQ and OHM:
86 * f2 17 84 21 21 08 00 00 00 64 01 01 17 12 37 02 40 00 7d
87 * So we keep the test around but accept when it fails.
88 * - The "gotta beep" activity of continuity/break test mode is not
89 * available in the packets.
90 * - The interpretation of range indices depends on the specific mode
91 * (meter's function, and range when selectable by the user like mV).
92 * As does the precision of results.
93 */
94
95#include "config.h"
96#include <ctype.h>
97#include <glib.h>
98#include <math.h>
99#include <string.h>
100#include <strings.h>
101#include "libsigrok/libsigrok.h"
102#include "libsigrok-internal.h"
103
104#define LOG_PREFIX "eev121gw"
105
106/*
107 * TODO:
108 * When these bit field extraction helpers move to some common location,
109 * their names may need adjustment to reduce the potential for conflicts.
110 */
111// #define BIT(n) (1UL << (n))
112#define MASK(len) ((1UL << (len)) - 1)
113#define FIELD_PL(v, pos, len) (((v) >> (pos)) & MASK(len))
114#define FIELD_NL(v, name) FIELD_PL(v, POS_ ## name, LEN_ ## name)
115#define FIELD_NB(v, name) FIELD_PL(v, POS_ ## name, 1)
116
117/*
118 * Support compile time checks for expected sizeof() results etc, like
119 * STATIC_ASSERT(sizeof(struct packet) == 19, "packet size");
120 * Probably should go to some common location.
121 * See http://www.pixelbeat.org/programming/gcc/static_assert.html for details.
122 */
123#define ASSERT_CONCAT_(a, b) a ## b
124#define ASSERT_CONCAT(a, b) ASSERT_CONCAT_(a, b)
125/* These can't be used after statements in c89. */
126#ifdef __COUNTER__
127 #define STATIC_ASSERT(e, m) \
128 ; enum { ASSERT_CONCAT(static_assert_, __COUNTER__) = 1 / (int)(!!(e)) }
129#else
130 /*
131 * This can't be used twice on the same line so ensure if using in headers
132 * that the headers are not included twice (by wrapping in #ifndef...#endif).
133 * Note it doesn't cause an issue when used on same line of separate modules
134 * compiled with gcc -combine -fwhole-program.
135 */
136 #define STATIC_ASSERT(e, m) \
137 ; enum { ASSERT_CONCAT(assert_line_, __LINE__) = 1 / (int)(!!(e)) }
138#endif
139
140/*
141 * Symbolic identifiers for access to the packet's payload. "Offsets"
142 * address bytes within the packet. "Positions" specify the (lowest)
143 * bit number of a field, "lengths" specify the fields' number of bits.
144 * "Values" specify magic values or fixed content (SBZ, RSV, etc).
145 */
146enum eev121gw_packet_offs {
147 OFF_START_CMD,
148#define VAL_START_CMD 0xf2
149 OFF_SERIAL_3,
150 OFF_SERIAL_2,
151 OFF_SERIAL_1,
152 OFF_SERIAL_0,
153#define POS_SERIAL_YEAR 24
154#define LEN_SERIAL_YEAR 8
155#define POS_SERIAL_MONTH 20
156#define LEN_SERIAL_MONTH 4
157#define POS_SERIAL_NUMBER 0
158#define LEN_SERIAL_NUMBER 20
159 OFF_MAIN_MODE,
160#define POS_MAIN_MODE_VAL_U 6
161#define LEN_MAIN_MODE_VAL_U 2
162#define POS_MAIN_MODE_RSV_5 5
163#define POS_MAIN_MODE_MODE 0
164#define LEN_MAIN_MODE_MODE 5
165 OFF_MAIN_RANGE,
166#define POS_MAIN_RANGE_OFL 7
167#define POS_MAIN_RANGE_SIGN 6
168#define POS_MAIN_RANGE_DEGC 5
169#define POS_MAIN_RANGE_DEGF 4
170#define POS_MAIN_RANGE_RANGE 0
171#define LEN_MAIN_RANGE_RANGE 4
172 OFF_MAIN_VAL_H,
173 OFF_MAIN_VAL_L,
174 OFF_SUB_MODE,
175#define POS_SUB_MODE_MODE 0
176#define LEN_SUB_MODE_MODE 8
177 OFF_SUB_RANGE,
178#define POS_SUB_RANGE_OFL 7
179#define POS_SUB_RANGE_SIGN 6
180#define POS_SUB_RANGE_K 5
181#define POS_SUB_RANGE_HZ 4
182#define POS_SUB_RANGE_RSV_3 3
183#define POS_SUB_RANGE_POINT 0
184#define LEN_SUB_RANGE_POINT 3
185 OFF_SUB_VAL_H,
186 OFF_SUB_VAL_L,
187 OFF_BAR_STATUS,
188#define POS_BAR_STATUS_RSV_5 5
189#define LEN_BAR_STATUS_RSV_5 3
190#define POS_BAR_STATUS_USE 4
191#define POS_BAR_STATUS_150 3
192#define POS_BAR_STATUS_SIGN 2
193#define POS_BAR_STATUS_1K_500 0
194#define LEN_BAR_STATUS_1K_500 2
195 OFF_BAR_VALUE,
196#define POS_BAR_VALUE_RSV_6 6
197#define LEN_BAR_VALUE_RSV_6 2
198#define POS_BAR_VALUE_RSV_5 5
199#define POS_BAR_VALUE_VALUE 0
200#define LEN_BAR_VALUE_VALUE 5
201 OFF_ICON_STS_1,
202#define POS_ICON_STS1_DEGC 7
203#define POS_ICON_STS1_1KHZ 6
204#define POS_ICON_STS1_1MSPK 5
205#define POS_ICON_STS1_DCAC 3
206#define LEN_ICON_STS1_DCAC 2
207#define POS_ICON_STS1_AUTO 2
208#define POS_ICON_STS1_APO 1
209#define POS_ICON_STS1_BAT 0
210 OFF_ICON_STS_2,
211#define POS_ICON_STS2_DEGF 7
212#define POS_ICON_STS2_BT 6
213#define POS_ICON_STS2_UNK 5 /* TODO: What is this flag? 20mA loop current? */
214#define POS_ICON_STS2_REL 4
215#define POS_ICON_STS2_DBM 3
216#define POS_ICON_STS2_MINMAX 0 /* TODO: How to interpret the 3-bit field? */
217#define LEN_ICON_STS2_MINMAX 3
218 OFF_ICON_STS_3,
219#define POS_ICON_STS3_RSV_7 7
220#define POS_ICON_STS3_TEST 6
221#define POS_ICON_STS3_MEM 4 /* TODO: How to interpret the 2-bit field? */
222#define LEN_ICON_STS3_MEM 2
223#define POS_ICON_STS3_AHOLD 2
224#define LEN_ICON_STS3_AHOLD 2
225#define POS_ICON_STS3_AC 1
226#define POS_ICON_STS3_DC 0
227 OFF_CHECKSUM,
228 /* This is not an offset, but the packet's "byte count". */
229 PACKET_LAST_OFF,
230};
231
232STATIC_ASSERT(PACKET_LAST_OFF == EEV121GW_PACKET_SIZE,
233 "byte offsets vs packet length mismatch");
234
235enum mode_codes {
236 /* Modes for 'main' and 'sub' displays. */
237 MODE_LOW_Z = 0,
238 MODE_DC_V = 1,
239 MODE_AC_V = 2,
240 MODE_DC_MV = 3,
241 MODE_AC_MV = 4,
242 MODE_TEMP = 5,
243 MODE_FREQ = 6,
244 MODE_PERIOD = 7,
245 MODE_DUTY = 8,
246 MODE_RES = 9,
247 MODE_CONT = 10,
248 MODE_DIODE = 11,
249 MODE_CAP = 12,
250 MODE_AC_UVA = 13,
251 MODE_AC_MVA = 14,
252 MODE_AC_VA = 15,
253 MODE_AC_UA = 16,
254 MODE_DC_UA = 17,
255 MODE_AC_MA = 18,
256 MODE_DC_MA = 19,
257 MODE_AC_A = 20,
258 MODE_DC_A = 21,
259 MODE_DC_UVA = 22,
260 MODE_DC_MVA = 23,
261 MODE_DC_VA = 24,
262 /* More modes for 'sub' display. */
263 MODE_SUB_TEMPC = 100,
264 MODE_SUB_TEMPF = 105,
265 MODE_SUB_BATT = 110,
266 MODE_SUB_APO_ON = 120,
267 MODE_SUB_APO_OFF = 125,
268 MODE_SUB_YEAR = 130,
269 MODE_SUB_DATE = 135,
270 MODE_SUB_TIME = 140,
271 MODE_SUB_B_VOLT = 150,
272 MODE_SUB_LCD = 160,
273 MODE_SUB_CONT_PARM_0 = 170,
274 MODE_SUB_CONT_PARM_1 = 171,
275 MODE_SUB_CONT_PARM_2 = 172,
276 MODE_SUB_CONT_PARM_3 = 173,
277 MODE_SUB_DBM = 180,
278 MODE_SUB_IVAL = 190,
279};
280
281enum range_codes {
282 RANGE_0,
283 RANGE_1,
284 RANGE_2,
285 RANGE_3,
286 RANGE_4,
287 RANGE_5,
288 RANGE_6,
289 RANGE_MAX,
290};
291
292enum bar_range_codes {
293 BAR_RANGE_5,
294 BAR_RANGE_50,
295 BAR_RANGE_500,
296 BAR_RANGE_1000,
297};
298#define BAR_VALUE_MAX 25
299
300enum acdc_codes {
301 ACDC_NONE,
302 ACDC_DC,
303 ACDC_AC,
304 ACDC_ACDC,
305};
306
307SR_PRIV const char *eev121gw_channel_formats[EEV121GW_DISPLAY_COUNT] = {
308 /*
309 * TODO:
310 * The "main", "sub", "bar" names were taken from the packet
311 * description. Will users prefer "primary", "secondary", and
312 * "bargraph" names? Or even-length "pri", "sec", "bar" instead?
313 */
314 "main", "sub", "bar",
315};
316
317/*
318 * See page 69 in the 2018-09-24 manual for a table of modes and their
319 * respective ranges ("Calibration Reference Table"). This is the input
320 * to get the number of significant digits, and the decimal's position.
321 */
322struct mode_range_item {
323 const char *desc; /* Description, for diagnostics. */
324 int digits; /* Number of significant digits, see @ref sr_analog_encoding. */
325 int factor; /* Factor to convert the uint to a float. */
326};
327
328struct mode_range_items {
329 size_t range_count;
330 const struct mode_range_item ranges[RANGE_MAX];
331};
332
333static const struct mode_range_items mode_ranges_lowz = {
334 .range_count = 1,
335 .ranges = {
336 { .desc = "600.0V", .digits = 1, .factor = 1, },
337 },
338};
339
340static const struct mode_range_items mode_ranges_volts = {
341 .range_count = 4,
342 .ranges = {
343 { .desc = "5.0000V", .digits = 4, .factor = 4, },
344 { .desc = "50.000V", .digits = 3, .factor = 3, },
345 { .desc = "500.00V", .digits = 2, .factor = 2, },
346 { .desc = "600.0V", .digits = 1, .factor = 1, },
347 },
348};
349
350static const struct mode_range_items mode_ranges_millivolts = {
351 .range_count = 2,
352 .ranges = {
353 { .desc = "50.000mV", .digits = 6, .factor = 6, },
354 { .desc = "500.00mV", .digits = 5, .factor = 5, },
355 },
356};
357
358static const struct mode_range_items mode_ranges_temp = {
359 .range_count = 1,
360 .ranges = {
361 { .desc = "-200.0C ~ 1350.0C", .digits = 1, .factor = 1, },
362 },
363};
364
365static const struct mode_range_items mode_ranges_freq = {
366 .range_count = 5,
367 .ranges = {
368 { .desc = "99.999Hz", .digits = 3, .factor = 3, },
369 { .desc = "999.99Hz", .digits = 2, .factor = 2, },
370 { .desc = "9.9999kHz", .digits = 1, .factor = 1, },
371 { .desc = "99.999kHz", .digits = 0, .factor = 0, },
372 { .desc = "999.99kHz", .digits = -1, .factor = -1, },
373 },
374};
375
376static const struct mode_range_items mode_ranges_period = {
377 .range_count = 3,
378 .ranges = {
379 { .desc = "9.9999ms", .digits = 7, .factor = 7, },
380 { .desc = "99.999ms", .digits = 6, .factor = 6, },
381 { .desc = "999.99ms", .digits = 5, .factor = 5, },
382 },
383};
384
385static const struct mode_range_items mode_ranges_duty = {
386 .range_count = 1,
387 .ranges = {
388 { .desc = "99.9%", .digits = 1, .factor = 1, },
389 },
390};
391
392static const struct mode_range_items mode_ranges_res = {
393 .range_count = 7,
394 .ranges = {
395 { .desc = "50.000R", .digits = 3, .factor = 3, },
396 { .desc = "500.00R", .digits = 2, .factor = 2, },
397 { .desc = "5.0000k", .digits = 1, .factor = 1, },
398 { .desc = "50.000k", .digits = 0, .factor = 0, },
399 { .desc = "500.00k", .digits = -1, .factor = -1, },
400 { .desc = "5.0000M", .digits = -2, .factor = -2, },
401 { .desc = "50.000M", .digits = -3, .factor = -3, },
402 },
403};
404
405static const struct mode_range_items mode_ranges_cont = {
406 .range_count = 1,
407 .ranges = {
408 { .desc = "500.00R", .digits = 2, .factor = 2, },
409 },
410};
411
412static const struct mode_range_items mode_ranges_diode = {
413 .range_count = 2,
414 .ranges = {
415 { .desc = "3.0000V", .digits = 4, .factor = 4, },
416 { .desc = "15.000V", .digits = 3, .factor = 3, },
417 },
418};
419
420static const struct mode_range_items mode_ranges_cap = {
421 .range_count = 6,
422 .ranges = {
423 { .desc = "10.00n", .digits = 11, .factor = 11, },
424 { .desc = "100.0n", .digits = 10, .factor = 10, },
425 { .desc = "1.000u", .digits = 9, .factor = 9, },
426 { .desc = "10.00u", .digits = 8, .factor = 8, },
427 { .desc = "100.0u", .digits = 7, .factor = 7, },
428 { .desc = "10.00m", .digits = 5, .factor = 5, },
429 },
430};
431
432static const struct mode_range_items mode_ranges_pow_va = {
433 .range_count = 4,
434 .ranges = {
435 { .desc = "2500.0mVA", .digits = 4, .factor = 4, },
436 { .desc = "25000.mVA", .digits = 3, .factor = 3, },
437 { .desc = "25.000VA", .digits = 3, .factor = 3, },
438 { .desc = "500.00VA", .digits = 2, .factor = 2, },
439 },
440};
441
442static const struct mode_range_items mode_ranges_pow_mva = {
443 .range_count = 4,
444 .ranges = {
445 { .desc = "25.000mVA", .digits = 6, .factor = 6, },
446 { .desc = "250.00mVA", .digits = 5, .factor = 5, },
447 { .desc = "250.00mVA", .digits = 5, .factor = 5, },
448 { .desc = "2500.0mVA", .digits = 4, .factor = 4, },
449 },
450};
451
452static const struct mode_range_items mode_ranges_pow_uva = {
453 .range_count = 4,
454 .ranges = {
455 { .desc = "250.00uVA", .digits = 8, .factor = 8, },
456 { .desc = "2500.0uVA", .digits = 7, .factor = 7, },
457 { .desc = "2500.0uVA", .digits = 7, .factor = 7, },
458 { .desc = "25000.uVA", .digits = 6, .factor = 6, },
459 },
460};
461
462static const struct mode_range_items mode_ranges_curr_a = {
463 .range_count = 3,
464 .ranges = {
465 { .desc = "500.00mA", .digits = 5, .factor = 5, },
466 { .desc = "5.0000A", .digits = 4, .factor = 4, },
467 { .desc = "10.000A", .digits = 3, .factor = 3, },
468 },
469};
470
471static const struct mode_range_items mode_ranges_curr_ma = {
472 .range_count = 2,
473 .ranges = {
474 { .desc = "5.0000mA", .digits = 7, .factor = 7, },
475 { .desc = "50.000mA", .digits = 6, .factor = 6, },
476 },
477};
478
479static const struct mode_range_items mode_ranges_curr_ua = {
480 .range_count = 2,
481 .ranges = {
482 { .desc = "50.000uA", .digits = 9, .factor = 9, },
483 { .desc = "500.00uA", .digits = 8, .factor = 8, },
484 },
485};
486
487static const struct mode_range_items *mode_ranges_main[] = {
488 [MODE_LOW_Z] = &mode_ranges_lowz,
489 [MODE_DC_V] = &mode_ranges_volts,
490 [MODE_AC_V] = &mode_ranges_volts,
491 [MODE_DC_MV] = &mode_ranges_millivolts,
492 [MODE_AC_MV] = &mode_ranges_millivolts,
493 [MODE_TEMP] = &mode_ranges_temp,
494 [MODE_FREQ] = &mode_ranges_freq,
495 [MODE_PERIOD] = &mode_ranges_period,
496 [MODE_DUTY] = &mode_ranges_duty,
497 [MODE_RES] = &mode_ranges_res,
498 [MODE_CONT] = &mode_ranges_cont,
499 [MODE_DIODE] = &mode_ranges_diode,
500 [MODE_CAP] = &mode_ranges_cap,
501 [MODE_DC_VA] = &mode_ranges_pow_va,
502 [MODE_AC_VA] = &mode_ranges_pow_va,
503 [MODE_DC_MVA] = &mode_ranges_pow_mva,
504 [MODE_AC_MVA] = &mode_ranges_pow_mva,
505 [MODE_DC_UVA] = &mode_ranges_pow_uva,
506 [MODE_AC_UVA] = &mode_ranges_pow_uva,
507 [MODE_DC_A] = &mode_ranges_curr_a,
508 [MODE_AC_A] = &mode_ranges_curr_a,
509 [MODE_DC_MA] = &mode_ranges_curr_ma,
510 [MODE_AC_MA] = &mode_ranges_curr_ma,
511 [MODE_DC_UA] = &mode_ranges_curr_ua,
512 [MODE_AC_UA] = &mode_ranges_curr_ua,
513};
514
515/*
516 * The secondary display encodes SI units / scaling differently from the
517 * main display, and fewer ranges are available. So we share logic between
518 * displays for scaling, but have to keep separate tables for the displays.
519 */
520
521static const struct mode_range_items mode_ranges_temp_sub = {
522 .range_count = 2,
523 .ranges = {
72b6f1c0 524 [1] = { .desc = "100.0C", .digits = 1, .factor = 1, },
1c3098aa
GS
525 },
526};
527
528static const struct mode_range_items mode_ranges_freq_sub = {
529 .range_count = 4,
530 .ranges = {
72b6f1c0
GS
531 [1] = { .desc = "999.9Hz", .digits = 1, .factor = 1, },
532 [2] = { .desc = "99.99Hz", .digits = 2, .factor = 2, },
533 [3] = { .desc = "9.999kHz", .digits = 3, .factor = 3, },
1c3098aa
GS
534 },
535};
536
537static const struct mode_range_items mode_ranges_batt_sub = {
538 .range_count = 2,
539 .ranges = {
72b6f1c0 540 [1] = { .desc = "10.0V", .digits = 1, .factor = 1, },
1c3098aa
GS
541 },
542};
543
544static const struct mode_range_items mode_ranges_gain_sub = {
545 .range_count = 4,
546 .ranges = {
72b6f1c0
GS
547 [1] = { .desc = "5000.0dBm", .digits = 1, .factor = 1, },
548 [2] = { .desc = "500.00dBm", .digits = 2, .factor = 2, },
549 [3] = { .desc = "50.000dBm", .digits = 3, .factor = 3, },
1c3098aa
GS
550 },
551};
552
553static const struct mode_range_items mode_ranges_diode_sub = {
554 .range_count = 1,
555 .ranges = {
72b6f1c0 556 [0] = { .desc = "15.0V", .digits = 0, .factor = 0, },
1c3098aa
GS
557 },
558};
559
1c3098aa
GS
560static const struct mode_range_items mode_ranges_volts_sub = {
561 .range_count = 5,
562 .ranges = {
39ea7b7d 563 [3] = { .desc = "50.000V", .digits = 3, .factor = 3, },
1c3098aa
GS
564 [4] = { .desc = "5.0000V", .digits = 4, .factor = 4, },
565 },
566};
567
1c3098aa 568static const struct mode_range_items mode_ranges_mamps_sub = {
39ea7b7d 569 .range_count = 5,
1c3098aa
GS
570 .ranges = {
571 [2] = { .desc = "500.00mA", .digits = 5, .factor = 5, },
39ea7b7d
GS
572 [3] = { .desc = "50.000mA", .digits = 6, .factor = 6, },
573 [4] = { .desc = "5.0000mA", .digits = 7, .factor = 7, },
574 },
575};
576
577static const struct mode_range_items mode_ranges_uamps_sub = {
578 .range_count = 5,
579 .ranges = {
580 [4] = { .desc = "5.0000mA", .digits = 7, .factor = 7, },
1c3098aa
GS
581 },
582};
583
584static const struct mode_range_items *mode_ranges_sub[] = {
585 [MODE_DC_V] = &mode_ranges_volts_sub,
586 [MODE_AC_V] = &mode_ranges_volts_sub,
587 [MODE_DC_A] = &mode_ranges_mamps_sub,
588 [MODE_AC_A] = &mode_ranges_mamps_sub,
39ea7b7d
GS
589 [MODE_DC_MA] = &mode_ranges_mamps_sub,
590 [MODE_AC_MA] = &mode_ranges_mamps_sub,
591 [MODE_DC_UA] = &mode_ranges_uamps_sub,
592 [MODE_AC_UA] = &mode_ranges_uamps_sub,
1c3098aa
GS
593 [MODE_FREQ] = &mode_ranges_freq_sub,
594 [MODE_DIODE] = &mode_ranges_diode_sub,
595 [MODE_SUB_TEMPC] = &mode_ranges_temp_sub,
596 [MODE_SUB_TEMPF] = &mode_ranges_temp_sub,
597 [MODE_SUB_BATT] = &mode_ranges_batt_sub,
598 [MODE_SUB_DBM] = &mode_ranges_gain_sub,
599};
600
601static const struct mode_range_item *mode_range_get_scale(
602 enum eev121gw_display display,
603 enum mode_codes mode, enum range_codes range)
604{
605 const struct mode_range_items *items;
606 const struct mode_range_item *item;
607
608 if (display == EEV121GW_DISPLAY_MAIN) {
609 if (mode >= ARRAY_SIZE(mode_ranges_main))
610 return NULL;
611 items = mode_ranges_main[mode];
612 if (!items || !items->range_count)
613 return NULL;
614 if (range >= items->range_count)
615 return NULL;
616 item = &items->ranges[range];
617 return item;
618 }
619 if (display == EEV121GW_DISPLAY_SUB) {
620 if (mode >= ARRAY_SIZE(mode_ranges_sub))
621 return NULL;
622 items = mode_ranges_sub[mode];
623 if (!items || !items->range_count)
624 return NULL;
625 if (range >= items->range_count)
626 return NULL;
627 item = &items->ranges[range];
628 if (!item->desc || !*item->desc)
629 return NULL;
630 return item;
631 }
632
633 return NULL;
634}
635
636SR_PRIV gboolean sr_eev121gw_packet_valid(const uint8_t *buf)
637{
638 uint8_t csum;
639 size_t idx;
640
641 /* Leading byte, literal / fixed value. */
642 if (buf[OFF_START_CMD] != VAL_START_CMD)
643 return FALSE;
644
645 /* Check some always-zero bits in reserved locations. */
646 if (FIELD_NB(buf[OFF_MAIN_MODE], MAIN_MODE_RSV_5))
647 return FALSE;
648 if (FIELD_NB(buf[OFF_SUB_RANGE], SUB_RANGE_RSV_3))
649 return FALSE;
650 if (FIELD_NL(buf[OFF_BAR_STATUS], BAR_STATUS_RSV_5))
651 return FALSE;
652 if (FIELD_NL(buf[OFF_BAR_VALUE], BAR_VALUE_RSV_6))
653 return FALSE;
654 /* See TODO for bit 5 of "bar value" not always being 0. */
655 if (0 && FIELD_NB(buf[OFF_BAR_VALUE], BAR_VALUE_RSV_5))
656 return FALSE;
657 if (FIELD_NB(buf[OFF_ICON_STS_3], ICON_STS3_RSV_7))
658 return FALSE;
659
660 /* Checksum, XOR over all previous bytes. */
661 csum = 0x00;
662 for (idx = OFF_START_CMD; idx < OFF_CHECKSUM; idx++)
663 csum ^= buf[idx];
664 if (csum != buf[OFF_CHECKSUM]) {
665 /* Non-critical condition, almost expected to see invalid data. */
666 sr_spew("Packet csum: want %02x, got %02x.", csum, buf[OFF_CHECKSUM]);
667 return FALSE;
668 }
669
670 sr_spew("Packet valid.");
671
672 return TRUE;
673}
674
675/**
676 * Parse a protocol packet.
677 *
678 * @param[in] buf Buffer containing the protocol packet. Must not be NULL.
679 * @param[out] floatval Pointer to a float variable. That variable will be
680 * modified in-place depending on the protocol packet.
681 * Must not be NULL.
682 * @param[out] analog Pointer to a struct sr_datafeed_analog. The struct will
683 * be filled with data according to the protocol packet.
684 * Must not be NULL.
685 * @param[out] info Pointer to a struct eevblog_121gw_info. The struct will be
686 * filled with data according to the protocol packet.
687 * Must not be NULL.
688 *
689 * @return SR_OK upon success, SR_ERR upon failure. Upon errors, the
690 * 'analog' variable contents are undefined and should not be used.
691 */
8556703a 692static int sr_eev121gw_parse(const uint8_t *buf, float *floatval,
1c3098aa
GS
693 struct sr_datafeed_analog *analog, void *info)
694{
695 struct eev121gw_info *info_local;
696 enum eev121gw_display display;
697 const char *channel_name;
698 uint32_t raw_serial;
699 uint8_t raw_main_mode, raw_main_range;
700 uint16_t raw_main_value;
701 uint8_t raw_sub_mode, raw_sub_range;
702 uint16_t raw_sub_value;
703 uint8_t raw_bar_status, raw_bar_value;
704 uint8_t raw_icon_stat_1, raw_icon_stat_2, raw_icon_stat_3;
705 uint32_t uint_value;
706 enum mode_codes main_mode;
707 enum range_codes main_range;
708 enum mode_codes sub_mode;
709 enum range_codes sub_range;
710 const struct mode_range_item *scale;
711 gboolean is_dc, is_sign, use_sign;
712 gboolean is_k;
713 unsigned int cont_code;
714
715 info_local = info;
716 display = info_local->ch_idx;
717 channel_name = eev121gw_channel_formats[display];
718 memset(info_local, 0, sizeof(*info_local));
719 *floatval = 0.0f;
720
721 /*
722 * Get the packet's bytes into native C language typed variables.
723 * This keeps byte position references out of logic/calculations.
724 * The start command and CRC were verified before we get here.
725 */
726 raw_serial = RB32(&buf[OFF_SERIAL_3]);
727 raw_main_mode = R8(&buf[OFF_MAIN_MODE]);
728 raw_main_range = R8(&buf[OFF_MAIN_RANGE]);
729 raw_main_value = RB16(&buf[OFF_MAIN_VAL_H]);
730 raw_sub_mode = R8(&buf[OFF_SUB_MODE]);
731 raw_sub_range = R8(&buf[OFF_SUB_RANGE]);
732 raw_sub_value = RB16(&buf[OFF_SUB_VAL_H]);
733 raw_bar_status = R8(&buf[OFF_BAR_STATUS]);
734 raw_bar_value = R8(&buf[OFF_BAR_VALUE]);
735 raw_icon_stat_1 = R8(&buf[OFF_ICON_STS_1]);
736 raw_icon_stat_2 = R8(&buf[OFF_ICON_STS_2]);
737 raw_icon_stat_3 = R8(&buf[OFF_ICON_STS_3]);
738
739 /*
740 * Packets contain a YEAR-MONTH date spec. It's uncertain how
741 * this data relates to the device's production or the firmware
742 * version. It certainly is not the current date either. Only
743 * optionally log this information, it's consistent across all
744 * packets (won't change within a session), and will be noisy if
745 * always enabled.
746 *
747 * Packets also contain a user adjustable device identification
748 * number (see the SETUP options). This is motivated by support
749 * for multiple devices, but won't change here within a session.
750 * The user chose to communicate to one specific device when the
751 * session started, by means of the conn= spec.
752 *
753 * It was suggested that this 'serial' field might be used as an
754 * additional means to check for a packet's validity (or absence
755 * of communication errors). This remains as an option for future
756 * improvement.
757 */
758 if (0) {
759 unsigned int ser_year, ser_mon, ser_nr;
760
761 ser_year = FIELD_NL(raw_serial, SERIAL_YEAR);
762 ser_mon = FIELD_NL(raw_serial, SERIAL_MONTH);
763 ser_nr = FIELD_NL(raw_serial, SERIAL_NUMBER);
764 sr_spew("Packet: Y-M %x-%x, nr %x.", ser_year, ser_mon, ser_nr);
765 }
766
767 switch (display) {
768
769 case EEV121GW_DISPLAY_MAIN:
770 /*
771 * Get those fields which correspond to the main display.
772 * The value's mantissa has 18 bits. The sign is separate
773 * (and is not universally applicable, mode needs to get
774 * inspected). The range's scaling and precision also
775 * depend on the mode.
776 */
777 main_mode = FIELD_NL(raw_main_mode, MAIN_MODE_MODE);
778 main_range = FIELD_NL(raw_main_range, MAIN_RANGE_RANGE);
779 scale = mode_range_get_scale(EEV121GW_DISPLAY_MAIN,
780 main_mode, main_range);
781 if (!scale)
782 return SR_ERR_NA;
783 info_local->factor = scale->factor;
784 info_local->digits = scale->digits;
785
786 uint_value = raw_main_value;
787 uint_value |= FIELD_NL(raw_main_mode, MAIN_MODE_VAL_U) << 16;
788 info_local->uint_value = uint_value;
789 info_local->is_ofl = FIELD_NB(raw_main_range, MAIN_RANGE_OFL);
790
791 switch (main_mode) {
792 case MODE_LOW_Z:
793 is_dc = FALSE;
794 if (FIELD_NB(raw_icon_stat_3, ICON_STS3_DC))
795 is_dc = TRUE;
796 if (FIELD_NB(raw_icon_stat_3, ICON_STS3_AC))
797 is_dc = FALSE;
798 use_sign = is_dc;
799 break;
800 case MODE_DC_V:
801 case MODE_DC_MV:
802 case MODE_TEMP:
803 case MODE_DC_UVA:
804 case MODE_DC_MVA:
805 case MODE_DC_VA:
806 case MODE_DC_UA:
807 case MODE_DC_MA:
808 case MODE_DC_A:
809 use_sign = TRUE;
810 break;
811 default:
812 use_sign = FALSE;
813 break;
814 }
815 if (use_sign) {
816 is_sign = FIELD_NB(raw_main_range, MAIN_RANGE_SIGN);
817 info_local->is_neg = is_sign;
818 }
819
820 switch (main_mode) {
821 case MODE_LOW_Z:
822 info_local->is_voltage = TRUE;
823 /* TODO: Need to determine AC/DC here? */
824 info_local->is_volt = TRUE;
825 info_local->is_low_pass = TRUE;
826 break;
827 case MODE_DC_V:
828 info_local->is_voltage = TRUE;
829 info_local->is_dc = TRUE;
830 info_local->is_volt = TRUE;
831 break;
832 case MODE_AC_V:
833 info_local->is_voltage = TRUE;
834 info_local->is_volt = TRUE;
835 info_local->is_ac = TRUE;
836 break;
837 case MODE_DC_MV:
838 info_local->is_voltage = TRUE;
839 info_local->is_dc = TRUE;
840 info_local->is_volt = TRUE;
841 break;
842 case MODE_AC_MV:
843 info_local->is_voltage = TRUE;
844 info_local->is_volt = TRUE;
845 info_local->is_ac = TRUE;
846 break;
847 case MODE_TEMP:
848 info_local->is_temperature = TRUE;
849 if (FIELD_NB(raw_main_range, MAIN_RANGE_DEGC))
850 info_local->is_celsius = TRUE;
851 if (FIELD_NB(raw_main_range, MAIN_RANGE_DEGF))
852 info_local->is_fahrenheit = TRUE;
853 break;
854 case MODE_FREQ:
855 info_local->is_frequency = TRUE;
856 info_local->is_hertz = TRUE;
857 break;
858 case MODE_PERIOD:
859 info_local->is_period = TRUE;
860 info_local->is_seconds = TRUE;
861 break;
862 case MODE_DUTY:
863 info_local->is_duty_cycle = TRUE;
864 info_local->is_percent = TRUE;
865 break;
866 case MODE_RES:
867 info_local->is_resistance = TRUE;
868 info_local->is_ohm = TRUE;
869 break;
870 case MODE_CONT:
871 info_local->is_continuity = TRUE;
872 info_local->is_ohm = TRUE;
873 /*
874 * In continuity mode the packet provides the
875 * resistance in ohms (500R range), but seems to
876 * _not_ carry the "boolean" open/closed state
877 * which controls the beeper. Users can select
878 * whether to trigger at 30R or 300R, and whether
879 * to trigger on values below (continuity) or
880 * above (cable break) the limit, but we cannot
881 * tell what the currently used setting is. So
882 * we neither get the beeper's state, nor can we
883 * derive it from other information.
884 */
885 break;
886 case MODE_DIODE:
887 info_local->is_diode = TRUE;
888 info_local->is_dc = TRUE;
889 info_local->is_volt = TRUE;
890 break;
891 case MODE_CAP:
892 info_local->is_capacitance = TRUE;
893 info_local->is_farad = TRUE;
894 break;
895 case MODE_AC_UVA:
896 info_local->is_power = TRUE;
897 info_local->is_ac = TRUE;
898 info_local->is_volt_ampere = TRUE;
899 break;
900 case MODE_AC_MVA:
901 info_local->is_power = TRUE;
902 info_local->is_ac = TRUE;
903 info_local->is_volt_ampere = TRUE;
904 break;
905 case MODE_AC_VA:
906 info_local->is_power = TRUE;
907 info_local->is_ac = TRUE;
908 info_local->is_volt_ampere = TRUE;
909 break;
910 case MODE_AC_UA:
911 info_local->is_current = TRUE;
912 info_local->is_ac = TRUE;
913 info_local->is_ampere = TRUE;
914 break;
915 case MODE_DC_UA:
916 info_local->is_current = TRUE;
917 info_local->is_dc = TRUE;
918 info_local->is_ampere = TRUE;
919 break;
920 case MODE_AC_MA:
921 info_local->is_current = TRUE;
922 info_local->is_ac = TRUE;
923 info_local->is_ampere = TRUE;
924 break;
925 case MODE_DC_MA:
926 info_local->is_current = TRUE;
927 info_local->is_dc = TRUE;
928 info_local->is_ampere = TRUE;
929 break;
930 case MODE_AC_A:
931 info_local->is_current = TRUE;
932 info_local->is_ac = TRUE;
933 info_local->is_ampere = TRUE;
934 break;
935 case MODE_DC_A:
936 info_local->is_current = TRUE;
937 info_local->is_dc = TRUE;
938 info_local->is_ampere = TRUE;
939 break;
940 case MODE_DC_UVA:
941 info_local->is_power = TRUE;
942 info_local->is_dc = TRUE;
943 info_local->is_volt_ampere = TRUE;
944 break;
945 case MODE_DC_MVA:
946 info_local->is_power = TRUE;
947 info_local->is_dc = TRUE;
948 info_local->is_volt_ampere = TRUE;
949 break;
950 case MODE_DC_VA:
951 info_local->is_power = TRUE;
952 info_local->is_dc = TRUE;
953 info_local->is_volt_ampere = TRUE;
954 break;
955 /* Modes 100-199 only apply to the secondary display. */
956 default:
957 return SR_ERR_NA;
958 }
959
960 /*
961 * Inspect the "icons" section, since it is associated
962 * with the primary display and global device state.
963 */
964 if (FIELD_NB(raw_icon_stat_1, ICON_STS1_1KHZ))
965 info_local->is_low_pass = TRUE;
966 if (FIELD_NB(raw_icon_stat_1, ICON_STS1_1MSPK))
967 info_local->is_1ms_peak = TRUE;
968 switch (FIELD_NL(raw_icon_stat_1, ICON_STS1_DCAC)) {
969 case ACDC_ACDC:
970 info_local->is_ac = TRUE;
971 info_local->is_dc = TRUE;
972 break;
973 case ACDC_AC:
974 info_local->is_ac = TRUE;
975 break;
976 case ACDC_DC:
977 info_local->is_dc = TRUE;
978 break;
979 case ACDC_NONE:
980 /* EMPTY */
981 break;
982 }
983 if (FIELD_NB(raw_icon_stat_1, ICON_STS1_AUTO))
984 info_local->is_auto_range = TRUE;
985 if (FIELD_NB(raw_icon_stat_1, ICON_STS1_APO))
986 info_local->is_auto_poweroff = TRUE;
987 if (FIELD_NB(raw_icon_stat_1, ICON_STS1_BAT))
988 info_local->is_low_batt = TRUE;
989 if (FIELD_NB(raw_icon_stat_2, ICON_STS2_BT))
990 info_local->is_bt = TRUE;
991 /* TODO: Is this the "20mA loop current" flag? */
992 if (FIELD_NB(raw_icon_stat_2, ICON_STS2_UNK))
993 info_local->is_loop_current = TRUE;
994 if (FIELD_NB(raw_icon_stat_2, ICON_STS2_REL))
995 info_local->is_rel = TRUE;
996 /* dBm only applies to secondary display, not main. */
997 switch (FIELD_NL(raw_icon_stat_2, ICON_STS2_MINMAX)) {
998 /* TODO: Do inspect the min/max/avg flags. */
999 default:
1000 /* EMPTY */
1001 break;
1002 }
1003 if (FIELD_NB(raw_icon_stat_3, ICON_STS3_TEST))
1004 info_local->is_test = TRUE;
1005 /* TODO: How to interpret the 2-bit MEM field? */
1006 if (FIELD_NL(raw_icon_stat_3, ICON_STS3_MEM))
1007 info_local->is_mem = TRUE;
1008 if (FIELD_NL(raw_icon_stat_3, ICON_STS3_AHOLD))
1009 info_local->is_hold = TRUE;
1010 /* TODO: Are these for the secondary display? See status-2 ACDC. */
1011 if (FIELD_NB(raw_icon_stat_3, ICON_STS3_AC))
1012 info_local->is_ac = TRUE;
1013 if (FIELD_NB(raw_icon_stat_3, ICON_STS3_DC))
1014 info_local->is_dc = TRUE;
1015
1016 sr_spew("Disp '%s', value: %lu (ov %d, neg %d), mode %d, range %d.",
1017 channel_name,
1018 (unsigned long)info_local->uint_value,
1019 info_local->is_ofl, info_local->is_neg,
1020 (int)main_mode, (int)main_range);
1021 /* Advance to the number and units conversion below. */
1022 break;
1023
1024 case EEV121GW_DISPLAY_SUB:
1025 /*
1026 * Get those fields which correspond to the secondary
1027 * display. The value's mantissa has 16 bits. The sign
6f7e1509 1028 * is separate and only applies to some of the modes.
1c3098aa
GS
1029 * Scaling and precision also depend on the mode. The
1030 * interpretation of the secondary display is different
1031 * from the main display: The 'range' is not an index
1032 * into ranges, instead it's the decimal's position.
1033 * Yet more scaling depends on the mode, to complicate
1034 * matters. The secondary display uses modes 100-199,
1035 * and some of the 0-24 modes as well.
1036 */
1037 sub_mode = FIELD_NL(raw_sub_mode, SUB_MODE_MODE);
1038 sub_range = FIELD_NL(raw_sub_range, SUB_RANGE_POINT);
1039 scale = mode_range_get_scale(EEV121GW_DISPLAY_SUB,
1040 sub_mode, sub_range);
1041 if (!scale)
1042 return SR_ERR_NA;
1043 info_local->factor = scale->factor;
1044 info_local->digits = scale->digits;
1045
1046 info_local->uint_value = raw_sub_value;
1047 info_local->is_ofl = FIELD_NB(raw_sub_range, SUB_RANGE_OFL);
1048
1049 switch (sub_mode) {
1050 case MODE_DC_V:
1051 case MODE_AC_V:
1052 case MODE_DC_A:
1053 case MODE_AC_A:
1054 case MODE_SUB_TEMPC:
1055 case MODE_SUB_TEMPF:
1056 case MODE_SUB_B_VOLT:
1057 case MODE_SUB_DBM:
1058 use_sign = TRUE;
1059 break;
1060 default:
1061 use_sign = FALSE;
1062 break;
1063 }
1064 if (use_sign) {
1065 is_sign = FIELD_NB(raw_sub_range, SUB_RANGE_SIGN);
1066 info_local->is_neg = is_sign;
1067 }
1068 is_k = FIELD_NB(raw_sub_range, SUB_RANGE_K);
1069
1c3098aa
GS
1070 switch (sub_mode) {
1071 case MODE_DC_V:
1072 info_local->is_voltage = TRUE;
1073 info_local->is_volt = TRUE;
1074 break;
1075 case MODE_DC_A:
1076 info_local->is_current = TRUE;
1077 info_local->is_ampere = TRUE;
1078 break;
1079 case MODE_FREQ:
1080 info_local->is_frequency = TRUE;
1081 info_local->is_hertz = TRUE;
1082 if (is_k) {
1083 info_local->factor -= 3;
1084 info_local->digits -= 3;
1085 }
1086 info_local->is_ofl = FALSE;
1087 break;
1088 case MODE_SUB_TEMPC:
1089 info_local->is_temperature = TRUE;
1090 info_local->is_celsius = TRUE;
1091 break;
1092 case MODE_SUB_TEMPF:
1093 info_local->is_temperature = TRUE;
1094 info_local->is_fahrenheit = TRUE;
1095 break;
1096 case MODE_SUB_BATT:
1097 /* TODO: How to communicate it's the *battery* voltage? */
1098 info_local->is_voltage = TRUE;
1099 info_local->is_volt = TRUE;
1100 break;
1101 case MODE_SUB_DBM:
1102 info_local->is_gain = TRUE;
1103 info_local->is_dbm = TRUE;
1104 break;
1105 case MODE_SUB_CONT_PARM_0:
1106 case MODE_SUB_CONT_PARM_1:
1107 case MODE_SUB_CONT_PARM_2:
1108 case MODE_SUB_CONT_PARM_3:
1109 /*
1110 * These "continuity parameters" are special. The
1111 * least significant bits represent the options:
1112 *
1113 * 0xaa = 170 => down 30
1114 * 0xab = 171 => up 30
1115 * 0xac = 172 => down 300
1116 * 0xad = 173 => up 300
1117 *
1118 * bit 0 value 0 -> close (cont)
1119 * bit 0 value 1 -> open (break)
1120 * bit 1 value 0 -> 30R limit
1121 * bit 1 value 1 -> 300R limit
1122 *
1123 * This "display value" is only seen during setup
1124 * but not during regular operation of continuity
1125 * mode. :( In theory we could somehow pass the
1126 * 30/300 ohm limit to sigrok, but that'd be of
1127 * somewhat limited use.
1128 */
1129 cont_code = sub_mode - MODE_SUB_CONT_PARM_0;
1130 info_local->is_resistance = TRUE;
1131 info_local->is_ohm = TRUE;
1132 info_local->uint_value = (cont_code & 0x02) ? 300 : 30;
1133 info_local->is_neg = FALSE;
1134 info_local->is_ofl = FALSE;
1135 info_local->factor = 0;
1136 info_local->digits = 0;
1137 break;
1138 case MODE_DIODE:
1139 /* Displays configured diode test voltage. */
1140 info_local->is_voltage = TRUE;
1141 info_local->is_volt = TRUE;
1142 break;
1143
1144 /* Reflecting these to users seems pointless, ignore them. */
1145 case MODE_SUB_APO_ON:
1146 case MODE_SUB_APO_OFF:
1147 case MODE_SUB_LCD:
1148 case MODE_SUB_YEAR:
1149 case MODE_SUB_DATE:
1150 case MODE_SUB_TIME:
1151 return SR_ERR_NA;
1152
1153 /* Unknown / unsupported sub display mode. */
1154 default:
1155 return SR_ERR_NA;
1156 }
1157
1158 sr_spew("disp '%s', value: %lu (ov %d, neg %d), mode %d, range %d",
1159 channel_name,
1160 (unsigned long)info_local->uint_value,
1161 info_local->is_ofl, info_local->is_neg,
1162 (int)sub_mode, (int)sub_range);
1163 /* Advance to the number and units conversion below. */
1164 break;
1165
1166 case EEV121GW_DISPLAY_BAR:
1167 /*
1168 * Get those fields which correspond to the bargraph.
1169 * There are 26 segments (ticks 0-25), several ranges
1170 * apply (up to 5, or up to 10, several decades). The
1171 * bargraph does not apply to all modes and ranges,
1172 * hence there is a "use" flag (negative logic, blank
1173 * signal). Bit 5 was also found to have undocumented
1174 * values, we refuse to use the bargraph value then.
1175 */
1176 if (FIELD_NB(raw_bar_status, BAR_STATUS_USE))
1177 return SR_ERR_NA;
1178 if (FIELD_NB(raw_bar_value, BAR_VALUE_RSV_5))
1179 return SR_ERR_NA;
1180 uint_value = FIELD_NL(raw_bar_value, BAR_VALUE_VALUE);
1181 if (uint_value > BAR_VALUE_MAX)
1182 uint_value = BAR_VALUE_MAX;
1183 info_local->is_neg = FIELD_NB(raw_bar_status, BAR_STATUS_SIGN);
1184 switch (FIELD_NL(raw_bar_status, BAR_STATUS_1K_500)) {
1185 case BAR_RANGE_5:
1186 /* Full range 5.0, in steps of 0.2 each. */
1187 uint_value *= 5000 / BAR_VALUE_MAX;
1188 info_local->factor = 3;
1189 info_local->digits = 1;
1190 break;
1191 case BAR_RANGE_50:
1192 /* Full range 50, in steps of 2 each. */
1193 uint_value *= 50 / BAR_VALUE_MAX;
1194 info_local->factor = 0;
1195 info_local->digits = 0;
1196 break;
1197 case BAR_RANGE_500:
1198 /* Full range 500, in steps of 20 each. */
1199 uint_value *= 500 / BAR_VALUE_MAX;
1200 info_local->factor = 0;
1201 info_local->digits = -1;
1202 break;
1203 case BAR_RANGE_1000:
1204 /* Full range 1000, in steps of 40 each. */
1205 uint_value *= 1000 / BAR_VALUE_MAX;
1206 info_local->factor = 0;
1207 info_local->digits = -1;
1208 break;
1209 default:
1210 return SR_ERR_NA;
1211 }
1212 info_local->uint_value = uint_value;
1213 info_local->is_unitless = TRUE;
1214 sr_spew("Disp '%s', value: %u.", channel_name,
1215 (unsigned int)info_local->uint_value);
1216 /* Advance to the number and units conversion below. */
1217 break;
1218
1219 default:
1220 /* Unknown display, programmer's error, ShouldNotHappen(TM). */
1221 sr_err("Disp '-?-'.");
1222 return SR_ERR_ARG;
1223 }
1224
1225 /*
1226 * Convert the unsigned mantissa and its modifiers to a float
1227 * analog value, including scale and quantity. Do the conversion
1228 * first, and optionally override the result with 'inf' later.
1229 * Apply the sign last so that +inf and -inf are supported.
1230 */
1231 *floatval = info_local->uint_value;
1232 if (info_local->factor)
1233 *floatval *= powf(10, -info_local->factor);
1234 if (info_local->is_ofl)
1235 *floatval = INFINITY;
1236 if (info_local->is_neg)
1237 *floatval = -*floatval;
1238
1239 analog->encoding->digits = info_local->digits;
1240 analog->spec->spec_digits = info_local->digits;
1241
1242 /*
1243 * Communicate the measured quantity.
1244 */
1245 /* Determine the quantity itself. */
1246 if (info_local->is_voltage)
1247 analog->meaning->mq = SR_MQ_VOLTAGE;
1248 if (info_local->is_current)
1249 analog->meaning->mq = SR_MQ_CURRENT;
1250 if (info_local->is_power)
1251 analog->meaning->mq = SR_MQ_POWER;
1252 if (info_local->is_gain)
1253 analog->meaning->mq = SR_MQ_GAIN;
1254 if (info_local->is_resistance)
1255 analog->meaning->mq = SR_MQ_RESISTANCE;
1256 if (info_local->is_capacitance)
1257 analog->meaning->mq = SR_MQ_CAPACITANCE;
1258 if (info_local->is_diode)
1259 analog->meaning->mq = SR_MQ_VOLTAGE;
1260 if (info_local->is_temperature)
1261 analog->meaning->mq = SR_MQ_TEMPERATURE;
1262 if (info_local->is_continuity)
1263 analog->meaning->mq = SR_MQ_CONTINUITY;
1264 if (info_local->is_frequency)
1265 analog->meaning->mq = SR_MQ_FREQUENCY;
1266 if (info_local->is_period)
1267 analog->meaning->mq = SR_MQ_TIME;
1268 if (info_local->is_duty_cycle)
1269 analog->meaning->mq = SR_MQ_DUTY_CYCLE;
1270 if (info_local->is_unitless)
1271 analog->meaning->mq = SR_MQ_COUNT;
1272 /* Add AC / DC / DC+AC flags. */
1273 if (info_local->is_ac)
1274 analog->meaning->mqflags |= SR_MQFLAG_AC;
1275 if (info_local->is_dc)
1276 analog->meaning->mqflags |= SR_MQFLAG_DC;
1277 /* Specify units. */
1278 if (info_local->is_ampere)
1279 analog->meaning->unit = SR_UNIT_AMPERE;
1280 if (info_local->is_volt)
1281 analog->meaning->unit = SR_UNIT_VOLT;
1282 if (info_local->is_volt_ampere)
1283 analog->meaning->unit = SR_UNIT_VOLT_AMPERE;
1284 if (info_local->is_dbm)
1285 analog->meaning->unit = SR_UNIT_DECIBEL_VOLT;
1286 if (info_local->is_ohm)
1287 analog->meaning->unit = SR_UNIT_OHM;
1288 if (info_local->is_farad)
1289 analog->meaning->unit = SR_UNIT_FARAD;
1290 if (info_local->is_celsius)
1291 analog->meaning->unit = SR_UNIT_CELSIUS;
1292 if (info_local->is_fahrenheit)
1293 analog->meaning->unit = SR_UNIT_FAHRENHEIT;
1294 if (info_local->is_hertz)
1295 analog->meaning->unit = SR_UNIT_HERTZ;
1296 if (info_local->is_seconds)
1297 analog->meaning->unit = SR_UNIT_SECOND;
1298 if (info_local->is_percent)
1299 analog->meaning->unit = SR_UNIT_PERCENTAGE;
1300 if (info_local->is_loop_current)
1301 analog->meaning->unit = SR_UNIT_PERCENTAGE;
1302 if (info_local->is_unitless)
1303 analog->meaning->unit = SR_UNIT_UNITLESS;
1304 if (info_local->is_logic)
1305 analog->meaning->unit = SR_UNIT_UNITLESS;
1306 /* Add other indicator flags. */
1307 if (info_local->is_diode) {
1308 analog->meaning->mqflags |= SR_MQFLAG_DIODE;
1309 analog->meaning->mqflags |= SR_MQFLAG_DC;
1310 }
1311 if (info_local->is_min)
1312 analog->meaning->mqflags |= SR_MQFLAG_MIN;
1313 if (info_local->is_max)
1314 analog->meaning->mqflags |= SR_MQFLAG_MAX;
1315 if (info_local->is_avg)
1316 analog->meaning->mqflags |= SR_MQFLAG_AVG;
1317 /* TODO: How to communicate info_local->is_1ms_peak? */
1318 if (info_local->is_rel)
1319 analog->meaning->mqflags |= SR_MQFLAG_RELATIVE;
1320 if (info_local->is_hold)
1321 analog->meaning->mqflags |= SR_MQFLAG_HOLD;
1322 /* TODO: How to communicate info_local->is_low_pass? */
1323 if (info_local->is_mem) /* XXX Is REF appropriate here? */
1324 analog->meaning->mqflags |= SR_MQFLAG_REFERENCE;
1325 if (info_local->is_auto_range)
1326 analog->meaning->mqflags |= SR_MQFLAG_AUTORANGE;
1327 /* TODO: How to communicate info->is_test? What's its meaning at all? */
1328 /* TODO: How to communicate info->is_auto_poweroff? */
1329 /* TODO: How to communicate info->is_low_batt? */
1330
1331 return SR_OK;
1332}
1333
1334/*
1335 * Parse the same packet multiple times, to extract individual analog
1336 * values which correspond to several displays of the device. Make sure
1337 * to keep the channel index in place, even if the parse routine will
1338 * clear the info structure.
1339 */
1340SR_PRIV int sr_eev121gw_3displays_parse(const uint8_t *buf, float *floatval,
1341 struct sr_datafeed_analog *analog, void *info)
1342{
1343 struct eev121gw_info *info_local;
1344 size_t ch_idx;
1345 int rc;
1346
1347 info_local = info;
1348 ch_idx = info_local->ch_idx;
1349 rc = sr_eev121gw_parse(buf, floatval, analog, info);
1350 info_local->ch_idx = ch_idx + 1;
1351
1352 return rc;
1353}