1 /* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3     Grig:  Gtk+ user interface for the Hamradio Control Libraries.
4 
5     Copyright (C)  2001-2007  Alexandru Csete.
6 
7     Authors: Alexandru Csete <oz9aec@gmail.com>
8 
9     Comments, questions and bugreports should be submitted via
10     http://sourceforge.net/projects/groundstation/
11     More details can be found at the project home page:
12 
13             http://groundstation.sourceforge.net/
14 
15     This program is free software; you can redistribute it and/or modify
16     it under the terms of the GNU General Public License as published by
17     the Free Software Foundation; either version 2 of the License, or
18     (at your option) any later version.
19 
20     This program is distributed in the hope that it will be useful,
21     but WITHOUT ANY WARRANTY; without even the implied warranty of
22     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
23     GNU General Public License for more details.
24 
25     You should have received a copy of the GNU General Public License
26     along with this program; if not, visit http://www.fsf.org/
27 
28 
29 */
30 /** \file    main.c
31  *  \ingroup main
32  *  \bief    Main program file.
33  *
34  * Add some more text.
35  *
36  * \bug What do we do if we don't have getopt.h? Change to glib getopt in 2.6
37  *
38  * \bug Debug level is not read from hamlib. Original debug level is
39  *      overwritten if used on rpcrig.
40  */
41 #include <stdlib.h>
42 #include <signal.h>
43 #include <gtk/gtk.h>
44 #include <glib/gi18n.h>
45 #include <hamlib/rig.h>
46 #ifdef HAVE_CONFIG_H
47 #  include <config.h>
48 #endif
49 #ifdef HAVE_GETOPT_H
50 #  include <getopt.h>
51 #endif
52 #include "compat.h"
53 #include "grig-config.h"
54 #include "rig-gui.h"
55 #include "grig-debug.h"
56 #include "rig-gui-message-window.h"
57 #include "rig-daemon.h"
58 #include "rig-data.h"
59 #include "rig-selector.h"
60 #include "key-press-handler.h"
61 
62 
63 
64 /** \brief Main GUI application widget */
65 GtkWidget    *grigapp;
66 
67 
68 /* command line arguments */
69 /* FIXME: These need not be global!
70     not in this baseline anyway.
71  */
72 static gint     rignum    = 0;       /*!< Flag indicating which radio to use.*/
73 static gchar   *rigfile   = NULL;    /*!< The port where the rig is atached. */
74 static gchar   *civaddr   = NULL;    /*!< CI-V address for ICOM rig. */
75 static gchar   *rigconf   = NULL;    /*!< Configuration parameter. */
76 static gint     rigspeed  = 0;       /*!< Optional serial speed. */
77 static gboolean listrigs  = FALSE;   /*!< List supported radios and exit. */
78 gint debug     = RIG_DEBUG_NONE; /*!< Hamlib debug level. Note: not static since menubar.c needs access. */
79 static gint     delay     = 0;       /*!< Command delay. */
80 static gboolean nothread  = FALSE;   /*!< Don't use threads, just a regular gtk-timeout. */
81 static gboolean pstat     = FALSE;   /*!< Enable power status button. */
82 static gboolean ptt       = FALSE;   /*!< Enable PTT button. */
83 static gboolean version   = FALSE;   /*!< Show version and exit. */
84 static gboolean help      = FALSE;   /*!< Show help and exit. */
85 //static gchar    *rigcfg   = NULL;    /*!< .radio file name. */
86 
87 /* group those which take no arg */
88 /** \brief Short options. */
89 #define SHORT_OPTIONS "m:r:s:c:C:d:D:nlpPhv"
90 
91 /** \brief Table of command line options. */
92 static struct option long_options[] =
93 {
94 	{"model",        1, 0, 'm'},
95 	{"rig-file",     1, 0, 'r'},
96 	{"speed",        1, 0, 's'},
97 	{"civaddr",      1, 0, 'c'},
98 	{"set-conf",     1, 0, 'C'},
99 	{"debug",        1, 0, 'd'},
100 	{"delay",        1, 0, 'D'},
101 	{"nothread",     0, 0, 'n'},
102 	{"list",         0, 0, 'l'},
103 	{"enable-ptt",   0, 0, 'p'},
104 	{"enable-pwr",   0, 0, 'P'},
105 	{"help",         0, 0, 'h'},
106 	{"version",      0, 0, 'v'},
107 	{NULL, 0, 0, 0}
108 };
109 
110 
111 /** \brief Radio info to be used by list-rigs. */
112 typedef struct {
113 	gint    id;       /*!< Model ID. */
114 	gchar  *mfg;      /*!< Manufacturer name (eg. KENWOOD). */
115 	gchar  *model;    /*!< Radio model (eg. TS-440). */
116 	gchar  *version;  /*!< Driver version (eg. 0.3.2) */
117         gint    status;   /*!< Driver status (0..5 use rig_strstatus). */
118 } grig_rig_info_t;
119 
120 
121 /* Private function prototypes */
122 static void        grig_list_rigs      (void);
123 static GtkWidget  *grig_app_create     (gint);
124 static gint        grig_app_delete     (GtkWidget *, GdkEvent *, gpointer);
125 static void        grig_app_destroy    (GtkWidget *, gpointer);
126 static void        grig_show_help      (void);
127 static void        grig_show_version   (void);
128 static gint        grig_list_add       (const struct rig_caps *, void *);
129 static gint        grig_list_compare   (gconstpointer, gconstpointer);
130 static void        grig_sig_handler    (int sig);
131 
132 
133 /** \bief Main program execution entry.
134  *  \param argc The number o command line arguments.
135  *  \param argv List of command line arguments.
136  *  \return Execution status (non-zero mean error ocurred).
137  *
138  * Some description.
139  *
140  * \bug Add more text.
141  *
142  */
143 int
main(int argc,char * argv[])144 main (int argc, char *argv[])
145 {
146 	gchar *fname;
147 
148 	/* Initialize NLS support */
149 #ifdef ENABLE_NLS
150 	bindtextdomain (PACKAGE, PACKAGE_LOCALE_DIR);
151 	bind_textdomain_codeset (PACKAGE, "UTF-8");
152 	textdomain (PACKAGE);
153 #endif
154 
155 	gtk_set_locale ();
156 	gtk_init (&argc, &argv);
157 /* 	setlocale (LCNUMERIC, "C"); */
158 
159 
160 	/* check whether installation is complete
161 	   by looking for some pixmps. This way we
162 	   can avoid surprises later on, when exit
163 	   is not an option anymore.
164 	*/
165 	//fname = g_strconcat (PACKAGE_PIXMAPS_DIR, G_DIR_SEPARATOR_S, "smeter.png", NULL);
166 	fname = pixmap_file_name ("smeter.png");
167 	if (!g_file_test (fname, G_FILE_TEST_EXISTS)) {
168 
169 		g_print ("\n\n");
170 		g_print (_("Grig can not find some necessary data files.\n"));
171 		g_print (_("This usually means that your installation is incomplete.\n"));
172 		g_print (_("Sorry... but I can not continue..."));
173 		g_print ("\n\n");
174 		g_print ("%s\n\n",fname);
175 		return 1;
176 	}
177 
178 	g_free (fname);
179 
180 
181 #if !GLIB_CHECK_VERSION(2,32,0)
182 	/* initialize threads; according to glib docs, this call will terminate
183 	   the program if threads are not supported... then why doesn''t it work
184 	   on FreeBSD?
185 	*/
186 	if (!g_thread_supported ())
187 		g_thread_init (NULL);
188 #endif
189 
190 
191 	/* decode command line arguments; this part of the code only sets the
192 	   global flags and variables, whereafter we check each variable in
193 	   descending priority order. This way it is easy to exit the program
194 	   in case of -v -h and such.
195 	*/
196 	while(1) {
197 		int c;
198 		int option_index = 0;
199 
200 		/* get next option */
201 		c = getopt_long (argc, argv, SHORT_OPTIONS,
202 			long_options, &option_index);
203 
204 		if (c == -1)
205 			break;
206 
207 		switch (c) {
208 
209 			/* set rig model*/
210 		case 'm':
211 			if (!optarg) {
212 				help = TRUE;
213 			}
214 			else {
215 				rignum = atoi (optarg);
216 			}
217 			break;
218 
219 			/* set rig port */
220 		case 'r':
221 			if (!optarg) {
222 				help = TRUE;
223 			}
224 			else {
225 				rigfile = optarg;
226 			}
227 			break;
228 
229 			/* set serial speed */
230 		case 's':
231 			if (!optarg) {
232 				help = TRUE;
233 			}
234 			else {
235 				rigspeed = atoi (optarg);
236 			}
237 			break;
238 
239 			/* set CIV address */
240 		case 'c':
241 			if (!optarg) {
242 				help = TRUE;
243 			}
244 			else {
245 				civaddr = optarg;
246 			}
247 			break;
248 
249 			/* set configuration parameter */
250 		case 'C':
251 			if (!optarg) {
252 				help = TRUE;
253 			}
254 			else {
255 				rigconf = optarg;
256 			}
257 			break;
258 
259 			/* list supported radios */
260 		case 'l':
261 			listrigs = TRUE;
262 			break;
263 
264 			/* set debug level */
265 		case 'd':
266 			if (!optarg) {
267 				help = TRUE;
268 			}
269 			else {
270 				debug = atoi (optarg);
271 			}
272 			break;
273 
274 			/* command delay */
275 		case 'D':
276 			if (!optarg) {
277 				help = TRUE;
278 			}
279 			else {
280 				delay = atoi (optarg);
281 			}
282 			break;
283 
284 			/* no threads */
285 		case 'n':
286 			nothread = TRUE;
287 			break;
288 
289 			/* enable PTT button */
290 		case 'p':
291 			ptt = TRUE;
292 			break;
293 
294 			/* enable POWER button */
295 		case 'P':
296 			pstat = TRUE;
297 			break;
298 
299 			/* show help */
300 		case 'h':
301 			help = TRUE;
302 			break;
303 
304 			/* show version */
305 		case 'v':
306 			version = TRUE;
307 			break;
308 
309 			/* unknown option: show usage */
310 		default:
311 			help = TRUE;
312 			break;
313 		}
314 	}
315 
316 
317 	/* check command line option flags in decreasing
318 	   priority.
319 	*/
320 	if (help) {
321 		grig_show_help ();
322 		return 0;
323 	}
324 
325 	if (version) {
326 		grig_show_version ();
327 		return 0;
328 	}
329 
330 	if (listrigs) {
331 		grig_list_rigs ();
332 		return 0;
333 	}
334 
335 
336 	/* we set hamlib debug level to TRACE while we fire up the daemon;
337 	   it will be reset when we create the menubar
338 	*/
339 	grig_debug_set_level (RIG_DEBUG_TRACE);
340 
341 	/* initialise debug handler */
342 	grig_debug_init (NULL);
343 
344 	/* check configuration */
345 	if (!grig_config_check ()) {
346 
347 		g_print ("\n\n");
348 		g_print (_("Grig configuration check failed!\n"));
349 		g_print (_("This usually means that your configuration is broken.\n"));
350 		g_print (_("Sorry... but I can not continue..."));
351 		g_print ("\n\n");
352 		g_print (_("Proposed solutions:\n"));
353 		return 1;
354 
355 	}
356 
357 	/* At this point, configuration is OK. */
358 
359 
360     /* 1. prio: .grc file */
361 
362     /* 2. prio: -m or --model */
363 
364     /* 3. prio: run rig-selector */
365     //g_print ("SELECT: %s\n", rig_selector_execute ());
366 
367 	/* launch rig daemon and pass the relevant
368 	   command line options
369 	*/
370 	if (rig_daemon_start (rignum,
371 						  rigfile,
372 						  rigspeed,
373 						  civaddr,
374 						  rigconf,
375 						  delay,
376 						  nothread,
377 						  ptt,
378 						  pstat))
379 	{
380 
381 		return 1;
382 	}
383 
384     /* install key press event handler */
385     key_press_handler_init ();
386 
387 	/* check whether the debug level is something meaningful
388 	   (it could be set to something junk by user); if yes, set
389 	   debuglevel, otherwise use RIG_DEBUG_WARN.
390 	*/
391 	if ((debug >= RIG_DEBUG_NONE) && (debug <= RIG_DEBUG_TRACE)) {
392 		grig_debug_set_level (debug);
393 	}
394 	else {
395 		grig_debug_set_level (RIG_DEBUG_WARN);
396 	}
397 
398 	/* create application */
399 	grigapp = grig_app_create (rignum);
400 
401 	/* add contents */
402 	gtk_container_add (GTK_CONTAINER (grigapp), rig_gui_create ());
403 	gtk_widget_show (grigapp);
404 
405 	gtk_main ();
406 
407 
408 	return 0;
409 }
410 
411 
412 
413 
414 
415 /** \brief Create and initialize main application window.
416  *  \param rignum The index of the radio wich is controled by the app
417  *  \return A new GtkWindow widget.
418  *
419  * This function creates and initializes a new GtkWindow which can be used
420  * by the main application to pack the rig controls in.
421  *
422  * \note This function creates no contents; that part is done by the
423  *       rig_gui.c package.
424  */
425 static GtkWidget *
grig_app_create(gint rignum)426 grig_app_create       (gint rignum)
427 {
428 	GtkWidget *app;        /* The main application */
429 	gchar     *title;      /* the window title  */
430 	gchar     *brand;
431 	gchar     *model;
432 	gchar     *icon;
433 
434 
435 	brand = rig_daemon_get_brand ();
436 	model = rig_daemon_get_model ();
437 
438 	/* construct title */
439 	title = g_strdup_printf (_("GRIG: %s %s"), brand, model);
440 
441 	/* window icon file */
442 	//icon = g_strconcat (PACKAGE_PIXMAPS_DIR, G_DIR_SEPARATOR_S, "ic910.png", NULL);
443 	icon = pixmap_file_name ("ic910.png");
444 
445 	/* create application */
446 	app = gtk_window_new (GTK_WINDOW_TOPLEVEL);
447 	gtk_window_set_title (GTK_WINDOW (app), title);
448 	gtk_window_set_icon_from_file (GTK_WINDOW (app), icon, NULL);
449 
450 	g_free (title);
451 	g_free (brand);
452 	g_free (model);
453 	g_free (icon);
454 
455 	/* connect delete and destroy signals */
456 	g_signal_connect (G_OBJECT (app), "delete_event",
457 			  G_CALLBACK (grig_app_delete), NULL);
458 	g_signal_connect (G_OBJECT (app), "destroy",
459 			  G_CALLBACK (grig_app_destroy), NULL);
460 
461 	/* register UNIX signals as well so that we
462 	   have a chance to clean up hamlib.
463 	*/
464 	signal (SIGTERM, (void *) grig_sig_handler);
465 	signal (SIGINT,  (void *) grig_sig_handler);
466 	signal (SIGABRT, (void *) grig_sig_handler);
467 
468 	return app;
469 }
470 
471 
472 /** \brief Handle terminate signals.
473  *  \param sig The signal that has been received.
474  *
475  * This function is used to handle termination signals received by the program.
476  * The currently caught signals are SIGTERM, SIGINT and SIGABRT. When one of
477  * these signals is received, the function sends an error message to hamlib and
478  * tries to make a clean exit.
479  */
grig_sig_handler(int sig)480 static void grig_sig_handler (int sig)
481 {
482 
483 	grig_debug_local (RIG_DEBUG_ERR,
484 			  _("Received signal %d\n"\
485 			    "Trying clean exit..."),
486 			  sig);
487 
488 	gtk_widget_destroy (grigapp);
489 }
490 
491 
492 /** \brief Handle delete events.
493  *  \param widget The widget which received the delete event signal.
494  *  \param event  Data structure describing the event.
495  *  \param data   User data (NULL).
496  *  \param return Always FALSE to indicate that the app should be destroyed.
497  *
498  * This function handles the delete event received by the main application
499  * window (eg. when the window is closed by the WM). This function simply
500  * returns FALSE indicating that the main application window should be
501  * destroyed by emiting the destroy signal.
502  *
503  */
504 static gint
grig_app_delete(GtkWidget * widget,GdkEvent * event,gpointer data)505 grig_app_delete      (GtkWidget *widget,
506 		      GdkEvent  *event,
507 		      gpointer   data)
508 {
509 
510 	/* return FALSE so that Gtk+ will emit the destroy signal */
511 	return FALSE;
512 }
513 
514 
515 
516 /** \brief Handle destroy signals.
517  *  \param widget The widget which received the signal.
518  *  \param data   User data (NULL).
519  *
520  * This function is called when the main application window receives the
521  * destroy signal, ie. it is destroyed. This function signals all daemons
522  * and other threads to stop and exits the Gtk+ main loop.
523  *
524  */
525 static void
grig_app_destroy(GtkWidget * widget,gpointer data)526 grig_app_destroy    (GtkWidget *widget,
527 		     gpointer   data)
528 {
529 
530 	/* set debug level to TRACE */
531 	grig_debug_set_level (RIG_DEBUG_TRACE);
532 
533     /* remove key press event handler */
534     key_press_handler_close ();
535 
536 	/* stop daemons */
537 	rig_daemon_stop ();
538 
539 	/* GUI timers are stopped automatically */
540 
541 	/* stop timeouts */
542 
543 	/* shut down debug handler */
544     grig_debug_close ();
545 
546 	/* exit Gtk+ */
547 	gtk_main_quit ();
548 }
549 
550 
551 
552 /** \brief Show help message.
553  *
554  * This function displays a brief help message for grig.
555  */
556 static void
grig_show_help()557 grig_show_help      ()
558 {
559 
560 	g_print (_("Usage: grig [OPTION]...\n\n"));
561 	g_print (_("  -m, --model=ID              "\
562 		   "select radio model number; see --list\n"));
563 	g_print (_("  -r, --rig-file=DEVICE       "\
564 		   "set device of the radio, eg. /dev/ttyS0\n"));
565 	g_print (_("  -s, --speed=BAUD            "\
566 		   "set transfer rate (serial port only)\n"));
567 	g_print (_("  -c, --civaddr=ID            "\
568 		   "set CI-V address (decimal, ICOM only)\n"));
569 	g_print (_("  -C, --set-conf=param=val    "\
570 		   "set config parameter (same as in rigctl)\n"));
571 	g_print (_("  -d, --debug=LEVEL           "\
572 		   "set hamlib debug level (0..5)\n"));
573 	g_print (_("  -D, --delay=val             "\
574 		   "set delay between commands in msec\n"));
575 	g_print (_("  -n, --nothread              "\
576 		   "start daemon without using threads\n"));
577 	g_print (_("  -l, --list                  "\
578 		   "list supported radios and exit\n"));
579 	g_print (_("  -p, --enable-ptt            "\
580 		   "enable PTT button\n"));
581 	g_print (_("  -P, --enable-pwr            "\
582 		   "enable POWER button\n"));
583 	g_print (_("  -h, --help                  "\
584 		   "show this help message and exit\n"));
585 	g_print (_("  -v, --version               "\
586 		   "show version information and exit\n"));
587 	g_print ("\n");
588 	g_print (_("Example:"));
589 	g_print ("\n");
590 	g_print (_("Start grig using YAESU FT-990 connected to the first "\
591 		   "serial port, using 4800 baud and debug level set to "\
592 		   "warning:"));
593 	g_print ("\n\n");
594 	g_print ("     grig -m 116 -r /dev/ttyS0 -s 4800 -d 3");
595 	g_print ("\n\n");
596 	g_print (_("or if you prefer the long options:"));
597 	g_print ("\n\n");
598 	g_print ("     grig --model=116 --rig-file=/dev/ttyS0 "\
599 		 "--speed=4800 --debug=3");
600 	g_print ("\n\n");
601 	g_print (_("It is usually enough to specify the model "\
602 		   "ID and the DEVICE."));
603 	g_print ("\n\n");
604 	g_print (_("If you start grig without any options it "\
605 		   "will use the Dummy backend "\
606 		   "and set the debug level to RIG_DEBUG_NONE. "\
607 		   "If you don't specify "\
608 		   "the transfer rate for the serial port, the "\
609 		   "default value will be "\
610 		   "used by the backend and even if you specify "\
611 		   "a value, it can be "\
612 		   "overridden by the backend."));
613 	g_print ("\n\n");
614 	g_print (_("Debug levels:"));
615 	g_print ("\n\n");
616 	g_print (_("   0    No debug, keep quiet.\n"));
617 	g_print (_("   1    Serious bug.\n"));
618 	g_print (_("   2    Error case (e.g. protocol, memory allocation).\n"));
619 	g_print (_("   3    Warnings.\n"));
620 	g_print (_("   4    Verbose information.\n"));
621 	g_print (_("   5    Trace.\n"));
622 	g_print ("\n\n");
623 }
624 
625 
626 /** \brief Show version info.
627  *
628  * This function shows the version information about grig.
629  */
630 static void
grig_show_version()631 grig_show_version   ()
632 {
633 	g_print (_("grig %s\n"), VERSION);
634 	g_print (_("Graphical User Interface for the "\
635 		   "Hamradio Control Libraries."));
636 	g_print ("\n\n");
637 	g_print (_("Copyright (C)  2001-2007  Alexandru Csete."));
638 	g_print ("\n");
639 	g_print (_("This is free software; see the source for "\
640 		   "copying conditions. "));
641 	g_print (_("There is NO warranty; not even for MERCHANTABILITY "
642 		   "or FITNESS FOR A PARTICULAR PURPOSE."));
643 	g_print ("\n");
644 
645 }
646 
647 
648 
649 /** \brief List rigs.
650  *
651  * This function lists the radios suported by hamlib. It shows the
652  * manufacturer, model, driver version and driver status in a list
653  * sorted by model number.
654  *
655  * The list of radios is obtained using the rig_list_foreach hamlib
656  * function and storing each entry in a GArray. When all models have
657  * been stored, the list is sorted by model number and printed.
658  *
659  * \bug Header string is not translated.
660  *
661  * \bug Should check retcode returned by rig_list_foreach.
662  *
663  * \sa grig_list_add, grig_list_compare
664  */
665 static void
grig_list_rigs()666 grig_list_rigs ()
667 {
668 	GArray *array;
669 	gint i;
670 	grig_rig_info_t *info;
671 
672 
673 	/* create the array */
674 	array = g_array_new (FALSE, FALSE, sizeof (grig_rig_info_t));
675 
676 	/* make hamlib quiet and load all backends */
677 	grig_debug_set_level (RIG_DEBUG_NONE);
678 	rig_load_all_backends();
679 
680 	/* fill list using rig_list_foreach */
681 	rig_list_foreach (grig_list_add, (void *) array);
682 
683 	/* sort the array */
684 	g_array_sort (array, grig_list_compare);
685 
686 	g_print ("\n");
687 	g_print (_("   ID  Manufacturer     Model                  "\
688 		 "Ver.   Status\n"));
689 	g_print ("-----------------------------------------------"\
690 		 "----------------\n");
691 
692 	/* loop over each element of array; after printing one element
693 	   free the dynamically allocated strings because GArray does
694 	   not know about them
695 	*/
696 	for (i = 0; i < array->len; i++) {
697 
698 		info = &g_array_index (array, grig_rig_info_t, i);
699 
700 		g_print ("%5d  %-16s %-22s %-6s %s\n",
701 			 info->id,
702 			 info->mfg,
703 			 info->model,
704 			 info->version,
705 			 rig_strstatus (info->status));
706 
707 		/* free dynamic strings */
708 		g_free (info->mfg);
709 		g_free (info->model);
710 		g_free (info->version);
711 	}
712 	g_print ("\n");
713 
714 	g_array_free (array,TRUE);
715 }
716 
717 
718 /** \brief Add new entry to list of radios.
719  *  \param caps Structure with the capablities of thecurrent radio.
720  *  \param array Pointer to the GArray into which the new entry should be
721  *               stored.
722  *  \return Always 1 to keep rig_list_foreach running.
723  *
724  * This function is called by the rig_list_foreach hamlib function for each
725  * supported radio. It copies the relevant data into a grig_rig_info_t
726  * structure and adds the new entry to the GArray containing the list of
727  * supported radios.
728  *
729  * \sa grig_list_rigs, grig_list_compare
730  */
731 static gint
grig_list_add(const struct rig_caps * caps,void * array)732 grig_list_add (const struct rig_caps *caps, void *array)
733 {
734 	grig_rig_info_t *info;
735 
736 	/* create new entry */
737 	info = g_malloc (sizeof (grig_rig_info_t));
738 
739 	/* fill values */
740 	info->id      = caps->rig_model;
741 	info->mfg     = g_strdup (caps->mfg_name);
742 	info->model   = g_strdup (caps->model_name);
743 	info->version = g_strdup (caps->version);
744 	info->status  = caps->status;
745 
746 	/* append new element to array */
747 	array = (void *) g_array_append_vals ((GArray *) array, info, 1);
748 
749 	/* keep on running */
750 	return 1;
751 }
752 
753 
754 
755 /** \brief Compare two rig info entries.
756  *  \param a Pointer to the first entry.
757  *  \param b Pointer to the second entry.
758  *  \return Negative value if a < b; zero if a = b; positive value if a > b.
759  *
760  * This function is used to compare two rig entries in the list of radios
761  * when the list is sorted. It compares the model ID of the two radios.
762  *
763  * \sa grig_list_rigs, grig_list_add
764  */
765 static gint
grig_list_compare(gconstpointer a,gconstpointer b)766 grig_list_compare  (gconstpointer a, gconstpointer b)
767 {
768 	gint ida, idb;
769 
770 	ida = ((grig_rig_info_t *) a)->id;
771 	idb = ((grig_rig_info_t *) b)->id;
772 
773 	if (ida < idb) {
774 		return -1;
775 	}
776 	else if (ida > idb) {
777 		return 1;
778 	}
779 	else {
780 		return 0;
781 	}
782 
783 }
784