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