]> sigrok.org Git - libsigrok.git/blame - hardware/kecheng-kc-330b/api.c
Add Kecheng KC-330B
[libsigrok.git] / hardware / kecheng-kc-330b / api.c
CommitLineData
ed759a08
BV
1/*
2 * This file is part of the libsigrok project.
3 *
4 * Copyright (C) 2013 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 "protocol.h"
21
a8806f03
BV
22#define USB_CONN "1041.8101"
23#define VENDOR "Kecheng"
24#define USB_INTERFACE 0
25#define EP_IN 0x80 | 1
26#define EP_OUT 2
27
28static const int32_t hwcaps[] = {
29 SR_CONF_SOUNDLEVELMETER,
30 SR_CONF_LIMIT_SAMPLES,
31 SR_CONF_CONTINUOUS,
32};
33
ed759a08
BV
34SR_PRIV struct sr_dev_driver kecheng_kc_330b_driver_info;
35static struct sr_dev_driver *di = &kecheng_kc_330b_driver_info;
36
37
38static int init(struct sr_context *sr_ctx)
39{
40 return std_init(sr_ctx, di, LOG_PREFIX);
41}
42
a8806f03
BV
43static int scan_kecheng(struct sr_usb_dev_inst *usb, char **model)
44{
45 struct drv_context *drvc;
46 int len, ret;
47 unsigned char cmd, buf[32];
48
49 drvc = di->priv;
50 if (sr_usb_open(drvc->sr_ctx->libusb_ctx, usb) != SR_OK)
51 return SR_ERR;
52
53 cmd = CMD_IDENTIFY;
54 ret = libusb_bulk_transfer(usb->devhdl, EP_OUT, &cmd, 1, &len, 5);
55 if (ret != 0) {
56 libusb_close(usb->devhdl);
57 sr_dbg("Failed to send Identify command: %s", libusb_error_name(ret));
58 return SR_ERR;
59 }
60
61 ret = libusb_bulk_transfer(usb->devhdl, EP_IN, buf, 32, &len, 10);
62 if (ret != 0) {
63 libusb_close(usb->devhdl);
64 sr_dbg("Failed to receive response: %s", libusb_error_name(ret));
65 return SR_ERR;
66 }
67
68 libusb_close(usb->devhdl);
69 usb->devhdl = NULL;
70
71 if (len < 2 || buf[0] != (CMD_IDENTIFY | 0x80) || buf[1] > 30) {
72 sr_dbg("Invalid response to Identify command");
73 return SR_ERR;
74 }
75
76 buf[buf[1] + 2] = '\x0';
77 *model = g_strndup((const gchar *)buf + 2, 30);
78 //g_strstrip(*model);
79
80 return SR_OK;
81}
82
ed759a08
BV
83static GSList *scan(GSList *options)
84{
85 struct drv_context *drvc;
a8806f03
BV
86 struct dev_context *devc;
87 struct sr_dev_inst *sdi;
88 struct sr_probe *probe;
89 GSList *usb_devices, *devices, *l;
90 char *model;
ed759a08
BV
91
92 (void)options;
93
ed759a08
BV
94 drvc = di->priv;
95 drvc->instances = NULL;
96
a8806f03
BV
97 devices = NULL;
98 if ((usb_devices = sr_usb_find(drvc->sr_ctx->libusb_ctx, USB_CONN))) {
99 /* We have a list of sr_usb_dev_inst matching the connection
100 * string. Wrap them in sr_dev_inst and we're done. */
101 for (l = usb_devices; l; l = l->next) {
102 if (scan_kecheng(l->data, &model) != SR_OK)
103 continue;
104 if (!(sdi = sr_dev_inst_new(0, SR_ST_INACTIVE, VENDOR,
105 model, NULL)))
106 return NULL;
107 g_free(model);
108 sdi->driver = di;
109 sdi->inst_type = SR_INST_USB;
110 sdi->conn = l->data;
111 if (!(probe = sr_probe_new(0, SR_PROBE_ANALOG, TRUE, "SPL")))
112 return NULL;
113 sdi->probes = g_slist_append(sdi->probes, probe);
114
115 if (!(devc = g_try_malloc(sizeof(struct dev_context)))) {
116 sr_dbg("Device context malloc failed.");
117 return NULL;
118 }
119 sdi->priv = devc;
120 devc->limit_samples = 0;
121
122 drvc->instances = g_slist_append(drvc->instances, sdi);
123 devices = g_slist_append(devices, sdi);
124 }
125 g_slist_free(usb_devices);
126 } else
127 g_slist_free_full(usb_devices, g_free);
ed759a08
BV
128
129 return devices;
130}
131
132static GSList *dev_list(void)
133{
134 struct drv_context *drvc;
135
136 drvc = di->priv;
137
138 return drvc->instances;
139}
140
141static int dev_clear(void)
142{
143 return std_dev_clear(di, NULL);
144}
145
146static int dev_open(struct sr_dev_inst *sdi)
147{
a8806f03
BV
148 struct drv_context *drvc;
149 struct sr_usb_dev_inst *usb;
150 int ret;
151
152 if (!(drvc = di->priv)) {
153 sr_err("Driver was not initialized.");
154 return SR_ERR;
155 }
156
157 usb = sdi->conn;
ed759a08 158
a8806f03
BV
159 if (sr_usb_open(drvc->sr_ctx->libusb_ctx, usb) != SR_OK)
160 return SR_ERR;
ed759a08 161
a8806f03
BV
162 if ((ret = libusb_claim_interface(usb->devhdl, USB_INTERFACE))) {
163 sr_err("Failed to claim interface: %s.", libusb_error_name(ret));
164 return SR_ERR;
165 }
ed759a08
BV
166 sdi->status = SR_ST_ACTIVE;
167
a8806f03 168 return ret;
ed759a08
BV
169}
170
171static int dev_close(struct sr_dev_inst *sdi)
172{
a8806f03
BV
173 struct sr_usb_dev_inst *usb;
174
175 if (!di->priv) {
176 sr_err("Driver was not initialized.");
177 return SR_ERR;
178 }
179
180 usb = sdi->conn;
ed759a08 181
a8806f03
BV
182 if (!usb->devhdl)
183 /* Nothing to do. */
184 return SR_OK;
ed759a08 185
a8806f03
BV
186 libusb_release_interface(usb->devhdl, USB_INTERFACE);
187 libusb_close(usb->devhdl);
188 usb->devhdl = NULL;
ed759a08
BV
189 sdi->status = SR_ST_INACTIVE;
190
191 return SR_OK;
192}
193
194static int cleanup(void)
195{
a8806f03
BV
196 int ret;
197 struct drv_context *drvc;
ed759a08 198
a8806f03
BV
199 if (!(drvc = di->priv))
200 /* Can get called on an unused driver, doesn't matter. */
201 return SR_OK;
ed759a08 202
a8806f03
BV
203 ret = dev_clear();
204 g_free(drvc);
205 di->priv = NULL;
206
207 return ret;
ed759a08
BV
208}
209
210static int config_get(int key, GVariant **data, const struct sr_dev_inst *sdi)
211{
a8806f03 212 struct dev_context *devc;
ed759a08 213
a8806f03 214 devc = sdi->priv;
ed759a08 215 switch (key) {
a8806f03
BV
216 case SR_CONF_LIMIT_SAMPLES:
217 *data = g_variant_new_uint64(devc->limit_samples);
218 break;
ed759a08
BV
219 default:
220 return SR_ERR_NA;
221 }
222
a8806f03 223 return SR_OK;
ed759a08
BV
224}
225
226static int config_set(int key, GVariant *data, const struct sr_dev_inst *sdi)
227{
a8806f03 228 struct dev_context *devc;
ed759a08
BV
229 int ret;
230
ed759a08
BV
231 if (sdi->status != SR_ST_ACTIVE)
232 return SR_ERR_DEV_CLOSED;
233
a8806f03
BV
234 if (!di->priv) {
235 sr_err("Driver was not initialized.");
236 return SR_ERR;
237 }
238
239 devc = sdi->priv;
ed759a08
BV
240 ret = SR_OK;
241 switch (key) {
a8806f03
BV
242 case SR_CONF_LIMIT_SAMPLES:
243 devc->limit_samples = g_variant_get_uint64(data);
244 sr_dbg("Setting sample limit to %" PRIu64 ".",
245 devc->limit_samples);
246 break;
ed759a08
BV
247 default:
248 ret = SR_ERR_NA;
249 }
250
251 return ret;
252}
253
254static int config_list(int key, GVariant **data, const struct sr_dev_inst *sdi)
255{
ed759a08
BV
256
257 (void)sdi;
ed759a08 258
ed759a08 259 switch (key) {
a8806f03
BV
260 case SR_CONF_DEVICE_OPTIONS:
261 *data = g_variant_new_fixed_array(G_VARIANT_TYPE_INT32,
262 hwcaps, ARRAY_SIZE(hwcaps), sizeof(int32_t));
263 break;
ed759a08
BV
264 default:
265 return SR_ERR_NA;
266 }
267
a8806f03 268 return SR_OK;
ed759a08
BV
269}
270
271static int dev_acquisition_start(const struct sr_dev_inst *sdi,
272 void *cb_data)
273{
274 (void)sdi;
275 (void)cb_data;
276
277 if (sdi->status != SR_ST_ACTIVE)
278 return SR_ERR_DEV_CLOSED;
279
280 /* TODO: configure hardware, reset acquisition state, set up
281 * callbacks and send header packet. */
282
283 return SR_OK;
284}
285
286static int dev_acquisition_stop(struct sr_dev_inst *sdi, void *cb_data)
287{
288 (void)cb_data;
289
290 if (sdi->status != SR_ST_ACTIVE)
291 return SR_ERR_DEV_CLOSED;
292
293 /* TODO: stop acquisition. */
294
295 return SR_OK;
296}
297
298SR_PRIV struct sr_dev_driver kecheng_kc_330b_driver_info = {
299 .name = "kecheng-kc-330b",
300 .longname = "Kecheng KC-330B",
301 .api_version = 1,
302 .init = init,
303 .cleanup = cleanup,
304 .scan = scan,
305 .dev_list = dev_list,
306 .dev_clear = dev_clear,
307 .config_get = config_get,
308 .config_set = config_set,
309 .config_list = config_list,
310 .dev_open = dev_open,
311 .dev_close = dev_close,
312 .dev_acquisition_start = dev_acquisition_start,
313 .dev_acquisition_stop = dev_acquisition_stop,
314 .priv = NULL,
315};