]> sigrok.org Git - libsigrok.git/blob - hardware/lascar-el-usb/protocol.c
lascar-el-usb: add scanning functionality
[libsigrok.git] / hardware / lascar-el-usb / protocol.c
1 /*
2  * This file is part of the libsigrok 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 <stdlib.h>
21 #include <sys/time.h>
22 #include <string.h>
23 #include <glib.h>
24 #include "libsigrok.h"
25 #include "libsigrok-internal.h"
26 #include "protocol.h"
27
28 #define LASCAR_VENDOR "Lascar"
29 #define LASCAR_INTERFACE 0
30 #define LASCAR_EP_IN 0x82
31 #define LASCAR_EP_OUT 2
32 /* Max 100ms for a device to positively identify. */
33 #define SCAN_TIMEOUT 100000
34
35 extern struct sr_dev_driver lascar_el_usb_driver_info;
36 static struct sr_dev_driver *di = &lascar_el_usb_driver_info;
37
38 static const struct elusb_profile profiles[] = {
39         { 1, "EL-USB-1", LOG_UNSUPPORTED },
40         { 2, "EL-USB-1", LOG_UNSUPPORTED },
41         { 3, "EL-USB-2", LOG_TEMP_RH },
42         { 4, "EL-USB-3", LOG_UNSUPPORTED },
43         { 5, "EL-USB-4", LOG_UNSUPPORTED },
44         { 6, "EL-USB-3", LOG_UNSUPPORTED },
45         { 7, "EL-USB-4", LOG_UNSUPPORTED },
46         { 8, "EL-USB-LITE", LOG_UNSUPPORTED },
47         { 9, "EL-USB-CO", LOG_CO },
48         { 10, "EL-USB-TC", LOG_UNSUPPORTED },
49         { 11, "EL-USB-CO300", LOG_UNSUPPORTED },
50         { 12, "EL-USB-2-LCD", LOG_UNSUPPORTED },
51         { 13, "EL-USB-2+", LOG_UNSUPPORTED },
52         { 14, "EL-USB-1-PRO", LOG_UNSUPPORTED },
53         { 15, "EL-USB-TC-LCD", LOG_UNSUPPORTED },
54         { 16, "EL-USB-2-LCD+", LOG_UNSUPPORTED },
55         { 17, "EL-USB-5", LOG_UNSUPPORTED },
56         { 18, "EL-USB-1-RCG", LOG_UNSUPPORTED },
57         { 19, "EL-USB-1-LCD", LOG_UNSUPPORTED },
58         { 20, "EL-OEM-3", LOG_UNSUPPORTED },
59         { 21, "EL-USB-1-LCD", LOG_UNSUPPORTED },
60         { 0, NULL, 0 }
61 };
62
63
64 static void scan_xfer(struct libusb_transfer *xfer)
65 {
66
67         xfer->user_data = GINT_TO_POINTER(1);
68
69 }
70
71 static struct sr_dev_inst *lascar_identify(libusb_device_handle *dev_hdl)
72 {
73         struct drv_context *drvc;
74         const struct elusb_profile *profile;
75         struct sr_dev_inst *sdi;
76         struct libusb_transfer *xfer_in, *xfer_out;
77         struct timeval tv;
78         int64_t start;
79         int modelid, buflen, i;
80         unsigned char cmd[3], buf[256];
81         char firmware[5];
82
83         drvc = di->priv;
84         modelid = 0;
85
86         /* Some of these fail, but it needs doing -- some sort of mode
87          * setup for the SILabs F32x. */
88         libusb_control_transfer(dev_hdl, LIBUSB_REQUEST_TYPE_VENDOR,
89                         0x00, 0xffff, 0x00, buf, 0, 50);
90         libusb_control_transfer(dev_hdl, LIBUSB_REQUEST_TYPE_VENDOR,
91                         0x02, 0x0002, 0x00, buf, 0, 50);
92         libusb_control_transfer(dev_hdl, LIBUSB_REQUEST_TYPE_VENDOR,
93                         0x02, 0x0001, 0x00, buf, 0, 50);
94
95         if (!(xfer_in = libusb_alloc_transfer(0)) ||
96                         !(xfer_out = libusb_alloc_transfer(0)))
97                 return 0;
98
99         /* Flush anything the F321 still has queued. */
100         while (libusb_bulk_transfer(dev_hdl, LASCAR_EP_IN, buf, 256, &buflen,
101                         5) == 0 && buflen > 0)
102                 ;
103
104         /* Keep a read request waiting in the wings, ready to pounce
105          * the moment the device sends something. */
106         libusb_fill_bulk_transfer(xfer_in, dev_hdl, LASCAR_EP_IN,
107                         buf, 256, scan_xfer, 0, 10000);
108         if (libusb_submit_transfer(xfer_in) != 0)
109                 goto cleanup;
110
111         /* Request device configuration structure. */
112         cmd[0] = 0x00;
113         cmd[1] = 0xff;
114         cmd[2] = 0xff;
115         libusb_fill_bulk_transfer(xfer_out, dev_hdl, LASCAR_EP_OUT,
116                         cmd, 3, scan_xfer, 0, 100);
117         if (libusb_submit_transfer(xfer_out) != 0)
118                 goto cleanup;
119
120         tv.tv_sec = 0;
121         tv.tv_usec = 0;
122         start = g_get_monotonic_time();
123         while (!xfer_in->user_data || !xfer_out->user_data) {
124                 if (g_get_monotonic_time() - start > SCAN_TIMEOUT) {
125                         start = 0;
126                         break;
127                 }
128                 g_usleep(5000);
129                 libusb_handle_events_timeout(drvc->sr_ctx->libusb_ctx, &tv);
130         }
131         if (!start) {
132                 sr_dbg("no response");
133                 goto cleanup;
134         }
135         if (xfer_in->actual_length != 3) {
136                 sr_dbg("expected 3-byte header, got %d bytes", xfer_in->actual_length);
137                 goto cleanup;
138         }
139
140         /* Got configuration structure header. */
141         sr_spew("response to config request: 0x%.2x 0x%.2x 0x%.2x ",
142                         buf[0], buf[1], buf[2]);
143         buflen = buf[1] | (buf[2] << 8);
144         if (buf[0] != 0x02 || buflen > 256) {
145                 sr_dbg("Invalid response to config request: "
146                                 "0x%.2x 0x%.2x 0x%.2x ", buf[0], buf[1], buf[2]);
147                 libusb_close(dev_hdl);
148                 goto cleanup;
149         }
150
151         /* Get configuration structure. */
152         xfer_in->length = buflen;
153         xfer_in->user_data = 0;
154         if (libusb_submit_transfer(xfer_in) != 0)
155                 goto cleanup;
156         while (!xfer_in->user_data) {
157                 if (g_get_monotonic_time() - start > SCAN_TIMEOUT) {
158                         start = 0;
159                         break;
160                 }
161                 g_usleep(5000);
162                 libusb_handle_events_timeout(drvc->sr_ctx->libusb_ctx, &tv);
163         }
164         if (!start) {
165                 sr_dbg("Timeout waiting for configuration structure.");
166                 goto cleanup;
167         }
168         if (xfer_in->actual_length != buflen) {
169                 sr_dbg("expected %d-byte structure, got %d bytes", buflen,
170                                 xfer_in->actual_length);
171                 goto cleanup;
172         }
173         modelid = buf[0];
174
175 cleanup:
176         if (!xfer_in->user_data || !xfer_in->user_data) {
177                 if (!xfer_in->user_data)
178                         libusb_cancel_transfer(xfer_in);
179                 if (!xfer_out->user_data)
180                         libusb_cancel_transfer(xfer_out);
181                 start = g_get_monotonic_time();
182                 while (!xfer_in->user_data || !xfer_out->user_data) {
183                         if (g_get_monotonic_time() - start > 10000)
184                                 break;
185                         g_usleep(1000);
186                         libusb_handle_events_timeout(drvc->sr_ctx->libusb_ctx, &tv);
187                 }
188         }
189         libusb_free_transfer(xfer_in);
190         libusb_free_transfer(xfer_out);
191
192         sdi = NULL;
193         if (modelid) {
194                 profile = NULL;
195                 for (i = 0; profiles[i].modelid; i++) {
196                         if (profiles[i].modelid == modelid) {
197                                 profile = &profiles[i];
198                                 break;
199                         }
200                 }
201                 if (!profile) {
202                         sr_dbg("unknown EL-USB modelid %d", modelid);
203                         return NULL;
204                 }
205
206                 i = buf[52] | (buf[53] << 8);
207                 memcpy(firmware, buf + 0x30, 4);
208                 firmware[4] = '\0';
209                 sr_dbg("found %s with firmware version %s serial %d",
210                                 profile->modelname, firmware, i);
211
212                 if (profile->logformat == LOG_UNSUPPORTED) {
213                         sr_dbg("unsupported EL-USB logformat for %s", profile->modelname);
214                         return NULL;
215                 }
216
217                 if (!(sdi = sr_dev_inst_new(0, SR_ST_INACTIVE, LASCAR_VENDOR,
218                                 profile->modelname, firmware)))
219                         return NULL;
220                 sdi->driver = di;
221         }
222
223         return sdi;
224 }
225
226 SR_PRIV struct sr_dev_inst *lascar_scan(int bus, int address)
227 {
228         struct drv_context *drvc;
229         struct sr_dev_inst *sdi;
230         struct libusb_device **devlist;
231         struct libusb_device_descriptor des;
232         libusb_device_handle *dev_hdl;
233         int ret, i;
234
235         drvc = di->priv;
236         sdi = NULL;
237
238         libusb_get_device_list(drvc->sr_ctx->libusb_ctx, &devlist);
239         for (i = 0; devlist[i]; i++) {
240                 if ((ret = libusb_get_device_descriptor(devlist[i], &des))) {
241                         sr_err("Failed to get device descriptor: %d.", ret);
242                         continue;
243                 }
244
245                 if (libusb_get_bus_number(devlist[i]) != bus ||
246                                 libusb_get_device_address(devlist[i]) != address)
247                         continue;
248
249                 if ((ret = libusb_open(devlist[i], &dev_hdl)) != 0) {
250                         sr_dbg("failed to open device for scan: %s",
251                                         libusb_error_name(ret));
252                         continue;
253                 }
254
255                 sdi = lascar_identify(dev_hdl);
256                 libusb_close(dev_hdl);
257         }
258
259         return sdi;
260 }
261
262
263 SR_PRIV int lascar_el_usb_receive_data(int fd, int revents, void *cb_data)
264 {
265         const struct sr_dev_inst *sdi;
266         struct dev_context *devc;
267
268         if (!(sdi = cb_data))
269                 return TRUE;
270
271         if (!(devc = sdi->priv))
272                 return TRUE;
273
274         if (revents == G_IO_IN) {
275                 /* TODO */
276         }
277
278         return TRUE;
279 }