]> sigrok.org Git - libsigrok.git/blob - hardware/uni-t-dmm/api.c
uni-t-dmm: Fix scanning, properly use new sr_usb_find().
[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 #define UNI_T_UT_D04_NEW "1a86.e008"
28
29 static const int hwcaps[] = {
30         SR_HWCAP_MULTIMETER,
31         SR_HWCAP_LIMIT_SAMPLES,
32         SR_HWCAP_LIMIT_MSEC,
33         SR_HWCAP_CONTINUOUS,
34         0,
35 };
36
37 SR_PRIV struct sr_dev_driver uni_t_ut61d_driver_info;
38 SR_PRIV struct sr_dev_driver voltcraft_vc820_driver_info;
39
40 static struct sr_dev_driver *di_ut61d = &uni_t_ut61d_driver_info;
41 static struct sr_dev_driver *di_vc820 = &voltcraft_vc820_driver_info;
42
43 /* After hw_init() this will point to a device-specific entry (see above). */
44 static struct sr_dev_driver *di = NULL;
45
46 static int clear_instances(void)
47 {
48         /* TODO: Use common code later. */
49
50         return SR_OK;
51 }
52
53 static int hw_init(struct sr_context *sr_ctx, int dmm)
54 {
55         struct drv_context *drvc;
56
57         if (!(drvc = g_try_malloc0(sizeof(struct drv_context)))) {
58                 sr_err("Driver context malloc failed.");
59                 return SR_ERR_MALLOC;
60         }
61
62         if (dmm == UNI_T_UT61D)
63                 di = di_ut61d;
64         else if (dmm == VOLTCRAFT_VC820)
65                 di = di_vc820;
66         sr_dbg("Selected '%s' subdriver.", di->name);
67
68         drvc->sr_ctx = sr_ctx;
69         di->priv = drvc;
70
71         return SR_OK;
72 }
73
74 static int hw_init_ut61d(struct sr_context *sr_ctx)
75 {
76         return hw_init(sr_ctx, UNI_T_UT61D);
77 }
78
79 static int hw_init_vc820(struct sr_context *sr_ctx)
80 {
81         return hw_init(sr_ctx, VOLTCRAFT_VC820);
82 }
83
84 static GSList *hw_scan(GSList *options)
85 {
86         GSList *usb_devices, *devices, *l;
87         struct sr_dev_inst *sdi;
88         struct dev_context *devc;
89         struct drv_context *drvc;
90         struct sr_usb_dev_inst *usb;
91         struct sr_hwopt *opt;
92         struct sr_probe *probe;
93         const char *conn;
94
95         (void)options;
96
97         drvc = di->priv;
98
99         /* USB scan is always authoritative. */
100         clear_instances();
101
102         conn = NULL;
103         for (l = options; l; l = l->next) {
104                 opt = l->data;
105                 switch (opt->hwopt) {
106                 case SR_HWOPT_CONN:
107                         conn = opt->value;
108                         break;
109                 }
110         }
111         if (!conn)
112                 conn = UNI_T_UT_D04_NEW;
113
114         devices = NULL;
115         if (!(usb_devices = sr_usb_find(drvc->sr_ctx->libusb_ctx, conn))) {
116                 g_slist_free_full(usb_devices, g_free);
117                 return NULL;
118         }
119
120         for (l = usb_devices; l; l = l->next) {
121                 usb = l->data;
122
123                 if (!(devc = g_try_malloc0(sizeof(struct dev_context)))) {
124                         sr_err("Device context malloc failed.");
125                         return NULL;
126                 }
127
128                 if (!(sdi = sr_dev_inst_new(0, SR_ST_INACTIVE,
129                                 di->longname, NULL, NULL))) {
130                         sr_err("sr_dev_inst_new returned NULL.");
131                         return NULL;
132                 }
133                 sdi->priv = devc;
134                 sdi->driver = di;
135                 if (!(probe = sr_probe_new(0, SR_PROBE_ANALOG, TRUE, "P1")))
136                         return NULL;
137                 sdi->probes = g_slist_append(sdi->probes, probe);
138
139                 devc->usb = usb;
140
141                 drvc->instances = g_slist_append(drvc->instances, sdi);
142                 devices = g_slist_append(devices, sdi);
143         }
144
145         return devices;
146 }
147
148 static GSList *hw_dev_list(void)
149 {
150         struct drv_context *drvc;
151
152         drvc = di->priv;
153
154         return drvc->instances;
155 }
156
157 static int hw_dev_open(struct sr_dev_inst *sdi)
158 {
159         struct drv_context *drvc;
160         struct dev_context *devc;
161
162         drvc = di->priv;
163         devc = sdi->priv;
164
165         return sr_usb_open(drvc->sr_ctx->libusb_ctx, devc->usb);
166 }
167
168 static int hw_dev_close(struct sr_dev_inst *sdi)
169 {
170         (void)sdi;
171
172         /* TODO */
173
174         return SR_OK;
175 }
176
177 static int hw_cleanup(void)
178 {
179         clear_instances();
180
181         return SR_OK;
182 }
183
184 static int hw_info_get(int info_id, const void **data,
185                        const struct sr_dev_inst *sdi)
186 {
187         (void)sdi;
188
189         sr_spew("Backend requested info_id %d.", info_id);
190
191         switch (info_id) {
192         case SR_DI_HWCAPS:
193                 *data = hwcaps;
194                 sr_spew("%s: Returning hwcaps.", __func__);
195                 break;
196         case SR_DI_SAMPLERATES:
197                 /* TODO: Get rid of this. */
198                 *data = NULL;
199                 sr_spew("%s: Returning samplerates.", __func__);
200                 return SR_ERR_ARG;
201                 break;
202         case SR_DI_CUR_SAMPLERATE:
203                 /* TODO: Get rid of this. */
204                 *data = NULL;
205                 sr_spew("%s: Returning current samplerate.", __func__);
206                 return SR_ERR_ARG;
207                 break;
208         default:
209                 return SR_ERR_ARG;
210                 break;
211         }
212
213         return SR_OK;
214 }
215
216 static int hw_dev_config_set(const struct sr_dev_inst *sdi, int hwcap,
217                              const void *value)
218 {
219         struct dev_context *devc;
220
221         devc = sdi->priv;
222
223         switch (hwcap) {
224         case SR_HWCAP_LIMIT_MSEC:
225                 /* TODO: Not yet implemented. */
226                 if (*(const uint64_t *)value == 0) {
227                         sr_err("Time limit cannot be 0.");
228                         return SR_ERR;
229                 }
230                 devc->limit_msec = *(const uint64_t *)value;
231                 sr_dbg("Setting time limit to %" PRIu64 "ms.",
232                        devc->limit_msec);
233                 break;
234         case SR_HWCAP_LIMIT_SAMPLES:
235                 if (*(const uint64_t *)value == 0) {
236                         sr_err("Sample limit cannot be 0.");
237                         return SR_ERR;
238                 }
239                 devc->limit_samples = *(const uint64_t *)value;
240                 sr_dbg("Setting sample limit to %" PRIu64 ".",
241                        devc->limit_samples);
242                 break;
243         default:
244                 sr_err("Unknown capability: %d.", hwcap);
245                 return SR_ERR;
246                 break;
247         }
248
249         return SR_OK;
250 }
251
252 static int hw_dev_acquisition_start(const struct sr_dev_inst *sdi,
253                                     void *cb_data)
254 {
255         struct sr_datafeed_packet packet;
256         struct sr_datafeed_header header;
257         struct sr_datafeed_meta_analog meta;
258         struct dev_context *devc;
259
260         devc = sdi->priv;
261
262         sr_dbg("Starting acquisition.");
263
264         devc->cb_data = cb_data;
265
266         /* Send header packet to the session bus. */
267         sr_dbg("Sending SR_DF_HEADER.");
268         packet.type = SR_DF_HEADER;
269         packet.payload = (uint8_t *)&header;
270         header.feed_version = 1;
271         gettimeofday(&header.starttime, NULL);
272         sr_session_send(devc->cb_data, &packet);
273
274         /* Send metadata about the SR_DF_ANALOG packets to come. */
275         sr_dbg("Sending SR_DF_META_ANALOG.");
276         packet.type = SR_DF_META_ANALOG;
277         packet.payload = &meta;
278         meta.num_probes = 1;
279         sr_session_send(devc->cb_data, &packet);
280
281         if (!strcmp(di->name, "uni-t-ut61d")) {
282                 sr_source_add(0, 0, 10 /* poll_timeout */,
283                               uni_t_ut61d_receive_data, (void *)sdi);
284         } else if (!strcmp(di->name, "voltcraft-vc820")) {
285                 sr_source_add(0, 0, 10 /* poll_timeout */,
286                               voltcraft_vc820_receive_data, (void *)sdi);
287         }
288
289         return SR_OK;
290 }
291
292 static int hw_dev_acquisition_stop(struct sr_dev_inst *sdi, void *cb_data)
293 {
294         struct sr_datafeed_packet packet;
295
296         (void)sdi;
297
298         sr_dbg("Stopping acquisition.");
299
300         /* Send end packet to the session bus. */
301         sr_dbg("Sending SR_DF_END.");
302         packet.type = SR_DF_END;
303         sr_session_send(cb_data, &packet);
304
305         /* TODO? */
306         sr_source_remove(0);
307
308         return SR_OK;
309 }
310
311 SR_PRIV struct sr_dev_driver uni_t_ut61d_driver_info = {
312         .name = "uni-t-ut61d",
313         .longname = "UNI-T UT61D",
314         .api_version = 1,
315         .init = hw_init_ut61d,
316         .cleanup = hw_cleanup,
317         .scan = hw_scan,
318         .dev_list = hw_dev_list,
319         .dev_clear = clear_instances,
320         .dev_open = hw_dev_open,
321         .dev_close = hw_dev_close,
322         .info_get = hw_info_get,
323         .dev_config_set = hw_dev_config_set,
324         .dev_acquisition_start = hw_dev_acquisition_start,
325         .dev_acquisition_stop = hw_dev_acquisition_stop,
326         .priv = NULL,
327 };
328
329 SR_PRIV struct sr_dev_driver voltcraft_vc820_driver_info = {
330         .name = "voltcraft-vc820",
331         .longname = "Voltcraft VC-820",
332         .api_version = 1,
333         .init = hw_init_vc820,
334         .cleanup = hw_cleanup,
335         .scan = hw_scan,
336         .dev_list = hw_dev_list,
337         .dev_clear = clear_instances,
338         .dev_open = hw_dev_open,
339         .dev_close = hw_dev_close,
340         .info_get = hw_info_get,
341         .dev_config_set = hw_dev_config_set,
342         .dev_acquisition_start = hw_dev_acquisition_start,
343         .dev_acquisition_stop = hw_dev_acquisition_stop,
344         .priv = NULL,
345 };