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