]> sigrok.org Git - libsigrok.git/blob - src/hardware/fluke-45/protocol.c
fluke-45: free memory that was allocated by SCPI get routines
[libsigrok.git] / src / hardware / fluke-45 / protocol.c
1 /*
2  * This file is part of the libsigrok project.
3  *
4  * Copyright (C) 2012 Bert Vermeulen <bert@biot.com>
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
21 #include <stdio.h>
22 #include <config.h>
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"
31 #include "protocol.h"
32
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)
36 {
37         struct dev_context *devc;
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
118 SR_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
171 int 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
212 SR_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];
227
228         (void)fd;
229         (void)revents;
230
231         if (!(sdi = cb_data))
232                 return TRUE;
233
234         if (!(devc = sdi->priv))
235                 return TRUE;
236
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                 }
307         }
308
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
317         return TRUE;
318 }
319
320 SR_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                  */
335                 g_free(devc->response);
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. */
343         if (strcmp(devc->response, "!>") == 0 ||
344             (strcmp(devc->response, "?>") == 0)) {
345                 /* Unable to execute CMD. */
346                 g_free(devc->response);
347                 devc->response = NULL;
348         }
349
350         return SR_OK;
351 }