1 /*
2 * Hamlib Interface - rotator ext parameter interface
3 * Copyright (c) 2020 by Mikael Nousiainen
4 *
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * This library 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 GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19 *
20 */
21
22 /**
23 * \addtogroup rotator
24 * @{
25 */
26
27 /**
28 * \file rot_ext.c
29 * \brief Rotator extension parameters and levels interface.
30 *
31 * \author Mikael Nousiainen
32 * \date 2020
33 *
34 * An open-ended set of extension parameters, functions and levels are
35 * available for each rotator, as provided in the rot_caps::extparms,
36 * rot_caps::extfuncs and rot_caps::extlevels lists. These provide a way to
37 * work with rotator-specific functions that don't fit into the basic "virtual
38 * rotator" of Hamlib.
39 */
40
41 #ifdef HAVE_CONFIG_H
42 # include "config.h"
43 #endif
44
45 #include <stdio.h> /* Standard input/output definitions */
46 #include <string.h> /* String function definitions */
47
48 #include <hamlib/rig.h>
49 #include <hamlib/rotator.h>
50
51 #include "token.h"
52
rot_has_ext_token(ROT * rot,token_t token)53 static int rot_has_ext_token(ROT *rot, token_t token)
54 {
55 int *ext_tokens = rot->caps->ext_tokens;
56 int i;
57
58 if (ext_tokens == NULL)
59 {
60 // Assume that all listed extfuncs/extlevels/extparms are supported if
61 // the ext_tokens list is not defined to preserve backwards-compatibility
62 return 1;
63 }
64
65 for (i = 0; ext_tokens[i] != TOK_BACKEND_NONE; i++)
66 {
67 if (ext_tokens[i] == token)
68 {
69 return 1;
70 }
71 }
72
73 return 0;
74 }
75
76
77 /**
78 * \brief Executes \a cfunc on all the elements stored in the
79 * rot_caps::extfuncs table.
80 *
81 * \param rot The #ROT handle.
82 * \param cfunc Callback function of each rot_caps::extfunc.
83 * \param data Cookie to be passed to the callback function \a cfunc.
84 *
85 * The callback \a cfunc is called until it returns a value which is not
86 * strictly positive.
87 *
88 * \returns A zero value means a normal end of iteration, or a **negative
89 * value** which means an abnormal end.
90 *
91 * \retval RIG_OK All extension functions elements successfully processed.
92 * \retval RIG_EINVAL \a rot or \a cfunc is NULL or inconsistent.
93 */
rot_ext_func_foreach(ROT * rot,int (* cfunc)(ROT *,const struct confparams *,rig_ptr_t),rig_ptr_t data)94 int HAMLIB_API rot_ext_func_foreach(ROT *rot,
95 int (*cfunc)(ROT *,
96 const struct confparams *,
97 rig_ptr_t),
98 rig_ptr_t data)
99 {
100 const struct confparams *cfp;
101
102 rig_debug(RIG_DEBUG_VERBOSE, "%s called\n", __func__);
103
104 if (!rot || !rot->caps || !cfunc)
105 {
106 return -RIG_EINVAL;
107 }
108
109 for (cfp = rot->caps->extfuncs; cfp && cfp->name; cfp++)
110 {
111 if (!rot_has_ext_token(rot, cfp->token))
112 {
113 continue;
114 }
115
116 int ret = (*cfunc)(rot, cfp, data);
117
118 if (ret == 0)
119 {
120 return RIG_OK;
121 }
122
123 if (ret < 0)
124 {
125 return ret;
126 }
127 }
128
129 return RIG_OK;
130 }
131
132
133 /**
134 * \brief Executes \a cfunc on all the elements stored in the
135 * rot_caps::extlevels extension levels table.
136 *
137 * \param rot The #ROT handle.
138 * \param cfunc Callback function of each rot_caps::extlevels.
139 * \param data Cookie to be passed to the callback function \a cfunc.
140 *
141 * The callback \a cfunc is called until it returns a value which is not
142 * strictly positive.
143 *
144 * \returns A zero value which means a normal end of iteration, or a
145 * **negative value** which means an abnormal end.
146 *
147 * \retval RIG_OK All extension levels elements successfully processed.
148 * \retval RIG_EINVAL \a rot or \a cfunc is NULL or inconsistent.
149 */
rot_ext_level_foreach(ROT * rot,int (* cfunc)(ROT *,const struct confparams *,rig_ptr_t),rig_ptr_t data)150 int HAMLIB_API rot_ext_level_foreach(ROT *rot,
151 int (*cfunc)(ROT *,
152 const struct confparams *,
153 rig_ptr_t),
154 rig_ptr_t data)
155 {
156 const struct confparams *cfp;
157
158 rig_debug(RIG_DEBUG_VERBOSE, "%s called\n", __func__);
159
160 if (!rot || !rot->caps || !cfunc)
161 {
162 return -RIG_EINVAL;
163 }
164
165 for (cfp = rot->caps->extlevels; cfp && cfp->name; cfp++)
166 {
167 if (!rot_has_ext_token(rot, cfp->token))
168 {
169 continue;
170 }
171
172 int ret = (*cfunc)(rot, cfp, data);
173
174 if (ret == 0)
175 {
176 return RIG_OK;
177 }
178
179 if (ret < 0)
180 {
181 return ret;
182 }
183 }
184
185 return RIG_OK;
186 }
187
188
189 /**
190 * \brief Executes \a cfunc on all the elements stored in the
191 * rot_caps::extparms extension parameters table.
192 *
193 * \param rot The #ROT handle.
194 * \param cfunc callback function of each rot_caps::extparms.
195 * \param data Cookie to be passed to the callback function \a cfunc.
196 *
197 * The callback function \a cfunc is called until it returns a value which is not
198 * strictly positive.
199 *
200 * \returns A zero value which means a normal end of iteration, or a
201 * **negative value** which means an abnormal end.
202 *
203 * \retval RIG_OK All extension parameters elements successfully processed.
204 * \retval RIG_EINVAL \a rot or \a cfunc is NULL or inconsistent.
205 */
rot_ext_parm_foreach(ROT * rot,int (* cfunc)(ROT *,const struct confparams *,rig_ptr_t),rig_ptr_t data)206 int HAMLIB_API rot_ext_parm_foreach(ROT *rot,
207 int (*cfunc)(ROT *,
208 const struct confparams *,
209 rig_ptr_t),
210 rig_ptr_t data)
211 {
212 const struct confparams *cfp;
213
214 rig_debug(RIG_DEBUG_VERBOSE, "%s called\n", __func__);
215
216 if (!rot || !rot->caps || !cfunc)
217 {
218 return -RIG_EINVAL;
219 }
220
221 for (cfp = rot->caps->extparms; cfp && cfp->name; cfp++)
222 {
223 if (!rot_has_ext_token(rot, cfp->token))
224 {
225 continue;
226 }
227
228 int ret = (*cfunc)(rot, cfp, data);
229
230 if (ret == 0)
231 {
232 return RIG_OK;
233 }
234
235 if (ret < 0)
236 {
237 return ret;
238 }
239 }
240
241 return RIG_OK;
242 }
243
244
245 /**
246 * \brief Lookup an extension functions, levels, or parameters token by its
247 * name and return a pointer to the containing #confparams structure member.
248 *
249 * \param rot The #ROT handle.
250 * \param name The extension functions, levels, or parameters token name.
251 *
252 * Searches the rot_caps::extlevels, rot_caps::extfuncs and the
253 * rot_caps::extparms tables in order for the token by its name.
254 *
255 * \note As this function is called by rot_ext_token_lookup(), it can be
256 * considered a lower level API.
257 *
258 * \return A pointer to the containing #confparams structure member or NULL if
259 * nothing found or if \a rot is NULL or inconsistent.
260 *
261 * \sa rot_ext_token_lookup()
262 *
263 * \todo Should use Lex to speed it up, strcmp() hurts!
264 */
rot_ext_lookup(ROT * rot,const char * name)265 const struct confparams *HAMLIB_API rot_ext_lookup(ROT *rot, const char *name)
266 {
267 const struct confparams *cfp;
268
269 rig_debug(RIG_DEBUG_VERBOSE, "%s called\n", __func__);
270
271 if (!rot || !rot->caps)
272 {
273 return NULL;
274 }
275
276 for (cfp = rot->caps->extlevels; cfp && cfp->name; cfp++)
277 {
278 if (!strcmp(cfp->name, name))
279 {
280 return cfp;
281 }
282 }
283
284 for (cfp = rot->caps->extfuncs; cfp && cfp->name; cfp++)
285 {
286 if (!strcmp(cfp->name, name))
287 {
288 return cfp;
289 }
290 }
291
292 for (cfp = rot->caps->extparms; cfp && cfp->name; cfp++)
293 {
294 if (!strcmp(cfp->name, name))
295 {
296 return cfp;
297 }
298 }
299
300 return NULL;
301 }
302
303 /**
304 * \brief Searches for an extension levels, functions, or parameters token by
305 * its constant value and return a pointer to the #confparams structure
306 * member.
307 *
308 * \param rot The #ROT handle.
309 * \param token The token value (constant).
310 *
311 * Searches the rot_caps::extlevels, rot_caps::extfuncs, and the
312 * rot_caps::extparms tables in order for the token by its constant value.
313 *
314 * \return A pointer to the containing #confparams structure member or NULL if
315 * nothing found or if \a rot is NULL or inconsistent.
316 */
rot_ext_lookup_tok(ROT * rot,token_t token)317 const struct confparams *HAMLIB_API rot_ext_lookup_tok(ROT *rot, token_t token)
318 {
319 const struct confparams *cfp;
320
321 rig_debug(RIG_DEBUG_VERBOSE, "%s called\n", __func__);
322
323 if (!rot || !rot->caps)
324 {
325 return NULL;
326 }
327
328 for (cfp = rot->caps->extlevels; cfp && cfp->token; cfp++)
329 {
330 if (cfp->token == token)
331 {
332 return cfp;
333 }
334 }
335
336 for (cfp = rot->caps->extfuncs; cfp && cfp->token; cfp++)
337 {
338 if (cfp->token == token)
339 {
340 return cfp;
341 }
342 }
343
344 for (cfp = rot->caps->extparms; cfp && cfp->token; cfp++)
345 {
346 if (cfp->token == token)
347 {
348 return cfp;
349 }
350 }
351
352 return NULL;
353 }
354
355
356 /**
357 * \brief Simple search returning the extension token ID associated with
358 * \a name.
359 *
360 * \param rot The #ROT handle.
361 * \param name The token name string to search.
362 *
363 * \note As this function calls rot_ext_lookup(), it can be considered a
364 * higher level API.
365 *
366 * \return The token ID or RIG_CONF_END if there is a lookup failure.
367 *
368 * \sa rot_ext_lookup()
369 */
rot_ext_token_lookup(ROT * rot,const char * name)370 token_t HAMLIB_API rot_ext_token_lookup(ROT *rot, const char *name)
371 {
372 const struct confparams *cfp;
373
374 rig_debug(RIG_DEBUG_VERBOSE, "%s called\n", __func__);
375
376 cfp = rot_ext_lookup(rot, name);
377
378 if (!cfp)
379 {
380 return RIG_CONF_END;
381 }
382
383 return cfp->token;
384 }
385
386 /** @} */
387