]> sigrok.org Git - libsigrok.git/blob - src/hardware/scpi-dmm/protocol.c
scpi-dmm: Add support for Owon XDM2041
[libsigrok.git] / src / hardware / scpi-dmm / protocol.c
1 /*
2  * This file is part of the libsigrok project.
3  *
4  * Copyright (C) 2018 Gerhard Sittig <gerhard.sittig@gmx.net>
5  *
6  * This program is free software: you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation, either version 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 <math.h>
22 #include <string.h>
23 #include "protocol.h"
24
25 #define WITH_CMD_DELAY 0        /* TODO See which devices need delays. */
26
27 SR_PRIV void scpi_dmm_cmd_delay(struct sr_scpi_dev_inst *scpi)
28 {
29         if (WITH_CMD_DELAY)
30                 g_usleep(WITH_CMD_DELAY * 1000);
31
32         if (!scpi->no_opc_command)
33                 sr_scpi_get_opc(scpi);
34 }
35
36 SR_PRIV const struct mqopt_item *scpi_dmm_lookup_mq_number(
37         const struct sr_dev_inst *sdi, enum sr_mq mq, enum sr_mqflag flag)
38 {
39         struct dev_context *devc;
40         size_t i;
41         const struct mqopt_item *item;
42
43         devc = sdi->priv;
44         for (i = 0; i < devc->model->mqopt_size; i++) {
45                 item = &devc->model->mqopts[i];
46                 if (item->mq != mq || item->mqflag != flag)
47                         continue;
48                 return item;
49         }
50
51         return NULL;
52 }
53
54 SR_PRIV const struct mqopt_item *scpi_dmm_lookup_mq_text(
55         const struct sr_dev_inst *sdi, const char *text)
56 {
57         struct dev_context *devc;
58         size_t i;
59         const struct mqopt_item *item;
60
61         devc = sdi->priv;
62         for (i = 0; i < devc->model->mqopt_size; i++) {
63                 item = &devc->model->mqopts[i];
64                 if (!item->scpi_func_query || !item->scpi_func_query[0])
65                         continue;
66                 if (!g_str_has_prefix(text, item->scpi_func_query))
67                         continue;
68                 return item;
69         }
70
71         return NULL;
72 }
73
74 SR_PRIV int scpi_dmm_get_mq(const struct sr_dev_inst *sdi,
75         enum sr_mq *mq, enum sr_mqflag *flag, char **rsp,
76         const struct mqopt_item **mqitem)
77 {
78         struct dev_context *devc;
79         const char *command;
80         char *response;
81         const char *have;
82         int ret;
83         const struct mqopt_item *item;
84
85         devc = sdi->priv;
86         if (mq)
87                 *mq = 0;
88         if (flag)
89                 *flag = 0;
90         if (rsp)
91                 *rsp = NULL;
92         if (mqitem)
93                 *mqitem = NULL;
94
95         scpi_dmm_cmd_delay(sdi->conn);
96         command = sr_scpi_cmd_get(devc->cmdset, DMM_CMD_QUERY_FUNC);
97         if (!command || !*command)
98                 return SR_ERR_NA;
99         response = NULL;
100         ret = sr_scpi_get_string(sdi->conn, command, &response);
101         if (ret != SR_OK)
102                 return ret;
103         if (!response || !*response)
104                 return SR_ERR_NA;
105         have = response;
106         if (*have == '"')
107                 have++;
108
109         ret = SR_ERR_NA;
110         item = scpi_dmm_lookup_mq_text(sdi, have);
111         if (item) {
112                 if (mq)
113                         *mq = item->mq;
114                 if (flag)
115                         *flag = item->mqflag;
116                 if (mqitem)
117                         *mqitem = item;
118                 ret = SR_OK;
119         } else {
120                 sr_warn("Unknown measurement quantity: %s", have);
121         }
122
123         if (rsp) {
124                 *rsp = response;
125                 response = NULL;
126         }
127         g_free(response);
128
129         return ret;
130 }
131
132 SR_PRIV int scpi_dmm_set_mq(const struct sr_dev_inst *sdi,
133         enum sr_mq mq, enum sr_mqflag flag)
134 {
135         struct dev_context *devc;
136         const struct mqopt_item *item;
137         const char *mode, *command;
138         int ret;
139
140         devc = sdi->priv;
141         item = scpi_dmm_lookup_mq_number(sdi, mq, flag);
142         if (!item)
143                 return SR_ERR_NA;
144
145         mode = item->scpi_func_setup;
146         command = sr_scpi_cmd_get(devc->cmdset, DMM_CMD_SETUP_FUNC);
147         scpi_dmm_cmd_delay(sdi->conn);
148         ret = sr_scpi_send(sdi->conn, command, mode);
149         if (ret != SR_OK)
150                 return ret;
151
152         return SR_OK;
153 }
154
155 SR_PRIV int scpi_dmm_get_meas_agilent(const struct sr_dev_inst *sdi, size_t ch)
156 {
157         struct sr_scpi_dev_inst *scpi;
158         struct dev_context *devc;
159         struct scpi_dmm_acq_info *info;
160         struct sr_datafeed_analog *analog;
161         int ret;
162         enum sr_mq mq;
163         enum sr_mqflag mqflag;
164         char *mode_response;
165         const char *p;
166         char **fields;
167         size_t count;
168         char prec_text[20];
169         const struct mqopt_item *item;
170         int prec_exp;
171         const char *command;
172         char *response;
173         gboolean use_double;
174         int sig_digits, val_exp;
175         int digits;
176         enum sr_unit unit;
177         double limit;
178
179         scpi = sdi->conn;
180         devc = sdi->priv;
181         info = &devc->run_acq_info;
182         analog = &info->analog[ch];
183
184         /*
185          * Get the meter's current mode, keep the response around.
186          * Skip the measurement if the mode is uncertain.
187          */
188         ret = scpi_dmm_get_mq(sdi, &mq, &mqflag, &mode_response, &item);
189         if (ret != SR_OK) {
190                 g_free(mode_response);
191                 return ret;
192         }
193         if (!mode_response)
194                 return SR_ERR;
195         if (!mq) {
196                 g_free(mode_response);
197                 return +1;
198         }
199
200         /*
201          * Get the last comma separated field of the function query
202          * response, or fallback to the model's default precision for
203          * the current function. This copes with either of these cases:
204          *   VOLT +1.00000E-01,+1.00000E-06
205          *   DIOD
206          *   TEMP THER,5000,+1.00000E+00,+1.00000E-01
207          */
208         p = sr_scpi_unquote_string(mode_response);
209         fields = g_strsplit(p, ",", 0);
210         count = g_strv_length(fields);
211         if (count >= 2) {
212                 snprintf(prec_text, sizeof(prec_text),
213                         "%s", fields[count - 1]);
214                 p = prec_text;
215         } else if (!item) {
216                 p = NULL;
217         } else if (item->default_precision == NO_DFLT_PREC) {
218                 p = NULL;
219         } else {
220                 snprintf(prec_text, sizeof(prec_text),
221                         "1e%d", item->default_precision);
222                 p = prec_text;
223         }
224         g_strfreev(fields);
225
226         /*
227          * Need to extract the exponent value ourselves, since a strtod()
228          * call will "eat" the exponent, too. Strip space, strip sign,
229          * strip float number (without! exponent), check for exponent
230          * and get exponent value. Accept absence of Esnn suffixes.
231          */
232         while (p && *p && g_ascii_isspace(*p))
233                 p++;
234         if (p && *p && (*p == '+' || *p == '-'))
235                 p++;
236         while (p && *p && g_ascii_isdigit(*p))
237                 p++;
238         if (p && *p && *p == '.')
239                 p++;
240         while (p && *p && g_ascii_isdigit(*p))
241                 p++;
242         ret = SR_OK;
243         if (!p || !*p)
244                 prec_exp = 0;
245         else if (*p != 'e' && *p != 'E')
246                 ret = SR_ERR_DATA;
247         else
248                 ret = sr_atoi(++p, &prec_exp);
249         g_free(mode_response);
250         if (ret != SR_OK)
251                 return ret;
252
253         /*
254          * Get the measurement value. Make sure to strip trailing space
255          * or else number conversion may fail in fatal ways. Detect OL
256          * conditions. Determine the measurement's precision: Count the
257          * number of significant digits before the period, and get the
258          * exponent's value.
259          *
260          * The text presentation of values is like this:
261          *   +1.09450000E-01
262          * Skip space/sign, count digits before the period, skip to the
263          * exponent, get exponent value.
264          *
265          * TODO Can sr_parse_rational() return the exponent for us? In
266          * addition to providing a precise rational value instead of a
267          * float that's an approximation of the received value? Can the
268          * 'analog' struct that we fill in carry rationals?
269          *
270          * Use double precision FP here during conversion. Optionally
271          * downgrade to single precision later to reduce the amount of
272          * logged information.
273          */
274         command = sr_scpi_cmd_get(devc->cmdset, DMM_CMD_QUERY_VALUE);
275         if (!command || !*command)
276                 return SR_ERR_NA;
277         scpi_dmm_cmd_delay(scpi);
278         ret = sr_scpi_get_string(scpi, command, &response);
279         if (ret != SR_OK)
280                 return ret;
281         g_strstrip(response);
282         use_double = devc->model->digits > 6;
283         ret = sr_atod_ascii(response, &info->d_value);
284         if (ret != SR_OK) {
285                 g_free(response);
286                 return ret;
287         }
288         if (!response)
289                 return SR_ERR;
290         limit = 9e37;
291         if (info->d_value > +limit) {
292                 info->d_value = +INFINITY;
293         } else if (info->d_value < -limit) {
294                 info->d_value = -INFINITY;
295         } else {
296                 p = response;
297                 while (p && *p && g_ascii_isspace(*p))
298                         p++;
299                 if (p && *p && (*p == '-' || *p == '+'))
300                         p++;
301                 sig_digits = 0;
302                 while (p && *p && g_ascii_isdigit(*p)) {
303                         sig_digits++;
304                         p++;
305                 }
306                 if (p && *p && *p == '.')
307                         p++;
308                 while (p && *p && g_ascii_isdigit(*p))
309                         p++;
310                 ret = SR_OK;
311                 if (!p || !*p)
312                         val_exp = 0;
313                 else if (*p != 'e' && *p != 'E')
314                         ret = SR_ERR_DATA;
315                 else
316                         ret = sr_atoi(++p, &val_exp);
317         }
318         g_free(response);
319         if (ret != SR_OK)
320                 return ret;
321         /*
322          * TODO Come up with the most appropriate 'digits' calculation.
323          * This implementation assumes that either the device provides
324          * the resolution with the query for the meter's function, or
325          * the driver uses a fallback text pretending the device had
326          * provided it. This works with supported Agilent devices.
327          *
328          * An alternative may be to assume a given digits count which
329          * depends on the device, and adjust that count based on the
330          * value's significant digits and exponent. But this approach
331          * fails if devices change their digits count depending on
332          * modes or user requests, and also fails when e.g. devices
333          * with "100000 counts" can provide values between 100000 and
334          * 120000 in either 4 or 5 digits modes, depending on the most
335          * recent trend of the values. This less robust approach should
336          * only be taken if the mode inquiry won't yield the resolution
337          * (as e.g. DIOD does on 34405A, though we happen to know the
338          * fixed resolution for this very mode on this very model).
339          *
340          * For now, let's keep the prepared code path for the second
341          * approach in place, should some Agilent devices need it yet
342          * benefit from re-using most of the remaining acquisition
343          * routine.
344          */
345 #if 1
346         digits = -prec_exp;
347 #else
348         digits = devc->model->digits;
349         digits -= sig_digits;
350         digits -= val_exp;
351 #endif
352
353         /*
354          * Fill in the 'analog' description: value, encoding, meaning.
355          * Callers will fill in the sample count, and channel name,
356          * and will send out the packet.
357          */
358         if (use_double) {
359                 analog->data = &info->d_value;
360                 analog->encoding->unitsize = sizeof(info->d_value);
361         } else {
362                 info->f_value = info->d_value;
363                 analog->data = &info->f_value;
364                 analog->encoding->unitsize = sizeof(info->f_value);
365         }
366         analog->encoding->digits = digits;
367         analog->meaning->mq = mq;
368         analog->meaning->mqflags = mqflag;
369         switch (mq) {
370         case SR_MQ_VOLTAGE:
371                 unit = SR_UNIT_VOLT;
372                 break;
373         case SR_MQ_CURRENT:
374                 unit = SR_UNIT_AMPERE;
375                 break;
376         case SR_MQ_RESISTANCE:
377         case SR_MQ_CONTINUITY:
378                 unit = SR_UNIT_OHM;
379                 break;
380         case SR_MQ_CAPACITANCE:
381                 unit = SR_UNIT_FARAD;
382                 break;
383         case SR_MQ_TEMPERATURE:
384                 unit = SR_UNIT_CELSIUS;
385                 break;
386         case SR_MQ_FREQUENCY:
387                 unit = SR_UNIT_HERTZ;
388                 break;
389         case SR_MQ_TIME:
390                 unit = SR_UNIT_SECOND;
391                 break;
392         default:
393                 return SR_ERR_NA;
394         }
395         analog->meaning->unit = unit;
396         analog->spec->spec_digits = digits;
397
398         return SR_OK;
399 }
400
401 SR_PRIV int scpi_dmm_get_meas_gwinstek(const struct sr_dev_inst *sdi, size_t ch)
402 {
403         struct sr_scpi_dev_inst *scpi;
404         struct dev_context *devc;
405         struct scpi_dmm_acq_info *info;
406         struct sr_datafeed_analog *analog;
407         int ret;
408         enum sr_mq mq;
409         enum sr_mqflag mqflag;
410         char *mode_response;
411         const char *p;
412         const struct mqopt_item *item;
413         const char *command;
414         char *response;
415         gboolean use_double;
416         double limit;
417         int sig_digits, val_exp;
418         int digits;
419         enum sr_unit unit;
420         int mmode;
421
422         scpi = sdi->conn;
423         devc = sdi->priv;
424         info = &devc->run_acq_info;
425         analog = &info->analog[ch];
426
427         /*
428          * Get the meter's current mode, keep the response around.
429          * Skip the measurement if the mode is uncertain.
430          */
431         ret = scpi_dmm_get_mq(sdi, &mq, &mqflag, &mode_response, &item);
432         if (ret != SR_OK) {
433                 g_free(mode_response);
434                 return ret;
435         }
436         if (!mode_response)
437                 return SR_ERR;
438         if (!mq) {
439                 g_free(mode_response);
440                 return +1;
441         }
442         mmode = atoi(mode_response);
443         g_free(mode_response);
444
445         /*
446          * Get the current reading from the meter.
447          */
448         scpi_dmm_cmd_delay(scpi);
449         command = sr_scpi_cmd_get(devc->cmdset, DMM_CMD_QUERY_VALUE);
450         if (!command || !*command)
451                 return SR_ERR_NA;
452         scpi_dmm_cmd_delay(scpi);
453         ret = sr_scpi_get_string(scpi, command, &response);
454         if (ret != SR_OK)
455                 return ret;
456         g_strstrip(response);
457         use_double = devc->model->digits > 6;
458         ret = sr_atod_ascii(response, &info->d_value);
459         if (ret != SR_OK) {
460                 g_free(response);
461                 return ret;
462         }
463         if (!response)
464                 return SR_ERR;
465         limit = 9e37;
466         if (devc->model->infinity_limit != 0.0)
467                 limit = devc->model->infinity_limit;
468         if (info->d_value >= +limit) {
469                 info->d_value = +INFINITY;
470         } else if (info->d_value <= -limit) {
471                 info->d_value = -INFINITY;
472         } else {
473                 p = response;
474                 while (p && *p && g_ascii_isspace(*p))
475                         p++;
476                 if (p && *p && (*p == '-' || *p == '+'))
477                         p++;
478                 sig_digits = 0;
479                 while (p && *p && g_ascii_isdigit(*p)) {
480                         sig_digits++;
481                         p++;
482                 }
483                 if (p && *p && *p == '.')
484                         p++;
485                 while (p && *p && g_ascii_isdigit(*p))
486                         p++;
487                 ret = SR_OK;
488                 if (!p || !*p)
489                         val_exp = 0;
490                 else if (*p != 'e' && *p != 'E')
491                         ret = SR_ERR_DATA;
492                 else
493                         ret = sr_atoi(++p, &val_exp);
494         }
495         g_free(response);
496         if (ret != SR_OK)
497                 return ret;
498
499         /*
500          * Make sure we report "INFINITY" when meter displays "0L".
501          */
502         switch (mmode) {
503         case 7:
504         case 16:
505                 /* In resitance modes 0L reads as 1.20000E8 or 1.99999E8. */
506                 limit = 1.2e8;
507                 if (strcmp(devc->model->model, "GDM8255A") == 0)
508                         limit = 1.99999e8;
509                 if (info->d_value >= limit)
510                         info->d_value = +INFINITY;
511                 break;
512         case 13:
513                 /* In continuity mode 0L reads as 1.20000E3. */
514                 if (info->d_value >= 1.2e3)
515                         info->d_value = +INFINITY;
516                 break;
517         case 17:
518                 /* In diode mode 0L reads as 1.00000E0. */
519                 if (info->d_value == 1.0e0)
520                         info->d_value = +INFINITY;
521                 break;
522         }
523
524         /*
525          * Calculate 'digits' based on the result of the optional
526          * precision reading which was done at acquisition start.
527          * The GW-Instek manual gives the following information
528          * regarding the resolution:
529          *
530          * Type      Digit
531          * --------  ------
532          * Slow      5 1/2
533          * Medium    4 1/2
534          * Fast      3 1/2
535          */
536         digits = devc->model->digits;
537         if (devc->precision && *devc->precision) {
538                 if (g_str_has_prefix(devc->precision, "Slow"))
539                         digits = 6;
540                 else if (g_str_has_prefix(devc->precision, "Mid"))
541                         digits = 5;
542                 else if (g_str_has_prefix(devc->precision, "Fast"))
543                         digits = 4;
544                 else
545                         sr_info("Unknown precision: '%s'", devc->precision);
546         }
547
548         /*
549          * Fill in the 'analog' description: value, encoding, meaning.
550          * Callers will fill in the sample count, and channel name,
551          * and will send out the packet.
552          */
553         if (use_double) {
554                 analog->data = &info->d_value;
555                 analog->encoding->unitsize = sizeof(info->d_value);
556         } else {
557                 info->f_value = info->d_value;
558                 analog->data = &info->f_value;
559                 analog->encoding->unitsize = sizeof(info->f_value);
560         }
561         analog->encoding->digits = digits;
562         analog->meaning->mq = mq;
563         analog->meaning->mqflags = mqflag;
564         switch (mq) {
565         case SR_MQ_VOLTAGE:
566                 unit = SR_UNIT_VOLT;
567                 break;
568         case SR_MQ_CURRENT:
569                 unit = SR_UNIT_AMPERE;
570                 break;
571         case SR_MQ_RESISTANCE:
572         case SR_MQ_CONTINUITY:
573                 unit = SR_UNIT_OHM;
574                 break;
575         case SR_MQ_CAPACITANCE:
576                 unit = SR_UNIT_FARAD;
577                 break;
578         case SR_MQ_TEMPERATURE:
579                 switch (mmode) {
580                 case 15:
581                         unit = SR_UNIT_FAHRENHEIT;
582                         break;
583                 case 9:
584                 default:
585                         unit = SR_UNIT_CELSIUS;
586                 }
587                 break;
588         case SR_MQ_FREQUENCY:
589                 unit = SR_UNIT_HERTZ;
590                 break;
591         case SR_MQ_TIME:
592                 unit = SR_UNIT_SECOND;
593                 break;
594         default:
595                 return SR_ERR_NA;
596         }
597         analog->meaning->unit = unit;
598         analog->spec->spec_digits = digits;
599
600         return SR_OK;
601 }
602
603 /* Strictly speaking this is a timer controlled poll routine. */
604 SR_PRIV int scpi_dmm_receive_data(int fd, int revents, void *cb_data)
605 {
606         struct sr_dev_inst *sdi;
607         struct sr_scpi_dev_inst *scpi;
608         struct dev_context *devc;
609         struct scpi_dmm_acq_info *info;
610         gboolean sent_sample;
611         size_t ch;
612         struct sr_channel *channel;
613         int ret;
614
615         (void)fd;
616         (void)revents;
617
618         sdi = cb_data;
619         if (!sdi)
620                 return TRUE;
621         scpi = sdi->conn;
622         devc = sdi->priv;
623         if (!scpi || !devc)
624                 return TRUE;
625         info = &devc->run_acq_info;
626
627         sent_sample = FALSE;
628         ret = SR_OK;
629         for (ch = 0; ch < devc->num_channels; ch++) {
630                 /* Check the channel's enabled status. */
631                 channel = g_slist_nth_data(sdi->channels, ch);
632                 if (!channel->enabled)
633                         continue;
634
635                 /*
636                  * Prepare an analog measurement value. Note that digits
637                  * will get updated later.
638                  */
639                 info->packet.type = SR_DF_ANALOG;
640                 info->packet.payload = &info->analog[ch];
641                 sr_analog_init(&info->analog[ch], &info->encoding[ch],
642                         &info->meaning[ch], &info->spec[ch], 0);
643
644                 /* Just check OPC before sending another request. */
645                 scpi_dmm_cmd_delay(sdi->conn);
646
647                 /*
648                  * Have the model take and interpret a measurement. Lack
649                  * of support is pointless, failed retrieval/conversion
650                  * is considered fatal. The routine will fill in the
651                  * 'analog' details, except for channel name and sample
652                  * count (assume one value per channel).
653                  *
654                  * Note that non-zero non-negative return codes signal
655                  * that the channel's data shell get skipped in this
656                  * iteration over the channels. This copes with devices
657                  * or modes where channels may provide data at different
658                  * rates.
659                  */
660                 if (!devc->model->get_measurement) {
661                         ret = SR_ERR_NA;
662                         break;
663                 }
664                 ret = devc->model->get_measurement(sdi, ch);
665                 if (ret > 0)
666                         continue;
667                 if (ret != SR_OK)
668                         break;
669
670                 /* Send the packet that was filled in by the model's routine. */
671                 info->analog[ch].num_samples = 1;
672                 info->analog[ch].meaning->channels = g_slist_append(NULL, channel);
673                 sr_session_send(sdi, &info->packet);
674                 g_slist_free(info->analog[ch].meaning->channels);
675                 sent_sample = TRUE;
676         }
677         if (sent_sample)
678                 sr_sw_limits_update_samples_read(&devc->limits, 1);
679         if (ret != SR_OK) {
680                 /* Stop acquisition upon communication or data errors. */
681                 sr_dev_acquisition_stop(sdi);
682                 return TRUE;
683         }
684         if (sr_sw_limits_check(&devc->limits))
685                 sr_dev_acquisition_stop(sdi);
686
687         return TRUE;
688 }