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