]> sigrok.org Git - libsigrok.git/blame - src/hardware/fluke-45/protocol.c
output/csv: use intermediate time_t var, silence compiler warning
[libsigrok.git] / src / hardware / fluke-45 / protocol.c
CommitLineData
e756c595
J
1/*
2 * This file is part of the libsigrok project.
3 *
ab2b21fb 4 * Copyright (C) 2012 Bert Vermeulen <bert@biot.com>
e756c595
J
5 * Copyright (C) 2017 John Chajecki <subs@qcontinuum.plus.com>
6 *
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.
11 *
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.
16 *
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/>.
19 */
20
ab2b21fb 21#include <stdio.h>
e756c595 22#include <config.h>
ab2b21fb
J
23#include <stdlib.h>
24#include <math.h>
25#include <string.h>
26#include <glib.h>
27#include <errno.h>
28#include <scpi.h>
29#include <libsigrok/libsigrok.h>
30#include "libsigrok-internal.h"
e756c595
J
31#include "protocol.h"
32
ab2b21fb
J
33/* Get the current state of the meter and sets analog object parameters. */
34SR_PRIV int fl45_get_status(const struct sr_dev_inst *sdi,
35 struct sr_datafeed_analog *analog, int idx)
e756c595 36{
e756c595 37 struct dev_context *devc;
ab2b21fb
J
38 char *cmd, *func;
39 int res;
40
41 res = 0;
42
43 /* Command string to read current function. */
44 cmd = g_strdup_printf("FUNC%d?", idx + 1);
45 sr_dbg("Sent command: %s.", cmd);
46
47 if (!(devc = sdi->priv))
48 return TRUE;
49
50 /* Default settings. */
51 analog[idx].meaning->mq = 0;
52 analog[idx].meaning->unit = 0;
53 analog[idx].meaning->mqflags = 0;
54
55 /* Get a response to the FUNC? command. */
56 res = fl45_scpi_get_response(sdi, cmd);
57 if (res == SR_ERR)
58 return res;
59 sr_dbg("Response to FUNC: %s.", devc->response);
60
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;
102 }
103 }
104
105 /* Is the meter in autorange mode? */
106 res = fl45_scpi_get_response(sdi, "AUTO?");
107 if (res == SR_ERR)
108 return res;
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;
113 }
114
115 return SR_OK;
116}
117
118SR_PRIV int fl45_get_modifiers(const struct sr_dev_inst *sdi,
119 struct sr_datafeed_analog *analog, int idx)
120{
121 struct dev_context *devc;
122 int res, mod;
123
124 if (!(devc = sdi->priv))
125 return TRUE;
126
127 /* Get modifier value. */
128 res = fl45_scpi_get_response(sdi, "MOD?");
129 if (res == SR_ERR)
130 return res;
131 sr_dbg("Response to MOD: %s.", devc->response);
132 if (res == SR_OK && devc->response != NULL) {
133 mod = atoi(devc->response);
134 if (mod & 0x01) {
135 analog[idx].meaning->mqflags |= SR_MQFLAG_MIN;
136 sr_dbg("MIN bit set: %s.", "1");
137 }
138 if (mod & 0x02) {
139 analog[idx].meaning->mqflags |= SR_MQFLAG_MAX;
140 sr_dbg("MAX bit set: %s.", "2");
141 }
142 if (mod & 0x04) {
143 analog[idx].meaning->mqflags |= SR_MQFLAG_HOLD;
144 sr_dbg("HOLD bit set: %s.", "4");
145 }
146 if (mod & 0x08) {
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;
153 }
154 if (mod & 0x10) {
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;
161 }
162 if (mod & 0x20) {
163 sr_dbg("REL bit set: %s.", "32");
164 analog[idx].meaning->mqflags |= SR_MQFLAG_HOLD;
165 }
166 }
167
168 return SR_OK;
169}
170
171int get_reading_dd(char *reading, size_t size)
172{
173 int pe, pd, digits;
174 unsigned int i;
175 char expstr[3];
176 char *eptr;
177 long exp;
178
179 /* Calculate required precision. */
180
181 pe = pd = digits = 0;
182
183 /* Get positions for '.' end 'E'. */
184 for (i = 0; i < size; i++) {
185 if (reading[i] == '.')
186 pd = i;
187 if (reading[i] == 'E') {
188 pe = i;
189 break;
190 }
191 }
192
193 digits = (pe - pd) - 1;
194
195 /* Get exponent element. */
196 expstr[0] = reading[pe + 1];
197 expstr[1] = reading[pe + 2];
198 expstr[2] = '\0';
199 errno = 0;
200 exp = strtol(expstr, &eptr, 10);
201 if (errno != 0)
202 return 2;
203 /* A negative exponent increses digits, a positive one reduces. */
204 exp = exp * (-1);
205
206 /* Adjust digits taking into account exponent. */
207 digits = digits + exp;
208
209 return digits;
210}
211
212SR_PRIV int fl45_scpi_receive_data(int fd, int revents, void *cb_data)
213{
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;
222 char *reading;
223 float fv;
224 int res, digits;
225 unsigned int i;
226 int sent_ch[2];
e756c595
J
227
228 (void)fd;
ab2b21fb 229 (void)revents;
e756c595
J
230
231 if (!(sdi = cb_data))
232 return TRUE;
233
234 if (!(devc = sdi->priv))
235 return TRUE;
236
ab2b21fb
J
237 res = 0;
238 sent_ch[0] = sent_ch[1] = 0;
239
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);
244
245 /* Detect current meter function. */
246 res = fl45_get_status(sdi, analog, i);
247
248 /* Get channel data. */
249 if (i == 0)
250 channel = sdi->channels->data;
251 else
252 channel = sdi->channels->next->data;
253
254 /* Is channel enabled? */
255 if (analog[i].meaning->mq != 0 && channel->enabled) {
256 /* Then get a reading from it. */
257 if (i == 0)
258 res = fl45_scpi_get_response(sdi, "VAL1?");
259 if (i == 1)
260 res = fl45_scpi_get_response(sdi, "VAL2?");
261 /* Note: Fluke 45 sends all data in text strings. */
262 reading = devc->response;
263
264 /* Deal with OL reading. */
265 if (strcmp(reading, "+1E+9") == 0) {
266 fv = INFINITY;
267 sr_dbg("Reading OL (infinity): %s.",
268 devc->response);
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;
276
277 } else {
278 sr_dbg("Invalid float string: '%s'.", reading);
279 return SR_ERR;
280 }
281
282 /* Are we on a little or big endian system? */
283#ifdef WORDS_BIGENDIAN
284 analog[i].encoding->is_bigendian = TRUE;
285#else
286 analog[i].encoding->is_bigendian = FALSE;
287#endif
288
289 /* Apply any modifiers. */
290 res = fl45_get_modifiers(sdi, analog, i);
291
292 /* Channal flag. */
293 sent_ch[i] = 1;
294
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);
299
300 packet.type = SR_DF_ANALOG;
301 packet.payload = &analog[i];
302
303 sr_session_send(sdi, &packet);
304
305 g_slist_free(analog[i].meaning->channels);
306 }
e756c595
J
307 }
308
ab2b21fb
J
309 /* Update appropriate channel limits. */
310 if (sent_ch[0] || sent_ch[1])
311 sr_sw_limits_update_samples_read(&devc->limits, 1);
312
313 /* Are we done collecting samples? */
314 if (sr_sw_limits_check(&devc->limits))
315 sr_dev_acquisition_stop(sdi);
316
e756c595
J
317 return TRUE;
318}
ab2b21fb
J
319
320SR_PRIV int fl45_scpi_get_response(const struct sr_dev_inst *sdi, char *cmd)
321{
322 struct dev_context *devc;
323 devc = sdi->priv;
324
325 /* Attempt to get a SCPI reponse. */
326 if (sr_scpi_get_string(sdi->conn, cmd, &devc->response) != SR_OK)
327 return SR_ERR;
328
329 /* Deal with RS232 '=>' prompt. */
330 if (strcmp(devc->response, "=>") == 0) {
331 /*
332 * If the response is a prompt then ignore and read the next
333 * response in the buffer.
334 */
c9cfcd25 335 g_free(devc->response);
ab2b21fb
J
336 devc->response = NULL;
337 /* Now attempt to read again. */
338 if (sr_scpi_get_string(sdi->conn, NULL, &devc->response) != SR_OK)
339 return SR_ERR;
340 }
341
342 /* NULL RS232 error prompts. */
c9cfcd25
GS
343 if (strcmp(devc->response, "!>") == 0 ||
344 (strcmp(devc->response, "?>") == 0)) {
ab2b21fb 345 /* Unable to execute CMD. */
c9cfcd25 346 g_free(devc->response);
ab2b21fb
J
347 devc->response = NULL;
348 }
349
350 return SR_OK;
351}