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