]> sigrok.org Git - libsigrok.git/blob - src/transform/transform.c
Doxygen: Properly mark a few symbols as private.
[libsigrok.git] / src / transform / transform.c
1 /*
2  * This file is part of the libsigrok project.
3  *
4  * Copyright (C) 2014 Bert Vermeulen <bert@biot.com>
5  * Copyright (C) 2015 Uwe Hermann <uwe@hermann-uwe.de>
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 <config.h>
22 #include <string.h>
23 #include <libsigrok/libsigrok.h>
24 #include "libsigrok-internal.h"
25
26 /** @cond PRIVATE */
27 #define LOG_PREFIX "transform"
28 /** @endcond */
29
30 /**
31  * @file
32  *
33  * Transform module handling.
34  */
35
36 /**
37  * @defgroup grp_transform Transform modules
38  *
39  * Transform module handling.
40  *
41  * @{
42  */
43
44 /** @cond PRIVATE */
45 extern SR_PRIV struct sr_transform_module transform_nop;
46 extern SR_PRIV struct sr_transform_module transform_scale;
47 extern SR_PRIV struct sr_transform_module transform_invert;
48 /** @endcond */
49
50 static const struct sr_transform_module *transform_module_list[] = {
51         &transform_nop,
52         &transform_scale,
53         &transform_invert,
54         NULL,
55 };
56
57 /**
58  * Returns a NULL-terminated list of all available transform modules.
59  *
60  * @since 0.4.0
61  */
62 SR_API const struct sr_transform_module **sr_transform_list(void)
63 {
64         return transform_module_list;
65 }
66
67 /**
68  * Returns the specified transform module's ID.
69  *
70  * @since 0.4.0
71  */
72 SR_API const char *sr_transform_id_get(const struct sr_transform_module *tmod)
73 {
74         if (!tmod) {
75                 sr_err("Invalid transform module NULL!");
76                 return NULL;
77         }
78
79         return tmod->id;
80 }
81
82 /**
83  * Returns the specified transform module's name.
84  *
85  * @since 0.4.0
86  */
87 SR_API const char *sr_transform_name_get(const struct sr_transform_module *tmod)
88 {
89         if (!tmod) {
90                 sr_err("Invalid transform module NULL!");
91                 return NULL;
92         }
93
94         return tmod->name;
95 }
96
97 /**
98  * Returns the specified transform module's description.
99  *
100  * @since 0.4.0
101  */
102 SR_API const char *sr_transform_description_get(const struct sr_transform_module *tmod)
103 {
104         if (!tmod) {
105                 sr_err("Invalid transform module NULL!");
106                 return NULL;
107         }
108
109         return tmod->desc;
110 }
111
112 /**
113  * Return the transform module with the specified ID, or NULL if no module
114  * with that ID is found.
115  *
116  * @since 0.4.0
117  */
118 SR_API const struct sr_transform_module *sr_transform_find(const char *id)
119 {
120         int i;
121
122         for (i = 0; transform_module_list[i]; i++) {
123                 if (!strcmp(transform_module_list[i]->id, id))
124                         return transform_module_list[i];
125         }
126
127         return NULL;
128 }
129
130 /**
131  * Returns a NULL-terminated array of struct sr_option, or NULL if the
132  * module takes no options.
133  *
134  * Each call to this function must be followed by a call to
135  * sr_transform_options_free().
136  *
137  * @since 0.4.0
138  */
139 SR_API const struct sr_option **sr_transform_options_get(const struct sr_transform_module *tmod)
140 {
141         const struct sr_option *mod_opts, **opts;
142         int size, i;
143
144         if (!tmod || !tmod->options)
145                 return NULL;
146
147         mod_opts = tmod->options();
148
149         for (size = 0; mod_opts[size].id; size++)
150                 ;
151         opts = g_malloc((size + 1) * sizeof(struct sr_option *));
152
153         for (i = 0; i < size; i++)
154                 opts[i] = &mod_opts[i];
155         opts[i] = NULL;
156
157         return opts;
158 }
159
160 /**
161  * After a call to sr_transform_options_get(), this function cleans up all
162  * resources returned by that call.
163  *
164  * @since 0.4.0
165  */
166 SR_API void sr_transform_options_free(const struct sr_option **options)
167 {
168         int i;
169
170         if (!options)
171                 return;
172
173         for (i = 0; options[i]; i++) {
174                 if (options[i]->def) {
175                         g_variant_unref(options[i]->def);
176                         ((struct sr_option *)options[i])->def = NULL;
177                 }
178
179                 if (options[i]->values) {
180                         g_slist_free_full(options[i]->values, (GDestroyNotify)g_variant_unref);
181                         ((struct sr_option *)options[i])->values = NULL;
182                 }
183         }
184         g_free(options);
185 }
186
187 /**
188  * Create a new transform instance using the specified transform module.
189  *
190  * <code>options</code> is a *GHashTable with the keys corresponding with
191  * the module options' <code>id</code> field. The values should be GVariant
192  * pointers with sunk * references, of the same GVariantType as the option's
193  * default value.
194  *
195  * The sr_dev_inst passed in can be used by the instance to determine
196  * channel names, samplerate, and so on.
197  *
198  * @since 0.4.0
199  */
200 SR_API const struct sr_transform *sr_transform_new(const struct sr_transform_module *tmod,
201                 GHashTable *options, const struct sr_dev_inst *sdi)
202 {
203         struct sr_transform *t;
204         const struct sr_option *mod_opts;
205         const GVariantType *gvt;
206         GHashTable *new_opts;
207         GHashTableIter iter;
208         gpointer key, value;
209         int i;
210
211         t = g_malloc(sizeof(struct sr_transform));
212         t->module = tmod;
213         t->sdi = sdi;
214
215         new_opts = g_hash_table_new_full(g_str_hash, g_str_equal, g_free,
216                         (GDestroyNotify)g_variant_unref);
217         if (tmod->options) {
218                 mod_opts = tmod->options();
219                 for (i = 0; mod_opts[i].id; i++) {
220                         if (options && g_hash_table_lookup_extended(options,
221                                         mod_opts[i].id, &key, &value)) {
222                                 /* Pass option along. */
223                                 gvt = g_variant_get_type(mod_opts[i].def);
224                                 if (!g_variant_is_of_type(value, gvt)) {
225                                         sr_err("Invalid type for '%s' option.",
226                                                 (char *)key);
227                                         g_free(t);
228                                         return NULL;
229                                 }
230                                 g_hash_table_insert(new_opts, g_strdup(mod_opts[i].id),
231                                                 g_variant_ref(value));
232                         } else {
233                                 /* Option not given: insert the default value. */
234                                 g_hash_table_insert(new_opts, g_strdup(mod_opts[i].id),
235                                                 g_variant_ref(mod_opts[i].def));
236                         }
237                 }
238
239                 /* Make sure no invalid options were given. */
240                 if (options) {
241                         g_hash_table_iter_init(&iter, options);
242                         while (g_hash_table_iter_next(&iter, &key, &value)) {
243                                 if (!g_hash_table_lookup(new_opts, key)) {
244                                         sr_err("Transform module '%s' has no option '%s'.",
245                                                 tmod->id, (char *)key);
246                                         g_hash_table_destroy(new_opts);
247                                         g_free(t);
248                                         return NULL;
249                                 }
250                         }
251                 }
252         }
253
254         if (t->module->init && t->module->init(t, new_opts) != SR_OK) {
255                 g_free(t);
256                 t = NULL;
257         }
258         if (new_opts)
259                 g_hash_table_destroy(new_opts);
260
261         /* Add the transform to the session's list of transforms. */
262         sdi->session->transforms = g_slist_append(sdi->session->transforms, t);
263
264         return t;
265 }
266
267 /**
268  * Free the specified transform instance and all associated resources.
269  *
270  * @since 0.4.0
271  */
272 SR_API int sr_transform_free(const struct sr_transform *t)
273 {
274         int ret;
275
276         if (!t)
277                 return SR_ERR_ARG;
278
279         ret = SR_OK;
280         if (t->module->cleanup)
281                 ret = t->module->cleanup((struct sr_transform *)t);
282         g_free((gpointer)t);
283
284         return ret;
285 }
286
287 /** @} */