]> sigrok.org Git - libsigrok.git/blob - src/std.c
f68cc12bd8954c29c684043fe368ef514427dca5
[libsigrok.git] / src / std.c
1 /*
2  * This file is part of the libsigrok project.
3  *
4  * Copyright (C) 2013 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, see <http://www.gnu.org/licenses/>.
18  */
19
20 /**
21  * @file
22  *
23  * Standard API helper functions.
24  *
25  * @internal
26  */
27
28 #include <config.h>
29 #include <glib.h>
30 #include <libsigrok/libsigrok.h>
31 #include "libsigrok-internal.h"
32 #include "scpi.h"
33
34 #define LOG_PREFIX "std"
35
36 /**
37  * Standard driver init() callback API helper.
38  *
39  * This function can be used to simplify most driver's init() API callback.
40  *
41  * Create a new 'struct drv_context' (drvc), assign sr_ctx to it, and
42  * then assign 'drvc' to the 'struct sr_dev_driver' (di) that is passed.
43  *
44  * @param[in] di The driver instance to use. Must not be NULL.
45  * @param[in] sr_ctx The libsigrok context to assign. May be NULL.
46  *
47  * @retval SR_OK Success.
48  * @retval SR_ERR_ARG Invalid argument.
49  */
50 SR_PRIV int std_init(struct sr_dev_driver *di, struct sr_context *sr_ctx)
51 {
52         struct drv_context *drvc;
53
54         if (!di) {
55                 sr_err("%s: Invalid argument.", __func__);
56                 return SR_ERR_ARG;
57         }
58
59         drvc = g_malloc0(sizeof(struct drv_context));
60         drvc->sr_ctx = sr_ctx;
61         drvc->instances = NULL;
62         di->context = drvc;
63
64         return SR_OK;
65 }
66
67 /**
68  * Standard driver cleanup() callback API helper.
69  *
70  * This function can be used to simplify most driver's cleanup() API callback.
71  *
72  * Free all device instances by calling sr_dev_clear() and then release any
73  * resources allocated by std_init().
74  *
75  * @param[in] di The driver instance to use. Must not be NULL.
76  *
77  * @retval SR_OK Success.
78  * @retval SR_ERR_ARG Invalid argument.
79  * @retval other Other error.
80  */
81 SR_PRIV int std_cleanup(const struct sr_dev_driver *di)
82 {
83         int ret;
84
85         if (!di) {
86                 sr_err("%s: Invalid argument.", __func__);
87                 return SR_ERR_ARG;
88         }
89
90         ret = sr_dev_clear(di);
91         g_free(di->context);
92
93         return ret;
94 }
95
96 /**
97  * Standard API helper for sending an SR_DF_HEADER packet.
98  *
99  * This function can be used to simplify most drivers'
100  * dev_acquisition_start() API callback.
101  *
102  * @param[in] sdi The device instance to use. Must not be NULL.
103  *
104  * @retval SR_OK Success.
105  * @retval SR_ERR_ARG Invalid argument.
106  * @retval other Other error.
107  */
108 SR_PRIV int std_session_send_df_header(const struct sr_dev_inst *sdi)
109 {
110         const char *prefix;
111         int ret;
112         struct sr_datafeed_packet packet;
113         struct sr_datafeed_header header;
114
115         if (!sdi) {
116                 sr_err("%s: Invalid argument.", __func__);
117                 return SR_ERR_ARG;
118         }
119
120         prefix = (sdi->driver) ? sdi->driver->name : "unknown";
121
122         /* Send header packet to the session bus. */
123         sr_dbg("%s: Sending SR_DF_HEADER packet.", prefix);
124         packet.type = SR_DF_HEADER;
125         packet.payload = (uint8_t *)&header;
126         header.feed_version = 1;
127         gettimeofday(&header.starttime, NULL);
128
129         if ((ret = sr_session_send(sdi, &packet)) < 0) {
130                 sr_err("%s: Failed to send SR_DF_HEADER packet: %d.", prefix, ret);
131                 return ret;
132         }
133
134         return SR_OK;
135 }
136
137 /**
138  * Standard API helper for sending an SR_DF_END packet.
139  *
140  * This function can be used to simplify most drivers'
141  * dev_acquisition_stop() API callback.
142  *
143  * @param[in] sdi The device instance to use. Must not be NULL.
144  *
145  * @retval SR_OK Success.
146  * @retval SR_ERR_ARG Invalid argument.
147  * @retval other Other error.
148  */
149 SR_PRIV int std_session_send_df_end(const struct sr_dev_inst *sdi)
150 {
151         const char *prefix;
152         int ret;
153         struct sr_datafeed_packet packet;
154
155         if (!sdi) {
156                 sr_err("%s: Invalid argument.", __func__);
157                 return SR_ERR_ARG;
158         }
159
160         prefix = (sdi->driver) ? sdi->driver->name : "unknown";
161
162         sr_dbg("%s: Sending SR_DF_END packet.", prefix);
163
164         packet.type = SR_DF_END;
165         packet.payload = NULL;
166
167         if ((ret = sr_session_send(sdi, &packet)) < 0) {
168                 sr_err("%s: Failed to send SR_DF_END packet: %d.", prefix, ret);
169                 return ret;
170         }
171
172         return SR_OK;
173 }
174
175 #ifdef HAVE_LIBSERIALPORT
176
177 /**
178  * Standard serial driver dev_open() callback API helper.
179  *
180  * This function can be used to implement the dev_open() driver API
181  * callback in drivers that use a serial port. The port is opened
182  * with the SERIAL_RDWR flag.
183  *
184  * @param[in] sdi The device instance to use. Must not be NULL.
185  *
186  * @retval SR_OK Success.
187  * @retval SR_ERR_ARG Invalid argument.
188  * @retval other Serial port open failed.
189  */
190 SR_PRIV int std_serial_dev_open(struct sr_dev_inst *sdi)
191 {
192         struct sr_serial_dev_inst *serial;
193
194         if (!sdi) {
195                 sr_err("%s: Invalid argument.", __func__);
196                 return SR_ERR_ARG;
197         }
198
199         serial = sdi->conn;
200
201         return serial_open(serial, SERIAL_RDWR);
202 }
203
204 /**
205  * Standard serial driver dev_close() callback API helper.
206  *
207  * This function can be used to implement the dev_close() driver API
208  * callback in drivers that use a serial port.
209  *
210  * @param[in] sdi The device instance to use. Must not be NULL.
211  *
212  * @retval SR_OK Success.
213  * @retval SR_ERR_ARG Invalid argument.
214  * @retval other Serial port close failed.
215  */
216 SR_PRIV int std_serial_dev_close(struct sr_dev_inst *sdi)
217 {
218         struct sr_serial_dev_inst *serial;
219
220         if (!sdi) {
221                 sr_err("%s: Invalid argument.", __func__);
222                 return SR_ERR_ARG;
223         }
224
225         serial = sdi->conn;
226
227         return serial_close(serial);
228 }
229
230 /**
231  * Standard serial driver dev_acquisition_stop() callback API helper.
232  *
233  * This function can be used to simplify most (serial port based) drivers'
234  * dev_acquisition_stop() API callback.
235  *
236  * @param[in] sdi The device instance for which acquisition should stop.
237  *                Must not be NULL.
238  *
239  * @retval SR_OK Success.
240  * @retval SR_ERR_ARG Invalid argument.
241  * @retval other Other error.
242  */
243 SR_PRIV int std_serial_dev_acquisition_stop(struct sr_dev_inst *sdi)
244 {
245         struct sr_serial_dev_inst *serial;
246         const char *prefix;
247         int ret;
248
249         if (!sdi) {
250                 sr_err("%s: Invalid argument.", __func__);
251                 return SR_ERR_ARG;
252         }
253
254         serial = sdi->conn;
255         prefix = sdi->driver->name;
256
257         if ((ret = serial_source_remove(sdi->session, serial)) < 0) {
258                 sr_err("%s: Failed to remove source: %d.", prefix, ret);
259                 return ret;
260         }
261
262         if ((ret = sr_dev_close(sdi)) < 0) {
263                 sr_err("%s: Failed to close device: %d.", prefix, ret);
264                 return ret;
265         }
266
267         return std_session_send_df_end(sdi);
268 }
269
270 #endif
271
272 /**
273  * Standard driver dev_clear() callback API helper.
274  *
275  * Clear driver, this means, close all instances.
276  *
277  * This function can be used to implement the dev_clear() driver API
278  * callback. dev_close() is called before every sr_dev_inst is cleared.
279  *
280  * The only limitation is driver-specific device contexts (sdi->priv).
281  * These are freed, but any dynamic allocation within structs stored
282  * there cannot be freed.
283  *
284  * @param[in] driver The driver which will have its instances released.
285  *                   Must not be NULL.
286  * @param[in] clear_private If not NULL, this points to a function called
287  *            with sdi->priv as argument. The function can then clear
288  *            any device instance-specific resources kept there.
289  *            It must also clear the struct pointed to by sdi->priv.
290  *
291  * @retval SR_OK Success.
292  * @retval SR_ERR_ARG Invalid argument.
293  * @retval SR_ERR_BUG Implementation bug.
294  * @retval other Other error.
295  */
296 SR_PRIV int std_dev_clear(const struct sr_dev_driver *driver,
297                 std_dev_clear_callback clear_private)
298 {
299         struct drv_context *drvc;
300         struct sr_dev_inst *sdi;
301         GSList *l;
302         int ret;
303
304         if (!driver) {
305                 sr_err("%s: Invalid argument.", __func__);
306                 return SR_ERR_ARG;
307         }
308
309         drvc = driver->context; /* Caller checked for context != NULL. */
310
311         ret = SR_OK;
312         for (l = drvc->instances; l; l = l->next) {
313                 if (!(sdi = l->data)) {
314                         sr_err("%s: Invalid device instance.", __func__);
315                         ret = SR_ERR_BUG;
316                         continue;
317                 }
318                 if (driver->dev_close)
319                         driver->dev_close(sdi);
320
321                 if (sdi->conn) {
322 #ifdef HAVE_LIBSERIALPORT
323                         if (sdi->inst_type == SR_INST_SERIAL)
324                                 sr_serial_dev_inst_free(sdi->conn);
325 #endif
326 #ifdef HAVE_LIBUSB_1_0
327                         if (sdi->inst_type == SR_INST_USB)
328                                 sr_usb_dev_inst_free(sdi->conn);
329 #endif
330                         if (sdi->inst_type == SR_INST_SCPI)
331                                 sr_scpi_free(sdi->conn);
332                         if (sdi->inst_type == SR_INST_MODBUS)
333                                 sr_modbus_free(sdi->conn);
334                 }
335                 if (clear_private)
336                         /* The helper function is responsible for freeing
337                          * its own sdi->priv! */
338                         clear_private(sdi->priv);
339                 else
340                         g_free(sdi->priv);
341
342                 sr_dev_inst_free(sdi);
343         }
344
345         g_slist_free(drvc->instances);
346         drvc->instances = NULL;
347
348         return ret;
349 }
350
351 /**
352  * Standard driver dev_list() callback API helper.
353  *
354  * This function can be used as the dev_list() callback by most drivers.
355  *
356  * Return the devices contained in the driver context instances list.
357  *
358  * @param[in] di The driver instance to use. Must not be NULL.
359  *
360  * @retval NULL Error, or the list is empty.
361  * @retval other The list of device instances of this driver.
362  */
363 SR_PRIV GSList *std_dev_list(const struct sr_dev_driver *di)
364 {
365         struct drv_context *drvc;
366
367         if (!di) {
368                 sr_err("%s: Invalid argument.", __func__);
369                 return NULL;
370         }
371
372         drvc = di->context;
373
374         return drvc->instances;
375 }
376
377 /**
378  * Standard driver scan() callback API helper.
379  *
380  * This function can be used to perform common tasks required by a driver's
381  * scan() callback. It will initialize the driver for each device on the list
382  * and add the devices on the list to the driver's device instance list.
383  * Usually it should be used as the last step in the scan() callback, right
384  * before returning.
385  *
386  * Note: This function can only be used if std_init() has been called
387  * previously by the driver.
388  *
389  * Example:
390  * @code{c}
391  * static GSList *scan(struct sr_dev_driver *di, GSList *options)
392  * {
393  *     struct GSList *device;
394  *     struct sr_dev_inst *sdi;
395  *
396  *     sdi = g_new0(sr_dev_inst, 1);
397  *     sdi->vendor = ...;
398  *     ...
399  *     devices = g_slist_append(devices, sdi);
400  *     ...
401  *     return std_scan_complete(di, devices);
402  * }
403  * @endcode
404  *
405  * @param[in] di The driver instance to use. Must not be NULL.
406  * @param[in] devices List of newly discovered devices (struct sr_dev_inst).
407  *                    May be NULL.
408  *
409  * @return The @p devices list.
410  */
411 SR_PRIV GSList *std_scan_complete(struct sr_dev_driver *di, GSList *devices)
412 {
413         struct drv_context *drvc;
414         GSList *l;
415
416         if (!di) {
417                 sr_err("Invalid driver instance (di), cannot complete scan.");
418                 return NULL;
419         }
420
421         drvc = di->context;
422
423         for (l = devices; l; l = l->next) {
424                 struct sr_dev_inst *sdi = l->data;
425                 if (!sdi) {
426                         sr_err("Invalid device instance, cannot complete scan.");
427                         return NULL;
428                 }
429                 sdi->driver = di;
430         }
431
432         drvc->instances = g_slist_concat(drvc->instances, g_slist_copy(devices));
433
434         return devices;
435 }