1 /*
2 * Hamlib Interface - provides registering for dynamically loadable backends.
3 * Copyright (c) 2000-2004 by Stephane Fillod
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 * \brief Dynamic registration of rotator backends
24 * \file rot_reg.c
25 *
26 * Similar to register.c
27 * doc todo: Let's explain what's going on here!
28 */
29
30 #ifdef HAVE_CONFIG_H
31 # include "config.h"
32 #endif
33
34 #include <errno.h>
35 #include <stdlib.h>
36 #include <string.h>
37 #include <unistd.h>
38 #include <stdio.h>
39 #include <sys/types.h>
40
41 #include <hamlib/rotator.h>
42
43 #include "register.h"
44
45 //! @cond Doxygen_Suppress
46 #ifndef PATH_MAX
47 # define PATH_MAX 1024
48 #endif
49
50 #define ROT_BACKEND_MAX 32
51
52 #define DEFINE_INITROT_BACKEND(backend) \
53 int MAKE_VERSIONED_FN(PREFIX_INITROTS, \
54 ABI_VERSION, \
55 backend(void *be_handle)); \
56 rig_model_t MAKE_VERSIONED_FN(PREFIX_PROBEROTS, \
57 ABI_VERSION, \
58 backend(hamlib_port_t *port, \
59 rig_probe_func_t cfunc, \
60 rig_ptr_t data))
61
62 #define ROT_FUNCNAMA(backend) MAKE_VERSIONED_FN(PREFIX_INITROTS, ABI_VERSION, backend)
63 #define ROT_FUNCNAMB(backend) MAKE_VERSIONED_FN(PREFIX_PROBEROTS, ABI_VERSION, backend)
64
65 #define ROT_FUNCNAM(backend) ROT_FUNCNAMA(backend),ROT_FUNCNAMB(backend)
66
67
68 DEFINE_INITROT_BACKEND(dummy);
69 DEFINE_INITROT_BACKEND(easycomm);
70 DEFINE_INITROT_BACKEND(fodtrack);
71 DEFINE_INITROT_BACKEND(rotorez);
72 DEFINE_INITROT_BACKEND(sartek);
73 DEFINE_INITROT_BACKEND(gs232a);
74 DEFINE_INITROT_BACKEND(kit);
75 DEFINE_INITROT_BACKEND(heathkit);
76 DEFINE_INITROT_BACKEND(spid);
77 DEFINE_INITROT_BACKEND(m2);
78 DEFINE_INITROT_BACKEND(ars);
79 DEFINE_INITROT_BACKEND(amsat);
80 DEFINE_INITROT_BACKEND(ts7400);
81 DEFINE_INITROT_BACKEND(celestron);
82 DEFINE_INITROT_BACKEND(ether6);
83 DEFINE_INITROT_BACKEND(cnctrk);
84 DEFINE_INITROT_BACKEND(prosistel);
85 DEFINE_INITROT_BACKEND(meade);
86 DEFINE_INITROT_BACKEND(ioptron);
87 DEFINE_INITROT_BACKEND(satel);
88 DEFINE_INITROT_BACKEND(radant);
89 #if HAVE_LIBINDI
90 DEFINE_INITROT_BACKEND(indi);
91 #endif
92 //! @endcond
93
94 /**
95 * \def rot_backend_list
96 * \brief Static list of rotator models.
97 *
98 * This is a NULL terminated list of available rotator backends. Each entry
99 * in the list consists of two fields: The branch number, which is an integer,
100 * and the branch name, which is a character string.
101 * An external library, loaded dynamically, could add its own functions
102 * pointers in this array.
103 */
104 static struct
105 {
106 int be_num;
107 const char *be_name;
108 int (*be_init)(void *);
109 rot_model_t (*be_probe)(hamlib_port_t *);
110 } rot_backend_list[ROT_BACKEND_MAX] =
111 {
112 { ROT_DUMMY, ROT_BACKEND_DUMMY, ROT_FUNCNAMA(dummy) },
113 { ROT_EASYCOMM, ROT_BACKEND_EASYCOMM, ROT_FUNCNAMA(easycomm) },
114 { ROT_FODTRACK, ROT_BACKEND_FODTRACK, ROT_FUNCNAMA(fodtrack) },
115 { ROT_ROTOREZ, ROT_BACKEND_ROTOREZ, ROT_FUNCNAMA(rotorez) },
116 { ROT_SARTEK, ROT_BACKEND_SARTEK, ROT_FUNCNAMA(sartek) },
117 { ROT_GS232A, ROT_BACKEND_GS232A, ROT_FUNCNAMA(gs232a) },
118 { ROT_KIT, ROT_BACKEND_KIT, ROT_FUNCNAMA(kit) },
119 { ROT_HEATHKIT, ROT_BACKEND_HEATHKIT, ROT_FUNCNAMA(heathkit) },
120 { ROT_SPID, ROT_BACKEND_SPID, ROT_FUNCNAMA(spid) },
121 { ROT_M2, ROT_BACKEND_M2, ROT_FUNCNAMA(m2) },
122 { ROT_ARS, ROT_BACKEND_ARS, ROT_FUNCNAMA(ars) },
123 { ROT_AMSAT, ROT_BACKEND_AMSAT, ROT_FUNCNAMA(amsat) },
124 { ROT_TS7400, ROT_BACKEND_TS7400, ROT_FUNCNAMA(ts7400) },
125 { ROT_CELESTRON, ROT_BACKEND_CELESTRON, ROT_FUNCNAMA(celestron) },
126 { ROT_ETHER6, ROT_BACKEND_ETHER6, ROT_FUNCNAMA(ether6) },
127 { ROT_CNCTRK, ROT_BACKEND_CNCTRK, ROT_FUNCNAMA(cnctrk) },
128 { ROT_PROSISTEL, ROT_BACKEND_PROSISTEL, ROT_FUNCNAMA(prosistel) },
129 { ROT_MEADE, ROT_BACKEND_MEADE, ROT_FUNCNAMA(meade) },
130 { ROT_IOPTRON, ROT_BACKEND_IOPTRON, ROT_FUNCNAMA(ioptron) },
131 { ROT_SATEL, ROT_BACKEND_SATEL, ROT_FUNCNAMA(satel) },
132 { ROT_RADANT, ROT_BACKEND_RADANT, ROT_FUNCNAMA(radant)},
133 #if HAVE_LIBINDI
134 { ROT_INDI, ROT_BACKEND_INDI, ROT_FUNCNAMA(indi) },
135 #endif
136 { 0, NULL }, /* end */
137 };
138
139
140 // Apparently, no rotator can be probed.
141
142 /*
143 * ROT_BACKEND_LIST is here, please keep it up to date,
144 * i.e. each time you implement a new backend.
145 */
146
147
148 /*
149 * This struct to keep track of known rot models.
150 * It is chained, and used in a hash table, see below.
151 */
152 //! @cond Doxygen_Suppress
153 struct rot_list
154 {
155 const struct rot_caps *caps;
156 struct rot_list *next;
157 };
158 //! @endcond
159
160
161 //! @cond Doxygen_Suppress
162 #define ROTLSTHASHSZ 16
163 #define HASH_FUNC(a) ((a)%ROTLSTHASHSZ)
164 //! @endcond
165
166
167 /*
168 * The rot_hash_table is a hash table pointing to a list of next==NULL
169 * terminated caps.
170 */
171 static struct rot_list *rot_hash_table[ROTLSTHASHSZ] = { NULL, };
172
173
174 static int rot_lookup_backend(rot_model_t rot_model);
175
176
177 /*
178 * Basically, this is a hash insert function that doesn't check for dup!
179 */
180 //! @cond Doxygen_Suppress
rot_register(const struct rot_caps * caps)181 int HAMLIB_API rot_register(const struct rot_caps *caps)
182 {
183 int hval;
184 struct rot_list *p;
185
186 if (!caps)
187 {
188 return -RIG_EINVAL;
189 }
190
191 rot_debug(RIG_DEBUG_VERBOSE, "rot_register (%d)\n", caps->rot_model);
192
193 #ifndef DONT_WANT_DUP_CHECK
194
195 if (rot_get_caps(caps->rot_model) != NULL)
196 {
197 return -RIG_EINVAL;
198 }
199
200 #endif
201
202 p = (struct rot_list *)malloc(sizeof(struct rot_list));
203
204 if (!p)
205 {
206 return -RIG_ENOMEM;
207 }
208
209 hval = HASH_FUNC(caps->rot_model);
210 p->caps = caps;
211 // p->handle = NULL;
212 p->next = rot_hash_table[hval];
213 rot_hash_table[hval] = p;
214
215 return RIG_OK;
216 }
217 //! @endcond
218
219
220 /*
221 * Get rot capabilities.
222 * i.e. rot_hash_table lookup
223 */
224 //! @cond Doxygen_Suppress
rot_get_caps(rot_model_t rot_model)225 const struct rot_caps *HAMLIB_API rot_get_caps(rot_model_t rot_model)
226 {
227 struct rot_list *p;
228
229 for (p = rot_hash_table[HASH_FUNC(rot_model)]; p; p = p->next)
230 {
231 if (p->caps->rot_model == rot_model)
232 {
233 return p->caps;
234 }
235 }
236
237 return NULL; /* sorry, caps not registered! */
238 }
239 //! @endcond
240
241
242 /*
243 * lookup for backend index in rot_backend_list table,
244 * according to BACKEND_NUM
245 * return -1 if not found.
246 */
rot_lookup_backend(rot_model_t rot_model)247 static int rot_lookup_backend(rot_model_t rot_model)
248 {
249 int i;
250
251 for (i = 0; i < ROT_BACKEND_MAX && rot_backend_list[i].be_name; i++)
252 {
253 if (ROT_BACKEND_NUM(rot_model) ==
254 rot_backend_list[i].be_num)
255 {
256 return i;
257 }
258 }
259
260 return -1;
261 }
262
263
264 /*
265 * rot_check_backend
266 * check the backend declaring this model has been loaded
267 * and if not loaded already, load it!
268 * This permits seamless operation in rot_init.
269 */
270 //! @cond Doxygen_Suppress
rot_check_backend(rot_model_t rot_model)271 int HAMLIB_API rot_check_backend(rot_model_t rot_model)
272 {
273 const struct rot_caps *caps;
274 int be_idx;
275 int retval;
276
277 /* already loaded ? */
278 caps = rot_get_caps(rot_model);
279
280 if (caps)
281 {
282 return RIG_OK;
283 }
284
285 be_idx = rot_lookup_backend(rot_model);
286
287 /*
288 * Never heard about this backend family!
289 */
290 if (be_idx == -1)
291 {
292 rot_debug(RIG_DEBUG_VERBOSE,
293 "%s: unsupported backend %d for model %d\n",
294 __func__,
295 ROT_BACKEND_NUM(rot_model),
296 rot_model);
297
298 return -RIG_ENAVAIL;
299 }
300
301 retval = rot_load_backend(rot_backend_list[be_idx].be_name);
302
303 return retval;
304 }
305 //! @endcond
306
307
308 //! @cond Doxygen_Suppress
rot_unregister(rot_model_t rot_model)309 int HAMLIB_API rot_unregister(rot_model_t rot_model)
310 {
311 int hval;
312 struct rot_list *p, *q;
313
314 hval = HASH_FUNC(rot_model);
315 q = NULL;
316
317 for (p = rot_hash_table[hval]; p; p = p->next)
318 {
319 if (p->caps->rot_model == rot_model)
320 {
321 if (q == NULL)
322 {
323 rot_hash_table[hval] = p->next;
324 }
325 else
326 {
327 q->next = p->next;
328 }
329
330 free(p);
331 return RIG_OK;
332 }
333
334 q = p;
335 }
336
337 return -RIG_EINVAL; /* sorry, caps not registered! */
338 }
339 //! @endcond
340
341
342 /*
343 * rot_list_foreach
344 * executes cfunc on all the elements stored in the rot hash list
345 */
346 //! @cond Doxygen_Suppress
rot_list_foreach(int (* cfunc)(const struct rot_caps *,rig_ptr_t),rig_ptr_t data)347 int HAMLIB_API rot_list_foreach(int (*cfunc)(const struct rot_caps *,
348 rig_ptr_t),
349 rig_ptr_t data)
350 {
351 struct rot_list *p;
352 int i;
353
354 if (!cfunc)
355 {
356 return -RIG_EINVAL;
357 }
358
359 for (i = 0; i < ROTLSTHASHSZ; i++)
360 {
361 for (p = rot_hash_table[i]; p; p = p->next)
362 if ((*cfunc)(p->caps, data) == 0)
363 {
364 return RIG_OK;
365 }
366 }
367
368 return RIG_OK;
369 }
370 //! @endcond
371
372
373 /*
374 * rot_probe_all
375 * called straight by rot_probe
376 */
377 //! @cond Doxygen_Suppress
rot_probe_all(hamlib_port_t * p)378 rot_model_t HAMLIB_API rot_probe_all(hamlib_port_t *p)
379 {
380 int i;
381 rot_model_t rot_model;
382
383 for (i = 0; i < ROT_BACKEND_MAX && rot_backend_list[i].be_name; i++)
384 {
385 if (rot_backend_list[i].be_probe)
386 {
387 rot_model = (*rot_backend_list[i].be_probe)(p);
388
389 if (rot_model != ROT_MODEL_NONE)
390 {
391 return rot_model;
392 }
393 }
394 }
395
396 return ROT_MODEL_NONE;
397 }
398 //! @endcond
399
400
401 //! @cond Doxygen_Suppress
rot_load_all_backends()402 int rot_load_all_backends()
403 {
404 int i;
405
406 for (i = 0; i < ROT_BACKEND_MAX && rot_backend_list[i].be_name; i++)
407 {
408 rot_load_backend(rot_backend_list[i].be_name);
409 }
410
411 return RIG_OK;
412 }
413 //! @endcond
414
415
416 /*
417 * rot_load_backend
418 * Dynamically load a rot backend through dlopen mechanism
419 */
420 //! @cond Doxygen_Suppress
rot_load_backend(const char * be_name)421 int HAMLIB_API rot_load_backend(const char *be_name)
422 {
423 int status;
424 int (*be_init)(rig_ptr_t);
425 int i;
426
427 for (i = 0; i < ROT_BACKEND_MAX && rot_backend_list[i].be_name; i++)
428 {
429 if (!strcmp(be_name, rot_backend_list[i].be_name))
430 {
431 be_init = rot_backend_list[i].be_init;
432
433 if (be_init == NULL)
434 {
435 printf("Null\n");
436 return -EINVAL;
437 }
438
439 status = (*be_init)(NULL);
440 return status;
441 }
442 }
443
444 return -EINVAL;
445
446 }
447 //! @endcond
448