1 /*
2 * Hamlib Interface - provides registering for dynamically loadable backends.
3 * Copyright (c) 2000-2015 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 backends
24 * \file register.c
25 *
26 * doc todo: Let's explain what's going on here!
27 */
28
29 #ifdef HAVE_CONFIG_H
30 # include "config.h"
31 #endif
32
33 #include <errno.h>
34 #include <stdlib.h>
35 #include <string.h>
36 #include <unistd.h>
37 #include <stdio.h>
38 #include <sys/types.h>
39
40 #include <register.h>
41
42 #include <hamlib/rig.h>
43 #include "misc.h"
44
45 //! @cond Doxygen_Suppress
46 #ifndef PATH_MAX
47 # define PATH_MAX 1024
48 #endif
49
50 #define RIG_BACKEND_MAX 32
51
52 #define DEFINE_INITRIG_BACKEND(backend) \
53 int MAKE_VERSIONED_FN(PREFIX_INITRIG, ABI_VERSION, backend(void *be_handle)); \
54 rig_model_t MAKE_VERSIONED_FN(PREFIX_PROBERIG, ABI_VERSION, backend(hamlib_port_t *port, rig_probe_func_t cfunc, rig_ptr_t data))
55
56 #define RIG_FUNCNAMA(backend) MAKE_VERSIONED_FN(PREFIX_INITRIG, ABI_VERSION, backend)
57 #define RIG_FUNCNAMB(backend) MAKE_VERSIONED_FN(PREFIX_PROBERIG, ABI_VERSION, backend)
58
59 #define RIG_FUNCNAM(backend) RIG_FUNCNAMA(backend),RIG_FUNCNAMB(backend)
60
61 /*
62 * RIG_BACKEND_LIST is defined here, please keep it up to date,
63 * i.e. each time you implement a new backend.
64 */
65 DEFINE_INITRIG_BACKEND(dummy);
66 DEFINE_INITRIG_BACKEND(yaesu);
67 DEFINE_INITRIG_BACKEND(kenwood);
68 DEFINE_INITRIG_BACKEND(icom);
69 DEFINE_INITRIG_BACKEND(icmarine);
70 DEFINE_INITRIG_BACKEND(pcr);
71 DEFINE_INITRIG_BACKEND(aor);
72 DEFINE_INITRIG_BACKEND(jrc);
73 DEFINE_INITRIG_BACKEND(uniden);
74 DEFINE_INITRIG_BACKEND(drake);
75 DEFINE_INITRIG_BACKEND(lowe);
76 DEFINE_INITRIG_BACKEND(racal);
77 DEFINE_INITRIG_BACKEND(wj);
78 DEFINE_INITRIG_BACKEND(skanti);
79 DEFINE_INITRIG_BACKEND(tentec);
80 DEFINE_INITRIG_BACKEND(alinco);
81 DEFINE_INITRIG_BACKEND(kachina);
82 DEFINE_INITRIG_BACKEND(tapr);
83 DEFINE_INITRIG_BACKEND(flexradio);
84 DEFINE_INITRIG_BACKEND(rft);
85 DEFINE_INITRIG_BACKEND(kit);
86 DEFINE_INITRIG_BACKEND(tuner);
87 DEFINE_INITRIG_BACKEND(rs);
88 DEFINE_INITRIG_BACKEND(prm80);
89 DEFINE_INITRIG_BACKEND(adat);
90 DEFINE_INITRIG_BACKEND(dorji);
91 DEFINE_INITRIG_BACKEND(barrett);
92 DEFINE_INITRIG_BACKEND(elad);
93 //! @endcond
94
95 #ifdef HAVE_WINRADIO
96 //! @cond Doxygen_Suppress
97 DEFINE_INITRIG_BACKEND(winradio);
98 //! @endcond
99 #endif
100
101
102 /**
103 * \def rig_backend_list
104 * \brief Static list of rig models.
105 *
106 * This is a NULL terminated list of available rig backends. Each entry in
107 * the list consists of two fields: The branch number, which is an integer,
108 * and the branch name, which is a character string.
109 */
110 static struct
111 {
112 int be_num;
113 const char *be_name;
114 int (* be_init_all)(void *handle);
115 rig_model_t (* be_probe_all)(hamlib_port_t *, rig_probe_func_t, rig_ptr_t);
116 } rig_backend_list[RIG_BACKEND_MAX] =
117 {
118 { RIG_DUMMY, RIG_BACKEND_DUMMY, RIG_FUNCNAMA(dummy) },
119 { RIG_YAESU, RIG_BACKEND_YAESU, RIG_FUNCNAM(yaesu) },
120 { RIG_KENWOOD, RIG_BACKEND_KENWOOD, RIG_FUNCNAM(kenwood) },
121 { RIG_ICOM, RIG_BACKEND_ICOM, RIG_FUNCNAM(icom) },
122 { RIG_ICMARINE, RIG_BACKEND_ICMARINE, RIG_FUNCNAMA(icmarine) },
123 { RIG_PCR, RIG_BACKEND_PCR, RIG_FUNCNAMA(pcr) },
124 { RIG_AOR, RIG_BACKEND_AOR, RIG_FUNCNAMA(aor) },
125 { RIG_JRC, RIG_BACKEND_JRC, RIG_FUNCNAMA(jrc) },
126 { RIG_UNIDEN, RIG_BACKEND_UNIDEN, RIG_FUNCNAM(uniden) },
127 { RIG_DRAKE, RIG_BACKEND_DRAKE, RIG_FUNCNAM(drake) },
128 { RIG_LOWE, RIG_BACKEND_LOWE, RIG_FUNCNAM(lowe) },
129 { RIG_RACAL, RIG_BACKEND_RACAL, RIG_FUNCNAMA(racal) },
130 { RIG_WJ, RIG_BACKEND_WJ, RIG_FUNCNAMA(wj) },
131 { RIG_SKANTI, RIG_BACKEND_SKANTI, RIG_FUNCNAMA(skanti) },
132 #ifdef HAVE_WINRADIO
133 { RIG_WINRADIO, RIG_BACKEND_WINRADIO, RIG_FUNCNAMA(winradio) },
134 #endif /* HAVE_WINRADIO */
135 { RIG_TENTEC, RIG_BACKEND_TENTEC, RIG_FUNCNAMA(tentec) },
136 { RIG_ALINCO, RIG_BACKEND_ALINCO, RIG_FUNCNAMA(alinco) },
137 { RIG_KACHINA, RIG_BACKEND_KACHINA, RIG_FUNCNAMA(kachina) },
138 { RIG_TAPR, RIG_BACKEND_TAPR, RIG_FUNCNAMA(tapr) },
139 { RIG_FLEXRADIO, RIG_BACKEND_FLEXRADIO, RIG_FUNCNAMA(flexradio) },
140 { RIG_RFT, RIG_BACKEND_RFT, RIG_FUNCNAMA(rft) },
141 { RIG_KIT, RIG_BACKEND_KIT, RIG_FUNCNAMA(kit) },
142 { RIG_TUNER, RIG_BACKEND_TUNER, RIG_FUNCNAMA(tuner) },
143 { RIG_RS, RIG_BACKEND_RS, RIG_FUNCNAMA(rs) },
144 { RIG_PRM80, RIG_BACKEND_PRM80, RIG_FUNCNAMA(prm80) },
145 { RIG_ADAT, RIG_BACKEND_ADAT, RIG_FUNCNAM(adat) },
146 { RIG_DORJI, RIG_BACKEND_DORJI, RIG_FUNCNAMA(dorji) },
147 { RIG_BARRETT, RIG_BACKEND_BARRETT, RIG_FUNCNAMA(barrett) },
148 { RIG_ELAD, RIG_BACKEND_ELAD, RIG_FUNCNAMA(elad) },
149 { 0, NULL }, /* end */
150 };
151
152
153 /*
154 * This struct to keep track of known rig models.
155 * It is chained, and used in a hash table, see below.
156 */
157 //! @cond Doxygen_Suppress
158 struct rig_list
159 {
160 const struct rig_caps *caps;
161 struct rig_list *next;
162 };
163 //! @endcond
164
165
166 // This size has to be > than the max# of rigs for any manufacturer
167 // A fatal error will occur when running rigctl if this value is too small
168 //! @cond Doxygen_Suppress
169 #define RIGLSTHASHSZ 65535
170 #define HASH_FUNC(a) ((a)%RIGLSTHASHSZ)
171 //! @endcond
172
173
174 /*
175 * The rig_hash_table is a hash table pointing to a list of next==NULL
176 * terminated caps.
177 */
178 static struct rig_list *rig_hash_table[RIGLSTHASHSZ] = { NULL, };
179
180
181 static int rig_lookup_backend(rig_model_t rig_model);
182
183
184 /*
185 * Basically, this is a hash insert function that doesn't check for dup!
186 */
187 //! @cond Doxygen_Suppress
rig_register(const struct rig_caps * caps)188 int HAMLIB_API rig_register(const struct rig_caps *caps)
189 {
190 int hval;
191 struct rig_list *p;
192
193 rig_debug(RIG_DEBUG_VERBOSE, "%s called\n", __func__);
194
195 if (!caps)
196 {
197 return -RIG_EINVAL;
198 }
199
200 rig_debug(RIG_DEBUG_VERBOSE,
201 "%s: rig_register (%u)\n",
202 __func__,
203 caps->rig_model);
204
205 p = (struct rig_list *)malloc(sizeof(struct rig_list));
206
207 if (!p)
208 {
209 return -RIG_ENOMEM;
210 }
211
212 hval = HASH_FUNC(caps->rig_model);
213
214 if (rig_hash_table[hval])
215 {
216 printf("Hash collision!!! Fatal error!!\n");
217 exit(1);
218 }
219
220 p->caps = caps;
221 // p->handle = NULL;
222 p->next = rig_hash_table[hval];
223 rig_hash_table[hval] = p;
224
225 RETURNFUNC(RIG_OK);
226 }
227 //! @endcond
228
229 /*
230 * Get rig capabilities.
231 * ie. rig_hash_table lookup
232 */
233
234 //! @cond Doxygen_Suppress
rig_get_caps(rig_model_t rig_model)235 const struct rig_caps *HAMLIB_API rig_get_caps(rig_model_t rig_model)
236 {
237 struct rig_list *p;
238
239 for (p = rig_hash_table[HASH_FUNC(rig_model)]; p; p = p->next)
240 {
241 if (p->caps->rig_model == rig_model)
242 {
243 return p->caps;
244 }
245 }
246
247 return NULL; /* sorry, caps not registered! */
248 }
249 //! @endcond
250
251 /*
252 * lookup for backend index in rig_backend_list table,
253 * according to BACKEND_NUM
254 * return -1 if not found.
255 */
256 //! @cond Doxygen_Suppress
rig_lookup_backend(rig_model_t rig_model)257 static int rig_lookup_backend(rig_model_t rig_model)
258 {
259 int i;
260
261 for (i = 0; i < RIG_BACKEND_MAX && rig_backend_list[i].be_name; i++)
262 {
263 if (RIG_BACKEND_NUM(rig_model) ==
264 rig_backend_list[i].be_num)
265
266 {
267 return i;
268 }
269 }
270
271 return -1;
272 }
273 //! @endcond
274
275 /*
276 * rig_check_backend
277 * check the backend declaring this model has been loaded
278 * and if not loaded already, load it!
279 * This permits seamless operation in rig_init.
280 */
281 //! @cond Doxygen_Suppress
rig_check_backend(rig_model_t rig_model)282 int HAMLIB_API rig_check_backend(rig_model_t rig_model)
283 {
284 const struct rig_caps *caps;
285 int be_idx;
286 int retval;
287 int i, n;
288
289 /* already loaded ? */
290 caps = rig_get_caps(rig_model);
291
292 if (caps)
293 {
294 return RIG_OK;
295 }
296
297 // hmmm...no caps so did we already load the rigs?
298 for (n = 0, i = 0; i < RIGLSTHASHSZ; i++)
299 {
300 if (rig_hash_table[i]) { ++n; }
301 }
302
303 if (n > 1)
304 {
305 rig_debug(RIG_DEBUG_ERR, "%s: rig model %d not found and rig count=%d\n",
306 __func__, rig_model, n);
307 return -RIG_ENAVAIL;
308 }
309
310 be_idx = rig_lookup_backend(rig_model);
311
312 /*
313 * Never heard about this backend family!
314 */
315 if (be_idx == -1)
316 {
317 rig_debug(RIG_DEBUG_VERBOSE,
318 "rig_check_backend: unsupported backend %u for model %u\n",
319 RIG_BACKEND_NUM(rig_model),
320 rig_model);
321 return -RIG_ENAVAIL;
322 }
323
324 // do we need to load the backend?
325 // if (rig_backend_list[be_idx].be_init_all == 0)
326 {
327 retval = rig_load_backend(rig_backend_list[be_idx].be_name);
328 }
329 #if 0
330 else
331 {
332 retval = RIG_OK;
333 }
334
335 #endif
336
337 return retval;
338 }
339 //! @endcond
340
341
342
343 //! @cond Doxygen_Suppress
rig_unregister(rig_model_t rig_model)344 int HAMLIB_API rig_unregister(rig_model_t rig_model)
345 {
346 int hval;
347 struct rig_list *p, *q;
348
349 hval = HASH_FUNC(rig_model);
350 q = NULL;
351
352 for (p = rig_hash_table[hval]; p; p = p->next)
353 {
354 if (p->caps->rig_model == rig_model)
355 {
356 if (q == NULL)
357 {
358 rig_hash_table[hval] = p->next;
359 }
360 else
361 {
362 q->next = p->next;
363 }
364
365 free(p);
366 return RIG_OK;
367 }
368
369 q = p;
370 }
371
372 return -RIG_EINVAL; /* sorry, caps not registered! */
373 }
374 //! @endcond
375
376 /*
377 * rig_list_foreach
378 * executes cfunc on all the elements stored in the rig hash list
379 */
380 //! @cond Doxygen_Suppress
rig_list_foreach(int (* cfunc)(const struct rig_caps *,rig_ptr_t),rig_ptr_t data)381 int HAMLIB_API rig_list_foreach(int (*cfunc)(const struct rig_caps *,
382 rig_ptr_t),
383 rig_ptr_t data)
384 {
385 struct rig_list *p;
386 int i;
387
388 if (!cfunc)
389 {
390 return -RIG_EINVAL;
391 }
392
393 for (i = 0; i < RIGLSTHASHSZ; i++)
394 {
395 struct rig_list *next = NULL;
396
397 for (p = rig_hash_table[i]; p; p = next)
398 {
399 next = p->next; /* read before call in case it is unregistered */
400
401 if ((*cfunc)(p->caps, data) == 0)
402 {
403 return RIG_OK;
404 }
405 }
406 }
407
408 return RIG_OK;
409 }
410 //! @endcond
411
412 /*
413 * rig_list_foreach_model
414 * executes cfunc on all the elements stored in the rig hash list
415 */
416 //! @cond Doxygen_Suppress
rig_list_foreach_model(int (* cfunc)(const rig_model_t rig_model,rig_ptr_t),rig_ptr_t data)417 int HAMLIB_API rig_list_foreach_model(int (*cfunc)(const rig_model_t rig_model,
418 rig_ptr_t),
419 rig_ptr_t data)
420 {
421 struct rig_list *p;
422 int i;
423
424 if (!cfunc)
425 {
426 return -RIG_EINVAL;
427 }
428
429 for (i = 0; i < RIGLSTHASHSZ; i++)
430 {
431 struct rig_list *next = NULL;
432
433 for (p = rig_hash_table[i]; p; p = next)
434 {
435 next = p->next; /* read before call in case it is unregistered */
436
437 if ((*cfunc)(p->caps->rig_model, data) == 0)
438 {
439 return RIG_OK;
440 }
441 }
442 }
443
444 return RIG_OK;
445 }
446 //! @endcond
447
448 //! @cond Doxygen_Suppress
dummy_rig_probe(const hamlib_port_t * p,rig_model_t model,rig_ptr_t data)449 static int dummy_rig_probe(const hamlib_port_t *p,
450 rig_model_t model,
451 rig_ptr_t data)
452 {
453 rig_debug(RIG_DEBUG_TRACE, "Found rig, model %u\n", model);
454
455 return RIG_OK;
456 }
457 //! @endcond
458
459
460 /*
461 * rig_probe_first
462 * called straight by rig_probe
463 */
464 //! @cond Doxygen_Suppress
rig_probe_first(hamlib_port_t * p)465 rig_model_t rig_probe_first(hamlib_port_t *p)
466 {
467 int i;
468 rig_model_t model;
469
470 for (i = 0; i < RIG_BACKEND_MAX && rig_backend_list[i].be_name; i++)
471 {
472 if (rig_backend_list[i].be_probe_all)
473 {
474 model = (*rig_backend_list[i].be_probe_all)(p, dummy_rig_probe,
475 (rig_ptr_t)NULL);
476
477 /* stop at first one found */
478 if (model != RIG_MODEL_NONE)
479 {
480 return model;
481 }
482 }
483 }
484
485 return RIG_MODEL_NONE;
486 }
487 //! @endcond
488
489
490 /*
491 * rig_probe_all_backends
492 * called straight by rig_probe_all
493 */
494 //! @cond Doxygen_Suppress
rig_probe_all_backends(hamlib_port_t * p,rig_probe_func_t cfunc,rig_ptr_t data)495 int rig_probe_all_backends(hamlib_port_t *p,
496 rig_probe_func_t cfunc,
497 rig_ptr_t data)
498 {
499 int i;
500
501 for (i = 0; i < RIG_BACKEND_MAX && rig_backend_list[i].be_name; i++)
502 {
503 if (rig_backend_list[i].be_probe_all)
504 {
505 (*rig_backend_list[i].be_probe_all)(p, cfunc, data);
506 }
507 }
508
509 return RIG_OK;
510 }
511 //! @endcond
512
513
514 //! @cond Doxygen_Suppress
rig_load_all_backends()515 int rig_load_all_backends()
516 {
517 int i;
518
519 memset(rig_hash_table, 0, sizeof(rig_hash_table));
520
521 for (i = 0; i < RIG_BACKEND_MAX && rig_backend_list[i].be_name; i++)
522 {
523 rig_load_backend(rig_backend_list[i].be_name);
524 }
525
526 return RIG_OK;
527 }
528 //! @endcond
529
530
531 //! @cond Doxygen_Suppress
532 typedef int (*backend_init_t)(rig_ptr_t);
533 //! @endcond
534
535
536 /*
537 * rig_load_backend
538 */
539 //! @cond Doxygen_Suppress
rig_load_backend(const char * be_name)540 int HAMLIB_API rig_load_backend(const char *be_name)
541 {
542 int i;
543 backend_init_t be_init;
544
545 for (i = 0; i < RIG_BACKEND_MAX && rig_backend_list[i].be_name; i++)
546 {
547 if (!strcmp(be_name, rig_backend_list[i].be_name))
548 {
549 be_init = rig_backend_list[i].be_init_all ;
550
551 if (be_init)
552 {
553 return (*be_init)(NULL);
554 }
555 else
556 {
557 return -RIG_EINVAL;
558 }
559 }
560 }
561
562 return -RIG_EINVAL;
563 }
564 //! @endcond
565