]> sigrok.org Git - libsigrok.git/blob - hardware/uni-t-dmm/api.c
25d3d02ffdbe1319a5b4dcc2f9a2ed5d4aab286b
[libsigrok.git] / hardware / uni-t-dmm / api.c
1 /*
2  * This file is part of the sigrok project.
3  *
4  * Copyright (C) 2012 Uwe Hermann <uwe@hermann-uwe.de>
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 2 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, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
19  */
20
21 #include <stdlib.h>
22 #include <string.h>
23 #include "libsigrok.h"
24 #include "libsigrok-internal.h"
25 #include "protocol.h"
26
27 /* Note: The order here must match the DMM/device enum in protocol.h. */
28 static const char *dev_names[] = {
29         "UNI-T UT61D",
30         "Voltcraft VC-820",
31 };
32
33 static const int hwcaps[] = {
34         SR_HWCAP_MULTIMETER,
35         SR_HWCAP_LIMIT_SAMPLES,
36         SR_HWCAP_LIMIT_MSEC,
37         SR_HWCAP_CONTINUOUS,
38         0,
39 };
40
41 static const char *probe_names[] = {
42         "Probe",
43         NULL,
44 };
45
46 SR_PRIV struct sr_dev_driver uni_t_ut61d_driver_info;
47 static struct sr_dev_driver *di_ut61d = &uni_t_ut61d_driver_info;
48
49 SR_PRIV struct sr_dev_driver voltcraft_vc820_driver_info;
50 static struct sr_dev_driver *di_vc820 = &voltcraft_vc820_driver_info;
51
52 static int open_usb(struct sr_dev_inst *sdi)
53 {
54         libusb_device **devlist;
55         struct libusb_device_descriptor des;
56         struct dev_context *devc;
57         int ret, tmp, cnt, i;
58
59         /* TODO: Use common code later, refactor. */
60
61         devc = sdi->priv;
62
63         if ((cnt = libusb_get_device_list(NULL, &devlist)) < 0) {
64                 sr_err("Error getting USB device list: %d.", cnt);
65                 return SR_ERR;
66         }
67
68         ret = SR_ERR;
69         for (i = 0; i < cnt; i++) {
70                 if ((tmp = libusb_get_device_descriptor(devlist[i], &des))) {
71                         sr_err("Failed to get device descriptor: %d.", tmp);
72                         continue;
73                 }
74
75                 if (libusb_get_bus_number(devlist[i]) != devc->usb->bus
76                         || libusb_get_device_address(devlist[i]) != devc->usb->address)
77                         continue;
78
79                 if ((tmp = libusb_open(devlist[i], &devc->usb->devhdl))) {
80                         sr_err("Failed to open device: %d.", tmp);
81                         break;
82                 }
83
84                 sr_info("Opened USB device on %d.%d.",
85                         devc->usb->bus, devc->usb->address);
86                 ret = SR_OK;
87                 break;
88         }
89         libusb_free_device_list(devlist, 1);
90
91         return ret;
92 }
93
94 static GSList *connect_usb(const char *conn, int dmm)
95 {
96         struct sr_dev_inst *sdi;
97         struct drv_context *drvc;
98         struct dev_context *devc;
99         struct sr_probe *probe;
100         libusb_device **devlist;
101         struct libusb_device_descriptor des;
102         GSList *devices;
103         int vid, pid, devcnt, err, i;
104
105         (void)conn;
106
107         /* TODO: Use common code later, refactor. */
108
109         if (dmm == UNI_T_UT61D)
110                 drvc = di_ut61d->priv;
111         else if (dmm == VOLTCRAFT_VC820)
112                 drvc = di_vc820->priv;
113
114         /* Hardcoded for now. */
115         vid = UT_D04_CABLE_USB_VID;
116         pid = UT_D04_CABLE_USB_DID;
117
118         devices = NULL;
119         libusb_get_device_list(NULL, &devlist);
120         for (i = 0; devlist[i]; i++) {
121                 if ((err = libusb_get_device_descriptor(devlist[i], &des))) {
122                         sr_err("Failed to get device descriptor: %d", err);
123                         continue;
124                 }
125
126                 if (des.idVendor != vid || des.idProduct != pid)
127                         continue;
128
129                 if (!(devc = g_try_malloc0(sizeof(struct dev_context)))) {
130                         sr_err("Device context malloc failed.");
131                         return NULL;
132                 }
133
134                 devcnt = g_slist_length(drvc->instances);
135                 if (!(sdi = sr_dev_inst_new(devcnt, SR_ST_INACTIVE,
136                                             dev_names[dmm], NULL, NULL))) {
137                         sr_err("sr_dev_inst_new returned NULL.");
138                         return NULL;
139                 }
140                 sdi->priv = devc;
141                 if (!(probe = sr_probe_new(0, SR_PROBE_ANALOG, TRUE, "P1")))
142                         return NULL;
143                 sdi->probes = g_slist_append(sdi->probes, probe);
144                 devc->usb = sr_usb_dev_inst_new(
145                                 libusb_get_bus_number(devlist[i]),
146                                 libusb_get_device_address(devlist[i]), NULL);
147                 devices = g_slist_append(devices, sdi);
148         }
149         libusb_free_device_list(devlist, 1);
150
151         return devices;
152 }
153
154 static int clear_instances(void)
155 {
156         /* TODO: Use common code later. */
157
158         return SR_OK;
159 }
160
161 static int hw_init(int dmm)
162 {
163         int ret;
164         struct drv_context *drvc;
165
166         if (!(drvc = g_try_malloc0(sizeof(struct drv_context)))) {
167                 sr_err("Driver context malloc failed.");
168                 return SR_ERR_MALLOC;
169         }
170
171         if ((ret = libusb_init(NULL)) < 0) {
172                 sr_err("Failed to initialize libusb: %s.",
173                        libusb_error_name(ret));
174                 return SR_ERR;
175         }
176
177         if (dmm == UNI_T_UT61D)
178                 di_ut61d->priv = drvc;
179         else if (dmm == VOLTCRAFT_VC820)
180                 di_vc820->priv = drvc;
181
182         return SR_OK;
183 }
184
185 static int hw_init_ut61d(void)
186 {
187         return hw_init(UNI_T_UT61D);
188 }
189
190 static int hw_init_vc820(void)
191 {
192         return hw_init(VOLTCRAFT_VC820);
193 }
194
195 static GSList *hw_scan(GSList *options, int dmm)
196 {
197         GSList *l, *devices;
198         struct sr_dev_inst *sdi;
199         struct drv_context *drvc;
200
201         (void)options;
202
203         if (dmm == UNI_T_UT61D)
204                 drvc = di_ut61d->priv;
205         else if (dmm == VOLTCRAFT_VC820)
206                 drvc = di_vc820->priv;
207
208         if (!(devices = connect_usb(NULL, dmm)))
209                 return NULL;
210
211         for (l = devices; l; l = l->next) {
212                 sdi = l->data;
213
214                 if (dmm == UNI_T_UT61D)
215                         sdi->driver = di_ut61d;
216                 else if (dmm == VOLTCRAFT_VC820)
217                         sdi->driver = di_vc820;
218
219                 drvc->instances = g_slist_append(drvc->instances, l->data);
220         }
221
222         return devices;
223 }
224
225 static GSList *hw_scan_ut61d(GSList *options)
226 {
227         return hw_scan(options, UNI_T_UT61D);
228 }
229
230 static GSList *hw_scan_vc820(GSList *options)
231 {
232         return hw_scan(options, VOLTCRAFT_VC820);
233 }
234
235 static GSList *hw_dev_list(int dmm)
236 {
237         struct drv_context *drvc;
238
239         if (dmm == UNI_T_UT61D)
240                 drvc = di_ut61d->priv;
241         else if (dmm == VOLTCRAFT_VC820)
242                 drvc = di_vc820->priv;
243
244         return drvc->instances;
245 }
246
247 static GSList *hw_dev_list_ut61d(void)
248 {
249         return hw_dev_list(UNI_T_UT61D);
250 }
251
252 static GSList *hw_dev_list_vc820(void)
253 {
254         return hw_dev_list(VOLTCRAFT_VC820);
255 }
256
257 static int hw_dev_open(struct sr_dev_inst *sdi)
258 {
259         return open_usb(sdi);
260 }
261
262 static int hw_dev_close(struct sr_dev_inst *sdi)
263 {
264         (void)sdi;
265
266         /* TODO */
267
268         return SR_OK;
269 }
270
271 static int hw_cleanup(void)
272 {
273         clear_instances();
274
275         // libusb_exit(NULL);
276
277         return SR_OK;
278 }
279
280 static int hw_info_get(int info_id, const void **data,
281                        const struct sr_dev_inst *sdi)
282 {
283         (void)sdi;
284
285         sr_spew("Backend requested info_id %d.", info_id);
286
287         switch (info_id) {
288         case SR_DI_HWCAPS:
289                 *data = hwcaps;
290                 sr_spew("%s: Returning hwcaps.", __func__);
291                 break;
292         case SR_DI_NUM_PROBES:
293                 *data = GINT_TO_POINTER(1);
294                 sr_spew("%s: Returning number of probes.", __func__);
295                 break;
296         case SR_DI_PROBE_NAMES:
297                 *data = probe_names;
298                 sr_spew("%s: Returning probe names.", __func__);
299                 break;
300         case SR_DI_SAMPLERATES:
301                 /* TODO: Get rid of this. */
302                 *data = NULL;
303                 sr_spew("%s: Returning samplerates.", __func__);
304                 return SR_ERR_ARG;
305                 break;
306         case SR_DI_CUR_SAMPLERATE:
307                 /* TODO: Get rid of this. */
308                 *data = NULL;
309                 sr_spew("%s: Returning current samplerate.", __func__);
310                 return SR_ERR_ARG;
311                 break;
312         default:
313                 sr_err("%s: Unknown info_id %d.", __func__, info_id);
314                 return SR_ERR_ARG;
315                 break;
316         }
317
318         return SR_OK;
319 }
320
321 static int hw_dev_config_set(const struct sr_dev_inst *sdi, int hwcap,
322                              const void *value)
323 {
324         struct dev_context *devc;
325
326         devc = sdi->priv;
327
328         switch (hwcap) {
329         case SR_HWCAP_LIMIT_MSEC:
330                 /* TODO: Not yet implemented. */
331                 if (*(const uint64_t *)value == 0) {
332                         sr_err("Time limit cannot be 0.");
333                         return SR_ERR;
334                 }
335                 devc->limit_msec = *(const uint64_t *)value;
336                 sr_dbg("Setting time limit to %" PRIu64 "ms.",
337                        devc->limit_msec);
338                 break;
339         case SR_HWCAP_LIMIT_SAMPLES:
340                 if (*(const uint64_t *)value == 0) {
341                         sr_err("Sample limit cannot be 0.");
342                         return SR_ERR;
343                 }
344                 devc->limit_samples = *(const uint64_t *)value;
345                 sr_dbg("Setting sample limit to %" PRIu64 ".",
346                        devc->limit_samples);
347                 break;
348         default:
349                 sr_err("Unknown capability: %d.", hwcap);
350                 return SR_ERR;
351                 break;
352         }
353
354         return SR_OK;
355 }
356
357 static int hw_dev_acquisition_start(const struct sr_dev_inst *sdi,
358                                     int dmm, void *cb_data)
359 {
360         struct sr_datafeed_packet packet;
361         struct sr_datafeed_header header;
362         struct sr_datafeed_meta_analog meta;
363         struct dev_context *devc;
364
365         devc = sdi->priv;
366
367         sr_dbg("Starting acquisition.");
368
369         devc->cb_data = cb_data;
370
371         /* Send header packet to the session bus. */
372         sr_dbg("Sending SR_DF_HEADER.");
373         packet.type = SR_DF_HEADER;
374         packet.payload = (uint8_t *)&header;
375         header.feed_version = 1;
376         gettimeofday(&header.starttime, NULL);
377         sr_session_send(devc->cb_data, &packet);
378
379         /* Send metadata about the SR_DF_ANALOG packets to come. */
380         sr_dbg("Sending SR_DF_META_ANALOG.");
381         packet.type = SR_DF_META_ANALOG;
382         packet.payload = &meta;
383         meta.num_probes = 1;
384         sr_session_send(devc->cb_data, &packet);
385
386         if (dmm == UNI_T_UT61D) {
387                 sr_source_add(0, 0, 10 /* poll_timeout */,
388                               uni_t_ut61d_receive_data, (void *)sdi);
389         } else if (dmm == VOLTCRAFT_VC820) {
390                 sr_source_add(0, 0, 10 /* poll_timeout */,
391                               voltcraft_vc820_receive_data, (void *)sdi);
392         }
393
394         return SR_OK;
395 }
396
397 static int hw_dev_acquisition_start_ut61d(const struct sr_dev_inst *sdi,
398                                           void *cb_data)
399 {
400         return hw_dev_acquisition_start(sdi, UNI_T_UT61D, cb_data);
401 }
402
403 static int hw_dev_acquisition_start_vc820(const struct sr_dev_inst *sdi,
404                                           void *cb_data)
405 {
406         return hw_dev_acquisition_start(sdi, VOLTCRAFT_VC820, cb_data);
407 }
408
409 static int hw_dev_acquisition_stop(const struct sr_dev_inst *sdi,
410                                    void *cb_data)
411 {
412         struct sr_datafeed_packet packet;
413
414         (void)sdi;
415
416         sr_dbg("Stopping acquisition.");
417
418         /* Send end packet to the session bus. */
419         sr_dbg("Sending SR_DF_END.");
420         packet.type = SR_DF_END;
421         sr_session_send(cb_data, &packet);
422
423         /* TODO? */
424         sr_source_remove(0);
425
426         return SR_OK;
427 }
428
429 SR_PRIV struct sr_dev_driver uni_t_ut61d_driver_info = {
430         .name = "uni-t-ut61d",
431         .longname = "UNI-T UT61D",
432         .api_version = 1,
433         .init = hw_init_ut61d,
434         .cleanup = hw_cleanup,
435         .scan = hw_scan_ut61d,
436         .dev_list = hw_dev_list_ut61d,
437         .dev_clear = clear_instances,
438         .dev_open = hw_dev_open,
439         .dev_close = hw_dev_close,
440         .info_get = hw_info_get,
441         .dev_config_set = hw_dev_config_set,
442         .dev_acquisition_start = hw_dev_acquisition_start_ut61d,
443         .dev_acquisition_stop = hw_dev_acquisition_stop,
444         .priv = NULL,
445 };
446
447 SR_PRIV struct sr_dev_driver voltcraft_vc820_driver_info = {
448         .name = "voltcraft-vc820",
449         .longname = "Voltcraft VC-820",
450         .api_version = 1,
451         .init = hw_init_vc820,
452         .cleanup = hw_cleanup,
453         .scan = hw_scan_vc820,
454         .dev_list = hw_dev_list_vc820,
455         .dev_clear = clear_instances,
456         .dev_open = hw_dev_open,
457         .dev_close = hw_dev_close,
458         .info_get = hw_info_get,
459         .dev_config_set = hw_dev_config_set,
460         .dev_acquisition_start = hw_dev_acquisition_start_vc820,
461         .dev_acquisition_stop = hw_dev_acquisition_stop,
462         .priv = NULL,
463 };