]> sigrok.org Git - libsigrok.git/blob - src/backend.c
output/csv: use intermediate time_t var, silence compiler warning
[libsigrok.git] / src / backend.c
1 /*
2  * This file is part of the libsigrok project.
3  *
4  * Copyright (C) 2010-2012 Bert Vermeulen <bert@biot.com>
5  * Copyright (C) 2012 Peter Stuge <peter@stuge.se>
6  *
7  * This program is free software: you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation, either version 3 of the License, or
10  * (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
19  */
20
21 #include <glib.h>
22 #include "config.h" /* Needed for HAVE_LIBUSB_1_0 and others. */
23 #include "libsigrok.h"
24 #include "libsigrok-internal.h"
25
26 /** @cond PRIVATE */
27 #define LOG_PREFIX "backend"
28 /** @endcond */
29
30 /**
31  * @mainpage libsigrok API
32  *
33  * @section sec_intro Introduction
34  *
35  * The <a href="http://sigrok.org">sigrok</a> project aims at creating a
36  * portable, cross-platform, Free/Libre/Open-Source signal analysis software
37  * suite that supports various device types (such as logic analyzers,
38  * oscilloscopes, multimeters, and more).
39  *
40  * <a href="http://sigrok.org/wiki/Libsigrok">libsigrok</a> is a shared
41  * library written in C which provides the basic API for talking to
42  * <a href="http://sigrok.org/wiki/Supported_hardware">supported hardware</a>
43  * and reading/writing the acquired data into various
44  * <a href="http://sigrok.org/wiki/Input_output_formats">input/output
45  * file formats</a>.
46  *
47  * @section sec_api API reference
48  *
49  * See the "Modules" page for an introduction to various libsigrok
50  * related topics and the detailed API documentation of the respective
51  * functions.
52  *
53  * You can also browse the API documentation by file, or review all
54  * data structures.
55  *
56  * @section sec_mailinglists Mailing lists
57  *
58  * There is one mailing list for sigrok/libsigrok: <a href="https://lists.sourceforge.net/lists/listinfo/sigrok-devel">sigrok-devel</a>.
59  *
60  * @section sec_irc IRC
61  *
62  * You can find the sigrok developers in the
63  * <a href="irc://chat.freenode.net/sigrok">\#sigrok</a>
64  * IRC channel on Freenode.
65  *
66  * @section sec_website Website
67  *
68  * <a href="http://sigrok.org/wiki/Libsigrok">sigrok.org/wiki/Libsigrok</a>
69  */
70
71 /**
72  * @file
73  *
74  * Initializing and shutting down libsigrok.
75  */
76
77 /**
78  * @defgroup grp_init Initialization
79  *
80  * Initializing and shutting down libsigrok.
81  *
82  * Before using any of the libsigrok functionality (except
83  * sr_log_loglevel_set() and sr_log_opts_set()), sr_init() must
84  * be called to initialize the library, which will return a struct sr_context
85  * when the initialization was successful.
86  *
87  * When libsigrok functionality is no longer needed, sr_exit() should be
88  * called, which will (among other things) free the struct sr_context.
89  *
90  * Example for a minimal program using libsigrok:
91  *
92  * @code{.c}
93  *   #include <stdio.h>
94  *   #include <libsigrok/libsigrok.h>
95  *
96  *   int main(int argc, char **argv)
97  *   {
98  *      int ret;
99  *      struct sr_context *sr_ctx;
100  *
101  *      if ((ret = sr_init(&sr_ctx)) != SR_OK) {
102  *              printf("Error initializing libsigrok (%s): %s.\n",
103  *                     sr_strerror_name(ret), sr_strerror(ret));
104  *              return 1;
105  *      }
106  *
107  *      // Use libsigrok functions here...
108  *
109  *      if ((ret = sr_exit(sr_ctx)) != SR_OK) {
110  *              printf("Error shutting down libsigrok (%s): %s.\n",
111  *                     sr_strerror_name(ret), sr_strerror(ret));
112  *              return 1;
113  *      }
114  *
115  *      return 0;
116  *   }
117  * @endcode
118  *
119  * @{
120  */
121
122 /**
123  * Sanity-check all libsigrok drivers.
124  *
125  * @param[in] ctx Pointer to a libsigrok context struct. Must not be NULL.
126  *
127  * @retval SR_OK All drivers are OK
128  * @retval SR_ERR One or more drivers have issues.
129  * @retval SR_ERR_ARG Invalid argument.
130  */
131 static int sanity_check_all_drivers(const struct sr_context *ctx)
132 {
133         int i, errors, ret = SR_OK;
134         struct sr_dev_driver **drivers;
135         const char *d;
136
137         if (!ctx)
138                 return SR_ERR_ARG;
139
140         sr_spew("Sanity-checking all drivers.");
141
142         drivers = sr_driver_list(ctx);
143         for (i = 0; drivers[i]; i++) {
144                 errors = 0;
145
146                 d = (drivers[i]->name) ? drivers[i]->name : "NULL";
147
148                 if (!drivers[i]->name) {
149                         sr_err("No name in driver %d ('%s').", i, d);
150                         errors++;
151                 }
152                 if (!drivers[i]->longname) {
153                         sr_err("No longname in driver %d ('%s').", i, d);
154                         errors++;
155                 }
156                 if (drivers[i]->api_version < 1) {
157                         sr_err("API version in driver %d ('%s') < 1.", i, d);
158                         errors++;
159                 }
160                 if (!drivers[i]->init) {
161                         sr_err("No init in driver %d ('%s').", i, d);
162                         errors++;
163                 }
164                 if (!drivers[i]->cleanup) {
165                         sr_err("No cleanup in driver %d ('%s').", i, d);
166                         errors++;
167                 }
168                 if (!drivers[i]->scan) {
169                         sr_err("No scan in driver %d ('%s').", i, d);
170                         errors++;
171                 }
172                 if (!drivers[i]->dev_list) {
173                         sr_err("No dev_list in driver %d ('%s').", i, d);
174                         errors++;
175                 }
176                 /* Note: config_get() is optional. */
177                 if (!drivers[i]->config_set) {
178                         sr_err("No config_set in driver %d ('%s').", i, d);
179                         errors++;
180                 }
181                 if (!drivers[i]->config_list) {
182                         sr_err("No config_list in driver %d ('%s').", i, d);
183                         errors++;
184                 }
185                 if (!drivers[i]->dev_open) {
186                         sr_err("No dev_open in driver %d ('%s').", i, d);
187                         errors++;
188                 }
189                 if (!drivers[i]->dev_close) {
190                         sr_err("No dev_close in driver %d ('%s').", i, d);
191                         errors++;
192                 }
193                 if (!drivers[i]->dev_acquisition_start) {
194                         sr_err("No dev_acquisition_start in driver %d ('%s').",
195                                i, d);
196                         errors++;
197                 }
198                 if (!drivers[i]->dev_acquisition_stop) {
199                         sr_err("No dev_acquisition_stop in driver %d ('%s').",
200                                i, d);
201                         errors++;
202                 }
203
204                 /* Note: 'priv' is allowed to be NULL. */
205
206                 if (errors == 0)
207                         continue;
208
209                 ret = SR_ERR;
210         }
211
212         return ret;
213 }
214
215 /**
216  * Sanity-check all libsigrok input modules.
217  *
218  * @retval SR_OK All modules are OK
219  * @retval SR_ERR One or more modules have issues.
220  */
221 static int sanity_check_all_input_modules(void)
222 {
223         int i, errors, ret = SR_OK;
224         const struct sr_input_module **inputs;
225         const char *d;
226
227         sr_spew("Sanity-checking all input modules.");
228
229         inputs = sr_input_list();
230         for (i = 0; inputs[i]; i++) {
231                 errors = 0;
232
233                 d = (inputs[i]->id) ? inputs[i]->id : "NULL";
234
235                 if (!inputs[i]->id) {
236                         sr_err("No ID in module %d ('%s').", i, d);
237                         errors++;
238                 }
239                 if (!inputs[i]->name) {
240                         sr_err("No name in module %d ('%s').", i, d);
241                         errors++;
242                 }
243                 if (!inputs[i]->desc) {
244                         sr_err("No description in module %d ('%s').", i, d);
245                         errors++;
246                 }
247                 if (!inputs[i]->init) {
248                         sr_err("No init in module %d ('%s').", i, d);
249                         errors++;
250                 }
251                 if (!inputs[i]->receive) {
252                         sr_err("No receive in module %d ('%s').", i, d);
253                         errors++;
254                 }
255                 if (!inputs[i]->end) {
256                         sr_err("No end in module %d ('%s').", i, d);
257                         errors++;
258                 }
259
260                 if (errors == 0)
261                         continue;
262
263                 ret = SR_ERR;
264         }
265
266         return ret;
267 }
268
269 /**
270  * Sanity-check all libsigrok output modules.
271  *
272  * @retval SR_OK All modules are OK
273  * @retval SR_ERR One or more modules have issues.
274  */
275 static int sanity_check_all_output_modules(void)
276 {
277         int i, errors, ret = SR_OK;
278         const struct sr_output_module **outputs;
279         const char *d;
280
281         sr_spew("Sanity-checking all output modules.");
282
283         outputs = sr_output_list();
284         for (i = 0; outputs[i]; i++) {
285                 errors = 0;
286
287                 d = (outputs[i]->id) ? outputs[i]->id : "NULL";
288
289                 if (!outputs[i]->id) {
290                         sr_err("No ID in module %d ('%s').", i, d);
291                         errors++;
292                 }
293                 if (!outputs[i]->name) {
294                         sr_err("No name in module %d ('%s').", i, d);
295                         errors++;
296                 }
297                 if (!outputs[i]->desc) {
298                         sr_err("No description in module '%s'.", d);
299                         errors++;
300                 }
301                 if (!outputs[i]->receive) {
302                         sr_err("No receive in module '%s'.", d);
303                         errors++;
304                 }
305
306                 if (errors == 0)
307                         continue;
308
309                 ret = SR_ERR;
310         }
311
312         return ret;
313 }
314
315 /**
316  * Sanity-check all libsigrok transform modules.
317  *
318  * @retval SR_OK All modules are OK
319  * @retval SR_ERR One or more modules have issues.
320  */
321 static int sanity_check_all_transform_modules(void)
322 {
323         int i, errors, ret = SR_OK;
324         const struct sr_transform_module **transforms;
325         const char *d;
326
327         sr_spew("Sanity-checking all transform modules.");
328
329         transforms = sr_transform_list();
330         for (i = 0; transforms[i]; i++) {
331                 errors = 0;
332
333                 d = (transforms[i]->id) ? transforms[i]->id : "NULL";
334
335                 if (!transforms[i]->id) {
336                         sr_err("No ID in module %d ('%s').", i, d);
337                         errors++;
338                 }
339                 if (!transforms[i]->name) {
340                         sr_err("No name in module %d ('%s').", i, d);
341                         errors++;
342                 }
343                 if (!transforms[i]->desc) {
344                         sr_err("No description in module '%s'.", d);
345                         errors++;
346                 }
347                 /* Note: options() is optional. */
348                 /* Note: init() is optional. */
349                 if (!transforms[i]->receive) {
350                         sr_err("No receive in module '%s'.", d);
351                         errors++;
352                 }
353                 /* Note: cleanup() is optional. */
354
355                 if (errors == 0)
356                         continue;
357
358                 ret = SR_ERR;
359         }
360
361         return ret;
362 }
363
364 /**
365  * Initialize libsigrok.
366  *
367  * This function must be called before any other libsigrok function.
368  *
369  * @param ctx Pointer to a libsigrok context struct pointer. Must not be NULL.
370  *            This will be a pointer to a newly allocated libsigrok context
371  *            object upon success, and is undefined upon errors.
372  *
373  * @return SR_OK upon success, a (negative) error code otherwise. Upon errors
374  *         the 'ctx' pointer is undefined and should not be used. Upon success,
375  *         the context will be free'd by sr_exit() as part of the libsigrok
376  *         shutdown.
377  *
378  * @since 0.2.0
379  */
380 SR_API int sr_init(struct sr_context **ctx)
381 {
382         int ret = SR_ERR;
383         struct sr_context *context;
384         struct sr_dev_driver ***lists, **drivers;
385         GArray *array;
386
387         if (!ctx) {
388                 sr_err("%s(): libsigrok context was NULL.", __func__);
389                 return SR_ERR;
390         }
391
392         context = g_malloc0(sizeof(struct sr_context));
393
394         /* Generate ctx->driver_list at runtime. */
395         array = g_array_new(TRUE, FALSE, sizeof(struct sr_dev_driver *));
396         for (lists = drivers_lists; *lists; lists++)
397                 for (drivers = *lists; *drivers; drivers++)
398                         g_array_append_val(array, *drivers);
399         context->driver_list = (struct sr_dev_driver **)array->data;
400         g_array_free(array, FALSE);
401
402         if (sanity_check_all_drivers(context) < 0) {
403                 sr_err("Internal driver error(s), aborting.");
404                 return ret;
405         }
406
407         if (sanity_check_all_input_modules() < 0) {
408                 sr_err("Internal input module error(s), aborting.");
409                 return ret;
410         }
411
412         if (sanity_check_all_output_modules() < 0) {
413                 sr_err("Internal output module error(s), aborting.");
414                 return ret;
415         }
416
417         if (sanity_check_all_transform_modules() < 0) {
418                 sr_err("Internal transform module error(s), aborting.");
419                 return ret;
420         }
421
422 #ifdef HAVE_LIBUSB_1_0
423         ret = libusb_init(&context->libusb_ctx);
424         if (LIBUSB_SUCCESS != ret) {
425                 sr_err("libusb_init() returned %s.", libusb_error_name(ret));
426                 ret = SR_ERR;
427                 goto done;
428         }
429 #endif
430
431         *ctx = context;
432         context = NULL;
433         ret = SR_OK;
434
435 #ifdef HAVE_LIBUSB_1_0
436 done:
437 #endif
438         g_free(context);
439         return ret;
440 }
441
442 /**
443  * Shutdown libsigrok.
444  *
445  * @param ctx Pointer to a libsigrok context struct. Must not be NULL.
446  *
447  * @retval SR_OK Success
448  * @retval other Error code SR_ERR, ...
449  *
450  * @since 0.2.0
451  */
452 SR_API int sr_exit(struct sr_context *ctx)
453 {
454         if (!ctx) {
455                 sr_err("%s(): libsigrok context was NULL.", __func__);
456                 return SR_ERR;
457         }
458
459         sr_hw_cleanup_all(ctx);
460
461 #ifdef HAVE_LIBUSB_1_0
462         libusb_exit(ctx->libusb_ctx);
463 #endif
464
465         g_free(sr_driver_list(ctx));
466         g_free(ctx);
467
468         return SR_OK;
469 }
470
471 /** @} */