2 * This file is part of the libsigrok project.
4 * Copyright (C) 2012 Bert Vermeulen <bert@biot.com>
5 * Copyright (C) 2017 John Chajecki <subs@qcontinuum.plus.com>
7 * This program is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation, either version 3 of the License, or
10 * (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program. If not, see <http://www.gnu.org/licenses/>.
29 #include <libsigrok/libsigrok.h>
30 #include "libsigrok-internal.h"
33 /* Get the current state of the meter and sets analog object parameters. */
34 SR_PRIV int fl45_get_status(const struct sr_dev_inst *sdi,
35 struct sr_datafeed_analog *analog, int idx)
37 struct dev_context *devc;
43 /* Command string to read current function. */
44 cmd = g_strdup_printf("FUNC%d?", idx + 1);
45 sr_dbg("Sent command: %s.", cmd);
47 if (!(devc = sdi->priv))
50 /* Default settings. */
51 analog[idx].meaning->mq = 0;
52 analog[idx].meaning->unit = 0;
53 analog[idx].meaning->mqflags = 0;
55 /* Get a response to the FUNC? command. */
56 res = fl45_scpi_get_response(sdi, cmd);
59 sr_dbg("Response to FUNC: %s.", devc->response);
61 /* Set up analog mq, unit and flags. */
62 if (res == SR_OK && devc->response != NULL) {
63 func = devc->response;
64 if (strcmp(func, "AAC") == 0) {
65 analog[idx].meaning->mq = SR_MQ_CURRENT;
66 analog[idx].meaning->unit = SR_UNIT_AMPERE;
67 analog[idx].meaning->mqflags = SR_MQFLAG_AC;
68 } else if (strcmp(func, "AACDC") == 0) {
69 analog[idx].meaning->mq = SR_MQ_CURRENT;
70 analog[idx].meaning->unit = SR_UNIT_AMPERE;
71 analog[idx].meaning->mqflags = SR_MQFLAG_AC;
72 } else if (strcmp(func, "ADC") == 0) {
73 analog[idx].meaning->mq = SR_MQ_CURRENT;
74 analog[idx].meaning->unit = SR_UNIT_AMPERE;
75 analog[idx].meaning->mqflags = SR_MQFLAG_DC;
76 } else if (strcmp(func, "CONT") == 0) {
77 analog[idx].meaning->mq = SR_MQ_CONTINUITY;
78 analog->meaning->unit = SR_UNIT_BOOLEAN;
79 } else if (strcmp(func, "DIODE") == 0) {
80 analog[idx].meaning->mq = SR_MQ_VOLTAGE;
81 analog[idx].meaning->unit = SR_UNIT_VOLT;
82 analog[idx].meaning->mqflags = SR_MQFLAG_DIODE;
83 } else if (strcmp(func, "FREQ") == 0) {
84 analog[idx].meaning->mq = SR_MQ_FREQUENCY;
85 analog[idx].meaning->unit = SR_UNIT_HERTZ;
86 } else if (strcmp(func, "OHMS") == 0) {
87 analog[idx].meaning->mq = SR_MQ_RESISTANCE;
88 analog[idx].meaning->unit = SR_UNIT_OHM;
89 } else if (strcmp(func, "VAC") == 0) {
90 analog[idx].meaning->mq = SR_MQ_VOLTAGE;
91 analog[idx].meaning->unit = SR_UNIT_VOLT;
92 analog[idx].meaning->mqflags = SR_MQFLAG_AC;
93 } else if (strcmp(func, "VACDC") == 0) {
94 analog[idx].meaning->mq = SR_MQ_VOLTAGE;
95 analog[idx].meaning->unit = SR_UNIT_VOLT;
96 analog[idx].meaning->mqflags |= SR_MQFLAG_AC;
97 analog[idx].meaning->mqflags |= SR_MQFLAG_DC;
98 } else if (strcmp(func, "VDC") == 0) {
99 analog[idx].meaning->mq = SR_MQ_VOLTAGE;
100 analog[idx].meaning->unit = SR_UNIT_VOLT;
101 analog[idx].meaning->mqflags = SR_MQFLAG_DC;
105 /* Is the meter in autorange mode? */
106 res = fl45_scpi_get_response(sdi, "AUTO?");
109 sr_dbg("Response to AUTO: %s.", devc->response);
110 if (res == SR_OK && devc->response != NULL) {
111 if (strcmp(devc->response, "1") == 0)
112 analog[idx].meaning->mqflags |= SR_MQFLAG_AUTORANGE;
118 SR_PRIV int fl45_get_modifiers(const struct sr_dev_inst *sdi,
119 struct sr_datafeed_analog *analog, int idx)
121 struct dev_context *devc;
124 if (!(devc = sdi->priv))
127 /* Get modifier value. */
128 res = fl45_scpi_get_response(sdi, "MOD?");
131 sr_dbg("Response to MOD: %s.", devc->response);
132 if (res == SR_OK && devc->response != NULL) {
133 mod = atoi(devc->response);
135 analog[idx].meaning->mqflags |= SR_MQFLAG_MIN;
136 sr_dbg("MIN bit set: %s.", "1");
139 analog[idx].meaning->mqflags |= SR_MQFLAG_MAX;
140 sr_dbg("MAX bit set: %s.", "2");
143 analog[idx].meaning->mqflags |= SR_MQFLAG_HOLD;
144 sr_dbg("HOLD bit set: %s.", "4");
147 sr_dbg("dB bit set: %s.", "8");
148 analog[idx].meaning->mq = SR_MQ_POWER_FACTOR;
149 analog[idx].meaning->unit = SR_UNIT_DECIBEL_MW;
150 analog[idx].meaning->mqflags = 0;
151 analog[idx].encoding->digits = 2;
152 analog[idx].spec->spec_digits = 2;
155 sr_dbg("dB Power mod bit set: %s.", "16");
156 analog[idx].meaning->mq = SR_MQ_POWER;
157 analog[idx].meaning->unit = SR_UNIT_DECIBEL_SPL;
158 analog[idx].meaning->mqflags = 0;
159 analog[idx].encoding->digits = 2;
160 analog[idx].spec->spec_digits = 2;
163 sr_dbg("REL bit set: %s.", "32");
164 analog[idx].meaning->mqflags |= SR_MQFLAG_HOLD;
171 int get_reading_dd(char *reading, size_t size)
179 /* Calculate required precision. */
181 pe = pd = digits = 0;
183 /* Get positions for '.' end 'E'. */
184 for (i = 0; i < size; i++) {
185 if (reading[i] == '.')
187 if (reading[i] == 'E') {
193 digits = (pe - pd) - 1;
195 /* Get exponent element. */
196 expstr[0] = reading[pe + 1];
197 expstr[1] = reading[pe + 2];
200 exp = strtol(expstr, &eptr, 10);
203 /* A negative exponent increses digits, a positive one reduces. */
206 /* Adjust digits taking into account exponent. */
207 digits = digits + exp;
212 SR_PRIV int fl45_scpi_receive_data(int fd, int revents, void *cb_data)
214 struct sr_dev_inst *sdi;
215 struct dev_context *devc;
216 struct sr_datafeed_packet packet;
217 struct sr_datafeed_analog analog[2];
218 struct sr_analog_encoding encoding[2];
219 struct sr_analog_meaning meaning[2];
220 struct sr_analog_spec spec[2];
221 struct sr_channel *channel;
231 if (!(sdi = cb_data))
234 if (!(devc = sdi->priv))
238 sent_ch[0] = sent_ch[1] = 0;
240 /* Process the list of channels. */
241 for (i = 0; i < devc->num_channels; i++) {
242 /* Note: digits/spec_digits will be overridden later. */
243 sr_analog_init(&analog[i], &encoding[i], &meaning[i], &spec[i], 0);
245 /* Detect current meter function. */
246 res = fl45_get_status(sdi, analog, i);
248 /* Get channel data. */
250 channel = sdi->channels->data;
252 channel = sdi->channels->next->data;
254 /* Is channel enabled? */
255 if (analog[i].meaning->mq != 0 && channel->enabled) {
256 /* Then get a reading from it. */
258 res = fl45_scpi_get_response(sdi, "VAL1?");
260 res = fl45_scpi_get_response(sdi, "VAL2?");
261 /* Note: Fluke 45 sends all data in text strings. */
262 reading = devc->response;
264 /* Deal with OL reading. */
265 if (strcmp(reading, "+1E+9") == 0) {
267 sr_dbg("Reading OL (infinity): %s.",
269 } else if (res == SR_OK && reading != NULL) {
270 /* Convert reading to float. */
271 sr_dbg("Meter reading string: %s.", reading);
272 res = sr_atof_ascii(reading, &fv);
273 digits = get_reading_dd(reading, strlen(reading));
274 analog[i].encoding->digits = digits;
275 analog[i].spec->spec_digits = digits;
278 sr_dbg("Invalid float string: '%s'.", reading);
282 /* Are we on a little or big endian system? */
283 #ifdef WORDS_BIGENDIAN
284 analog[i].encoding->is_bigendian = TRUE;
286 analog[i].encoding->is_bigendian = FALSE;
289 /* Apply any modifiers. */
290 res = fl45_get_modifiers(sdi, analog, i);
295 /* Set up analog object. */
296 analog[i].num_samples = 1;
297 analog[i].data = &fv;
298 analog[i].meaning->channels = g_slist_append(NULL, channel);
300 packet.type = SR_DF_ANALOG;
301 packet.payload = &analog[i];
303 sr_session_send(sdi, &packet);
305 g_slist_free(analog[i].meaning->channels);
309 /* Update appropriate channel limits. */
310 if (sent_ch[0] || sent_ch[1])
311 sr_sw_limits_update_samples_read(&devc->limits, 1);
313 /* Are we done collecting samples? */
314 if (sr_sw_limits_check(&devc->limits))
315 sr_dev_acquisition_stop(sdi);
320 SR_PRIV int fl45_scpi_get_response(const struct sr_dev_inst *sdi, char *cmd)
322 struct dev_context *devc;
325 /* Attempt to get a SCPI reponse. */
326 if (sr_scpi_get_string(sdi->conn, cmd, &devc->response) != SR_OK)
329 /* Deal with RS232 '=>' prompt. */
330 if (strcmp(devc->response, "=>") == 0) {
332 * If the response is a prompt then ignore and read the next
333 * response in the buffer.
335 devc->response = NULL;
336 /* Now attempt to read again. */
337 if (sr_scpi_get_string(sdi->conn, NULL, &devc->response) != SR_OK)
341 /* NULL RS232 error prompts. */
342 if (strcmp(devc->response, "!>") == 0
343 || (strcmp(devc->response, "?>") == 0)) {
344 /* Unable to execute CMD. */
345 devc->response = NULL;