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