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