]> sigrok.org Git - libsigrok.git/blob - src/dmm/bm52x.c
dmm/bm52x: unbreak build when serial comm is not available
[libsigrok.git] / src / dmm / bm52x.c
1 /*
2  * This file is part of the libsigrok project.
3  *
4  * Copyright (C) 2014 Aurelien Jacobs <aurel@gnuage.org>
5  * Copyright (C) 2019-2020 Gerhard Sittig <gerhard.sittig@gmx.net>
6  *
7  * This program is free software: you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation, either version 3 of the License, or
10  * (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
19  */
20
21 /**
22  * @file
23  *
24  * Brymen BM52x serial protocol parser. The USB protocol (for the cable)
25  * and the packet description (for the meter) were retrieved from:
26  * http://brymen.com/product-html/Download2.html
27  * http://brymen.com/product-html/PD02BM520s_protocolDL.html
28  * http://brymen.com/product-html/images/DownloadList/ProtocolList/BM520-BM520s_List/BM520-BM520s-10000-count-professional-dual-display-mobile-logging-DMMs-protocol.zip
29  *
30  * This parser was initially created for BM520s devices and tested with
31  * BM525s. The Brymen BM820s family of devices uses the same protocol,
32  * with just 0x82 instead of 0x52 in request packets and in the fixed
33  * fields of the responses. Which means that the packet parser can get
34  * shared among the BM520s and BM820s devices, but validity check needs
35  * to be individual, and the "wrong" packet request will end up without
36  * a response. Compared to BM520s the BM820s has dBm (in the protocol)
37  * and NCV (not seen in the protocol) and is non-logging (live only).
38  * BM820s support was tested with BM829s.
39  *
40  * The parser implementation was tested with a Brymen BM525s meter. Some
41  * of the responses differ from the vendor's documentation:
42  * - Recording session total byte counts don't start after the byte count
43  *   field, but instead include this field and the model ID (spans _every_
44  *   byte in the stream).
45  * - Recording session start/end markers are referred to as DLE, STX,
46  *   and ETX. Observed traffic instead sends 0xee, 0xa0, and 0xc0.
47  */
48
49 /*
50  * TODO
51  * - Some of the meter's functions and indications cannot get expressed
52  *   by means of sigrok MQ and flags terms. Some indicator's meaning is
53  *   unknown or uncertain, and thus their state is not evaluated.
54  *   - MAX-MIN, the span between extreme values, referred to as Vp-p.
55  *   - AVG is not available in BM525s and BM521s.
56  *   - LoZ, eliminating ghost voltages.
57  *   - LPF, low pass filter.
58  *   - low battery, emits sr_warn() but isn't seen in the feed.
59  *   - @, 4-20mA loop, % (main display, left hand side), Hi/Lo. Some of
60  *     these are in the vendor's documentation for the DMM packet but not
61  *     supported by the BM525s device which motivated the creation of the
62  *     parser's and was used to test its operation.
63  *   - It's a guess that the many undocumented bits (44 of them) are
64  *     related to the bargraph (40 ticks, overflow, sign, 6/10 scale).
65  *   - Should T1-T2 have a delta ("relative") decoration? But the meter's
66  *     "relative" feature is flexible, accepts any display value as the
67  *     reference, including min/max/diff when displayed upon activation.
68  *   - The "beep jack" displays "InEr" in the secondary display. This is
69  *     not caught here, no PC side message gets emitted.
70  * - Support for recordings is mostly untested. It was written to the
71  *   letter of the vendor documentation, but was not verified to work
72  *   for all of the many meter's modes including ranges. Inspection of
73  *   the full byte stream is necessary on one hand since random access
74  *   is not available, and useful on the other hand for consistency
75  *   checks.
76  */
77
78 #include <config.h>
79 #include <libsigrok/libsigrok.h>
80 #include "libsigrok-internal.h"
81 #include <math.h>
82 #include <string.h>
83 #include <strings.h>
84
85 #define LOG_PREFIX "brymen-bm52x"
86
87 /*
88  * DMM specific device options, and state keeping. All of it is related
89  * to recorded information in contrast to live readings. There also are
90  * four types of requesting HID reports that need to be sent.
91  */
92
93 static const uint32_t devopts[] = {
94         SR_CONF_CONTINUOUS,
95         SR_CONF_LIMIT_SAMPLES | SR_CONF_SET,
96         SR_CONF_LIMIT_MSEC | SR_CONF_SET,
97         SR_CONF_DATA_SOURCE | SR_CONF_GET | SR_CONF_SET | SR_CONF_LIST,
98 };
99
100 struct brymen_bm52x_state {
101         size_t sess_idx;
102         struct {
103                 uint8_t buff[2 * 32];
104                 size_t fill_pos;
105                 size_t read_pos;
106                 size_t remain;
107         } rsp;
108         const struct sr_dev_inst *sdi;
109 };
110
111 enum bm52x_reqtype {
112         REQ_LIVE_READ_520,
113         REQ_LIVE_READ_820,
114         REQ_REC_HEAD,
115         REQ_REC_NEXT,
116         REQ_REC_CURR,
117 };
118
119 #ifdef HAVE_SERIAL_COMM
120 static int bm52x_send_req(struct sr_serial_dev_inst *serial, enum bm52x_reqtype t)
121 {
122         static const uint8_t req_live_520[] = { 0x00, 0x00, 0x52, 0x66, };
123         static const uint8_t req_live_820[] = { 0x00, 0x00, 0x82, 0x66, };
124         static const uint8_t req_head[] = { 0x00, 0x00, 0x52, 0x88, };
125         static const uint8_t req_next[] = { 0x00, 0x00, 0x52, 0x89, };
126         static const uint8_t req_curr[] = { 0x00, 0x00, 0x52, 0x8a, };
127         static const uint8_t *req_bytes[] = {
128                 [REQ_LIVE_READ_520] = req_live_520,
129                 [REQ_LIVE_READ_820] = req_live_820,
130                 [REQ_REC_HEAD] = req_head,
131                 [REQ_REC_NEXT] = req_next,
132                 [REQ_REC_CURR] = req_curr,
133         };
134         static const size_t req_len = ARRAY_SIZE(req_live_520);
135
136         const uint8_t *p;
137         size_t l;
138         int ret;
139
140         if (t >= ARRAY_SIZE(req_bytes))
141                 return SR_ERR_ARG;
142         p = req_bytes[t];
143         l = req_len;
144         ret = serial_write_nonblocking(serial, p, l);
145         if (ret < 0)
146                 return ret;
147         if ((size_t)ret != l)
148                 return SR_ERR_IO;
149
150         return SR_OK;
151 }
152
153 SR_PRIV int sr_brymen_bm52x_packet_request(struct sr_serial_dev_inst *serial)
154 {
155         return bm52x_send_req(serial, REQ_LIVE_READ_520);
156 }
157
158 SR_PRIV int sr_brymen_bm82x_packet_request(struct sr_serial_dev_inst *serial)
159 {
160         return bm52x_send_req(serial, REQ_LIVE_READ_820);
161 }
162 #endif
163
164 /*
165  * The following code interprets live readings ("real-time download")
166  * which arrive in the "traditional" bitmap for LCD segments. Reading
167  * previously recorded measurements ("memory data sets") differs a lot
168  * and is handled in other code paths.
169  */
170
171 SR_PRIV gboolean sr_brymen_bm52x_packet_valid(const uint8_t *buf)
172 {
173         if (buf[16] != 0x52)
174                 return FALSE;
175         if (buf[17] != 0x52)
176                 return FALSE;
177         if (buf[18] != 0x52)
178                 return FALSE;
179         if (buf[19] != 0x52)
180                 return FALSE;
181
182         return TRUE;
183 }
184
185 SR_PRIV gboolean sr_brymen_bm82x_packet_valid(const uint8_t *buf)
186 {
187         if (buf[16] != 0x82)
188                 return FALSE;
189         if (buf[17] != 0x82)
190                 return FALSE;
191         if (buf[18] != 0x82)
192                 return FALSE;
193         if (buf[19] != 0x82)
194                 return FALSE;
195
196         return TRUE;
197 }
198
199 /*
200  * Data bytes in the DMM packet encode LCD segments in an unusual order
201  * (bgcpafed) and in an unusual position (bit 4 being the decimal point
202  * for some digits, an additional indicator for others). Fortunately all
203  * eight digits encode their segments in identical ways across the bytes.
204  *
205  * These routines convert LCD segments to characters, and a section of the
206  * DMM packet (which corresponds to the primary or secondary display) to
207  * the text representation of the measurement's value, before regular text
208  * to number conversion is applied, and SI units and their prefixes get
209  * derived from more indicators. It's important to keep in mind similar
210  * indicators exist for main and secondary displays in different locations.
211  */
212
213 static char brymen_bm52x_parse_digit(uint8_t b)
214 {
215         switch (b & ~0x10) {
216         /* Sign. */
217         case 0x40: /* ------g */ return '-';
218         /* Decimal digits. */
219         case 0xaf: /* abcdef- */ return '0';
220         case 0xa0: /* -bc---- */ return '1';
221         case 0xcb: /* ab-de-g */ return '2';
222         case 0xe9: /* abcd--g */ return '3';
223         case 0xe4: /* -bc--fg */ return '4';
224         case 0x6d: /* a-cd-fg */ return '5';
225         case 0x6f: /* a-cdefg */ return '6';
226         case 0xa8: /* abc---- */ return '7';
227         case 0xef: /* abcdefg */ return '8';
228         case 0xed: /* abcd-fg */ return '9';
229         /* Temperature units. */
230         case 0x0f: /* a--def- */ return 'C';
231         case 0x4e: /* a---efg */ return 'F';
232         /* OL condition, and diode and "Auto" modes. */
233         case 0x07: /* ---def- */ return 'L';
234         case 0xe3: /* -bcde-g */ return 'd';
235         case 0x20: /* --c---- */ return 'i';
236         case 0x63: /* --cde-g */ return 'o';
237         case 0xee: /* abc-efg */ return 'A';
238         case 0x23: /* --cde-- */ return 'u';
239         case 0x47: /* ---defg */ return 't';
240         /* Blank digit. */
241         case 0x00: /* ------- */ return '\0';
242         /* Invalid or unknown segment combination. */
243         default:
244                 sr_warn("Unknown encoding for digit: 0x%02x.", b);
245                 return '\0';
246         }
247 }
248
249 static int brymen_bm52x_parse_digits(const uint8_t *pkt, size_t pktlen,
250         char *txtbuf, float *value, char *temp_unit, int *digits, int signflag)
251 {
252         uint8_t byte;
253         char *txtptr, txtchar;
254         size_t pos;
255         int ret;
256
257         txtptr = txtbuf;
258         if (digits)
259                 *digits = INT_MIN;
260
261         if (pkt[0] & signflag)
262                 *txtptr++ = '-';
263         for (pos = 0; pos < pktlen; pos++) {
264                 byte = pkt[1 + pos];
265                 txtchar = brymen_bm52x_parse_digit(byte);
266                 if (pos == 3 && (txtchar == 'C' || txtchar == 'F')) {
267                         if (temp_unit)
268                                 *temp_unit = txtchar;
269                 } else if (txtchar) {
270                         *txtptr++ = txtchar;
271                         if (digits)
272                                 (*digits)++;
273                 }
274                 if (pos < 3 && (byte & 0x10)) {
275                         *txtptr++ = '.';
276                         if (digits)
277                                 *digits = 0;
278                 }
279         }
280         *txtptr = '\0';
281
282         if (digits && *digits < 0)
283                 *digits = 0;
284
285         ret = value ? sr_atof_ascii(txtbuf, value) : SR_OK;
286         if (ret != SR_OK) {
287                 sr_dbg("invalid float string: '%s'", txtbuf);
288                 return ret;
289         }
290
291         return SR_OK;
292 }
293
294 /*
295  * Extract the measurement value and its properties for one of the
296  * meter's displays from the DMM packet.
297  */
298 static void brymen_bm52x_parse(const uint8_t *buf, float *floatval,
299         struct sr_datafeed_analog *analog, size_t ch_idx)
300 {
301         char txtbuf[16], temp_unit;
302         int ret, digits, scale;
303         int is_diode, is_auto, is_no_temp, is_ol, is_db, is_main_milli;
304         int is_mm_max, is_mm_min, is_mm_avg, is_mm_dash;
305
306         temp_unit = '\0';
307         if (ch_idx == 0) {
308                 /*
309                  * Main display. Note that _some_ of the second display's
310                  * indicators are involved in the inspection of the _first_
311                  * display's measurement value. So we have to get the
312                  * second display's text buffer here, too.
313                  */
314                 (void)brymen_bm52x_parse_digits(&buf[7], 4, txtbuf,
315                         NULL, NULL, NULL, 0);
316                 is_diode = strcmp(txtbuf, "diod") == 0;
317                 is_auto = strcmp(txtbuf, "Auto") == 0;
318                 ret = brymen_bm52x_parse_digits(&buf[2], 4, txtbuf,
319                         floatval, &temp_unit, &digits, 0x80);
320                 is_ol = strstr(txtbuf, "0L") || strstr(txtbuf, "0.L");
321                 is_no_temp = strcmp(txtbuf, "---C") == 0;
322                 is_no_temp |= strcmp(txtbuf, "---F") == 0;
323                 if (ret != SR_OK && !is_ol)
324                         return;
325
326                 /* SI unit, derived from meter's current function. */
327                 is_db = buf[6] & 0x10;
328                 is_main_milli = buf[14] & 0x40;
329                 if (buf[14] & 0x20) {
330                         analog->meaning->mq = SR_MQ_VOLTAGE;
331                         analog->meaning->unit = SR_UNIT_VOLT;
332                         if (is_diode) {
333                                 analog->meaning->mqflags |= SR_MQFLAG_DIODE;
334                                 analog->meaning->mqflags |= SR_MQFLAG_DC;
335                         }
336                 } else if (buf[14] & 0x10) {
337                         analog->meaning->mq = SR_MQ_CURRENT;
338                         analog->meaning->unit = SR_UNIT_AMPERE;
339                 } else if (buf[14] & 0x01) {
340                         analog->meaning->mq = SR_MQ_CAPACITANCE;
341                         analog->meaning->unit = SR_UNIT_FARAD;
342                 } else if (buf[14] & 0x02) {
343                         analog->meaning->mq = SR_MQ_CONDUCTANCE;
344                         analog->meaning->unit = SR_UNIT_SIEMENS;
345                 } else if (buf[13] & 0x10) {
346                         analog->meaning->mq = SR_MQ_FREQUENCY;
347                         analog->meaning->unit = SR_UNIT_HERTZ;
348                 } else if (buf[7] & 0x01) {
349                         analog->meaning->mq = SR_MQ_CONTINUITY;
350                         analog->meaning->unit = SR_UNIT_OHM;
351                 } else if (buf[13] & 0x20) {
352                         analog->meaning->mq = SR_MQ_RESISTANCE;
353                         analog->meaning->unit = SR_UNIT_OHM;
354                 } else if (is_db && is_main_milli) {
355                         analog->meaning->mq = SR_MQ_POWER;
356                         analog->meaning->unit = SR_UNIT_DECIBEL_MW;
357                 } else if (buf[14] & 0x04) {
358                         analog->meaning->mq = SR_MQ_DUTY_CYCLE;
359                         analog->meaning->unit = SR_UNIT_PERCENTAGE;
360                 } else if ((buf[2] & 0x09) && temp_unit) {
361                         if (is_no_temp)
362                                 return;
363                         analog->meaning->mq = SR_MQ_TEMPERATURE;
364                         if (temp_unit == 'F')
365                                 analog->meaning->unit = SR_UNIT_FAHRENHEIT;
366                         else
367                                 analog->meaning->unit = SR_UNIT_CELSIUS;
368                 }
369
370                 /*
371                  * Remove the MIN/MAX/AVG indicators when all of them
372                  * are shown at the same time (indicating that recording
373                  * is active, but live readings are shown). This also
374                  * removes the MAX-MIN (V p-p) indication which cannot
375                  * get represented by SR_MQFLAG_* means.
376                  *
377                  * Keep the check conditions separate to simplify future
378                  * maintenance when Vp-p gets added. Provide the value of
379                  * currently unsupported modes just without flags (show
380                  * the maximum amount of LCD content on screen that we
381                  * can represent in sigrok).
382                  */
383                 is_mm_max = buf[1] & 0x01;
384                 is_mm_min = buf[1] & 0x08;
385                 is_mm_avg = buf[1] & 0x02;
386                 is_mm_dash = buf[1] & 0x04;
387                 if (is_mm_max && is_mm_min && is_mm_avg)
388                         is_mm_max = is_mm_min = is_mm_avg = 0;
389                 if (is_mm_max && is_mm_min && is_mm_dash)
390                         is_mm_max = is_mm_min = 0;
391                 if (is_mm_max && is_mm_min && !is_mm_dash)
392                         is_mm_max = is_mm_min = 0;
393
394                 /* AC/DC/Auto flags. Hold/Min/Max/Rel etc flags. */
395                 if (buf[1] & 0x20)
396                         analog->meaning->mqflags |= SR_MQFLAG_DC;
397                 if (buf[1] & 0x10)
398                         analog->meaning->mqflags |= SR_MQFLAG_AC;
399                 if (buf[20] & 0x10)
400                         analog->meaning->mqflags |= SR_MQFLAG_AUTORANGE;
401                 if (buf[20] & 0x80)
402                         analog->meaning->mqflags |= SR_MQFLAG_HOLD;
403                 if (is_mm_max)
404                         analog->meaning->mqflags |= SR_MQFLAG_MAX;
405                 if (is_mm_min)
406                         analog->meaning->mqflags |= SR_MQFLAG_MIN;
407                 if (is_mm_avg)
408                         analog->meaning->mqflags |= SR_MQFLAG_AVG;
409                 if (buf[2] & 0x40)
410                         analog->meaning->mqflags |= SR_MQFLAG_RELATIVE;
411
412                 /*
413                  * Remove the "dBm" indication's "m" indicator before the
414                  * SI unit's prefixes get inspected. Avoids an interaction
415                  * with the "milli" prefix. Strictly speaking BM525s does
416                  * not support dBm, but other models do and we may want
417                  * to share the protocol parser.
418                  */
419                 if (is_db)
420                         is_main_milli = 0;
421
422                 /* SI prefix. */
423                 scale = 0;
424                 if (buf[14] & 0x08) /* n */
425                         scale = -9;
426                 if (buf[14] & 0x80) /* u */
427                         scale = -6;
428                 if (is_main_milli) /* m */
429                         scale = -3;
430                 if (buf[13] & 0x80) /* k */
431                         scale = +3;
432                 if (buf[13] & 0x40) /* M */
433                         scale = +6;
434                 if (scale) {
435                         *floatval *= pow(10, scale);
436                         digits += -scale;
437                 }
438
439                 if (is_ol)
440                         *floatval = INFINITY;
441
442                 analog->encoding->digits  = digits;
443                 analog->spec->spec_digits = digits;
444         } else if (ch_idx == 1) {
445                 /*
446                  * Secondary display. Also inspect _some_ primary display
447                  * data, to determine the secondary display's validity.
448                  */
449                 (void)brymen_bm52x_parse_digits(&buf[2], 4, txtbuf,
450                         NULL, &temp_unit, NULL, 0x80);
451                 ret = brymen_bm52x_parse_digits(&buf[7], 4, txtbuf,
452                         floatval, NULL, &digits, 0x20);
453                 is_diode = strcmp(txtbuf, "diod") == 0;
454                 is_auto = strcmp(txtbuf, "Auto") == 0;
455                 is_no_temp = strcmp(txtbuf, "---C") == 0;
456                 is_no_temp |= strcmp(txtbuf, "---F") == 0;
457                 if (is_diode || is_auto)
458                         return;
459                 if (is_no_temp)
460                         return;
461
462                 /* SI unit. */
463                 if (buf[12] & 0x10) {
464                         analog->meaning->mq = SR_MQ_VOLTAGE;
465                         analog->meaning->unit = SR_UNIT_VOLT;
466                 } else if (buf[12] & 0x20) {
467                         analog->meaning->mq = SR_MQ_CURRENT;
468                         if (buf[11] & 0x10)
469                                 analog->meaning->unit = SR_UNIT_PERCENTAGE;
470                         else
471                                 analog->meaning->unit = SR_UNIT_AMPERE;
472                 } else if (buf[13] & 0x02) {
473                         analog->meaning->mq = SR_MQ_RESISTANCE;
474                         analog->meaning->unit = SR_UNIT_OHM;
475                 } else if (buf[12] & 0x02) {
476                         analog->meaning->mq = SR_MQ_CONDUCTANCE;
477                         analog->meaning->unit = SR_UNIT_SIEMENS;
478                 } else if (buf[12] & 0x01) {
479                         analog->meaning->mq = SR_MQ_CAPACITANCE;
480                         analog->meaning->unit = SR_UNIT_FARAD;
481                 } else if (buf[7] & 0x06) {
482                         if (strstr(txtbuf, "---"))
483                                 return;
484                         analog->meaning->mq = SR_MQ_TEMPERATURE;
485                         if (temp_unit == 'F')
486                                 analog->meaning->unit = SR_UNIT_FAHRENHEIT;
487                         else
488                                 analog->meaning->unit = SR_UNIT_CELSIUS;
489                 } else if (buf[13] & 0x01) {
490                         analog->meaning->mq = SR_MQ_FREQUENCY;
491                         analog->meaning->unit = SR_UNIT_HERTZ;
492                 } else if (buf[11] & 0x08) {
493                         analog->meaning->mq = SR_MQ_DUTY_CYCLE;
494                         analog->meaning->unit = SR_UNIT_PERCENTAGE;
495                 }
496
497                 /* DC/AC flags. */
498                 if (buf[7] & 0x80)
499                         analog->meaning->mqflags |= SR_MQFLAG_DC;
500                 if (buf[7] & 0x40)
501                         analog->meaning->mqflags |= SR_MQFLAG_AC;
502
503                 /* SI prefix. */
504                 scale = 0;
505                 if (buf[12] & 0x04) /* n */
506                         scale = -9;
507                 if (buf[12] & 0x40) /* u */
508                         scale = -6;
509                 if (buf[12] & 0x80) /* m */
510                         scale = -3;
511                 if (buf[13] & 0x04) /* k */
512                         scale = +3;
513                 if (buf[13] & 0x08) /* M */
514                         scale = +6;
515                 if (scale) {
516                         *floatval *= pow(10, scale);
517                         digits += -scale;
518                 }
519
520                 analog->encoding->digits  = digits;
521                 analog->spec->spec_digits = digits;
522         }
523
524         if (buf[7] & 0x08)
525                 sr_warn("Battery is low.");
526 }
527
528 SR_PRIV int sr_brymen_bm52x_parse(const uint8_t *buf, float *val,
529         struct sr_datafeed_analog *analog, void *info)
530 {
531         struct brymen_bm52x_info *info_local;
532         size_t ch_idx;
533
534         /*
535          * Scan a portion of the received DMM packet which corresponds
536          * to the caller's specified display. Then prepare to scan a
537          * different portion of the packet for another display. This
538          * routine gets called multiple times for one received packet.
539          */
540         info_local = info;
541         ch_idx = info_local->ch_idx;
542         brymen_bm52x_parse(buf, val, analog, ch_idx);
543         info_local->ch_idx = ch_idx + 1;
544
545         return SR_OK;
546 }
547
548 /*
549  * The above code paths support live readings ("real-time download").
550  * The below code paths support recordings ("memory data sets") which
551  * use different requests and responses and measurement representation
552  * which feels like "a different meter".
553  */
554
555 /*
556  * Developer notes, example data for recorded sessions.
557  *
558  * model
559  * 01
560  *    total bytes
561  *    e6 02 00
562  *             session count
563  *             01 00
564  *                   "DLE/STX" marker
565  *                   ee a0
566  *                         PS/NS addresses
567  *                         8a 03 a0 60 03 a0
568  *                                           func/sel/stat (DC-V, single display)
569  *                                           02 00 00
570  *                                                    session page length in bytes (3 * 240)
571  *                                                    d0 02 00
572  *                                                             main[/secondary] display data
573  *                                                             00 00 00 00
574  *                                                                          checksums and padding
575  *                                                                          7c 05 00 00 00 00 00 00
576  * 00 00 80 00 00 80 00 00 80 00 00 80 00 00 00 00 00 80 00 00 80 00 00 80  80 03 00 00 00 00 00 00
577  * 00 00 00 00 00 00 00 00 80 00 00 80 00 00 80 00 00 80 00 00 80 00 00 80  00 03 00 00 00 00 00 00
578  * ...
579  * 00 00 80 00 00 00 00 00 00 00 00 80 00 00 80 00 00 80 00 00 80 00 00 80  00 03 00 00 00 00 00 00
580  * 00 00 80 00 00 80 00 00 80 00 00 80 00 00 80 00 00 80 00 00
581  *                                                             "DLE/ETX" marker
582  *                                                             ee c0
583  *                                                                          ae 04 00 00 00 00 00 00
584  *
585  * - Checksum in bytes[25:24] is the mere sum of bytes[0:23].
586  * - Model ID is 0 or 1 -- does this translate to BM521s and BM525s?
587  * - Total byte count _includes_ everything starting at model ID.
588  * - There is no measurements count for a session page, but its length
589  *   in bytes, and a dual display flag, which lets us derive the count.
590  * - STX/ETX/DLE markers don't use the expected ASCII codes.
591  */
592
593 /*
594  * See vendor doc table 3.1 "Logging interval". Includes sub-1Hz rates,
595  * but also sub-1s intervals. Let's keep both presentations at hand.
596  */
597 static const struct {
598         unsigned int ival_secs;
599         unsigned int freq_rate;
600 } bm52x_rec_ivals[] = {
601         [ 0] = {   0, 20, },
602         [ 1] = {   0, 10, },
603         [ 2] = {   0,  2, },
604         [ 3] = {   1,  1, },
605         [ 4] = {   2,  0, },
606         [ 5] = {   3,  0, },
607         [ 6] = {   4,  0, },
608         [ 7] = {   5,  0, },
609         [ 8] = {  10,  0, },
610         [ 9] = {  15,  0, },
611         [10] = {  30,  0, },
612         [11] = {  60,  0, },
613         [12] = { 120,  0, },
614         [13] = { 180,  0, },
615         [14] = { 300,  0, },
616         [15] = { 600,  0, },
617 };
618
619 /*
620  * See vendor doc table 6 "Range bits". Temperature is not listed there
621  * but keeping it here unifies the processing code paths.
622  */
623 static const int bm52x_ranges_volt[16] = { 3, 2, 1, 0, };
624 static const int bm52x_ranges_millivolt[16] = { 5, 4, };
625 static const int bm52x_ranges_freq[16] = { 3, 2, 1, 0, -1, -2, -3, };
626 static const int bm52x_ranges_duty[16] = { 2, 1, };
627 static const int bm52x_ranges_ohm[16] = { 1, 0, -1, -2, -3, -4, };
628 static const int bm52x_ranges_cond[16] = { 11, };
629 static const int bm52x_ranges_cap[16] = { 11, 10, 9, 8, 7, 6, 5, };
630 static const int bm52x_ranges_diode[16] = { 3, };
631 static const int bm52x_ranges_temp[16] = { 0, };
632 static const int bm52x_ranges_amp[16] = { 3, 2, };
633 static const int bm52x_ranges_milliamp[16] = { 5, 4, };
634 static const int bm52x_ranges_microamp[16] = { 7, 6, };
635
636 /** Calculate checksum of four-HID-report responses (recordings). */
637 static uint16_t bm52x_rec_checksum(const uint8_t *b, size_t l)
638 {
639         uint16_t cs;
640
641         cs = 0;
642         while (l--)
643                 cs += *b++;
644
645         return cs;
646 }
647
648 /**
649  * Retrieve the first/next chunk of recording information.
650  * Support for live readings is theoretical, and unused/untested.
651  */
652 #ifdef HAVE_SERIAL_COMM
653 static int bm52x_rec_next_rsp(struct sr_serial_dev_inst *serial,
654         enum bm52x_reqtype req, struct brymen_bm52x_state *state)
655 {
656         uint8_t *b;
657         size_t l;
658         int ret;
659
660         /* Seed internal state when sending the HEAD request. */
661         if (req == REQ_REC_HEAD || req == REQ_LIVE_READ_520)
662                 memset(&state->rsp, 0, sizeof(state->rsp));
663
664         /* Move unprocessed content to the front. */
665         if (state->rsp.read_pos) {
666                 b = &state->rsp.buff[0];
667                 l = state->rsp.fill_pos - state->rsp.read_pos;
668                 if (l)
669                         memmove(&b[0], &b[state->rsp.read_pos], l);
670                 state->rsp.fill_pos -= state->rsp.read_pos;
671                 state->rsp.read_pos = 0;
672         }
673
674         /* Avoid queries for non-existing data. Limit NEXT requests. */
675         if (req == REQ_REC_NEXT && !state->rsp.remain)
676                 return SR_ERR_IO;
677
678         /* Add another response chunk to the read buffer. */
679         b = &state->rsp.buff[state->rsp.fill_pos];
680         l = req == REQ_LIVE_READ_520 ? 24 : 32;
681         if (sizeof(state->rsp.buff) - state->rsp.fill_pos < l)
682                 return SR_ERR_BUG;
683         ret = bm52x_send_req(serial, req);
684         if (ret != SR_OK)
685                 return ret;
686         ret = serial_read_blocking(serial, b, l, 1000);
687         if (ret < 0)
688                 return ret;
689         if ((size_t)ret != l)
690                 return SR_ERR_IO;
691         state->rsp.fill_pos += l;
692
693         /* Devel support: dump the new receive data. */
694         if (sr_log_loglevel_get() >= SR_LOG_SPEW) {
695                 GString *text;
696                 const char *req_text;
697
698                 req_text = (req == REQ_LIVE_READ_520) ? "LIVE" :
699                         (req == REQ_REC_HEAD) ? "MEM HEAD" :
700                         (req == REQ_REC_NEXT) ? "MEM NEXT" :
701                         (req == REQ_REC_CURR) ? "MEM CURR" :
702                         "<inv>";
703                 text = sr_hexdump_new(b, l);
704                 sr_spew("%s: %s", req_text, text->str);
705                 sr_hexdump_free(text);
706         }
707
708         /* Verify checksum. No CURR repetition is attempted here. */
709         if (l > 24) {
710                 uint16_t calc, rcvd;
711
712                 calc = bm52x_rec_checksum(b, 24);
713                 rcvd = read_u16le(&b[24]);
714                 if (calc != rcvd)
715                         return SR_ERR_DATA;
716                 state->rsp.fill_pos -= 32 - 24;
717         }
718
719         /* Seed amount of total available data from HEAD response. */
720         if (req == REQ_REC_HEAD) {
721                 const uint8_t *rdptr;
722
723                 rdptr = &state->rsp.buff[0];
724                 (void)read_u8_inc(&rdptr); /* model ID */
725                 state->rsp.remain = read_u24le_inc(&rdptr); /* byte count */
726         }
727
728         return SR_OK;
729 }
730 #else /* have serial comm */
731 static int bm52x_rec_next_rsp(struct sr_serial_dev_inst *serial,
732         enum bm52x_reqtype req, struct brymen_bm52x_state *state)
733 {
734         (void)serial;
735         (void)req;
736         (void)state;
737         (void)bm52x_rec_checksum;
738         return SR_ERR_NA;
739 }
740 #endif /* have serial comm */
741
742 /** Make sure a minimum amount of response data is available. */
743 static const uint8_t *bm52x_rec_ensure(struct sr_serial_dev_inst *serial,
744         size_t min_count, struct brymen_bm52x_state *state)
745 {
746         size_t got;
747         const uint8_t *read_ptr;
748         int ret;
749
750         got = state->rsp.fill_pos - state->rsp.read_pos;
751         if (got >= min_count) {
752                 read_ptr = &state->rsp.buff[state->rsp.read_pos];
753                 return read_ptr;
754         }
755         ret = bm52x_rec_next_rsp(serial, REQ_REC_NEXT, state);
756         if (ret < 0)
757                 return NULL;
758         read_ptr = &state->rsp.buff[state->rsp.read_pos];
759         return read_ptr;
760 }
761
762 /** Get a u8 quantity of response data, with auto-fetch and position increment. */
763 static uint8_t bm52x_rec_get_u8(struct sr_serial_dev_inst *serial,
764         struct brymen_bm52x_state *state)
765 {
766         const uint8_t *read_ptr;
767         uint8_t value;
768         size_t length;
769
770         length = sizeof(value);
771         if (length > state->rsp.remain) {
772                 state->rsp.remain = 0;
773                 return 0;
774         }
775         read_ptr = bm52x_rec_ensure(serial, length, state);
776         if (!read_ptr)
777                 return 0;
778         value = read_u8(read_ptr);
779         state->rsp.read_pos += length;
780         state->rsp.remain -= length;
781         return value;
782 }
783
784 /** Get a u16 quantity of response data, with auto-fetch and position increment. */
785 static uint16_t bm52x_rec_get_u16(struct sr_serial_dev_inst *serial,
786         struct brymen_bm52x_state *state)
787 {
788         const uint8_t *read_ptr;
789         uint16_t value;
790         size_t length;
791
792         length = sizeof(value);
793         if (length > state->rsp.remain) {
794                 state->rsp.remain = 0;
795                 return 0;
796         }
797         read_ptr = bm52x_rec_ensure(serial, length, state);
798         if (!read_ptr)
799                 return 0;
800         value = read_u16le(read_ptr);
801         state->rsp.read_pos += length;
802         state->rsp.remain -= length;
803         return value;
804 }
805
806 /** Get a u24 quantity of response data, with auto-fetch and position increment. */
807 static uint32_t bm52x_rec_get_u24(struct sr_serial_dev_inst *serial,
808         struct brymen_bm52x_state *state)
809 {
810         const uint8_t *read_ptr;
811         uint32_t value;
812         size_t length;
813
814         length = 24 / sizeof(uint8_t) / 8;
815         if (length > state->rsp.remain) {
816                 state->rsp.remain = 0;
817                 return 0;
818         }
819         read_ptr = bm52x_rec_ensure(serial, length, state);
820         if (!read_ptr)
821                 return 0;
822         value = read_u24le(read_ptr);
823         state->rsp.read_pos += length;
824         state->rsp.remain -= length;
825         return value;
826 }
827
828 /** Get the HEAD chunk of recording data, determine session page count. */
829 static int bm52x_rec_get_count(struct brymen_bm52x_state *state,
830         struct sr_serial_dev_inst *serial)
831 {
832         int ret;
833         size_t byte_count, sess_count;
834
835         memset(&state->rsp, 0, sizeof(state->rsp));
836         ret = bm52x_rec_next_rsp(serial, REQ_REC_HEAD, state);
837         if (ret != SR_OK)
838                 return ret;
839
840         (void)bm52x_rec_get_u8(serial, state); /* model ID */
841         byte_count = bm52x_rec_get_u24(serial, state); /* total bytes count */
842         sess_count = bm52x_rec_get_u16(serial, state); /* session count */
843         sr_dbg("bytes %zu, sessions %zu", byte_count, sess_count);
844
845         return sess_count;
846 }
847
848 static double bm52x_rec_get_value(uint32_t raw, const int *ranges, int *digits)
849 {
850         uint16_t val_digs;
851         gboolean is_neg, is_ol, low_batt;
852         uint8_t range;
853         double value;
854         int decimals;
855
856         val_digs = raw >> 8;
857         is_neg = raw & (1u << 7);
858         is_ol = raw & (1u << 6);
859         low_batt = raw & (1u << 5);
860         range = raw & 0x0f;
861         sr_dbg("item: %s%u, %s %s, range %01x",
862                 is_neg ? "-" : "+", val_digs,
863                 is_ol ? "OL" : "ol", low_batt ? "BATT" : "batt",
864                 range);
865
866         /* Convert to number. OL takes precedence. */
867         *digits = 0;
868         value = val_digs;
869         if (ranges && ranges[range]) {
870                 decimals = ranges[range];
871                 value /= pow(10, decimals);
872                 *digits = decimals;
873         }
874         if (is_ol)
875                 value = INFINITY;
876         if (is_neg)
877                 value *= -1;
878
879         /*
880          * Implementor's note: "Low battery" conditions are worth a
881          * warning since the reading could be incorrect. Rate limiting
882          * is not needed since the Brymen DMM will stop recording in
883          * that case, so at most the last sample in the session page
884          * could be affected.
885          */
886         if (low_batt)
887                 sr_warn("Recording was taken when battery was low.");
888
889         return value;
890 }
891
892 static int bm52x_rec_prep_feed(uint8_t bfunc, uint8_t bsel, uint8_t bstat,
893         struct sr_datafeed_analog *analog1, struct sr_datafeed_analog *analog2,
894         double *value1, double *value2, const int **ranges1, const int **ranges2,
895         const struct sr_dev_inst *sdi)
896 {
897         struct sr_channel *ch;
898         gboolean is_amp, is_deg_f;
899         enum sr_mq *mq1, *mq2;
900         enum sr_unit *unit1, *unit2;
901         enum sr_mqflag *mqf1, *mqf2;
902         enum sr_unit unit_c_f;
903         const int *r_a_ma;
904
905         /* Prepare general submission on first channel. */
906         analog1->data = value1;
907         analog1->encoding->unitsize = sizeof(*value1);
908         analog1->num_samples = 1;
909         ch = g_slist_nth_data(sdi->channels, 0);
910         analog1->meaning->channels = g_slist_append(NULL, ch);
911         *ranges1 = NULL;
912         mq1 = &analog1->meaning->mq;
913         mqf1 = &analog1->meaning->mqflags;
914         unit1 = &analog1->meaning->unit;
915
916         /* Prepare general submission on second channel. */
917         analog2->data = value2;
918         analog2->encoding->unitsize = sizeof(*value2);
919         analog2->num_samples = 1;
920         ch = g_slist_nth_data(sdi->channels, 1);
921         analog2->meaning->channels = g_slist_append(NULL, ch);
922         *ranges2 = NULL;
923         mq2 = &analog2->meaning->mq;
924         mqf2 = &analog2->meaning->mqflags;
925         unit2 = &analog2->meaning->unit;
926
927         /* Derive main/secondary display functions from bfunc/bsel/bstat. */
928         is_amp = bstat & (1u << 5);
929         is_deg_f = bstat & (1u << 4);
930         switch (bfunc) {
931         case 1: /* AC V */
932                 switch (bsel) {
933                 case 0: /* AC volt, Hz */
934                         *ranges1 = bm52x_ranges_volt;
935                         *mq1 = SR_MQ_VOLTAGE;
936                         *mqf1 |= SR_MQFLAG_AC;
937                         *unit1 = SR_UNIT_VOLT;
938                         *ranges2 = bm52x_ranges_freq;
939                         *mq2 = SR_MQ_FREQUENCY;
940                         *unit2 = SR_UNIT_HERTZ;
941                         break;
942                 case 1: /* Hz, AC volt */
943                         *ranges1 = bm52x_ranges_freq;
944                         *mq1 = SR_MQ_FREQUENCY;
945                         *unit1 = SR_UNIT_HERTZ;
946                         *ranges2 = bm52x_ranges_volt;
947                         *mq2 = SR_MQ_VOLTAGE;
948                         *mqf2 |= SR_MQFLAG_AC;
949                         *unit2 = SR_UNIT_VOLT;
950                         break;
951                 default:
952                         return SR_ERR_DATA;
953                 }
954                 break;
955         case 2: /* DC V */
956                 switch (bsel) {
957                 case 0: /* DC V, - */
958                         *ranges1 = bm52x_ranges_volt;
959                         *mq1 = SR_MQ_VOLTAGE;
960                         *mqf1 |= SR_MQFLAG_DC;
961                         *unit1 = SR_UNIT_VOLT;
962                         break;
963                 case 1: /* DC V, AC V */
964                         *ranges1 = bm52x_ranges_volt;
965                         *mq1 = SR_MQ_VOLTAGE;
966                         *mqf1 |= SR_MQFLAG_DC;
967                         *unit1 = SR_UNIT_VOLT;
968                         *ranges2 = bm52x_ranges_volt;
969                         *mq2 = SR_MQ_VOLTAGE;
970                         *mqf2 |= SR_MQFLAG_AC;
971                         *unit2 = SR_UNIT_VOLT;
972                         break;
973                 case 2: /* DC+AC V, AC V */
974                         *ranges1 = bm52x_ranges_volt;
975                         *mq1 = SR_MQ_VOLTAGE;
976                         *mqf1 |= SR_MQFLAG_DC;
977                         *mqf1 |= SR_MQFLAG_AC;
978                         *unit1 = SR_UNIT_VOLT;
979                         *ranges2 = bm52x_ranges_volt;
980                         *mq2 = SR_MQ_VOLTAGE;
981                         *mqf2 |= SR_MQFLAG_AC;
982                         *unit2 = SR_UNIT_VOLT;
983                         break;
984                 default:
985                         return SR_ERR_DATA;
986                 }
987                 break;
988         case 3: /* DC mV */
989                 switch (bsel) {
990                 case 0: /* DC mV, - */
991                         *ranges1 = bm52x_ranges_millivolt;
992                         *mq1 = SR_MQ_VOLTAGE;
993                         *mqf1 |= SR_MQFLAG_DC;
994                         *unit1 = SR_UNIT_VOLT;
995                         break;
996                 case 1: /* DC mV, AC mV */
997                         *ranges1 = bm52x_ranges_millivolt;
998                         *mq1 = SR_MQ_VOLTAGE;
999                         *mqf1 |= SR_MQFLAG_DC;
1000                         *unit1 = SR_UNIT_VOLT;
1001                         *ranges2 = bm52x_ranges_millivolt;
1002                         *mq2 = SR_MQ_VOLTAGE;
1003                         *mqf2 |= SR_MQFLAG_AC;
1004                         *unit2 = SR_UNIT_VOLT;
1005                         break;
1006                 case 2: /* DC+AC mV, AC mV */
1007                         *ranges1 = bm52x_ranges_millivolt;
1008                         *mq1 = SR_MQ_VOLTAGE;
1009                         *mqf1 |= SR_MQFLAG_DC;
1010                         *mqf1 |= SR_MQFLAG_AC;
1011                         *unit1 = SR_UNIT_VOLT;
1012                         *ranges2 = bm52x_ranges_millivolt;
1013                         *mq2 = SR_MQ_VOLTAGE;
1014                         *mqf2 |= SR_MQFLAG_AC;
1015                         *unit2 = SR_UNIT_VOLT;
1016                         break;
1017                 case 3: /* Hz, - */
1018                         *ranges1 = bm52x_ranges_freq;
1019                         *mq1 = SR_MQ_FREQUENCY;
1020                         *unit1 = SR_UNIT_HERTZ;
1021                         break;
1022                 case 4: /* %, - */
1023                         *ranges1 = bm52x_ranges_duty;
1024                         *mq1 = SR_MQ_DUTY_CYCLE;
1025                         *unit1 = SR_UNIT_PERCENTAGE;
1026                         break;
1027                 default:
1028                         return SR_ERR_DATA;
1029                 }
1030                 break;
1031         case 4: /* AC mV */
1032                 switch (bsel) {
1033                 case 0: /* AC mV, Hz */
1034                         *ranges1 = bm52x_ranges_millivolt;
1035                         *mq1 = SR_MQ_VOLTAGE;
1036                         *mqf1 |= SR_MQFLAG_AC;
1037                         *unit1 = SR_UNIT_VOLT;
1038                         *ranges2 = bm52x_ranges_freq;
1039                         *mq2 = SR_MQ_FREQUENCY;
1040                         *unit2 = SR_UNIT_HERTZ;
1041                         break;
1042                 case 1: /* Hz, AC mV */
1043                         *ranges1 = bm52x_ranges_freq;
1044                         *mq1 = SR_MQ_FREQUENCY;
1045                         *unit1 = SR_UNIT_HERTZ;
1046                         *ranges2 = bm52x_ranges_millivolt;
1047                         *mq2 = SR_MQ_VOLTAGE;
1048                         *mqf2 |= SR_MQFLAG_AC;
1049                         *unit2 = SR_UNIT_VOLT;
1050                         break;
1051                 default:
1052                         return SR_ERR_DATA;
1053                 }
1054                 break;
1055         case 5: /* Res/Cond/Cont */
1056                 switch (bsel) {
1057                 case 0: /* Resistance */
1058                         *ranges1 = bm52x_ranges_ohm;
1059                         *mq1 = SR_MQ_RESISTANCE;
1060                         *unit1 = SR_UNIT_OHM;
1061                         break;
1062                 case 1: /* Siemens */
1063                         *ranges1 = bm52x_ranges_cond;
1064                         *mq1 = SR_MQ_CONDUCTANCE;
1065                         *unit1 = SR_UNIT_SIEMENS;
1066                         break;
1067                 case 2: /* Continuity */
1068                         *ranges1 = bm52x_ranges_ohm;
1069                         *mq1 = SR_MQ_CONTINUITY;
1070                         *unit1 = SR_UNIT_OHM;
1071                         break;
1072                 default:
1073                         return SR_ERR_DATA;
1074                 }
1075                 break;
1076         case 6: /* Temperature */
1077                 unit_c_f = is_deg_f ? SR_UNIT_FAHRENHEIT : SR_UNIT_CELSIUS;
1078                 switch (bsel) {
1079                 case 0: /* T1, - */
1080                         *ranges1 = bm52x_ranges_temp;
1081                         *mq1 = SR_MQ_TEMPERATURE;
1082                         *unit1 = unit_c_f;
1083                         break;
1084                 case 1: /* T2, - */
1085                         *ranges1 = bm52x_ranges_temp;
1086                         *mq1 = SR_MQ_TEMPERATURE;
1087                         *unit1 = unit_c_f;
1088                         break;
1089                 case 2: /* T1, T2 */
1090                         *ranges1 = bm52x_ranges_temp;
1091                         *mq1 = SR_MQ_TEMPERATURE;
1092                         *unit1 = unit_c_f;
1093                         *ranges2 = bm52x_ranges_temp;
1094                         *mq2 = SR_MQ_TEMPERATURE;
1095                         *unit2 = unit_c_f;
1096                         break;
1097                 case 3: /* T1-T2, T2 */
1098                         *ranges1 = bm52x_ranges_temp;
1099                         *mq1 = SR_MQ_TEMPERATURE;
1100                         *unit1 = unit_c_f;
1101                         *ranges2 = bm52x_ranges_temp;
1102                         *mq2 = SR_MQ_TEMPERATURE;
1103                         *unit2 = unit_c_f;
1104                         break;
1105                 default:
1106                         return SR_ERR_DATA;
1107                 }
1108                 break;
1109         case 7: /* Cap/Diode */
1110                 switch (bsel) {
1111                 case 0: /* Capacitance, - */
1112                         *ranges1 = bm52x_ranges_cap;
1113                         *mq1 = SR_MQ_CAPACITANCE;
1114                         *unit1 |= SR_UNIT_FARAD;
1115                         break;
1116                 case 1: /* Diode voltage, - */
1117                         *ranges1 = bm52x_ranges_diode;
1118                         *mq1 = SR_MQ_VOLTAGE;
1119                         *mqf1 |= SR_MQFLAG_DC;
1120                         *mqf1 |= SR_MQFLAG_DIODE;
1121                         *unit1 |= SR_UNIT_VOLT;
1122                         break;
1123                 default:
1124                         return SR_ERR_DATA;
1125                 }
1126                 break;
1127         case 8: /* DC A/mA */
1128                 r_a_ma = is_amp ? bm52x_ranges_amp : bm52x_ranges_milliamp;
1129                 switch (bsel) {
1130                 case 0: /* DC A/mA, - */
1131                         *ranges1 = r_a_ma;
1132                         *mq1 = SR_MQ_CURRENT;
1133                         *mqf1 |= SR_MQFLAG_DC;
1134                         *unit1 = SR_UNIT_AMPERE;
1135                         break;
1136                 case 1: /* DC A/mA, AC A/mA */
1137                         *ranges1 = r_a_ma;
1138                         *mq1 = SR_MQ_CURRENT;
1139                         *mqf1 |= SR_MQFLAG_DC;
1140                         *unit1 = SR_UNIT_AMPERE;
1141                         *ranges2 = r_a_ma;
1142                         *mq2 = SR_MQ_CURRENT;
1143                         *mqf2 |= SR_MQFLAG_AC;
1144                         *unit2 = SR_UNIT_AMPERE;
1145                         break;
1146                 case 2: /* DC+AC A/mA, AC A/mA */
1147                         *ranges1 = r_a_ma;
1148                         *mq1 = SR_MQ_CURRENT;
1149                         *mqf1 |= SR_MQFLAG_DC;
1150                         *mqf1 |= SR_MQFLAG_AC;
1151                         *unit1 = SR_UNIT_AMPERE;
1152                         *ranges2 = r_a_ma;
1153                         *mq2 = SR_MQ_CURRENT;
1154                         *mqf2 |= SR_MQFLAG_AC;
1155                         *unit2 = SR_UNIT_AMPERE;
1156                         break;
1157                 case 3: /* AC A/mA, Hz */
1158                         *ranges1 = r_a_ma;
1159                         *mq1 = SR_MQ_CURRENT;
1160                         *mqf1 |= SR_MQFLAG_AC;
1161                         *unit1 = SR_UNIT_AMPERE;
1162                         *ranges2 = bm52x_ranges_freq;
1163                         *mq2 = SR_MQ_FREQUENCY;
1164                         *unit2 = SR_UNIT_HERTZ;
1165                         break;
1166                 default:
1167                         return SR_ERR_DATA;
1168                 }
1169                 break;
1170         case 9: /* DC uA */
1171                 switch (bsel) {
1172                 case 0: /* DC uA, - */
1173                         *ranges1 = bm52x_ranges_microamp;
1174                         *mq1 = SR_MQ_CURRENT;
1175                         *mqf1 |= SR_MQFLAG_DC;
1176                         *unit1 = SR_UNIT_AMPERE;
1177                         break;
1178                 case 1: /* DC uA, AC uA */
1179                         *ranges1 = bm52x_ranges_microamp;
1180                         *mq1 = SR_MQ_CURRENT;
1181                         *mqf1 |= SR_MQFLAG_DC;
1182                         *unit1 = SR_UNIT_AMPERE;
1183                         *ranges2 = bm52x_ranges_microamp;
1184                         *mq2 = SR_MQ_CURRENT;
1185                         *mqf2 |= SR_MQFLAG_AC;
1186                         *unit2 = SR_UNIT_AMPERE;
1187                         break;
1188                 case 2: /* DC+AC uA, AC uA */
1189                         *ranges1 = bm52x_ranges_microamp;
1190                         *mq1 = SR_MQ_CURRENT;
1191                         *mqf1 |= SR_MQFLAG_DC;
1192                         *mqf1 |= SR_MQFLAG_AC;
1193                         *unit1 = SR_UNIT_AMPERE;
1194                         *ranges2 = bm52x_ranges_microamp;
1195                         *mq2 = SR_MQ_CURRENT;
1196                         *mqf2 |= SR_MQFLAG_AC;
1197                         *unit2 = SR_UNIT_AMPERE;
1198                         break;
1199                 case 3: /* AC uA, Hz */
1200                         *ranges1 = bm52x_ranges_microamp;
1201                         *mq1 = SR_MQ_CURRENT;
1202                         *mqf1 |= SR_MQFLAG_AC;
1203                         *unit1 = SR_UNIT_AMPERE;
1204                         *ranges2 = bm52x_ranges_freq;
1205                         *mq2 = SR_MQ_FREQUENCY;
1206                         *unit2 = SR_UNIT_HERTZ;
1207                         break;
1208                 default:
1209                         return SR_ERR_DATA;
1210                 }
1211                 break;
1212         default:
1213                 return SR_ERR_DATA;
1214         }
1215
1216         return SR_OK;
1217 }
1218
1219 /** Traverse one recorded session page, optionally feed session bus. */
1220 static int bm52x_rec_read_page_int(const struct sr_dev_inst *sdi,
1221         struct brymen_bm52x_state *state, struct sr_serial_dev_inst *serial,
1222         gboolean skip)
1223 {
1224         uint8_t bfunc, bsel, bstat;
1225         uint8_t ival;
1226         gboolean has_sec_disp;
1227         size_t page_len, meas_len, meas_count;
1228         uint32_t meas_data;
1229         struct sr_datafeed_packet packet;
1230         struct sr_datafeed_analog analog1, analog2;
1231         struct sr_analog_encoding encoding1, encoding2;
1232         struct sr_analog_meaning meaning1, meaning2;
1233         struct sr_analog_spec spec1, spec2;
1234         int digits, ret;
1235         double values[2];
1236         const int *ranges1, *ranges2;
1237         enum sr_configkey key;
1238         uint64_t num;
1239
1240         sr_dbg("progress: %s, %s", __func__, skip ? "skip" : "feed");
1241
1242         /* Get the header information of the session page (raw). */
1243         if (bm52x_rec_get_u8(serial, state) != 0xee) /* "DLE" */
1244                 return SR_ERR_DATA;
1245         if (bm52x_rec_get_u8(serial, state) != 0xa0) /* "STX" */
1246                 return SR_ERR_DATA;
1247         (void)bm52x_rec_get_u24(serial, state); /* prev page addr */
1248         (void)bm52x_rec_get_u24(serial, state); /* next page addr */
1249         bfunc = bm52x_rec_get_u8(serial, state); /* meter function */
1250         bsel = bm52x_rec_get_u8(serial, state); /* fun selection */
1251         bstat = bm52x_rec_get_u8(serial, state); /* status */
1252         page_len = bm52x_rec_get_u24(serial, state); /* page length */
1253         sr_dbg("page head: func/sel/state %02x/%02x/%02x, len %zu",
1254                 bfunc, bsel, bstat, page_len);
1255
1256         /* Interpret the header information of the session page. */
1257         ival = bstat & 0x0f;
1258         has_sec_disp = bstat & (1u << 7);
1259         meas_len = (has_sec_disp ? 2 : 1) * 3;
1260         if (page_len % meas_len)
1261                 return SR_ERR_DATA;
1262         meas_count = page_len / meas_len;
1263         sr_dbg("page head: ival %u, %s, samples %zu",
1264                 ival, has_sec_disp ? "dual" : "main", meas_count);
1265
1266         /* Prepare feed to the sigrok session. Send rate/interval. */
1267         sr_analog_init(&analog1, &encoding1, &meaning1, &spec1, 0);
1268         sr_analog_init(&analog2, &encoding2, &meaning2, &spec2, 0);
1269         ret = bm52x_rec_prep_feed(bfunc, bsel, bstat,
1270                 &analog1, &analog2, &values[0], &values[1],
1271                 &ranges1, &ranges2, sdi);
1272         if (ret != SR_OK)
1273                 return SR_ERR_DATA;
1274         if (!skip) {
1275                 memset(&packet, 0, sizeof(packet));
1276                 packet.type = SR_DF_ANALOG;
1277
1278                 if (bm52x_rec_ivals[ival].freq_rate) {
1279                         sr_dbg("rate: %u", bm52x_rec_ivals[ival].freq_rate);
1280                         key = SR_CONF_SAMPLERATE;
1281                         num = bm52x_rec_ivals[ival].freq_rate;
1282                         (void)sr_session_send_meta(sdi,
1283                                 key, g_variant_new_uint64(num));
1284                 }
1285                 if (bm52x_rec_ivals[ival].ival_secs) {
1286                         sr_dbg("ival: %u", bm52x_rec_ivals[ival].ival_secs);
1287                         key = SR_CONF_SAMPLE_INTERVAL;
1288                         num = bm52x_rec_ivals[ival].ival_secs * 1000; /* in ms */
1289                         (void)sr_session_send_meta(sdi,
1290                                 key, g_variant_new_uint64(num));
1291                 }
1292         }
1293
1294         /*
1295          * Implementor's note:
1296          * Software limits require devc access, which is an internal
1297          * detail of the serial-dmm driver, which this bm52x parser
1298          * is not aware of. So we always provide the complete set of
1299          * recorded samples. Should be acceptable. Duplicating limit
1300          * support in local config get/set is considered undesirable.
1301          */
1302         while (meas_count--) {
1303                 meas_data = bm52x_rec_get_u24(serial, state);
1304                 values[0] = bm52x_rec_get_value(meas_data, ranges1, &digits);
1305                 if (!skip) {
1306                         analog1.encoding->digits  = digits;
1307                         analog1.spec->spec_digits = digits;
1308                         packet.payload = &analog1;
1309                         ret = sr_session_send(sdi, &packet);
1310                         if (ret != SR_OK)
1311                                 return ret;
1312                 }
1313
1314                 if (!has_sec_disp)
1315                         continue;
1316                 meas_data = bm52x_rec_get_u24(serial, state);
1317                 values[1] = bm52x_rec_get_value(meas_data, ranges2, &digits);
1318                 if (!skip) {
1319                         analog2.encoding->digits  = digits;
1320                         analog2.spec->spec_digits = digits;
1321                         packet.payload = &analog2;
1322                         ret = sr_session_send(sdi, &packet);
1323                         if (ret != SR_OK)
1324                                 return ret;
1325                 }
1326         }
1327
1328         /* Check termination of the session page. */
1329         if (bm52x_rec_get_u8(serial, state) != 0xee) /* "DLE" */
1330                 return SR_ERR_DATA;
1331         if (bm52x_rec_get_u8(serial, state) != 0xc0) /* "ETX" */
1332                 return SR_ERR_DATA;
1333
1334         return SR_OK;
1335 }
1336
1337 /** Skip one recorded session page. */
1338 static int bm52x_rec_skip_page(const struct sr_dev_inst *sdi,
1339         struct brymen_bm52x_state *state, struct sr_serial_dev_inst *serial)
1340 {
1341         return bm52x_rec_read_page_int(sdi, state, serial, TRUE);
1342 }
1343
1344 /** Forward one recorded session page. */
1345 static int bm52x_rec_read_page(const struct sr_dev_inst *sdi,
1346         struct brymen_bm52x_state *state, struct sr_serial_dev_inst *serial)
1347 {
1348         return bm52x_rec_read_page_int(sdi, state, serial, FALSE);
1349 }
1350
1351 SR_PRIV void *brymen_bm52x_state_init(void)
1352 {
1353         return g_malloc0(sizeof(struct brymen_bm52x_state));
1354 }
1355
1356 SR_PRIV void brymen_bm52x_state_free(void *state)
1357 {
1358         g_free(state);
1359 }
1360
1361 SR_PRIV int brymen_bm52x_config_get(void *st, uint32_t key, GVariant **data,
1362         const struct sr_dev_inst *sdi, const struct sr_channel_group *cg)
1363 {
1364         struct brymen_bm52x_state *state;
1365         char text[20];
1366
1367         state = st;
1368
1369         if (!sdi)
1370                 return SR_ERR_NA;
1371         (void)cg;
1372
1373         switch (key) {
1374         case SR_CONF_DATA_SOURCE:
1375                 if (!state)
1376                         return SR_ERR_ARG;
1377                 if (state->sess_idx == 0)
1378                         snprintf(text, sizeof(text), "Live");
1379                 else
1380                         snprintf(text, sizeof(text), "Rec-%zu", state->sess_idx);
1381                 *data = g_variant_new_string(text);
1382                 return SR_OK;
1383         default:
1384                 return SR_ERR_NA;
1385         }
1386 }
1387
1388 SR_PRIV int brymen_bm52x_config_set(void *st, uint32_t key, GVariant *data,
1389         const struct sr_dev_inst *sdi, const struct sr_channel_group *cg)
1390 {
1391         struct brymen_bm52x_state *state;
1392         const char *s;
1393         int ret, nr;
1394
1395         state = st;
1396
1397         if (!sdi)
1398                 return SR_ERR_NA;
1399         (void)cg;
1400
1401         switch (key) {
1402         case SR_CONF_DATA_SOURCE:
1403                 s = g_variant_get_string(data, NULL);
1404                 if (!s || !*s)
1405                         return SR_ERR_ARG;
1406                 if (strcasecmp(s, "Live") == 0) {
1407                         state->sess_idx = 0;
1408                         return SR_OK;
1409                 }
1410                 if (strncasecmp(s, "Rec-", strlen("Rec-")) != 0)
1411                         return SR_ERR_ARG;
1412                 s += strlen("Rec-");
1413                 ret = sr_atoi(s, &nr);
1414                 if (ret != SR_OK || nr <= 0 || nr > 999)
1415                         return SR_ERR_ARG;
1416                 state->sess_idx = nr;
1417                 return SR_OK;
1418         default:
1419                 return SR_ERR_NA;
1420         }
1421 }
1422
1423 SR_PRIV int brymen_bm52x_config_list(void *st, uint32_t key, GVariant **data,
1424         const struct sr_dev_inst *sdi, const struct sr_channel_group *cg)
1425 {
1426         struct brymen_bm52x_state *state;
1427         struct sr_serial_dev_inst *serial;
1428         int ret;
1429         size_t count, idx;
1430         GVariantBuilder gvb;
1431         char name[20];
1432
1433         /*
1434          * Have common keys handled by caller's common code.
1435          * ERR N/A results in the caller's logic handling the request.
1436          * Only handle strictly local properties here in this code path.
1437          */
1438         switch (key) {
1439         case SR_CONF_SCAN_OPTIONS:
1440                 /* Scan options. Common property. */
1441                 return SR_ERR_NA;
1442         case SR_CONF_DEVICE_OPTIONS:
1443                 if (!sdi)
1444                         /* Driver options. Common property. */
1445                         return SR_ERR_NA;
1446                 if (cg)
1447                         /* Channel group's devopts. Common error path. */
1448                         return SR_ERR_NA;
1449                 /* List meter's local device options. Overrides common data. */
1450                 *data = g_variant_new_fixed_array(G_VARIANT_TYPE_UINT32,
1451                                 devopts, ARRAY_SIZE(devopts), sizeof(uint32_t));
1452                 return SR_OK;
1453         case SR_CONF_DATA_SOURCE:
1454                 state = st;
1455                 if (!sdi)
1456                         return SR_ERR_ARG;
1457                 serial = sdi->conn;
1458                 ret = bm52x_rec_get_count(state, serial);
1459                 if (ret < 0)
1460                         return ret;
1461                 count = ret;
1462                 g_variant_builder_init(&gvb, G_VARIANT_TYPE_ARRAY);
1463                 for (idx = 0; idx <= count; idx++) {
1464                         if (idx == 0)
1465                                 snprintf(name, sizeof(name), "Live");
1466                         else
1467                                 snprintf(name, sizeof(name), "Rec-%zu", idx);
1468                         g_variant_builder_add(&gvb, "s", name);
1469                 }
1470                 *data = g_variant_builder_end(&gvb);
1471                 return SR_OK;
1472         default:
1473                 return SR_ERR_NA;
1474         }
1475 }
1476
1477 /**
1478  * BM520s specific receive routine for recorded measurements.
1479  *
1480  * @param[in] fd File descriptor.
1481  * @param[in] revents Mask of pending events.
1482  * @param[in] cb_data Call back data (receive handler state).
1483  *
1484  * @return TRUE when the routine needs to get re-invoked, FALSE when the
1485  *   routine is done and no further invocations are required.
1486  *
1487  * @private
1488  *
1489  * It's an implementation detail that a single invocation will carry out
1490  * all the work that is involved in reading back recorded measurements.
1491  */
1492 static int bm52x_rec_receive_data(int fd, int revents, void *cb_data)
1493 {
1494         struct brymen_bm52x_state *state;
1495         const struct sr_dev_inst *sdi;
1496         struct sr_dev_inst *sdi_rw;
1497         struct sr_serial_dev_inst *serial;
1498         int ret;
1499         size_t count, idx;
1500
1501         (void)fd;
1502         (void)revents;
1503         state = cb_data;
1504
1505         sdi = state->sdi;
1506         serial = sdi->conn;
1507
1508         ret = bm52x_rec_get_count(state, serial);
1509         if (ret < 0)
1510                 return FALSE;
1511         count = ret;
1512
1513         /* Un-const 'sdi' since sr_dev_acquisition_stop() needs that. */
1514         sdi_rw = (struct sr_dev_inst *)sdi;
1515
1516         /*
1517          * Immediate (silent, zero data) stop for non-existent sessions.
1518          * Early exit is an arbitrary implementation detail, in theory
1519          * the loop below would transparently handle the situation when
1520          * users request non-existing session pages.
1521          */
1522         if (state->sess_idx > count) {
1523                 sr_dev_acquisition_stop(sdi_rw);
1524                 return FALSE;
1525         }
1526
1527         /* Iterate all session pages, forward the one of interest. */
1528         for (idx = 1; idx <= count; idx++) {
1529                 if (idx == state->sess_idx)
1530                         ret = bm52x_rec_read_page(sdi, state, serial);
1531                 else
1532                         ret = bm52x_rec_skip_page(sdi, state, serial);
1533                 if (ret != SR_OK)
1534                         break;
1535         }
1536
1537         sr_dev_acquisition_stop(sdi_rw);
1538         return FALSE;
1539 }
1540
1541 /**
1542  * BM520s specific acquisition start callback.
1543  *
1544  * @param[in] st DMM parser state.
1545  * @param[in] sdi Device instance.
1546  * @param[out] cb Receive callback for the acquisition.
1547  * @param[out] cb_data Callback data for receive callback.
1548  *
1549  * @returns SR_OK upon success.
1550  * @returns SR_ERR* upon failure.
1551  *
1552  * @private
1553  *
1554  * The BM520s protocol parser uses common logic and the packet parser
1555  * for live acquisition, but runs a different set of requests and a
1556  * different response layout interpretation for recorded measurements.
1557  */
1558 SR_PRIV int brymen_bm52x_acquire_start(void *st, const struct sr_dev_inst *sdi,
1559         sr_receive_data_callback *cb, void **cb_data)
1560 {
1561         struct brymen_bm52x_state *state;
1562
1563         if (!sdi || !st)
1564                 return SR_ERR_ARG;
1565         state = st;
1566
1567         /* Read live measurements. No local override required. */
1568         if (state->sess_idx == 0)
1569                 return SR_OK;
1570
1571         /* Arrange to read back recorded session. */
1572         sr_dbg("session page requested: %zu", state->sess_idx);
1573         state->sdi = sdi;
1574         *cb = bm52x_rec_receive_data;
1575         *cb_data = state;
1576         return SR_OK;
1577 }