]> sigrok.org Git - libsigrok.git/blob - hardware/colead-slm/api.c
45e19ba670116f82fd8e6db7f688dd3c6ea349e3
[libsigrok.git] / hardware / colead-slm / api.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 <glib.h>
21 #include "libsigrok.h"
22 #include "libsigrok-internal.h"
23 #include "protocol.h"
24 #include <sys/types.h>
25 #include <sys/stat.h>
26 #include <fcntl.h>
27 #include <errno.h>
28 #include <string.h>
29
30 /* The Colead SL-5868P uses this. */
31 #define SERIALCOMM "2400/8n1"
32
33 static const int hwopts[] = {
34         SR_HWOPT_CONN,
35         SR_HWOPT_SERIALCOMM,
36         0,
37 };
38
39 static const int hwcaps[] = {
40         SR_HWCAP_SOUNDLEVELMETER,
41         SR_HWCAP_LIMIT_SAMPLES,
42         SR_HWCAP_LIMIT_MSEC,
43         SR_HWCAP_CONTINUOUS,
44         0,
45 };
46
47 static const char *probe_names[] = {
48         "P1",
49         NULL,
50 };
51
52 SR_PRIV struct sr_dev_driver colead_slm_driver_info;
53 static struct sr_dev_driver *di = &colead_slm_driver_info;
54
55 /* Properly close and free all devices. */
56 static int clear_instances(void)
57 {
58         struct sr_dev_inst *sdi;
59         struct drv_context *drvc;
60         struct dev_context *devc;
61         GSList *l;
62
63         if (!(drvc = di->priv))
64                 return SR_OK;
65
66         for (l = drvc->instances; l; l = l->next) {
67                 if (!(sdi = l->data))
68                         continue;
69                 if (!(devc = sdi->priv))
70                         continue;
71                 sr_serial_dev_inst_free(devc->serial);
72                 sr_dev_inst_free(sdi);
73         }
74         g_slist_free(drvc->instances);
75         drvc->instances = NULL;
76
77         return SR_OK;
78 }
79
80 static int hw_init(void)
81 {
82         struct drv_context *drvc;
83
84         if (!(drvc = g_try_malloc0(sizeof(struct drv_context)))) {
85                 sr_err("Driver context malloc failed.");
86                 return SR_ERR;
87         }
88
89         di->priv = drvc;
90
91         return SR_OK;
92 }
93
94 static GSList *hw_scan(GSList *options)
95 {
96         struct drv_context *drvc;
97         struct dev_context *devc;
98         struct sr_dev_inst *sdi;
99         struct sr_hwopt *opt;
100         struct sr_probe *probe;
101         GSList *devices, *l;
102         const char *conn, *serialcomm;
103
104         devices = NULL;
105         drvc = di->priv;
106         drvc->instances = NULL;
107
108         conn = serialcomm = NULL;
109         for (l = options; l; l = l->next) {
110                 opt = l->data;
111                 switch (opt->hwopt) {
112                 case SR_HWOPT_CONN:
113                         conn = opt->value;
114                         break;
115                 case SR_HWOPT_SERIALCOMM:
116                         serialcomm = opt->value;
117                         break;
118                 }
119         }
120         if (!conn)
121                 return NULL;
122         if (!serialcomm)
123                 serialcomm = SERIALCOMM;
124
125         if (!(sdi = sr_dev_inst_new(0, SR_ST_INACTIVE, "Colead",
126                         "SL-5868P", NULL)))
127                 return NULL;
128
129         if (!(devc = g_try_malloc0(sizeof(struct dev_context)))) {
130                 sr_dbg("failed to malloc devc");
131                 return NULL;
132         }
133
134         if (!(devc->serial = sr_serial_dev_inst_new(conn, serialcomm)))
135                 return NULL;
136
137         sdi->priv = devc;
138         sdi->driver = di;
139         if (!(probe = sr_probe_new(0, SR_PROBE_ANALOG, TRUE, "P1")))
140                 return NULL;
141         sdi->probes = g_slist_append(sdi->probes, probe);
142         drvc->instances = g_slist_append(drvc->instances, sdi);
143         devices = g_slist_append(devices, sdi);
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 dev_context *devc;
160
161         if (!(devc = sdi->priv)) {
162                 sr_err("sdi->priv was NULL.");
163                 return SR_ERR_BUG;
164         }
165
166         if (serial_open(devc->serial, SERIAL_RDWR) != SR_OK)
167                 return SR_ERR;
168
169         sdi->status = SR_ST_ACTIVE;
170
171         return SR_OK;
172 }
173
174 static int hw_dev_close(struct sr_dev_inst *sdi)
175 {
176         struct dev_context *devc;
177
178         if (!(devc = sdi->priv)) {
179                 sr_err("sdi->priv was NULL.");
180                 return SR_ERR_BUG;
181         }
182
183         if (devc->serial && devc->serial->fd != -1) {
184                 serial_close(devc->serial);
185                 sdi->status = SR_ST_INACTIVE;
186         }
187
188         return SR_OK;
189 }
190
191 static int hw_cleanup(void)
192 {
193         clear_instances();
194
195         return SR_OK;
196 }
197
198 static int hw_info_get(int info_id, const void **data,
199                        const struct sr_dev_inst *sdi)
200 {
201         
202         (void)sdi;
203
204         switch (info_id) {
205         case SR_DI_HWOPTS:
206                 *data = hwopts;
207                 break;
208         case SR_DI_HWCAPS:
209                 *data = hwcaps;
210                 break;
211         case SR_DI_NUM_PROBES:
212                 *data = GINT_TO_POINTER(1);
213                 break;
214         case SR_DI_PROBE_NAMES:
215                 *data = probe_names;
216                 break;
217         default:
218                 return SR_ERR_ARG;
219         }
220
221         return SR_OK;
222 }
223
224 static int hw_dev_config_set(const struct sr_dev_inst *sdi, int hwcap,
225                              const void *value)
226 {
227         struct dev_context *devc;
228
229         if (sdi->status != SR_ST_ACTIVE)
230                 return SR_ERR;
231
232         if (!(devc = sdi->priv)) {
233                 sr_err("sdi->priv was NULL.");
234                 return SR_ERR_BUG;
235         }
236
237         switch (hwcap) {
238         case SR_HWCAP_LIMIT_MSEC:
239                 /* TODO: not yet implemented */
240                 if (*(const uint64_t *)value == 0) {
241                         sr_err("LIMIT_MSEC can't be 0.");
242                         return SR_ERR;
243                 }
244                 devc->limit_msec = *(const uint64_t *)value;
245                 sr_dbg("Setting time limit to %" PRIu64 "ms.",
246                        devc->limit_msec);
247                 break;
248         case SR_HWCAP_LIMIT_SAMPLES:
249                 devc->limit_samples = *(const uint64_t *)value;
250                 sr_dbg("Setting sample limit to %" PRIu64 ".",
251                        devc->limit_samples);
252                 break;
253         default:
254                 sr_err("Unknown capability: %d.", hwcap);
255                 return SR_ERR;
256                 break;
257         }
258
259         return SR_OK;
260 }
261
262 static int hw_dev_acquisition_start(const struct sr_dev_inst *sdi,
263                                     void *cb_data)
264 {
265         struct sr_datafeed_packet packet;
266         struct sr_datafeed_header header;
267         struct sr_datafeed_meta_analog meta;
268         struct dev_context *devc;
269
270         if (!(devc = sdi->priv)) {
271                 sr_err("sdi->priv was NULL.");
272                 return SR_ERR_BUG;
273         }
274
275         sr_dbg("Starting acquisition.");
276
277         devc->cb_data = cb_data;
278
279         /* Send header packet to the session bus. */
280         sr_dbg("Sending SR_DF_HEADER.");
281         packet.type = SR_DF_HEADER;
282         packet.payload = (uint8_t *)&header;
283         header.feed_version = 1;
284         gettimeofday(&header.starttime, NULL);
285         sr_session_send(devc->cb_data, &packet);
286
287         /* Send metadata about the SR_DF_ANALOG packets to come. */
288         sr_dbg("Sending SR_DF_META_ANALOG.");
289         packet.type = SR_DF_META_ANALOG;
290         packet.payload = &meta;
291         meta.num_probes = 1;
292         sr_session_send(devc->cb_data, &packet);
293
294         /* Poll every 150ms, or whenever some data comes in. */
295         sr_source_add(devc->serial->fd, G_IO_IN, 150, colead_slm_receive_data,
296                         (void *)sdi);
297
298         return SR_OK;
299 }
300
301 static int hw_dev_acquisition_stop(struct sr_dev_inst *sdi, void *cb_data)
302 {
303         struct sr_datafeed_packet packet;
304         struct dev_context *devc;
305
306         if (sdi->status != SR_ST_ACTIVE)
307                 return SR_ERR;
308
309         if (!(devc = sdi->priv)) {
310                 sr_err("sdi->priv was NULL.");
311                 return SR_ERR_BUG;
312         }
313
314         sr_dbg("Stopping acquisition.");
315
316         sr_source_remove(devc->serial->fd);
317         hw_dev_close((struct sr_dev_inst *)sdi);
318
319         /* Send end packet to the session bus. */
320         sr_dbg("Sending SR_DF_END.");
321         packet.type = SR_DF_END;
322         sr_session_send(cb_data, &packet);
323
324         return SR_OK;
325 }
326
327 SR_PRIV struct sr_dev_driver colead_slm_driver_info = {
328         .name = "colead-slm",
329         .longname = "Colead SLM",
330         .api_version = 1,
331         .init = hw_init,
332         .cleanup = hw_cleanup,
333         .scan = hw_scan,
334         .dev_list = hw_dev_list,
335         .dev_clear = clear_instances,
336         .dev_open = hw_dev_open,
337         .dev_close = hw_dev_close,
338         .info_get = hw_info_get,
339         .dev_config_set = hw_dev_config_set,
340         .dev_acquisition_start = hw_dev_acquisition_start,
341         .dev_acquisition_stop = hw_dev_acquisition_stop,
342         .priv = NULL,
343 };