]> sigrok.org Git - libsigrok.git/blob - hardware/fluke-dmm/api.c
fluke-dmm: Use message logging helpers.
[libsigrok.git] / hardware / fluke-dmm / api.c
1 /*
2  * This file is part of the sigrok project.
3  *
4  * Copyright (C) 2012 Bert Vermeulen <bert@biot.com>
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 <glib.h>
21 #include "libsigrok.h"
22 #include "libsigrok-internal.h"
23 #include "fluke-dmm.h"
24 #include <sys/types.h>
25 #include <sys/stat.h>
26 #include <fcntl.h>
27 #include <string.h>
28 #include <errno.h>
29
30 static const int hwopts[] = {
31         SR_HWOPT_CONN,
32         SR_HWOPT_SERIALCOMM,
33         0,
34 };
35
36 static const int hwcaps[] = {
37         SR_HWCAP_MULTIMETER,
38         SR_HWCAP_LIMIT_SAMPLES,
39         SR_HWCAP_LIMIT_MSEC,
40         SR_HWCAP_CONTINUOUS,
41         0,
42 };
43
44 static const char *probe_names[] = {
45         "Probe",
46         NULL,
47 };
48
49 SR_PRIV struct sr_dev_driver flukedmm_driver_info;
50 static struct sr_dev_driver *di = &flukedmm_driver_info;
51
52 static const struct flukedmm_profile supported_flukedmm[] = {
53         { FLUKE_187, "187", 100 },
54         { FLUKE_287, "287", 100 },
55 };
56
57
58 /* Properly close and free all devices. */
59 static int clear_instances(void)
60 {
61         struct sr_dev_inst *sdi;
62         struct drv_context *drvc;
63         struct dev_context *devc;
64         GSList *l;
65
66         if (!(drvc = di->priv))
67                 return SR_OK;
68
69         drvc = di->priv;
70         for (l = drvc->instances; l; l = l->next) {
71                 if (!(sdi = l->data))
72                         continue;
73                 if (!(devc = sdi->priv))
74                         continue;
75                 sr_serial_dev_inst_free(devc->serial);
76                 sr_dev_inst_free(sdi);
77         }
78         g_slist_free(drvc->instances);
79         drvc->instances = NULL;
80
81         return SR_OK;
82 }
83
84 static int hw_init(void)
85 {
86         struct drv_context *drvc;
87
88         if (!(drvc = g_try_malloc0(sizeof(struct drv_context)))) {
89                 sr_err("Driver context malloc failed.");
90                 return SR_ERR;
91         }
92
93         di->priv = drvc;
94
95         return SR_OK;
96 }
97
98 static int serial_readline(int fd, char **buf, int *buflen, uint64_t timeout_ms)
99 {
100         uint64_t start;
101         int maxlen, len;
102
103         timeout_ms *= 1000;
104         start = g_get_monotonic_time();
105
106         maxlen = *buflen;
107         *buflen = len = 0;
108         while(1) {
109                 len = maxlen - *buflen - 1;
110                 if (len < 1)
111                         break;
112                 len = serial_read(fd, *buf + *buflen, 1);
113                 if (len > 0) {
114                         *buflen += len;
115                         *(*buf + *buflen) = '\0';
116                         if (*buflen > 0 && *(*buf + *buflen - 1) == '\r') {
117                                 /* Strip LF and terminate. */
118                                 *(*buf + --*buflen) = '\0';
119                                 break;
120                         }
121                 }
122                 if (g_get_monotonic_time() - start > timeout_ms)
123                         /* Timeout */
124                         break;
125                 g_usleep(2000);
126         }
127         sr_dbg("Received %d: '%s'.", *buflen, *buf);
128
129         return SR_OK;
130 }
131
132 static GSList *fluke_scan(const char *conn, const char *serialcomm)
133 {
134         struct sr_dev_inst *sdi;
135         struct drv_context *drvc;
136         struct dev_context *devc;
137         struct sr_probe *probe;
138         GSList *devices;
139         int fd, retry, len, i, s;
140         char buf[128], *b, **tokens;
141
142         if ((fd = serial_open(conn, O_RDWR|O_NONBLOCK)) == -1) {
143                 sr_err("Unable to open %s: %s.", conn, strerror(errno));
144                 return NULL;
145         }
146         if (serial_set_paramstr(fd, serialcomm) != SR_OK) {
147                 sr_err("Unable to set serial parameters.");
148                 return NULL;
149         }
150
151         drvc = di->priv;
152         b = buf;
153         retry = 0;
154         devices = NULL;
155         /* We'll try the discovery sequence three times in case the device
156          * is not in an idle state when we send ID. */
157         while (!devices && retry < 3) {
158                 retry++;
159                 serial_flush(fd);
160                 if (serial_write(fd, "ID\r", 3) == -1) {
161                         sr_err("Unable to send ID string: %s.",
162                                strerror(errno));
163                         continue;
164                 }
165
166                 /* Response is first a CMD_ACK byte (ASCII '0' for OK,
167                  * or '1' to signify an error. */
168                 len = 128;
169                 serial_readline(fd, &b, &len, 150);
170                 if (len != 1)
171                         continue;
172                 if (buf[0] != '0')
173                         continue;
174
175                 /* If CMD_ACK was OK, ID string follows. */
176                 len = 128;
177                 serial_readline(fd, &b, &len, 150);
178                 if (len < 10)
179                         continue;
180                 tokens = g_strsplit(buf, ",", 3);
181                 if (!strncmp("FLUKE", tokens[0], 5)
182                                 && tokens[1] && tokens[2]) {
183                         for (i = 0; supported_flukedmm[i].model; i++) {
184                                 if (strcmp(supported_flukedmm[i].modelname, tokens[0] + 6))
185                                         continue;
186                                 /* Skip leading spaces in version number. */
187                                 for (s = 0; tokens[1][s] == ' '; s++);
188                                 if (!(sdi = sr_dev_inst_new(0, SR_ST_INACTIVE, "Fluke",
189                                                 tokens[0] + 6, tokens[1] + s)))
190                                         return NULL;
191                                 if (!(devc = g_try_malloc0(sizeof(struct dev_context)))) {
192                                         sr_err("Device context malloc failed.");
193                                         return NULL;
194                                 }
195                                 devc->profile = &supported_flukedmm[i];
196                                 devc->serial = sr_serial_dev_inst_new(conn, -1);
197                                 devc->serialcomm = g_strdup(serialcomm);
198                                 sdi->priv = devc;
199                                 sdi->driver = di;
200                                 if (!(probe = sr_probe_new(0, SR_PROBE_ANALOG, TRUE, "P1")))
201                                         return NULL;
202                                 sdi->probes = g_slist_append(sdi->probes, probe);
203                                 drvc->instances = g_slist_append(drvc->instances, sdi);
204                                 devices = g_slist_append(devices, sdi);
205                                 break;
206                         }
207                 }
208                 g_strfreev(tokens);
209         }
210         serial_close(fd);
211
212         return devices;
213 }
214
215 static GSList *hw_scan(GSList *options)
216 {
217         struct sr_hwopt *opt;
218         GSList *l, *devices;
219         const char *conn, *serialcomm;
220
221         conn = serialcomm = NULL;
222         for (l = options; l; l = l->next) {
223                 opt = l->data;
224                 switch (opt->hwopt) {
225                 case SR_HWOPT_CONN:
226                         conn = opt->value;
227                         break;
228                 case SR_HWOPT_SERIALCOMM:
229                         serialcomm = opt->value;
230                         break;
231                 }
232         }
233         if (!conn)
234                 return NULL;
235
236         if (serialcomm) {
237                 /* Use the provided comm specs. */
238                 devices = fluke_scan(conn, serialcomm);
239         } else {
240                 /* Try 115200, as used on 287/289. */
241                 devices = fluke_scan(conn, "115200/8n1");
242                 if (!devices)
243                         /* Fall back to 9600 for 187/189. */
244                         devices = fluke_scan(conn, "9600/8n1");
245         }
246
247         return devices;
248 }
249
250 static GSList *hw_dev_list(void)
251 {
252         struct drv_context *drvc;
253
254         drvc = di->priv;
255
256         return drvc->instances;
257 }
258
259 static int hw_dev_open(struct sr_dev_inst *sdi)
260 {
261         struct dev_context *devc;
262
263         if (!(devc = sdi->priv)) {
264                 sr_err("sdi->priv was NULL.");
265                 return SR_ERR_BUG;
266         }
267
268         devc->serial->fd = serial_open(devc->serial->port, O_RDWR | O_NONBLOCK);
269         if (devc->serial->fd == -1) {
270                 sr_err("Couldn't open serial port '%s'.", devc->serial->port);
271                 return SR_ERR;
272         }
273         if (serial_set_paramstr(devc->serial->fd, devc->serialcomm) != SR_OK) {
274                 sr_err("Unable to set serial parameters.");
275                 return SR_ERR;
276         }
277         sdi->status = SR_ST_ACTIVE;
278
279         return SR_OK;
280 }
281
282 static int hw_dev_close(struct sr_dev_inst *sdi)
283 {
284         struct dev_context *devc;
285
286         if (!(devc = sdi->priv)) {
287                 sr_err("sdi->priv was NULL.");
288                 return SR_ERR_BUG;
289         }
290
291         if (devc->serial && devc->serial->fd != -1) {
292                 serial_close(devc->serial->fd);
293                 devc->serial->fd = -1;
294                 sdi->status = SR_ST_INACTIVE;
295         }
296
297         return SR_OK;
298 }
299
300 static int hw_cleanup(void)
301 {
302
303         clear_instances();
304
305         return SR_OK;
306 }
307
308 static int hw_info_get(int info_id, const void **data,
309        const struct sr_dev_inst *sdi)
310 {
311
312         (void)sdi;
313
314         switch (info_id) {
315         case SR_DI_HWOPTS:
316                 *data = hwopts;
317                 break;
318         case SR_DI_HWCAPS:
319                 *data = hwcaps;
320                 break;
321         case SR_DI_NUM_PROBES:
322                 *data = GINT_TO_POINTER(1);
323                 break;
324         case SR_DI_PROBE_NAMES:
325                 *data = probe_names;
326                 break;
327         default:
328                 return SR_ERR_ARG;
329         }
330
331         return SR_OK;
332 }
333
334 static int hw_dev_config_set(const struct sr_dev_inst *sdi, int hwcap,
335                 const void *value)
336 {
337         struct dev_context *devc;
338
339         if (sdi->status != SR_ST_ACTIVE)
340                 return SR_ERR;
341
342         if (!(devc = sdi->priv)) {
343                 sr_err("sdi->priv was NULL.");
344                 return SR_ERR_BUG;
345         }
346
347         switch (hwcap) {
348         case SR_HWCAP_LIMIT_MSEC:
349                 /* TODO: not yet implemented */
350                 if (*(const uint64_t *)value == 0) {
351                         sr_err("LIMIT_MSEC can't be 0.");
352                         return SR_ERR;
353                 }
354                 devc->limit_msec = *(const uint64_t *)value;
355                 sr_dbg("Setting time limit to %" PRIu64 "ms.",
356                        devc->limit_msec);
357                 break;
358         case SR_HWCAP_LIMIT_SAMPLES:
359                 devc->limit_samples = *(const uint64_t *)value;
360                 sr_dbg("Setting sample limit to %" PRIu64 ".",
361                        devc->limit_samples);
362                 break;
363         default:
364                 sr_err("Unknown capability: %d.", hwcap);
365                 return SR_ERR;
366                 break;
367         }
368
369         return SR_OK;
370 }
371
372 static int hw_dev_acquisition_start(const struct sr_dev_inst *sdi,
373                 void *cb_data)
374 {
375         struct sr_datafeed_packet packet;
376         struct sr_datafeed_header header;
377         struct sr_datafeed_meta_analog meta;
378         struct dev_context *devc;
379
380         if (!(devc = sdi->priv)) {
381                 sr_err("sdi->priv was NULL.");
382                 return SR_ERR_BUG;
383         }
384
385         sr_dbg("Starting acquisition.");
386
387         devc->cb_data = cb_data;
388
389         /* Send header packet to the session bus. */
390         sr_dbg("Sending SR_DF_HEADER.");
391         packet.type = SR_DF_HEADER;
392         packet.payload = (uint8_t *)&header;
393         header.feed_version = 1;
394         gettimeofday(&header.starttime, NULL);
395         sr_session_send(devc->cb_data, &packet);
396
397         /* Send metadata about the SR_DF_ANALOG packets to come. */
398         sr_dbg("Sending SR_DF_META_ANALOG.");
399         packet.type = SR_DF_META_ANALOG;
400         packet.payload = &meta;
401         meta.num_probes = 1;
402         sr_session_send(devc->cb_data, &packet);
403
404         /* Poll every 100ms, or whenever some data comes in. */
405         sr_source_add(devc->serial->fd, G_IO_IN, 50, fluke_receive_data, (void *)sdi);
406
407         if (serial_write(devc->serial->fd, "QM\r", 3) == -1) {
408                 sr_err("Unable to send QM: %s.", strerror(errno));
409                 return SR_ERR;
410         }
411         devc->cmd_sent_at = g_get_monotonic_time() / 1000;
412         devc->expect_response = TRUE;
413
414         return SR_OK;
415 }
416
417 static int hw_dev_acquisition_stop(const struct sr_dev_inst *sdi,
418                 void *cb_data)
419 {
420         struct sr_datafeed_packet packet;
421         struct dev_context *devc;
422
423         if (sdi->status != SR_ST_ACTIVE)
424                 return SR_ERR;
425
426         if (!(devc = sdi->priv)) {
427                 sr_err("sdi->priv was NULL.");
428                 return SR_ERR_BUG;
429         }
430
431         sr_dbg("Stopping acquisition.");
432
433         sr_source_remove(devc->serial->fd);
434         hw_dev_close((struct sr_dev_inst *)sdi);
435
436         /* Send end packet to the session bus. */
437         sr_dbg("Sending SR_DF_END.");
438         packet.type = SR_DF_END;
439         sr_session_send(cb_data, &packet);
440
441         return SR_OK;
442 }
443
444 SR_PRIV struct sr_dev_driver flukedmm_driver_info = {
445         .name = "fluke-dmm",
446         .longname = "Fluke 18x/28x series DMMs",
447         .api_version = 1,
448         .init = hw_init,
449         .cleanup = hw_cleanup,
450         .scan = hw_scan,
451         .dev_list = hw_dev_list,
452         .dev_clear = clear_instances,
453         .dev_open = hw_dev_open,
454         .dev_close = hw_dev_close,
455         .info_get = hw_info_get,
456         .dev_config_set = hw_dev_config_set,
457         .dev_acquisition_start = hw_dev_acquisition_start,
458         .dev_acquisition_stop = hw_dev_acquisition_stop,
459         .priv = NULL,
460 };