]> sigrok.org Git - libsigrok.git/blob - src/hardware/agilent-dmm/protocol.c
agilent-dmm: add support for pulse width and duty cycle on U128x
[libsigrok.git] / src / hardware / agilent-dmm / protocol.c
1 /*
2  * This file is part of the libsigrok project.
3  *
4  * Copyright (C) 2012 Bert Vermeulen <bert@biot.com>
5  *
6  * This program is free software: you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation, either version 3 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
18  */
19
20 #include <config.h>
21 #include <glib.h>
22 #include <stdlib.h>
23 #include <stdarg.h>
24 #include <string.h>
25 #include <math.h>
26 #include <libsigrok/libsigrok.h>
27 #include "libsigrok-internal.h"
28 #include "protocol.h"
29
30 static void dispatch(const struct sr_dev_inst *sdi)
31 {
32         struct dev_context *devc;
33         const struct agdmm_job *jobs;
34         int64_t now;
35         int i;
36
37         devc = sdi->priv;
38         jobs = devc->profile->jobs;
39         now = g_get_monotonic_time() / 1000;
40         for (i = 0; (&jobs[i])->interval; i++) {
41                 if (now - devc->jobqueue[i] > (&jobs[i])->interval) {
42                         sr_spew("Running job %d.", i);
43                         (&jobs[i])->send(sdi);
44                         devc->jobqueue[i] = now;
45                 }
46         }
47 }
48
49 static void receive_line(const struct sr_dev_inst *sdi)
50 {
51         struct dev_context *devc;
52         const struct agdmm_recv *recvs, *recv;
53         GRegex *reg;
54         GMatchInfo *match;
55         int i;
56
57         devc = sdi->priv;
58
59         /* Strip CRLF */
60         while (devc->buflen) {
61                 if (*(devc->buf + devc->buflen - 1) == '\r'
62                                 || *(devc->buf + devc->buflen - 1) == '\n')
63                         *(devc->buf + --devc->buflen) = '\0';
64                 else
65                         break;
66         }
67         sr_spew("Received '%s'.", devc->buf);
68
69         recv = NULL;
70         recvs = devc->profile->recvs;
71         for (i = 0; (&recvs[i])->recv_regex; i++) {
72                 reg = g_regex_new((&recvs[i])->recv_regex, 0, 0, NULL);
73                 if (g_regex_match(reg, (char *)devc->buf, 0, &match)) {
74                         recv = &recvs[i];
75                         break;
76                 }
77                 g_match_info_unref(match);
78                 g_regex_unref(reg);
79         }
80         if (recv) {
81                 recv->recv(sdi, match);
82                 g_match_info_unref(match);
83                 g_regex_unref(reg);
84         } else
85                 sr_dbg("Unknown line '%s'.", devc->buf);
86
87         /* Done with this. */
88         devc->buflen = 0;
89 }
90
91 SR_PRIV int agdmm_receive_data(int fd, int revents, void *cb_data)
92 {
93         struct sr_dev_inst *sdi;
94         struct dev_context *devc;
95         struct sr_serial_dev_inst *serial;
96         int len;
97
98         (void)fd;
99
100         if (!(sdi = cb_data))
101                 return TRUE;
102
103         if (!(devc = sdi->priv))
104                 return TRUE;
105
106         serial = sdi->conn;
107         if (revents == G_IO_IN) {
108                 /* Serial data arrived. */
109                 while (AGDMM_BUFSIZE - devc->buflen - 1 > 0) {
110                         len = serial_read_nonblocking(serial, devc->buf + devc->buflen, 1);
111                         if (len < 1)
112                                 break;
113                         devc->buflen += len;
114                         *(devc->buf + devc->buflen) = '\0';
115                         if (*(devc->buf + devc->buflen - 1) == '\n') {
116                                 /* End of line */
117                                 receive_line(sdi);
118                                 break;
119                         }
120                 }
121         }
122
123         dispatch(sdi);
124
125         if (sr_sw_limits_check(&devc->limits))
126                 sdi->driver->dev_acquisition_stop(sdi);
127
128         return TRUE;
129 }
130
131 static int agdmm_send(const struct sr_dev_inst *sdi, const char *cmd, ...)
132 {
133         struct sr_serial_dev_inst *serial;
134         va_list args;
135         char buf[32];
136
137         serial = sdi->conn;
138
139         va_start(args, cmd);
140         vsnprintf(buf, sizeof(buf) - 3, cmd, args);
141         va_end(args);
142         sr_spew("Sending '%s'.", buf);
143         if (!strncmp(buf, "*IDN?", 5))
144                 strcat(buf, "\r\n");
145         else
146                 strcat(buf, "\n\r\n");
147         if (serial_write_blocking(serial, buf, strlen(buf), SERIAL_WRITE_TIMEOUT_MS) < (int)strlen(buf)) {
148                 sr_err("Failed to send.");
149                 return SR_ERR;
150         }
151
152         return SR_OK;
153 }
154
155 static int send_stat(const struct sr_dev_inst *sdi)
156 {
157         return agdmm_send(sdi, "STAT?");
158 }
159
160 static int recv_stat_u123x(const struct sr_dev_inst *sdi, GMatchInfo *match)
161 {
162         struct dev_context *devc;
163         char *s;
164
165         devc = sdi->priv;
166         s = g_match_info_fetch(match, 1);
167         sr_spew("STAT response '%s'.", s);
168
169         /* Max, Min or Avg mode -- no way to tell which, so we'll
170          * set both flags to denote it's not a normal measurement. */
171         if (s[0] == '1')
172                 devc->cur_mqflags[0] |= SR_MQFLAG_MAX | SR_MQFLAG_MIN;
173         else
174                 devc->cur_mqflags[0] &= ~(SR_MQFLAG_MAX | SR_MQFLAG_MIN);
175
176         if (s[1] == '1')
177                 devc->cur_mqflags[0] |= SR_MQFLAG_RELATIVE;
178         else
179                 devc->cur_mqflags[0] &= ~SR_MQFLAG_RELATIVE;
180
181         /* Triggered or auto hold modes. */
182         if (s[2] == '1' || s[3] == '1')
183                 devc->cur_mqflags[0] |= SR_MQFLAG_HOLD;
184         else
185                 devc->cur_mqflags[0] &= ~SR_MQFLAG_HOLD;
186
187         /* Temp/aux mode. */
188         if (s[7] == '1')
189                 devc->mode_tempaux = TRUE;
190         else
191                 devc->mode_tempaux = FALSE;
192
193         /* Continuity mode. */
194         if (s[16] == '1')
195                 devc->mode_continuity = TRUE;
196         else
197                 devc->mode_continuity = FALSE;
198
199         g_free(s);
200
201         return SR_OK;
202 }
203
204 static int recv_stat_u124x(const struct sr_dev_inst *sdi, GMatchInfo *match)
205 {
206         struct dev_context *devc;
207         char *s;
208
209         devc = sdi->priv;
210         s = g_match_info_fetch(match, 1);
211         sr_spew("STAT response '%s'.", s);
212
213         /* Max, Min or Avg mode -- no way to tell which, so we'll
214          * set both flags to denote it's not a normal measurement. */
215         if (s[0] == '1')
216                 devc->cur_mqflags[0] |= SR_MQFLAG_MAX | SR_MQFLAG_MIN;
217         else
218                 devc->cur_mqflags[0] &= ~(SR_MQFLAG_MAX | SR_MQFLAG_MIN);
219
220         if (s[1] == '1')
221                 devc->cur_mqflags[0] |= SR_MQFLAG_RELATIVE;
222         else
223                 devc->cur_mqflags[0] &= ~SR_MQFLAG_RELATIVE;
224
225         /* Hold mode. */
226         if (s[7] == '1')
227                 devc->cur_mqflags[0] |= SR_MQFLAG_HOLD;
228         else
229                 devc->cur_mqflags[0] &= ~SR_MQFLAG_HOLD;
230
231         g_free(s);
232
233         return SR_OK;
234 }
235
236 static int recv_stat_u125x(const struct sr_dev_inst *sdi, GMatchInfo *match)
237 {
238         struct dev_context *devc;
239         char *s;
240
241         devc = sdi->priv;
242         s = g_match_info_fetch(match, 1);
243         sr_spew("STAT response '%s'.", s);
244
245         /* dBm/dBV modes. */
246         if ((s[2] & ~0x20) == 'M')
247                 devc->mode_dbm_dbv = devc->cur_unit[0] = SR_UNIT_DECIBEL_MW;
248         else if ((s[2] & ~0x20) == 'V')
249                 devc->mode_dbm_dbv = devc->cur_unit[0] = SR_UNIT_DECIBEL_VOLT;
250         else
251                 devc->mode_dbm_dbv = 0;
252
253         /* Peak hold mode. */
254         if (s[4] == '1')
255                 devc->cur_mqflags[0] |= SR_MQFLAG_MAX;
256         else
257                 devc->cur_mqflags[0] &= ~SR_MQFLAG_MAX;
258
259         /* Triggered hold mode. */
260         if (s[7] == '1')
261                 devc->cur_mqflags[0] |= SR_MQFLAG_HOLD;
262         else
263                 devc->cur_mqflags[0] &= ~SR_MQFLAG_HOLD;
264
265         g_free(s);
266
267         return SR_OK;
268 }
269
270 static int recv_stat_u128x(const struct sr_dev_inst *sdi, GMatchInfo *match)
271 {
272         struct dev_context *devc;
273         char *s;
274
275         devc = sdi->priv;
276         s = g_match_info_fetch(match, 1);
277         sr_spew("STAT response '%s'.", s);
278
279         /* Max, Min or Avg mode -- no way to tell which, so we'll
280          * set both flags to denote it's not a normal measurement. */
281         if (s[0] == '1')
282                 devc->cur_mqflags[0] |= SR_MQFLAG_MAX | SR_MQFLAG_MIN | SR_MQFLAG_AVG;
283         else
284                 devc->cur_mqflags[0] &= ~(SR_MQFLAG_MAX | SR_MQFLAG_MIN | SR_MQFLAG_AVG);
285
286         /* dBm/dBV modes. */
287         if ((s[2] & ~0x20) == 'M')
288                 devc->mode_dbm_dbv = devc->cur_unit[0] = SR_UNIT_DECIBEL_MW;
289         else if ((s[2] & ~0x20) == 'V')
290                 devc->mode_dbm_dbv = devc->cur_unit[0] = SR_UNIT_DECIBEL_VOLT;
291         else
292                 devc->mode_dbm_dbv = 0;
293
294         /* Peak hold mode. */
295         if (s[4] == '4')
296                 devc->cur_mqflags[0] |= SR_MQFLAG_MAX;
297         else
298                 devc->cur_mqflags[0] &= ~SR_MQFLAG_MAX;
299
300         /* Null function. */
301         if (s[1] == '1')
302                 devc->cur_mqflags[0] |= SR_MQFLAG_RELATIVE;
303         else
304                 devc->cur_mqflags[0] &= ~SR_MQFLAG_RELATIVE;
305
306         /* Triggered or auto hold modes. */
307         if (s[7] == '1' || s[11] == '1')
308                 devc->cur_mqflags[0] |= SR_MQFLAG_HOLD;
309         else
310                 devc->cur_mqflags[0] &= ~SR_MQFLAG_HOLD;
311
312         g_free(s);
313
314         return SR_OK;
315 }
316
317 static int send_fetc(const struct sr_dev_inst *sdi)
318 {
319         struct dev_context *devc;
320         devc = sdi->priv;
321         if (devc->mode_squarewave)
322                 return SR_OK;
323         devc->cur_channel = sr_next_enabled_channel(sdi, devc->cur_channel);
324         if (devc->cur_channel->index > 0)
325                 return agdmm_send(sdi, "FETC? @%d", devc->cur_channel->index + 1);
326         else
327                 return agdmm_send(sdi, "FETC?");
328 }
329
330 static int recv_fetc(const struct sr_dev_inst *sdi, GMatchInfo *match)
331 {
332         struct dev_context *devc;
333         struct sr_datafeed_packet packet;
334         struct sr_datafeed_analog analog;
335         struct sr_analog_encoding encoding;
336         struct sr_analog_meaning meaning;
337         struct sr_analog_spec spec;
338         float fvalue;
339         const char *s;
340         char *mstr;
341         int i, exp;
342
343         sr_spew("FETC reply '%s'.", g_match_info_get_string(match));
344         devc = sdi->priv;
345         i = devc->cur_channel->index;
346
347         if (devc->cur_mq[i] == -1)
348                 /* Haven't seen configuration yet, so can't know what
349                  * the fetched float means. Not really an error, we'll
350                  * get metadata soon enough. */
351                 return SR_OK;
352
353         s = g_match_info_get_string(match);
354         if (!strcmp(s, "-9.90000000E+37") || !strcmp(s, "+9.90000000E+37")) {
355                 /* An invalid measurement shows up on the display as "O.L", but
356                  * comes through like this. Since comparing 38-digit floats
357                  * is rather problematic, we'll cut through this here. */
358                 fvalue = NAN;
359         } else {
360                 mstr = g_match_info_fetch(match, 1);
361                 if (sr_atof_ascii(mstr, &fvalue) != SR_OK) {
362                         g_free(mstr);
363                         sr_dbg("Invalid float.");
364                         return SR_ERR;
365                 }
366                 g_free(mstr);
367                 if (devc->cur_exponent[i] != 0)
368                         fvalue *= powf(10, devc->cur_exponent[i]);
369         }
370
371         if (devc->cur_unit[i] == SR_UNIT_DECIBEL_MW ||
372             devc->cur_unit[i] == SR_UNIT_DECIBEL_VOLT ||
373             devc->cur_unit[i] == SR_UNIT_PERCENTAGE) {
374                 mstr = g_match_info_fetch(match, 2);
375                 if (mstr && sr_atoi(mstr, &exp) == SR_OK) {
376                         devc->cur_digits[i] = MIN(4 - exp, devc->cur_digits[i]);
377                         devc->cur_encoding[i] = MIN(5 - exp, devc->cur_encoding[i]);
378                 }
379                 g_free(mstr);
380         }
381
382         sr_analog_init(&analog, &encoding, &meaning, &spec,
383                        devc->cur_digits[i] - devc->cur_exponent[i]);
384         analog.meaning->mq = devc->cur_mq[i];
385         analog.meaning->unit = devc->cur_unit[i];
386         analog.meaning->mqflags = devc->cur_mqflags[i];
387         analog.meaning->channels = g_slist_append(NULL, devc->cur_channel);
388         analog.num_samples = 1;
389         analog.data = &fvalue;
390         encoding.digits = devc->cur_encoding[i] - devc->cur_exponent[i];
391         packet.type = SR_DF_ANALOG;
392         packet.payload = &analog;
393         sr_session_send(sdi, &packet);
394         g_slist_free(analog.meaning->channels);
395
396         sr_sw_limits_update_samples_read(&devc->limits, 1);
397
398         return SR_OK;
399 }
400
401 static int send_conf(const struct sr_dev_inst *sdi)
402 {
403         struct dev_context *devc = sdi->priv;
404
405         devc->cur_conf = sr_next_enabled_channel(sdi, devc->cur_conf);
406
407         /* Do not try to send CONF? for internal temperature channel. */
408         if (devc->cur_conf->index == MAX(devc->profile->nb_channels - 1, 1))
409                 devc->cur_conf = sr_next_enabled_channel(sdi, devc->cur_conf);
410         if (devc->cur_conf->index == MAX(devc->profile->nb_channels - 1, 1))
411                 return SR_ERR_NA;
412
413         if (devc->cur_conf->index > 0)
414                 return agdmm_send(sdi, "CONF? @%d", devc->cur_conf->index + 1);
415         else
416                 return agdmm_send(sdi, "CONF?");
417 }
418
419 static int recv_conf_u123x(const struct sr_dev_inst *sdi, GMatchInfo *match)
420 {
421         struct dev_context *devc;
422         char *mstr, *rstr;
423         int i, resolution;
424
425         sr_spew("CONF? response '%s'.", g_match_info_get_string(match));
426         devc = sdi->priv;
427         i = devc->cur_conf->index;
428
429         rstr = g_match_info_fetch(match, 2);
430         if (rstr)
431                 sr_atoi(rstr, &resolution);
432         g_free(rstr);
433
434         mstr = g_match_info_fetch(match, 1);
435         if (!strcmp(mstr, "V")) {
436                 devc->cur_mq[i] = SR_MQ_VOLTAGE;
437                 devc->cur_unit[i] = SR_UNIT_VOLT;
438                 devc->cur_mqflags[i] = 0;
439                 devc->cur_exponent[i] = 0;
440                 devc->cur_digits[i] = 4 - resolution;
441         } else if (!strcmp(mstr, "MV")) {
442                 if (devc->mode_tempaux) {
443                         devc->cur_mq[i] = SR_MQ_TEMPERATURE;
444                         /* No way to detect whether Fahrenheit or Celsius
445                          * is used, so we'll just default to Celsius. */
446                         devc->cur_unit[i] = SR_UNIT_CELSIUS;
447                         devc->cur_mqflags[i] = 0;
448                         devc->cur_exponent[i] = 0;
449                         devc->cur_digits[i] = 1;
450                 } else {
451                         devc->cur_mq[i] = SR_MQ_VOLTAGE;
452                         devc->cur_unit[i] = SR_UNIT_VOLT;
453                         devc->cur_mqflags[i] = 0;
454                         devc->cur_exponent[i] = -3;
455                         devc->cur_digits[i] = 5 - resolution;
456                 }
457         } else if (!strcmp(mstr, "A")) {
458                 devc->cur_mq[i] = SR_MQ_CURRENT;
459                 devc->cur_unit[i] = SR_UNIT_AMPERE;
460                 devc->cur_mqflags[i] = 0;
461                 devc->cur_exponent[i] = 0;
462                 devc->cur_digits[i] = 3 - resolution;
463         } else if (!strcmp(mstr, "UA")) {
464                 devc->cur_mq[i] = SR_MQ_CURRENT;
465                 devc->cur_unit[i] = SR_UNIT_AMPERE;
466                 devc->cur_mqflags[i] = 0;
467                 devc->cur_exponent[i] = -6;
468                 devc->cur_digits[i] = 8 - resolution;
469         } else if (!strcmp(mstr, "FREQ")) {
470                 devc->cur_mq[i] = SR_MQ_FREQUENCY;
471                 devc->cur_unit[i] = SR_UNIT_HERTZ;
472                 devc->cur_mqflags[i] = 0;
473                 devc->cur_exponent[i] = 0;
474                 devc->cur_digits[i] = 2 - resolution;
475         } else if (!strcmp(mstr, "RES")) {
476                 if (devc->mode_continuity) {
477                         devc->cur_mq[i] = SR_MQ_CONTINUITY;
478                         devc->cur_unit[i] = SR_UNIT_BOOLEAN;
479                 } else {
480                         devc->cur_mq[i] = SR_MQ_RESISTANCE;
481                         devc->cur_unit[i] = SR_UNIT_OHM;
482                 }
483                 devc->cur_mqflags[i] = 0;
484                 devc->cur_exponent[i] = 0;
485                 devc->cur_digits[i] = 1 - resolution;
486         } else if (!strcmp(mstr, "DIOD")) {
487                 devc->cur_mq[i] = SR_MQ_VOLTAGE;
488                 devc->cur_unit[i] = SR_UNIT_VOLT;
489                 devc->cur_mqflags[i] = SR_MQFLAG_DIODE;
490                 devc->cur_exponent[i] = 0;
491                 devc->cur_digits[i] = 3;
492         } else if (!strcmp(mstr, "CAP")) {
493                 devc->cur_mq[i] = SR_MQ_CAPACITANCE;
494                 devc->cur_unit[i] = SR_UNIT_FARAD;
495                 devc->cur_mqflags[i] = 0;
496                 devc->cur_exponent[i] = 0;
497                 devc->cur_digits[i] = 9 - resolution;
498         } else
499                 sr_dbg("Unknown first argument.");
500         g_free(mstr);
501
502         /* This is based on guess, supposing similarity with other models. */
503         devc->cur_encoding[i] = devc->cur_digits[i] + 1;
504
505         if (g_match_info_get_match_count(match) == 4) {
506                 mstr = g_match_info_fetch(match, 3);
507                 /* Third value, if present, is always AC or DC. */
508                 if (!strcmp(mstr, "AC")) {
509                         devc->cur_mqflags[i] |= SR_MQFLAG_AC;
510                         if (devc->cur_mq[i] == SR_MQ_VOLTAGE)
511                                 devc->cur_mqflags[i] |= SR_MQFLAG_RMS;
512                 } else if (!strcmp(mstr, "DC")) {
513                         devc->cur_mqflags[i] |= SR_MQFLAG_DC;
514                 } else {
515                 sr_dbg("Unknown first argument '%s'.", mstr);
516                 }
517                 g_free(mstr);
518         } else
519                 devc->cur_mqflags[i] &= ~(SR_MQFLAG_AC | SR_MQFLAG_DC);
520
521         return SR_OK;
522 }
523
524 static int recv_conf_u124x_5x(const struct sr_dev_inst *sdi, GMatchInfo *match)
525 {
526         struct dev_context *devc;
527         char *mstr, *rstr, *m2;
528         int i, resolution;
529
530         sr_spew("CONF? response '%s'.", g_match_info_get_string(match));
531         devc = sdi->priv;
532         i = devc->cur_conf->index;
533
534         devc->mode_squarewave = 0;
535
536         rstr = g_match_info_fetch(match, 4);
537         if (rstr && sr_atoi(rstr, &resolution) == SR_OK) {
538                 devc->cur_digits[i] = -resolution;
539                 devc->cur_encoding[i] = -resolution + 1;
540         }
541         g_free(rstr);
542
543         mstr = g_match_info_fetch(match, 1);
544         if (!strncmp(mstr, "VOLT", 4)) {
545                 devc->cur_mq[i] = SR_MQ_VOLTAGE;
546                 devc->cur_unit[i] = SR_UNIT_VOLT;
547                 devc->cur_mqflags[i] = 0;
548                 devc->cur_exponent[i] = 0;
549                 if (i == 0 && devc->mode_dbm_dbv) {
550                         devc->cur_unit[i] = devc->mode_dbm_dbv;
551                         devc->cur_digits[i] = 3;
552                         devc->cur_encoding[i] = 4;
553                 }
554                 if (mstr[4] == ':') {
555                         if (!strncmp(mstr + 5, "ACDC", 4)) {
556                                 /* AC + DC offset */
557                                 devc->cur_mqflags[i] |= SR_MQFLAG_AC | SR_MQFLAG_DC | SR_MQFLAG_RMS;
558                         } else if (!strncmp(mstr + 5, "AC", 2)) {
559                                 devc->cur_mqflags[i] |= SR_MQFLAG_AC | SR_MQFLAG_RMS;
560                         } else if (!strncmp(mstr + 5, "DC", 2)) {
561                                 devc->cur_mqflags[i] |= SR_MQFLAG_DC;
562                         }
563                 } else
564                         devc->cur_mqflags[i] |= SR_MQFLAG_DC;
565         } else if (!strncmp(mstr, "CURR", 4)) {
566                 devc->cur_mq[i] = SR_MQ_CURRENT;
567                 devc->cur_unit[i] = SR_UNIT_AMPERE;
568                 devc->cur_mqflags[i] = 0;
569                 devc->cur_exponent[i] = 0;
570                 if (mstr[4] == ':') {
571                         if (!strncmp(mstr + 5, "ACDC", 4)) {
572                                 /* AC + DC offset */
573                                 devc->cur_mqflags[i] |= SR_MQFLAG_AC | SR_MQFLAG_DC | SR_MQFLAG_RMS;
574                         } else if (!strncmp(mstr + 5, "AC", 2)) {
575                                 devc->cur_mqflags[i] |= SR_MQFLAG_AC | SR_MQFLAG_RMS;
576                         } else if (!strncmp(mstr + 5, "DC", 2)) {
577                                 devc->cur_mqflags[i] |= SR_MQFLAG_DC;
578                         }
579                 } else
580                         devc->cur_mqflags[i] |= SR_MQFLAG_DC;
581         } else if (!strcmp(mstr, "RES")) {
582                 devc->cur_mq[i] = SR_MQ_RESISTANCE;
583                 devc->cur_unit[i] = SR_UNIT_OHM;
584                 devc->cur_mqflags[i] = 0;
585                 devc->cur_exponent[i] = 0;
586         } else if (!strcmp(mstr, "COND")) {
587                 devc->cur_mq[i] = SR_MQ_CONDUCTANCE;
588                 devc->cur_unit[i] = SR_UNIT_SIEMENS;
589                 devc->cur_mqflags[i] = 0;
590                 devc->cur_exponent[i] = 0;
591         } else if (!strcmp(mstr, "CAP")) {
592                 devc->cur_mq[i] = SR_MQ_CAPACITANCE;
593                 devc->cur_unit[i] = SR_UNIT_FARAD;
594                 devc->cur_mqflags[i] = 0;
595                 devc->cur_exponent[i] = 0;
596         } else if (!strncmp(mstr, "FREQ", 4) || !strncmp(mstr, "FC1", 3)) {
597                 devc->cur_mq[i] = SR_MQ_FREQUENCY;
598                 devc->cur_unit[i] = SR_UNIT_HERTZ;
599                 devc->cur_mqflags[i] = 0;
600                 devc->cur_exponent[i] = 0;
601         } else if (!strncmp(mstr, "PULS:PWID", 9)) {
602                 devc->cur_mq[i] = SR_MQ_PULSE_WIDTH;
603                 devc->cur_unit[i] = SR_UNIT_SECOND;
604                 devc->cur_mqflags[i] = 0;
605                 devc->cur_exponent[i] = 0;
606                 devc->cur_encoding[i] = MIN(devc->cur_encoding[i], 6);
607         } else if (!strncmp(mstr, "PULS:PDUT", 9)) {
608                 devc->cur_mq[i] = SR_MQ_DUTY_CYCLE;
609                 devc->cur_unit[i] = SR_UNIT_PERCENTAGE;
610                 devc->cur_mqflags[i] = 0;
611                 devc->cur_exponent[i] = 0;
612                 devc->cur_digits[i] = 3;
613                 devc->cur_encoding[i] = 4;
614         } else if (!strcmp(mstr, "CONT")) {
615                 devc->cur_mq[i] = SR_MQ_CONTINUITY;
616                 devc->cur_unit[i] = SR_UNIT_BOOLEAN;
617                 devc->cur_mqflags[i] = 0;
618                 devc->cur_exponent[i] = 0;
619         } else if (!strcmp(mstr, "DIOD")) {
620                 devc->cur_mq[i] = SR_MQ_VOLTAGE;
621                 devc->cur_unit[i] = SR_UNIT_VOLT;
622                 devc->cur_mqflags[i] = SR_MQFLAG_DIODE;
623                 devc->cur_exponent[i] = 0;
624                 devc->cur_digits[i] = 4;
625                 devc->cur_encoding[i] = 5;
626         } else if (!strncmp(mstr, "T1", 2) || !strncmp(mstr, "T2", 2) ||
627                    !strncmp(mstr, "TEMP", 2)) {
628                 devc->cur_mq[i] = SR_MQ_TEMPERATURE;
629                 m2 = g_match_info_fetch(match, 2);
630                 if (!m2)
631                         /*
632                          * TEMP without param is for secondary display (channel P2)
633                          * and is identical to channel P3, so discard it.
634                          */
635                         devc->cur_mq[i] = -1;
636                 else if (!strcmp(m2, "FAR"))
637                         devc->cur_unit[i] = SR_UNIT_FAHRENHEIT;
638                 else
639                         devc->cur_unit[i] = SR_UNIT_CELSIUS;
640                 g_free(m2);
641                 devc->cur_mqflags[i] = 0;
642                 devc->cur_exponent[i] = 0;
643                 devc->cur_digits[i] = 1;
644                 devc->cur_encoding[i] = 2;
645         } else if (!strcmp(mstr, "SCOU")) {
646                 /*
647                  * Switch counter, not supported. Not sure what values
648                  * come from FETC in this mode, or how they would map
649                  * into libsigrok.
650                  */
651         } else if (!strncmp(mstr, "CPER:", 5)) {
652                 devc->cur_mq[i] = SR_MQ_CURRENT;
653                 devc->cur_unit[i] = SR_UNIT_PERCENTAGE;
654                 devc->cur_mqflags[i] = 0;
655                 devc->cur_exponent[i] = 0;
656                 devc->cur_digits[i] = 2;
657                 devc->cur_encoding[i] = 3;
658         } else if (!strcmp(mstr, "SQU")) {
659                 /*
660                  * Square wave output, not supported. FETC just return
661                  * an error in this mode, so don't even call it.
662                  */
663                 devc->mode_squarewave = 1;
664         } else {
665                 sr_dbg("Unknown first argument '%s'.", mstr);
666         }
667         g_free(mstr);
668
669         return SR_OK;
670 }
671
672 /* This comes in whenever the rotary switch is changed to a new position.
673  * We could use it to determine the major measurement mode, but we already
674  * have the output of CONF? for that, which is more detailed. However
675  * we do need to catch this here, or it'll show up in some other output. */
676 static int recv_switch(const struct sr_dev_inst *sdi, GMatchInfo *match)
677 {
678         (void)sdi;
679
680         sr_spew("Switch '%s'.", g_match_info_get_string(match));
681
682         return SR_OK;
683 }
684
685 /* Poll keys/switches and values at 7Hz, mode at 1Hz. */
686 SR_PRIV const struct agdmm_job agdmm_jobs_u12xx[] = {
687         { 143, send_stat },
688         { 1000, send_conf },
689         { 143, send_fetc },
690         ALL_ZERO
691 };
692
693 SR_PRIV const struct agdmm_recv agdmm_recvs_u123x[] = {
694         { "^\"(\\d\\d.{18}\\d)\"$", recv_stat_u123x },
695         { "^\\*([0-9])$", recv_switch },
696         { "^([-+][0-9]\\.[0-9]{8}E[-+][0-9]{2})$", recv_fetc },
697         { "^\"(V|MV|A|UA|FREQ),(\\d),(AC|DC)\"$", recv_conf_u123x },
698         { "^\"(RES|CAP),(\\d)\"$", recv_conf_u123x},
699         { "^\"(DIOD)\"$", recv_conf_u123x },
700         ALL_ZERO
701 };
702
703 SR_PRIV const struct agdmm_recv agdmm_recvs_u124x[] = {
704         { "^\"(\\d\\d.{18}\\d)\"$", recv_stat_u124x },
705         { "^\\*([0-9])$", recv_switch },
706         { "^([-+][0-9]\\.[0-9]{8}E[-+][0-9]{2})$", recv_fetc },
707         { "^\"(VOLT|CURR|RES|CAP|FREQ) ([-+][0-9\\.E\\-+]+),([-+][0-9]\\.[0-9]{8}E([-+][0-9]{2}))\"$", recv_conf_u124x_5x },
708         { "^\"(VOLT:[ACD]+) ([-+][0-9\\.E\\-+]+),([-+][0-9]\\.[0-9]{8}E([-+][0-9]{2}))\"$", recv_conf_u124x_5x },
709         { "^\"(CURR:[ACD]+) ([-+][0-9\\.E\\-+]+),([-+][0-9]\\.[0-9]{8}E([-+][0-9]{2}))\"$", recv_conf_u124x_5x },
710         { "^\"(CPER:[40]-20mA) ([-+][0-9\\.E\\-+]+),([-+][0-9]\\.[0-9]{8}E([-+][0-9]{2}))\"$", recv_conf_u124x_5x },
711         { "^\"(T[0-9]:[A-Z]+) ([A-Z]+)\"$", recv_conf_u124x_5x },
712         { "^\"(DIOD)\"$", recv_conf_u124x_5x },
713         ALL_ZERO
714 };
715
716 SR_PRIV const struct agdmm_recv agdmm_recvs_u125x[] = {
717         { "^\"(\\d\\d.{18}\\d)\"$", recv_stat_u125x },
718         { "^\\*([0-9])$", recv_switch },
719         { "^([-+][0-9]\\.[0-9]{8}E[-+][0-9]{2})$", recv_fetc },
720         { "^\"(VOLT|CURR|RES|CAP|FREQ) ([-+][0-9\\.E\\-+]+),([-+][0-9]\\.[0-9]{8}E([-+][0-9]{2}))\"$", recv_conf_u124x_5x },
721         { "^\"(VOLT:[ACD]+) ([-+][0-9\\.E\\-+]+),([-+][0-9]\\.[0-9]{8}E([-+][0-9]{2}))\"$", recv_conf_u124x_5x },
722         { "^\"(CURR:[ACD]+) ([-+][0-9\\.E\\-+]+),([-+][0-9]\\.[0-9]{8}E([-+][0-9]{2}))\"$", recv_conf_u124x_5x },
723         { "^\"(CPER:[40]-20mA) ([-+][0-9\\.E\\-+]+),([-+][0-9]\\.[0-9]{8}E([-+][0-9]{2}))\"$", recv_conf_u124x_5x },
724         { "^\"(T[0-9]:[A-Z]+) ([A-Z]+)\"$", recv_conf_u124x_5x },
725         { "^\"(DIOD)\"$", recv_conf_u124x_5x },
726         ALL_ZERO
727 };
728
729 SR_PRIV const struct agdmm_recv agdmm_recvs_u128x[] = {
730         { "^\"(\\d\\d.{18}\\d)\"$", recv_stat_u128x },
731         { "^\\*([0-9])$", recv_switch },
732         { "^([-+][0-9]\\.[0-9]{8}E([-+][0-9]{2}))$", recv_fetc },
733         { "^\"(VOLT|CURR|RES|COND|CAP|FREQ|FC1|FC100) ([-+][0-9\\.E\\-+]+),([-+][0-9]\\.[0-9]{8}E([-+][0-9]{2}))\"$", recv_conf_u124x_5x },
734         { "^\"(VOLT:[ACD]+) ([-+][0-9\\.E\\-+]+),([-+][0-9]\\.[0-9]{8}E([-+][0-9]{2}))\"$", recv_conf_u124x_5x },
735         { "^\"(CURR:[ACD]+) ([-+][0-9\\.E\\-+]+),([-+][0-9]\\.[0-9]{8}E([-+][0-9]{2}))\"$", recv_conf_u124x_5x },
736         { "^\"(FREQ:[ACD]+) ([-+][0-9\\.E\\-+]+),([-+][0-9]\\.[0-9]{8}E([-+][0-9]{2}))\"$", recv_conf_u124x_5x },
737         { "^\"(CPER:[40]-20mA) ([-+][0-9\\.E\\-+]+),([-+][0-9]\\.[0-9]{8}E([-+][0-9]{2}))\"$", recv_conf_u124x_5x },
738         { "^\"(PULS:PWID|PULS:PWID:[ACD]+) ([-+][0-9\\.E\\-+]+),([-+][0-9]\\.[0-9]{8}E([-+][0-9]{2}))\"$", recv_conf_u124x_5x },
739         { "^\"(TEMP:[A-Z]+) ([A-Z]+)\"$", recv_conf_u124x_5x },
740         { "^\"(DIOD|SQU|PULS:PDUT|TEMP)\"$", recv_conf_u124x_5x },
741         ALL_ZERO
742 };