]> sigrok.org Git - libsigrok.git/blame - hardware/genericdmm/api.c
genericdmm: use driver struct-based device instance list
[libsigrok.git] / hardware / genericdmm / api.c
CommitLineData
ca3d84cc
BV
1/*
2 * This file is part of the sigrok project.
3 *
4 * Copyright (C) 2012 Uwe Hermann <uwe@hermann-uwe.de>
5 * Copyright (C) 2012 Bert Vermeulen <bert@biot.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 2 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, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
20 */
21
22#include <stdlib.h>
23#include <string.h>
24#include <fcntl.h>
45c59c8b
BV
25#include "libsigrok.h"
26#include "libsigrok-internal.h"
ca3d84cc
BV
27#include "genericdmm.h"
28
29
30extern SR_PRIV struct dmmchip dmmchip_fs9922;
31
7fc754a0
BV
32static struct sr_hwopt victor_70c_vidpid[] = {
33 { SR_HWOPT_CONN, "1244.d237" },
34 { 0, NULL }
35};
ca3d84cc
BV
36static struct dev_profile dev_profiles[] = {
37 { "victor-70c", "Victor", "70C", &dmmchip_fs9922,
7fc754a0
BV
38 DMM_TRANSPORT_USBHID, victor_70c_vidpid
39 },
40 { "mastech-va18b", "Mastech", "VA18B", NULL, DMM_TRANSPORT_SERIAL, NULL},
41 { NULL, NULL, NULL, NULL, 0, NULL }
ca3d84cc
BV
42};
43
44static const int hwcaps[] = {
45 SR_HWCAP_MULTIMETER,
46 SR_HWCAP_LIMIT_SAMPLES,
47 SR_HWCAP_LIMIT_MSEC,
48 SR_HWCAP_CONTINUOUS,
49 SR_HWCAP_MODEL,
50 SR_HWCAP_CONN,
51 SR_HWCAP_SERIALCOMM,
52 0,
53};
54
55static const char *probe_names[] = {
56 "Probe",
57 NULL,
58};
59
75337758
BV
60SR_PRIV struct sr_dev_driver genericdmm_driver_info;
61static struct sr_dev_driver *gdi = &genericdmm_driver_info;
62/* TODO need a way to keep this local to the static library */
ca3d84cc
BV
63SR_PRIV libusb_context *genericdmm_usb_context = NULL;
64
65
40dda2c3 66static int hw_init(void)
ca3d84cc 67{
ca3d84cc 68
ca3d84cc
BV
69 if (libusb_init(&genericdmm_usb_context) != 0) {
70 sr_err("genericdmm: Failed to initialize USB.");
61136ea6 71 return SR_ERR;
ca3d84cc
BV
72 }
73
61136ea6
BV
74
75 return SR_OK;
76}
77
78static int hw_scan(void)
79{
80 struct sr_dev_inst *sdi;
81 struct context *ctx;
82 int devcnt = 0;
83
ca3d84cc
BV
84 if (!(ctx = g_try_malloc0(sizeof(struct context)))) {
85 sr_err("genericdmm: ctx malloc failed.");
86 return 0;
87 }
88
89 devcnt = g_slist_length(genericdmm_dev_insts);
90 if (!(sdi = sr_dev_inst_new(devcnt, SR_ST_ACTIVE, "Generic DMM",
91 NULL, NULL))) {
92 sr_err("genericdmm: sr_dev_inst_new returned NULL.");
93 return 0;
94 }
95 sdi->priv = ctx;
96 genericdmm_dev_insts = g_slist_append(genericdmm_dev_insts, sdi);
97
98 /* Always initialized just one device instance. */
99 return 0;
100}
101
102static int hw_dev_open(int dev_index)
103{
104 struct sr_dev_inst *sdi;
105 struct context *ctx;
106
75337758 107 if (!(sdi = sr_dev_inst_get(gdi->instances, dev_index))) {
ca3d84cc
BV
108 sr_err("genericdmm: sdi was NULL.");
109 return SR_ERR_BUG;
110 }
111
112 if (!(ctx = sdi->priv)) {
113 sr_err("genericdmm: sdi->priv was NULL.");
114 return SR_ERR_BUG;
115 }
116
117 sr_dbg("genericdmm: Opening serial port '%s'.", ctx->serial->port);
118
119 switch (ctx->profile->transport) {
120 case DMM_TRANSPORT_USBHID:
121 /* TODO */
122 break;
123 case DMM_TRANSPORT_SERIAL:
124 /* TODO: O_NONBLOCK? */
125 ctx->serial->fd = serial_open(ctx->serial->port, O_RDWR | O_NONBLOCK);
126 if (ctx->serial->fd == -1) {
127 sr_err("genericdmm: Couldn't open serial port '%s'.",
128 ctx->serial->port);
129 return SR_ERR;
130 }
131 // serial_set_params(ctx->serial->fd, 2400, 8, 0, 1, 2);
132 break;
133 default:
134 sr_err("No transport set.");
135 }
136
137 return SR_OK;
138}
139
140static int hw_dev_close(int dev_index)
141{
142 struct sr_dev_inst *sdi;
143 struct context *ctx;
144
75337758 145 if (!(sdi = sr_dev_inst_get(gdi->instances, dev_index))) {
ca3d84cc
BV
146 sr_err("genericdmm: %s: sdi was NULL.", __func__);
147 return SR_ERR_BUG;
148 }
149
150 if (!(ctx = sdi->priv)) {
151 sr_err("genericdmm: %s: sdi->priv was NULL.", __func__);
152 return SR_ERR_BUG;
153 }
154
155 /* TODO: Check for != NULL. */
156
157 switch (ctx->profile->transport) {
158 case DMM_TRANSPORT_USBHID:
159 /* TODO */
160 break;
161 case DMM_TRANSPORT_SERIAL:
162 if (ctx->serial && ctx->serial->fd != -1) {
163 serial_close(ctx->serial->fd);
164 ctx->serial->fd = -1;
165 sdi->status = SR_ST_INACTIVE;
166 }
167 break;
168 }
169
170 return SR_OK;
171}
172
173static int hw_cleanup(void)
174{
175 GSList *l;
176 struct sr_dev_inst *sdi;
177 struct context *ctx;
178
179 /* Properly close and free all devices. */
75337758 180 for (l = gdi->instances; l; l = l->next) {
ca3d84cc
BV
181 if (!(sdi = l->data)) {
182 /* Log error, but continue cleaning up the rest. */
183 sr_err("genericdmm: sdi was NULL, continuing.");
184 continue;
185 }
186 if (!(ctx = sdi->priv)) {
187 /* Log error, but continue cleaning up the rest. */
188 sr_err("genericdmm: sdi->priv was NULL, continuing.");
189 continue;
190 }
191
192 if (ctx->profile) {
193 switch (ctx->profile->transport) {
194 case DMM_TRANSPORT_USBHID:
195 /* TODO */
196 break;
197 case DMM_TRANSPORT_SERIAL:
198 if (ctx->serial && ctx->serial->fd != -1)
199 serial_close(ctx->serial->fd);
200 sr_serial_dev_inst_free(ctx->serial);
201 break;
202 }
203 }
204
205 sr_dev_inst_free(sdi);
206 }
207
75337758
BV
208 g_slist_free(gdi->instances);
209 gdi->instances = NULL;
ca3d84cc
BV
210
211 if (genericdmm_usb_context)
212 libusb_exit(genericdmm_usb_context);
213
214 return SR_OK;
215}
216
217static const void *hw_dev_info_get(int dev_index, int dev_info_id)
218{
219 struct sr_dev_inst *sdi;
220 struct context *ctx;
221 const void *info;
222
75337758 223 if (!(sdi = sr_dev_inst_get(gdi->instances, dev_index))) {
ca3d84cc
BV
224 sr_err("genericdmm: sdi was NULL.");
225 return NULL;
226 }
227
228 if (!(ctx = sdi->priv)) {
229 sr_err("genericdmm: sdi->priv was NULL.");
230 return NULL;
231 }
232
233 sr_spew("genericdmm: dev_index %d, dev_info_id %d.",
234 dev_index, dev_info_id);
235
236 switch (dev_info_id) {
237 case SR_DI_INST:
238 info = sdi;
239 sr_spew("genericdmm: Returning sdi.");
240 break;
241 case SR_DI_NUM_PROBES:
242 info = GINT_TO_POINTER(1);
243 sr_spew("genericdmm: Returning number of probes: 1.");
244 break;
245 case SR_DI_PROBE_NAMES:
246 info = probe_names;
247 sr_spew("genericdmm: Returning probenames.");
248 break;
249 case SR_DI_CUR_SAMPLERATE:
250 /* TODO get rid of this */
251 info = NULL;
252 sr_spew("genericdmm: Returning samplerate: 0.");
253 break;
254 default:
255 /* Unknown device info ID. */
256 sr_err("genericdmm: Unknown device info ID: %d.", dev_info_id);
257 info = NULL;
258 break;
259 }
260
261 return info;
262}
263
264static int hw_dev_status_get(int dev_index)
265{
266 struct sr_dev_inst *sdi;
267
75337758 268 if (!(sdi = sr_dev_inst_get(gdi->instances, dev_index))) {
ca3d84cc
BV
269 sr_err("genericdmm: sdi was NULL, device not found.");
270 return SR_ST_NOT_FOUND;
271 }
272
273 sr_dbg("genericdmm: Returning status: %d.", sdi->status);
274
275 return sdi->status;
276}
277
278static const int *hw_hwcap_get_all(void)
279{
280 sr_spew("genericdmm: Returning list of device capabilities.");
281
282 return hwcaps;
283}
284
285static int parse_conn_vidpid(struct sr_dev_inst *sdi, const char *conn)
286{
287 struct context *ctx;
288 libusb_device **devlist;
289 struct libusb_device_descriptor des;
290 GRegex *reg;
291 GMatchInfo *match;
292 int vid, pid, found, err, i;
293 char *vidstr, *pidstr;
294
295 found = FALSE;
296
297 reg = g_regex_new(DMM_CONN_USB_VIDPID, 0, 0, NULL);
298 if (g_regex_match(reg, conn, 0, &match)) {
299 /* Extract VID. */
300 if (!(vidstr = g_match_info_fetch(match, 0))) {
301 sr_err("failed to fetch VID from regex");
302 goto err;
303 }
304 vid = strtoul(vidstr, NULL, 16);
305 g_free(vidstr);
306 if (vid > 0xffff) {
307 sr_err("invalid VID");
308 goto err;
309 }
310
311 /* Extract PID. */
312 if (!(pidstr = g_match_info_fetch(match, 0))) {
313 sr_err("failed to fetch PID from regex");
314 goto err;
315 }
316 pid = strtoul(pidstr, NULL, 16);
317 g_free(pidstr);
318 if (pid > 0xffff) {
319 sr_err("invalid PID");
320 goto err;
321 }
322
323 /* Looks like a valid VID:PID, but is it connected? */
324 libusb_get_device_list(genericdmm_usb_context, &devlist);
325 for (i = 0; devlist[i]; i++) {
326 if ((err = libusb_get_device_descriptor(devlist[i], &des))) {
327 sr_err("genericdmm: failed to get device descriptor: %d", err);
328 goto err;
329 }
330
331 if (des.idVendor == vid && des.idProduct == pid) {
332 ctx = sdi->priv;
333 ctx->usb = sr_usb_dev_inst_new(
334 libusb_get_bus_number(devlist[i]),
335 libusb_get_device_address(devlist[i]), NULL);
336 found = TRUE;
337 break;
338 }
339 }
340 libusb_free_device_list(devlist, 1);
341 }
342
343err:
344 if (match)
345 g_match_info_unref(match);
346 g_regex_unref(reg);
347
348 return found;
349}
350
351static int parse_conn_busaddr(struct sr_dev_inst *sdi, const char *conn)
352{
353 struct context *ctx;
354 libusb_device **devlist;
355 struct libusb_device_descriptor des;
356 GRegex *reg;
357 GMatchInfo *match;
358 int bus, addr, found, err, i;
359 char *busstr, *addrstr;
360
361 found = FALSE;
362
363 reg = g_regex_new(DMM_CONN_USB_BUSADDR, 0, 0, NULL);
364 if (g_regex_match(reg, conn, 0, &match)) {
365 /* Extract bus. */
366 if (!(busstr = g_match_info_fetch(match, 0))) {
367 sr_err("failed to fetch bus from regex");
368 goto err;
369 }
370 bus = strtoul(busstr, NULL, 16);
371 g_free(busstr);
372 if (bus > 64) {
373 sr_err("invalid bus");
374 goto err;
375 }
376
377 /* Extract address. */
378 if (!(addrstr = g_match_info_fetch(match, 0))) {
379 sr_err("failed to fetch address from regex");
380 goto err;
381 }
382 addr = strtoul(addrstr, NULL, 16);
383 g_free(addrstr);
384 if (addr > 127) {
385 sr_err("invalid address");
386 goto err;
387 }
388
389 /* Looks like a valid bus/address, but is it connected? */
390 libusb_get_device_list(genericdmm_usb_context, &devlist);
391 for (i = 0; devlist[i]; i++) {
392 if ((err = libusb_get_device_descriptor(devlist[i], &des))) {
393 sr_err("genericdmm: failed to get device descriptor: %d", err);
394 goto err;
395 }
396
397 if (libusb_get_bus_number(devlist[i]) == bus
398 && libusb_get_device_address(devlist[i]) == addr) {
399 ctx = sdi->priv;
400 ctx->usb = sr_usb_dev_inst_new(bus, addr, NULL);
401 found = TRUE;
402 break;
403 }
404 }
405 libusb_free_device_list(devlist, 1);
406 }
407
408err:
409 if (match)
410 g_match_info_unref(match);
411 g_regex_unref(reg);
412
413 return found;
414}
415
416static int parse_conn_serial(struct sr_dev_inst *sdi, const char *conn)
417{
418 int found;
419
420 found = FALSE;
421
422 /* TODO */
423
424 return found;
425}
426
427static int parse_conn(struct sr_dev_inst *sdi, const char *conn)
428{
429
430 if (parse_conn_vidpid(sdi, conn))
431 return SR_OK;
432
433 if (parse_conn_busaddr(sdi, conn))
434 return SR_OK;
435
436 if (parse_conn_serial(sdi, conn))
437 return SR_OK;
438
439 sr_err("Invalid connection specification");
440
441 return SR_ERR;
442}
443
444static int parse_serialcomm(struct sr_dev_inst *sdi, const char *conn)
445{
446
447 /* TODO */
448 /* set ctx->serial_* */
449
450 return SR_OK;
451}
452
453static int hw_dev_config_set(int dev_index, int hwcap, const void *value)
454{
455 struct sr_dev_inst *sdi;
456 struct context *ctx;
457 int i;
458
75337758 459 if (!(sdi = sr_dev_inst_get(gdi->instances, dev_index))) {
ca3d84cc
BV
460 sr_err("genericdmm: sdi was NULL.");
461 return SR_ERR_BUG;
462 }
463
464 if (!(ctx = sdi->priv)) {
465 sr_err("genericdmm: sdi->priv was NULL.");
466 return SR_ERR_BUG;
467 }
468
469 sr_spew("genericdmm: dev_index %d, hwcap %d.", dev_index, hwcap);
470
471 switch (hwcap) {
472 case SR_HWCAP_LIMIT_MSEC:
473 if (*(const uint64_t *)value == 0) {
474 sr_err("genericdmm: LIMIT_MSEC can't be 0.");
475 return SR_ERR;
476 }
477 ctx->limit_msec = *(const uint64_t *)value;
478 sr_dbg("genericdmm: Setting LIMIT_MSEC to %" PRIu64 ".",
479 ctx->limit_msec);
480 break;
481 case SR_HWCAP_LIMIT_SAMPLES:
482 ctx->limit_samples = *(const uint64_t *)value;
483 sr_dbg("genericdmm: Setting LIMIT_SAMPLES to %" PRIu64 ".",
484 ctx->limit_samples);
485 break;
486 case SR_HWCAP_MODEL:
487 for (i = 0; dev_profiles[i].model; i++) {
488 if (!strcasecmp(dev_profiles[i].model, value)) {
489 ctx->profile = &dev_profiles[i];
490 /* Frontends access these fields directly, so we
491 * need to copy them over. */
492 sdi->vendor = g_strdup(dev_profiles[i].vendor);
493 sdi->model = g_strdup(dev_profiles[i].model);
494 /* This is the first time we actually know which
495 * DMM chip we're talking to, so let's init
496 * anything specific to it now */
497 if (ctx->profile->chip->init)
498 if (ctx->profile->chip->init(ctx) != SR_OK)
499 return SR_ERR;
500 break;
501 }
502 }
503 if (!ctx->profile) {
504 sr_err("unknown model %s", value);
505 return SR_ERR;
506 }
507 break;
508 case SR_HWCAP_CONN:
509 if (parse_conn(sdi, value) != SR_OK)
510 return SR_ERR_ARG;
511 break;
512 case SR_HWCAP_SERIALCOMM:
513 if (parse_serialcomm(sdi, value) != SR_OK)
514 return SR_ERR_ARG;
515 break;
516 default:
517 sr_err("genericdmm: Unknown capability: %d.", hwcap);
518 return SR_ERR;
519 break;
520 }
521
522 return SR_OK;
523}
524
525static int receive_data(int fd, int revents, void *cb_data)
526{
527 struct sr_dev_inst *sdi;
528 struct context *ctx;
529
530 if (!(sdi = cb_data))
531 return FALSE;
532
533 if (!(ctx = sdi->priv))
534 return FALSE;
535
536 if (revents != G_IO_IN) {
537 sr_err("genericdmm: No data?");
538 return FALSE;
539 }
540
541 switch (ctx->profile->transport) {
542 case DMM_TRANSPORT_USBHID:
543 /* TODO */
544 break;
545 case DMM_TRANSPORT_SERIAL:
546 /* TODO */
547 break;
548 }
549
550 return TRUE;
551}
552
553static int hw_dev_acquisition_start(int dev_index, void *cb_data)
554{
555 struct sr_datafeed_packet packet;
556 struct sr_datafeed_header header;
557 struct sr_datafeed_meta_analog meta;
558 struct sr_dev_inst *sdi;
559 struct context *ctx;
560
75337758 561 if (!(sdi = sr_dev_inst_get(gdi->instances, dev_index))) {
ca3d84cc
BV
562 sr_err("genericdmm: sdi was NULL.");
563 return SR_ERR_BUG;
564 }
565
566 if (!(ctx = sdi->priv)) {
567 sr_err("genericdmm: sdi->priv was NULL.");
568 return SR_ERR_BUG;
569 }
570
571 sr_dbg("genericdmm: Starting acquisition.");
572
573 ctx->cb_data = cb_data;
574
575 /* Send header packet to the session bus. */
576 sr_dbg("genericdmm: Sending SR_DF_HEADER.");
577 packet.type = SR_DF_HEADER;
578 packet.payload = (uint8_t *)&header;
579 header.feed_version = 1;
580 gettimeofday(&header.starttime, NULL);
581 sr_session_send(ctx->cb_data, &packet);
582
583 /* Send metadata about the SR_DF_ANALOG packets to come. */
584 sr_dbg("genericdmm: Sending SR_DF_META_ANALOG.");
585 packet.type = SR_DF_META_ANALOG;
586 packet.payload = &meta;
587 meta.num_probes = 1;
588 sr_session_send(ctx->cb_data, &packet);
589
590 /* Hook up a proxy handler to receive data from the device. */
591 switch (ctx->profile->transport) {
592 case DMM_TRANSPORT_USBHID:
593 /* TODO libusb FD setup */
594 break;
595 case DMM_TRANSPORT_SERIAL:
596 /* TODO serial FD setup */
597 // sr_source_add(ctx->serial->fd, G_IO_IN, -1, receive_data, sdi);
598 break;
599 }
600
601 return SR_OK;
602}
603
604static int hw_dev_acquisition_stop(int dev_index, void *cb_data)
605{
606 struct sr_datafeed_packet packet;
607
608 /* Avoid compiler warnings. */
609 (void)dev_index;
610
611 sr_dbg("genericdmm: Stopping acquisition.");
612
613 /* Send end packet to the session bus. */
614 sr_dbg("genericdmm: Sending SR_DF_END.");
615 packet.type = SR_DF_END;
616 sr_session_send(cb_data, &packet);
617
618 return SR_OK;
619}
620
621SR_PRIV struct sr_dev_driver genericdmm_driver_info = {
622 .name = "genericdmm",
623 .longname = "Generic DMM",
624 .api_version = 1,
625 .init = hw_init,
626 .cleanup = hw_cleanup,
61136ea6 627 .scan = hw_scan,
ca3d84cc
BV
628 .dev_open = hw_dev_open,
629 .dev_close = hw_dev_close,
630 .dev_info_get = hw_dev_info_get,
631 .dev_status_get = hw_dev_status_get,
632 .hwcap_get_all = hw_hwcap_get_all,
633 .dev_config_set = hw_dev_config_set,
634 .dev_acquisition_start = hw_dev_acquisition_start,
635 .dev_acquisition_stop = hw_dev_acquisition_stop,
75337758 636 .instances = NULL,
ca3d84cc 637};