]> sigrok.org Git - libsigrok.git/blob - hardware/brymen-dmm/api.c
brymen-dmm: Add support for Brymen BM857
[libsigrok.git] / hardware / brymen-dmm / api.c
1 /*
2  * This file is part of the libsigrok project.
3  *
4  * Copyright (C) 2012 Alexandru Gagniuc <mr.nuke.me@gmail.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 <glib.h>
21 #include <errno.h>
22 #include <string.h>
23 #include <fcntl.h>
24 #include "libsigrok.h"
25 #include "libsigrok-internal.h"
26 #include "protocol.h"
27
28 static const int hwopts[] = {
29         SR_CONF_CONN,
30         SR_CONF_SERIALCOMM,
31         0,
32 };
33
34 static const int hwcaps[] = {
35         SR_CONF_MULTIMETER,
36         SR_CONF_LIMIT_SAMPLES,
37         SR_CONF_CONTINUOUS,
38         SR_CONF_LIMIT_MSEC,
39         0,
40 };
41
42 SR_PRIV struct sr_dev_driver brymen_dmm_driver_info;
43 static struct sr_dev_driver *di = &brymen_dmm_driver_info;
44
45 static int hw_init(struct sr_context *sr_ctx)
46 {
47         struct drv_context *drvc;
48
49         if (!(drvc = g_try_malloc0(sizeof(struct drv_context)))) {
50                 sr_err("Driver context malloc failed.");
51                 return SR_ERR_MALLOC;
52         }
53
54         drvc->sr_ctx = sr_ctx;
55         di->priv = drvc;
56
57         return SR_OK;
58 }
59
60 static void free_instance(void *inst)
61 {
62         struct sr_dev_inst *sdi;
63         struct dev_context *devc;
64         if (!(sdi = inst))
65                 return;
66         if (!(devc = sdi->priv))
67                 return;
68         sr_serial_dev_inst_free(devc->serial);
69         sr_dev_inst_free(sdi);
70 }
71
72 /* Properly close and free all devices. */
73 static int clear_instances(void)
74 {
75         struct drv_context *drvc;
76
77         if (!(drvc = di->priv))
78                 return SR_OK;
79
80         g_slist_free_full(drvc->instances, free_instance);
81         drvc->instances = NULL;
82
83         return SR_OK;
84 }
85
86 static GSList *brymen_scan(const char *conn, const char *serialcomm)
87 {
88         struct sr_dev_inst *sdi;
89         struct dev_context *devc;
90         struct drv_context *drvc;
91         struct sr_probe *probe;
92         struct sr_serial_dev_inst *serial;
93         GSList *devices;
94         int ret;
95
96         if (!(serial = sr_serial_dev_inst_new(conn, serialcomm)))
97                 return NULL;
98
99         if (serial_open(serial, SERIAL_RDWR|SERIAL_NONBLOCK) != SR_OK)
100                 return NULL;
101
102         sr_info("Probing port %s.", conn);
103
104         devices = NULL;
105
106         /* Request reading */
107         if (brymen_packet_request(serial) == -1) {
108                 sr_err("Unable to send command. code: %d.", errno);
109                 goto scan_cleanup;
110         }
111
112         uint8_t buf[128];
113         size_t len = 128;
114
115         ret = brymen_stream_detect(serial, buf, &len, brymen_packet_length,
116                              brymen_packet_is_valid, 1000, 9600);
117         if (ret != SR_OK)
118                 goto scan_cleanup;
119
120         sr_info("Found device on port %s.", conn);
121
122         if (!(sdi = sr_dev_inst_new(0, SR_ST_INACTIVE, "Brymen", "BM85x", "")))
123                 goto scan_cleanup;
124
125         if (!(devc = g_try_malloc0(sizeof(struct dev_context)))) {
126                 sr_err("Device context malloc failed.");
127                 goto scan_cleanup;
128         }
129
130         devc->serial = serial;
131         drvc = di->priv;
132         sdi->priv = devc;
133         sdi->driver = di;
134
135         if (!(probe = sr_probe_new(0, SR_PROBE_ANALOG, TRUE, "P1")))
136                 goto scan_cleanup;
137
138         sdi->probes = g_slist_append(sdi->probes, probe);
139         drvc->instances = g_slist_append(drvc->instances, sdi);
140         devices = g_slist_append(devices, sdi);
141
142
143 scan_cleanup:
144         serial_close(serial);
145
146         return devices;
147 }
148
149 static GSList *hw_scan(GSList *options)
150 {
151         struct drv_context *drvc;
152         struct sr_config *src;
153         GSList *devices, *l;
154         const char *conn, *serialcomm;
155
156         (void)options;
157
158         devices = NULL;
159         drvc = di->priv;
160         drvc->instances = NULL;
161
162         conn = serialcomm = NULL;
163         for (l = options; l; l = l->next) {
164                 src = l->data;
165                 switch (src->key) {
166                         case SR_CONF_CONN:
167                                 conn = src->value;
168                                 break;
169                         case SR_CONF_SERIALCOMM:
170                                 serialcomm = src->value;
171                                 break;
172                 }
173         }
174         if (!conn) {
175                 return NULL;
176         }
177
178         if (serialcomm) {
179                 /* Use the provided comm specs. */
180                 devices = brymen_scan(conn, serialcomm);
181         } else {
182                 /* But 9600 8N1 should work all of the time */
183                 devices = brymen_scan(conn, "9600/8n1/dtr=1/rts=1");
184         }
185
186         return devices;
187 }
188
189 static GSList *hw_dev_list(void)
190 {
191         struct drv_context *drvc;
192
193         drvc = di->priv;
194
195         return drvc->instances;
196 }
197
198 static int hw_dev_open(struct sr_dev_inst *sdi)
199 {
200         struct dev_context *devc;
201
202         if (!(devc = sdi->priv)) {
203                 sr_err("sdi->priv was NULL.");
204                 return SR_ERR_BUG;
205         }
206
207         if (serial_open(devc->serial, SERIAL_RDWR | SERIAL_NONBLOCK) != SR_OK)
208                 return SR_ERR;
209
210         sdi->status = SR_ST_ACTIVE;
211
212         return SR_OK;
213 }
214
215 static int hw_dev_close(struct sr_dev_inst *sdi)
216 {
217         struct dev_context *devc;
218
219         if (!(devc = sdi->priv)) {
220                 sr_err("sdi->priv was NULL.");
221                 return SR_ERR_BUG;
222         }
223
224         if (devc->serial && devc->serial->fd != -1) {
225                 serial_close(devc->serial);
226                 sdi->status = SR_ST_INACTIVE;
227         }
228
229         return SR_OK;
230 }
231
232 static int hw_cleanup(void)
233 {
234         clear_instances();
235
236         return SR_OK;
237 }
238
239 static int config_list(int key, const void **data,
240                        const struct sr_dev_inst *sdi)
241 {
242         (void)sdi;
243
244         switch (key) {
245                 case SR_CONF_SCAN_OPTIONS:
246                         *data = hwopts;
247                         break;
248                 case SR_CONF_DEVICE_OPTIONS:
249                         *data = hwcaps;
250                         break;
251         default:
252                 sr_err("Unknown config key: %d.", key);
253                 return SR_ERR_ARG;
254         }
255
256         return SR_OK;
257 }
258
259 static int hw_dev_config_set(int id, const void *value,
260                              const struct sr_dev_inst *sdi)
261 {
262         struct dev_context *devc;
263         int ret;
264
265         if (sdi->status != SR_ST_ACTIVE) {
266                 sr_err("Device inactive, can't set config options.");
267                 return SR_ERR;
268         }
269
270         if (!(devc = sdi->priv)) {
271                 sr_err("sdi->priv was NULL.");
272                 return SR_ERR_BUG;
273         }
274
275         ret = SR_OK;
276         switch (id) {
277                 case SR_CONF_LIMIT_SAMPLES:
278                 devc->limit_samples = *(const uint64_t*)value;
279                 break;
280                 case SR_CONF_LIMIT_MSEC:
281                 devc->limit_msec = *(const uint64_t*)value;
282                 break;
283         default:
284                 sr_err("Unknown hardware capability: %d.", id);
285                 ret = SR_ERR_ARG;
286         }
287
288         return ret;
289 }
290
291 static int hw_dev_acquisition_start(const struct sr_dev_inst *sdi,
292                                     void *cb_data)
293 {
294         struct sr_datafeed_packet packet;
295         struct sr_datafeed_header header;
296         struct dev_context *devc;
297
298         if (!(devc = sdi->priv)) {
299                 sr_err("sdi->priv was NULL.");
300                 return SR_ERR_BUG;
301         }
302
303         sr_dbg("Starting acquisition.");
304
305         devc->cb_data = cb_data;
306
307         /*
308          * Reset the number of samples to take. If we've already collected our
309          * quota, but we start a new session, and don't reset this, we'll just
310          * quit without acquiring any new samples.
311          */
312         devc->num_samples = 0;
313         devc->starttime = g_get_monotonic_time();
314
315         /* Send header packet to the session bus. */
316         sr_dbg("Sending SR_DF_HEADER.");
317         packet.type = SR_DF_HEADER;
318         packet.payload = &header;
319         header.feed_version = 1;
320         gettimeofday(&header.starttime, NULL);
321         sr_session_send(devc->cb_data, &packet);
322
323         /* Poll every 50ms, or whenever some data comes in. */
324         sr_source_add(devc->serial->fd, G_IO_IN, 50,
325                       brymen_dmm_receive_data, (void *)sdi);
326
327         return SR_OK;
328 }
329
330 static int hw_dev_acquisition_stop(struct sr_dev_inst *sdi, void *cb_data)
331 {
332         struct sr_datafeed_packet packet;
333         struct dev_context *devc;
334
335         if (sdi->status != SR_ST_ACTIVE) {
336                 sr_err("Device inactive, can't stop acquisition.");
337                 return SR_ERR;
338         }
339
340         if (!(devc = sdi->priv)) {
341                 sr_err("sdi->priv was NULL.");
342                 return SR_ERR_BUG;
343         }
344
345         sr_dbg("Stopping acquisition.");
346
347         sr_source_remove(devc->serial->fd);
348         hw_dev_close((struct sr_dev_inst *)sdi);
349
350         /* Send end packet to the session bus. */
351         sr_dbg("Sending SR_DF_END.");
352         packet.type = SR_DF_END;
353         sr_session_send(cb_data, &packet);
354
355         return SR_OK;
356 }
357
358 SR_PRIV struct sr_dev_driver brymen_dmm_driver_info = {
359         .name = "brymen-dmm",
360         .longname = "Brymen BM850 series",
361         .api_version = 1,
362         .init = hw_init,
363         .cleanup = hw_cleanup,
364         .scan = hw_scan,
365         .dev_list = hw_dev_list,
366         .dev_clear = clear_instances,
367         .dev_open = hw_dev_open,
368         .dev_close = hw_dev_close,
369         .config_list = config_list,
370         .config_set = hw_dev_config_set,
371         .dev_acquisition_start = hw_dev_acquisition_start,
372         .dev_acquisition_stop = hw_dev_acquisition_stop,
373         .priv = NULL,
374 };