diff --git a/src/gtk-freq-knob.c b/src/gtk-freq-knob.c index c849831..711db42 100644 --- a/src/gtk-freq-knob.c +++ b/src/gtk-freq-knob.c @@ -4,6 +4,7 @@ Copyright (C) 2001-2009 Alexandru Csete, OZ9AEC. Authors: Alexandru Csete + Patrick Dohmen Comments, questions and bugreports should be submitted via http://sourceforge.net/projects/gpredict/ @@ -24,6 +25,15 @@ You should have received a copy of the GNU General Public License along with this program; if not, visit http://www.fsf.org/ */ +/** \brief FREQ control. + * + * More info... + * + * 1 222.333 444 MHz + * + * \bug This should be a generic widget, not just frequency specific + * + */ #include #include #include @@ -35,15 +45,17 @@ static void gtk_freq_knob_class_init(GtkFreqKnobClass * class); static void gtk_freq_knob_init(GtkFreqKnob * list); -static void gtk_freq_knob_destroy(GtkWidget * widget); -static void gtk_freq_knob_update(GtkFreqKnob * knob); +static void gtk_freq_knob_destroy(GtkObject * object); +static void *gtk_freq_knob_update(GtkFreqKnob * knob); static void button_clicked_cb(GtkWidget * button, gpointer data); static gboolean on_button_press(GtkWidget * digit, GdkEventButton * event, gpointer data); static gboolean on_button_scroll(GtkWidget * digit, GdkEventScroll * event, gpointer data); -static GtkBoxClass *parent_class = NULL; +G_LOCK_DEFINE_STATIC(updatelock); + +static GtkHBoxClass *parent_class = NULL; #define FMTSTR "%c" @@ -63,12 +75,14 @@ static const guint idx[] = { static guint freq_changed_signal = 0; + GType gtk_freq_knob_get_type() { static GType gtk_freq_knob_type = 0; if (!gtk_freq_knob_type) { + static const GTypeInfo gtk_freq_knob_info = { sizeof(GtkFreqKnobClass), NULL, /* base_init */ @@ -81,7 +95,8 @@ GType gtk_freq_knob_get_type() (GInstanceInitFunc) gtk_freq_knob_init, NULL, }; - gtk_freq_knob_type = g_type_register_static(GTK_TYPE_BOX, + + gtk_freq_knob_type = g_type_register_static(GTK_TYPE_VBOX, "GtkFreqKnob", >k_freq_knob_info, 0); } @@ -91,16 +106,23 @@ GType gtk_freq_knob_get_type() static void gtk_freq_knob_class_init(GtkFreqKnobClass * class) { - GtkWidgetClass *widget_class = (GtkWidgetClass *) class; - widget_class->destroy = gtk_freq_knob_destroy; + /*GObjectClass *gobject_class; */ + GtkObjectClass *object_class; + + /*GtkWidgetClass *widget_class; */ + /*GtkContainerClass *container_class; */ + + /*gobject_class = G_OBJECT_CLASS (class); */ + object_class = (GtkObjectClass *) class; + /*widget_class = (GtkWidgetClass*) class; */ + /*container_class = (GtkContainerClass*) class; */ parent_class = g_type_class_peek_parent(class); + object_class->destroy = gtk_freq_knob_destroy; + /* create freq changed signal */ - freq_changed_signal = g_signal_new("freq-changed", - G_TYPE_FROM_CLASS(class), - G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION, - 0, + freq_changed_signal = g_signal_new("freq-changed", G_TYPE_FROM_CLASS(class), G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION, 0, //G_STRUCT_OFFSET (GtkFreqKnobClass, tictactoe), NULL, NULL, g_cclosure_marshal_VOID__VOID, @@ -114,17 +136,16 @@ static void gtk_freq_knob_init(GtkFreqKnob * knob) } -static void gtk_freq_knob_destroy(GtkWidget * widget) +static void gtk_freq_knob_destroy(GtkObject * object) { - (*GTK_WIDGET_CLASS(parent_class)->destroy) (widget); + (*GTK_OBJECT_CLASS(parent_class)->destroy) (object); } /** - * Create a new Frequency control widget. - * - * @param val The initial value of the control. - * @param buttons Flag indicating whether buttons should be shown - * @return A new frequency control widget. + * \brief Create a new Frequency control widget. + * \param[in] val The initial value of the control. + * \param[in] buttons Flag indicating whether buttons should be shown + * \return A new frequency control widget. * */ GtkWidget *gtk_freq_knob_new(gdouble val, gboolean buttons) @@ -135,6 +156,7 @@ GtkWidget *gtk_freq_knob_new(gdouble val, gboolean buttons) guint i; gint delta; + widget = g_object_new(GTK_TYPE_FREQ_KNOB, NULL); GTK_FREQ_KNOB(widget)->value = val; @@ -158,6 +180,7 @@ GtkWidget *gtk_freq_knob_new(gdouble val, gboolean buttons) else { /* active widget that allows changing the value */ + gtk_widget_set_tooltip_text(GTK_FREQ_KNOB(widget)->digits[i], _ ("Use mouse buttons and wheel to change value")); @@ -172,12 +195,14 @@ GtkWidget *gtk_freq_knob_new(gdouble val, gboolean buttons) GTK_FREQ_KNOB(widget)->evtbox[i], idx[i], idx[i] + 1, 1, 2, GTK_SHRINK, GTK_FILL | GTK_EXPAND, 0, 0); + g_signal_connect(GTK_FREQ_KNOB(widget)->evtbox[i], "button_press_event", (GCallback) on_button_press, widget); g_signal_connect(GTK_FREQ_KNOB(widget)->evtbox[i], "scroll_event", (GCallback) on_button_scroll, widget); + /* UP buttons */ GTK_FREQ_KNOB(widget)->buttons[i] = gtk_button_new(); @@ -230,7 +255,8 @@ GtkWidget *gtk_freq_knob_new(gdouble val, gboolean buttons) gtk_table_attach(GTK_TABLE(table), label, 13, 14, 1, 2, GTK_SHRINK, GTK_SHRINK, 0, 0); - gtk_freq_knob_update(GTK_FREQ_KNOB(widget)); + + g_idle_add((GSourceFunc) gtk_freq_knob_update, GTK_FREQ_KNOB(widget)); gtk_container_add(GTK_CONTAINER(widget), table); gtk_widget_show_all(widget); @@ -239,10 +265,9 @@ GtkWidget *gtk_freq_knob_new(gdouble val, gboolean buttons) } /** - * Set the value of the frequency control widget. - * - * @param knob The frequency control widget. - * @param val The new value. + * \brief Set the value of the frequency control widget. + * \param[in] knob The frequency control widget. + * \param[in] val The new value. * */ void gtk_freq_knob_set_value(GtkFreqKnob * knob, gdouble val) @@ -253,15 +278,14 @@ void gtk_freq_knob_set_value(GtkFreqKnob * knob, gdouble val) knob->value = val; /* update the display */ - gtk_freq_knob_update(knob); + g_idle_add((GSourceFunc) gtk_freq_knob_update, knob); } } /** - * Get the current value of the frequency control widget. - * - * @param knob The frequency control widget. - * @return The current value. + * \brief Get the current value of the frequency control widget. + * \param[in] knob The frequency control widget. + * \return The current value. * * Hint: For reading the value you can also access knob->value. * @@ -272,17 +296,19 @@ gdouble gtk_freq_knob_get_value(GtkFreqKnob * knob) } /** - * Update frequency display widget. - * - * @param knob The frequency control widget. + * \brief Update frequency display widget. + * \param[in] knob The frequency control widget. * */ -static void gtk_freq_knob_update(GtkFreqKnob * knob) +static void *gtk_freq_knob_update(GtkFreqKnob * knob) { gchar b[11]; gchar *buff; guint i; + /* Enter critical section! */ + G_LOCK(updatelock); + g_ascii_formatd(b, 11, "%10.0f", fabs(knob->value)); /* set label markups */ @@ -292,13 +318,16 @@ static void gtk_freq_knob_update(GtkFreqKnob * knob) gtk_label_set_markup(GTK_LABEL(knob->digits[i]), buff); g_free(buff); } + + /* Leave critical section! */ + G_UNLOCK(updatelock); + return FALSE; } /** - * Button clicked event. - * - * @param button The button that was clicked. - * @param data Pointer to the GtkFreqKnob widget. + * \brief Button clicked event. + * \param button The button that was clicked. + * \param data Pointer to the GtkFreqKnob widget. * */ static void button_clicked_cb(GtkWidget * button, gpointer data) @@ -316,19 +345,18 @@ static void button_clicked_cb(GtkWidget * button, gpointer data) knob->value += delta; } - gtk_freq_knob_update(knob); + g_idle_add((GSourceFunc) gtk_freq_knob_update, knob); /* emit "freq_changed" signal */ g_signal_emit(G_OBJECT(data), freq_changed_signal, 0); } /** - * Manage button press events - * - * @param digit Pointer to the event box that received the event - * @param event Pointer to the GdkEventButton that contains details for te event - * @param data Pointer to the GtkFreqKnob widget (we need it to update the value) - * @return Always TRUE to prevent further propagation of the event + * \brief Manage button press events + * \param digit Pointer to the event box that received the event + * \param event Pointer to the GdkEventButton that contains details for te event + * \param data Pointer to the GtkFreqKnob widget (we need it to update the value) + * \return Always TRUE to prevent further propagation of the event * * This function is called when a mouse button is pressed on a digit. This is used * to increment or decrement the value: @@ -336,13 +364,16 @@ static void button_clicked_cb(GtkWidget * button, gpointer data) * - Right button: down * - Middle button: set digit to 0 (TBC) * - * Wheel up/down are managed in a separate callback since these are treated as scroll events - * rather than button press events (they used to be button press events though) + * Wheel up/down are managed in a separate callback since these are treated as + * scroll events rather than button press events (they used to be button press + * events though) * - * The digit labels are stored in an array. To get the amount of change corresponding to the - * clicked label we can convert the index (attached to the evtbox): delta = 10^(9-index) + * The digit labels are stored in an array. To get the amount of change corresponding + * to the clicked label we can convert the index (attached to the evtbox): + * delta = 10^(9-index) * - * Whether the delta is positive or negative depends on which mouse button triggered the event. + * Whether the delta is positive or negative depends on which mouse button triggered + * the event. */ static gboolean on_button_press(GtkWidget * evtbox, GdkEventButton * event, gpointer data) @@ -394,21 +425,21 @@ static gboolean on_button_press(GtkWidget * evtbox, } /** - * Manage scroll wheel events + * \brief Manage scroll wheel events + * \param digit Pointer to the event box that received the event + * \param event Pointer to the GdkEventScroll that contains details for te event + * \param data Pointer to the GtkFreqKnob widget (we need it to update the value) + * \return Always TRUE to prevent further propagation of the event * - * @param digit Pointer to the event box that received the event - * @param event Pointer to the GdkEventScroll that contains details for te event - * @param data Pointer to the GtkFreqKnob widget (we need it to update the value) - * @return Always TRUE to prevent further propagation of the event - * - * This function is called when the mouse wheel is moved up or down. This is used to increment - * or decrement the value. + * This function is called when the mouse wheel is moved up or down. This is used + * to increment or decrement the value. * - * Button presses are managed in a separate callback since these are treated as different - * events. + * Button presses are managed in a separate callback since these are treated as + * different events. * - * The digit labels are stored in an array. To get the amount of change corresponding to the - * clicked label we can convert the index (attached to the evtbox): delta = 10^(9-index) + * The digit labels are stored in an array. To get the amount of change corresponding + * to the clicked label we can convert the index (attached to the evtbox): + * delta = 10^(9-index) * * Whether the delta is positive or negative depends on the scroll direction. */ @@ -421,6 +452,7 @@ static gboolean on_button_scroll(GtkWidget * evtbox, gdouble delta = pow(10, 9 - idx); gdouble value; + if (delta < 0.01) { /* no change, user clicked on sign or decimal separator */ @@ -435,6 +467,7 @@ static gboolean on_button_scroll(GtkWidget * evtbox, switch (event->direction) { + /* decrease value by delta */ case GDK_SCROLL_DOWN: case GDK_SCROLL_LEFT: diff --git a/src/gtk-freq-knob.h b/src/gtk-freq-knob.h index ee3cd56..06084fb 100644 --- a/src/gtk-freq-knob.h +++ b/src/gtk-freq-knob.h @@ -35,12 +35,13 @@ #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ -/* *INDENT-ON* */ +/* *INDENT-OO* */ + #define GTK_TYPE_FREQ_KNOB (gtk_freq_knob_get_type ()) #define GTK_FREQ_KNOB(obj) G_TYPE_CHECK_INSTANCE_CAST (obj,\ - gtk_freq_knob_get_type (),\ - GtkFreqKnob) + gtk_freq_knob_get_type (),\ + GtkFreqKnob) #define GTK_FREQ_KNOB_CLASS(klass) G_TYPE_CHECK_CLASS_CAST (klass,\ gtk_freq_knob_get_type (),\ @@ -48,29 +49,32 @@ extern "C" { #define IS_GTK_FREQ_KNOB(obj) G_TYPE_CHECK_INSTANCE_TYPE (obj, gtk_freq_knob_get_type ()) -typedef struct _gtk_freq_knob GtkFreqKnob; -typedef struct _GtkFreqKnobClass GtkFreqKnobClass; -struct _gtk_freq_knob { - GtkBox box; +typedef struct _gtk_freq_knob GtkFreqKnob; +typedef struct _GtkFreqKnobClass GtkFreqKnobClass; - GtkWidget *digits[10]; /*!< Labels for the digits */ - GtkWidget *evtbox[10]; /*!< Event boxes to catch mouse events over the digits */ - GtkWidget *buttons[20]; /*!< Buttons; 0..9 up; 10..19 down */ - - gdouble min; - gdouble max; - gdouble value; +struct _gtk_freq_knob +{ + GtkVBox vbox; + + GtkWidget *digits[10]; /*!< Labels for the digits */ + GtkWidget *evtbox[10]; /*!< Event boxes to catch mouse events over the digits */ + GtkWidget *buttons[20]; /*!< Buttons; 0..9 up; 10..19 down */ + + gdouble min; + gdouble max; + gdouble value; }; -struct _GtkFreqKnobClass { - GtkBoxClass parent_class; +struct _GtkFreqKnobClass +{ + GtkVBoxClass parent_class; }; -GType gtk_freq_knob_get_type(void); -GtkWidget *gtk_freq_knob_new(gdouble val, gboolean buttons); -void gtk_freq_knob_set_value(GtkFreqKnob * knob, gdouble val); -gdouble gtk_freq_knob_get_value(GtkFreqKnob * knob); +GType gtk_freq_knob_get_type (void); +GtkWidget* gtk_freq_knob_new (gdouble val, gboolean buttons); +void gtk_freq_knob_set_value (GtkFreqKnob *knob, gdouble val); +gdouble gtk_freq_knob_get_value (GtkFreqKnob *knob); /* *INDENT-OFF* */ diff --git a/src/gtk-rig-ctrl.c b/src/gtk-rig-ctrl.c index 5e00a46..f57d6a2 100644 --- a/src/gtk-rig-ctrl.c +++ b/src/gtk-rig-ctrl.c @@ -4,6 +4,7 @@ Copyright (C) 2001-2013 Alexandru Csete, OZ9AEC. Authors: Alexandru Csete + Patrick Dohmen Comments, questions and bugreports should be submitted via http://sourceforge.net/projects/gpredict/ @@ -76,7 +77,7 @@ static void gtk_rig_ctrl_class_init(GtkRigCtrlClass * class); static void gtk_rig_ctrl_init(GtkRigCtrl * list); -static void gtk_rig_ctrl_destroy(GtkWidget * widget); +static void gtk_rig_ctrl_destroy(GtkObject * object); static GtkWidget *create_downlink_widgets(GtkRigCtrl * ctrl); static GtkWidget *create_uplink_widgets(GtkRigCtrl * ctrl); @@ -145,6 +146,13 @@ static inline gboolean check_get_response(gchar * buff, gboolean retcode, static gint sat_name_compare(sat_t * a, sat_t * b); static gint rig_name_compare(const gchar * a, const gchar * b); +/* add thread for hamlib communication */ +gpointer rigctl_run(gpointer data); +static void rigctrl_open(GtkRigCtrl * data); +static void rigctrl_close(GtkRigCtrl * data); +static void setconfig(gpointer data); +static void remove_timer(GtkRigCtrl * data); +static void start_timer(GtkRigCtrl * data); static GtkVBoxClass *parent_class = NULL; @@ -179,11 +187,20 @@ GType gtk_rig_ctrl_get_type() static void gtk_rig_ctrl_class_init(GtkRigCtrlClass * class) { - GtkWidgetClass *widget_class = (GtkWidgetClass *) class; + //GObjectClass *gobject_class; + GtkObjectClass *object_class; - widget_class->destroy = gtk_rig_ctrl_destroy; + //GtkWidgetClass *widget_class; + //GtkContainerClass *container_class; + + //gobject_class = G_OBJECT_CLASS (class); + object_class = (GtkObjectClass *) class; + //widget_class = (GtkWidgetClass*) class; + //container_class = (GtkContainerClass*) class; parent_class = g_type_class_peek_parent(class); + + object_class->destroy = gtk_rig_ctrl_destroy; } static void gtk_rig_ctrl_init(GtkRigCtrl * ctrl) @@ -211,13 +228,23 @@ static void gtk_rig_ctrl_init(GtkRigCtrl * ctrl) ctrl->last_toggle_tx = -1; } -static void gtk_rig_ctrl_destroy(GtkWidget * widget) +static void gtk_rig_ctrl_destroy(GtkObject * object) { - GtkRigCtrl *ctrl = GTK_RIG_CTRL(widget); + GtkRigCtrl *ctrl = GTK_RIG_CTRL(object); - /* stop timer */ - if (ctrl->timerid > 0) - g_source_remove(ctrl->timerid); + if (ctrl->rigctl_thread != NULL) + { + + g_mutex_lock(&ctrl->widgetsync); + + ctrl->engaged = 0; + setconfig(ctrl); + + /* synchronization */ + g_cond_wait(&ctrl->widgetready, &ctrl->widgetsync); + g_mutex_unlock(&ctrl->widgetsync); + ctrl->rigctl_thread = NULL; + } /* free configuration */ if (ctrl->conf != NULL) @@ -242,12 +269,7 @@ static void gtk_rig_ctrl_destroy(GtkWidget * widget) ctrl->trsplist = NULL; } - /* close sockets if they are open */ - if (ctrl->sock) - close_rigctld_socket(&(ctrl->sock)); - if (ctrl->sock2) - close_rigctld_socket(&(ctrl->sock2)); - (*GTK_WIDGET_CLASS(parent_class)->destroy) (widget); + (*GTK_OBJECT_CLASS(parent_class)->destroy) (object); } /** @@ -310,10 +332,6 @@ GtkWidget *gtk_rig_ctrl_new(GtkSatModule * module) gtk_container_add(GTK_CONTAINER(widget), table); - GTK_RIG_CTRL(widget)->timerid = g_timeout_add(GTK_RIG_CTRL(widget)->delay, - rig_ctrl_timeout_cb, - GTK_RIG_CTRL(widget)); - if (module->target > 0) gtk_rig_ctrl_select_sat(GTK_RIG_CTRL(widget), module->target); @@ -333,6 +351,9 @@ void gtk_rig_ctrl_update(GtkRigCtrl * ctrl, gdouble t) gdouble satfreq; gchar *buff; + /* Enter critical section! */ + g_mutex_lock(&ctrl->rig_ctrl_updatelock); + if (ctrl->target) { /* update Az/El */ @@ -401,6 +422,8 @@ void gtk_rig_ctrl_update(GtkRigCtrl * ctrl, gdouble t) ctrl->pass = get_next_pass(ctrl->target, ctrl->qth, 3.0); } } + /* Leave critical section! */ + g_mutex_unlock(&ctrl->rig_ctrl_updatelock); } /** Select a satellite */ @@ -941,7 +964,6 @@ static void sat_selected_cb(GtkComboBox * satsel, gpointer data) free_pass(ctrl->pass); ctrl->pass = NULL; } - } } @@ -1075,10 +1097,10 @@ static void delay_changed_cb(GtkSpinButton * spin, gpointer data) ctrl->delay = (guint) gtk_spin_button_get_value(spin); - if (ctrl->timerid > 0) - g_source_remove(ctrl->timerid); - - ctrl->timerid = g_timeout_add(ctrl->delay, rig_ctrl_timeout_cb, ctrl); + if (ctrl->engaged) + { + start_timer(ctrl); + } } /** @@ -1283,74 +1305,21 @@ static void rig_engaged_cb(GtkToggleButton * button, gpointer data) gtk_widget_set_sensitive(ctrl->DevSel, TRUE); gtk_widget_set_sensitive(ctrl->DevSel2, TRUE); ctrl->engaged = FALSE; - ctrl->lasttxf = 0.0; - ctrl->lastrxf = 0.0; - if ((ctrl->conf->type == RIG_TYPE_TOGGLE_AUTO) || - (ctrl->conf->type == RIG_TYPE_TOGGLE_MAN)) - { - unset_toggle(ctrl, ctrl->sock); - } - - if (ctrl->conf2 != NULL) - { - close_rigctld_socket(&(ctrl->sock2)); - } - close_rigctld_socket(&(ctrl->sock)); + /* stop worker thread... */ + setconfig(ctrl); + ctrl->rigctl_thread = NULL; } else { gtk_widget_set_sensitive(ctrl->DevSel, FALSE); gtk_widget_set_sensitive(ctrl->DevSel2, FALSE); ctrl->engaged = TRUE; - ctrl->wrops = 0; - open_rigctld_socket(ctrl->conf, &(ctrl->sock)); - - /* set initial frequency */ - if (ctrl->conf2 != NULL) - { - open_rigctld_socket(ctrl->conf2, &(ctrl->sock2)); - /* set initial dual mode */ - exec_dual_rig_cycle(ctrl); - } - else - { - switch (ctrl->conf->type) - { - - case RIG_TYPE_RX: - exec_rx_cycle(ctrl); - break; - - case RIG_TYPE_TX: - exec_tx_cycle(ctrl); - break; - - case RIG_TYPE_TRX: - exec_trx_cycle(ctrl); - break; - - case RIG_TYPE_DUPLEX: - /* set rig into SAT mode (hamlib needs it even if rig already in SAT) */ - setup_split(ctrl); - exec_duplex_cycle(ctrl); - break; - - case RIG_TYPE_TOGGLE_AUTO: - case RIG_TYPE_TOGGLE_MAN: - set_toggle(ctrl, ctrl->sock); - ctrl->last_toggle_tx = -1; - exec_toggle_cycle(ctrl); - break; - - default: - /* this is an error! */ - ctrl->conf->type = RIG_TYPE_RX; - exec_rx_cycle(ctrl); - break; - } - } + /* start worker thread... */ + ctrl->rigctlq = g_async_queue_new(); + ctrl->rigctl_thread = g_thread_new("rigctl_run", rigctl_run, ctrl); + setconfig(ctrl); } } @@ -1367,7 +1336,7 @@ static void rig_engaged_cb(GtkToggleButton * button, gpointer data) static gboolean setup_split(GtkRigCtrl * ctrl) { gchar *buff; - gchar buffback[128]; + gchar buffback[256 /*128 */ ]; /* issues with receiving rigctld answer (assertion failed) */ gboolean retcode; /* select TX VFO */ @@ -1458,7 +1427,7 @@ static gboolean rig_ctrl_timeout_cb(gpointer data) sat_log_log(SAT_LOG_LEVEL_ERROR, _("%s: Controller does not have a valid configuration"), __func__); - return (TRUE); + return FALSE; } @@ -1469,63 +1438,8 @@ static gboolean rig_ctrl_timeout_cb(gpointer data) return TRUE; } - check_aos_los(ctrl); - - if (ctrl->conf2 != NULL) - { - exec_dual_rig_cycle(ctrl); - } - else - { - /* Execute controller cycle depending on primary radio type */ - switch (ctrl->conf->type) - { - - case RIG_TYPE_RX: - exec_rx_cycle(ctrl); - break; - - case RIG_TYPE_TX: - exec_tx_cycle(ctrl); - break; - - case RIG_TYPE_TRX: - exec_trx_cycle(ctrl); - break; - - case RIG_TYPE_DUPLEX: - exec_duplex_cycle(ctrl); - break; - - case RIG_TYPE_TOGGLE_AUTO: - case RIG_TYPE_TOGGLE_MAN: - exec_toggle_cycle(ctrl); - break; - - default: - /* invalid mode */ - sat_log_log(SAT_LOG_LEVEL_ERROR, - _("%s: Invalid radio type %d. Setting type to " - "RIG_TYPE_RX"), __func__, ctrl->conf->type); - ctrl->conf->type = RIG_TYPE_RX; - } - } - - /* perform error count checking */ - if (ctrl->errcnt >= MAX_ERROR_COUNT) - { - /* disengage device */ - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(ctrl->LockBut), FALSE); - ctrl->engaged = FALSE; - ctrl->errcnt = 0; - sat_log_log(SAT_LOG_LEVEL_ERROR, - _("%s: MAX_ERROR_COUNT (%d) reached. Disengaging device!"), - __func__, MAX_ERROR_COUNT); - - //g_print ("ERROR. WROPS = %d\n", ctrl->wrops); - } - - //g_print (" WROPS = %d\n", ctrl->wrops); + /* push event */ + setconfig(ctrl); g_mutex_unlock(&(ctrl->busy)); @@ -1890,7 +1804,6 @@ static void exec_toggle_tx_cycle(GtkRigCtrl * ctrl) } - /** * \brief Execute TX cycle for full duplex radios. * \param ctrl Pointer to the GtkRigCtrl structure. @@ -2058,8 +1971,7 @@ static void exec_dual_rig_cycle(GtkRigCtrl * ctrl) { satfreqd = readfreq + ctrl->conf->lo; } - gtk_freq_knob_set_value(GTK_FREQ_KNOB(ctrl->SatFreqDown), - satfreqd); + gtk_freq_knob_set_value(GTK_FREQ_KNOB(ctrl->SatFreqDown), satfreqd); /* Update uplink if locked to downlink */ if (ctrl->trsplock) @@ -2301,6 +2213,7 @@ static gboolean get_ptt(GtkRigCtrl * ctrl, gint sock) pttstat = g_ascii_strtoull(vbuff[0], NULL, 0); //FIXME base = 0 ok? g_strfreev(vbuff); } + g_free(buff); return (pttstat == 1) ? TRUE : FALSE; @@ -2326,8 +2239,8 @@ static gboolean set_ptt(GtkRigCtrl * ctrl, gint sock, gboolean ptt) buff = g_strdup_printf("T 0\x0aq\x0a"); retcode = send_rigctld_command(ctrl, sock, buff, buffback, 128); - g_free(buff); + return (check_set_response(buffback, retcode, __func__)); } @@ -2511,6 +2424,7 @@ static gboolean get_freq_simplex(GtkRigCtrl * ctrl, gint sock, gdouble * freq) retval = FALSE; } + //g_free(buff); return retval; } @@ -2554,6 +2468,7 @@ static gboolean get_freq_toggle(GtkRigCtrl * ctrl, gint sock, gdouble * freq) retval = FALSE; } + //g_free(buff); return retval; } @@ -2886,6 +2801,9 @@ gboolean send_rigctld_command(GtkRigCtrl * ctrl, gint sock, gchar * buff, gint written; gint size; + /* Enter critical section! */ + g_mutex_lock(&ctrl->writelock); + /* added by Marcel Cimander; win32 newline -> \10\13 */ #ifdef WIN32 size = strlen(buff) - 1; @@ -2933,6 +2851,9 @@ gboolean send_rigctld_command(GtkRigCtrl * ctrl, gint sock, gchar * buff, } ctrl->wrops++; + /* Leave critical section! */ + g_mutex_unlock(&ctrl->writelock); + return TRUE; } @@ -2961,7 +2882,7 @@ static gboolean key_press_cb(GtkWidget * widget, GdkEventKey * pKey, switch (pKey->keyval) { /* keyvals not in API docs. See for a complete list */ - case GDK_KEY_space: + case GDK_space: sat_log_log(SAT_LOG_LEVEL_INFO, _("%s: Detected SPACEBAR pressed event"), __func__); @@ -3175,8 +3096,8 @@ static inline gboolean check_set_response(gchar * buffback, gboolean retcode, if (strncmp(buffback, "RPRT 0", 6) != 0) { sat_log_log(SAT_LOG_LEVEL_ERROR, - _("%s: %s rigctld returned error (%s)"), - __FILE__, function, buffback); + _("%s:%s: %s rigctld returned error (%s)"), + __FILE__, __func__, function, buffback); retcode = FALSE; } @@ -3200,8 +3121,8 @@ static inline gboolean check_get_response(gchar * buffback, gboolean retcode, if (strncmp(buffback, "RPRT", 4) == 0) { sat_log_log(SAT_LOG_LEVEL_ERROR, - _("%s: %s rigctld returned error (%s)"), - __FILE__, function, buffback); + _("%s:%s: %s rigctld returned error (%s)"), + __FILE__, __func__, function, buffback); retcode = FALSE; } @@ -3209,3 +3130,245 @@ static inline gboolean check_get_response(gchar * buffback, gboolean retcode, return retcode; } + +static void rigctrl_close(GtkRigCtrl * data) +{ + GtkRigCtrl *ctrl = GTK_RIG_CTRL(data); + + ctrl->lasttxf = 0.0; + ctrl->lastrxf = 0.0; + + remove_timer(ctrl); + + if ((ctrl->conf->type == RIG_TYPE_TOGGLE_AUTO) || + (ctrl->conf->type == RIG_TYPE_TOGGLE_MAN)) + { + unset_toggle(ctrl, ctrl->sock); + } + + if (ctrl->conf2 != NULL) + { + close_rigctld_socket(&(ctrl->sock2)); + } + close_rigctld_socket(&(ctrl->sock)); +} + +static void rigctrl_open(GtkRigCtrl * data) +{ + GtkRigCtrl *ctrl = GTK_RIG_CTRL(data); + + ctrl->wrops = 0; + + start_timer(ctrl); + + open_rigctld_socket(ctrl->conf, &(ctrl->sock)); + + /* set initial frequency */ + if (ctrl->conf2 != NULL) + { + open_rigctld_socket(ctrl->conf2, &(ctrl->sock2)); + /* set initial dual mode */ + exec_dual_rig_cycle(ctrl); + } + else + { + switch (ctrl->conf->type) + { + + case RIG_TYPE_RX: + exec_rx_cycle(ctrl); + break; + + case RIG_TYPE_TX: + exec_tx_cycle(ctrl); + break; + + case RIG_TYPE_TRX: + exec_trx_cycle(ctrl); + break; + + case RIG_TYPE_DUPLEX: + /* set rig into SAT mode (hamlib needs it even if rig already in SAT) */ + setup_split(ctrl); + exec_duplex_cycle(ctrl); + break; + + case RIG_TYPE_TOGGLE_AUTO: + case RIG_TYPE_TOGGLE_MAN: + set_toggle(ctrl, ctrl->sock); + ctrl->last_toggle_tx = -1; + exec_toggle_cycle(ctrl); + break; + + default: + /* this is an error! */ + ctrl->conf->type = RIG_TYPE_RX; + exec_rx_cycle(ctrl); + break; + } + } +} + +/** + * \brief Communication thread for hamlib rigctld + * \param data + * \return NULL + */ +gpointer rigctl_run(gpointer data) +{ + GtkRigCtrl *ctrl = GTK_RIG_CTRL(data); + GtkRigCtrl *t_ctrl = GTK_RIG_CTRL(data); + + while (1) + { + t_ctrl = GTK_RIG_CTRL(g_async_queue_pop(ctrl->rigctlq)); + ctrl = t_ctrl; + while (g_main_context_iteration(NULL, FALSE)); + + if (t_ctrl == NULL) + { + sat_log_log(SAT_LOG_LEVEL_ERROR, + _("%s:%s: ERROR: NO VALID ctrl-struct"), __FILE__, + __func__); + continue; + } + + if (t_ctrl->engaged) + { + if (!t_ctrl->sock) + { + rigctrl_open(t_ctrl); + } + + if (!t_ctrl->timerid) + { + start_timer(t_ctrl); + } + } + else + { + g_mutex_lock(&t_ctrl->widgetsync); + + if (t_ctrl->sock > 0) + { + rigctrl_close(t_ctrl); + } + + if (t_ctrl->timerid) + { + remove_timer(t_ctrl); + } + + g_cond_signal(&t_ctrl->widgetready); + g_mutex_unlock(&t_ctrl->widgetsync); + break; + } + + check_aos_los(t_ctrl); + + if (t_ctrl->conf2 != NULL) + { + exec_dual_rig_cycle(t_ctrl); + } + else + { + /* Execute controller cycle depending on primary radio type */ + switch (t_ctrl->conf->type) + { + + case RIG_TYPE_RX: + exec_rx_cycle(t_ctrl); + break; + + case RIG_TYPE_TX: + exec_tx_cycle(t_ctrl); + break; + + case RIG_TYPE_TRX: + exec_trx_cycle(t_ctrl); + break; + + case RIG_TYPE_DUPLEX: + exec_duplex_cycle(t_ctrl); + break; + + case RIG_TYPE_TOGGLE_AUTO: + case RIG_TYPE_TOGGLE_MAN: + exec_toggle_cycle(t_ctrl); + break; + + default: + /* invalid mode */ + sat_log_log(SAT_LOG_LEVEL_ERROR, + _("%s:%s: Invalid radio type %d. Setting type to " + "RIG_TYPE_RX"), __FILE__, __func__, + t_ctrl->conf->type); + t_ctrl->conf->type = RIG_TYPE_RX; + } + } + + /* perform error count checking */ + if (t_ctrl->errcnt >= MAX_ERROR_COUNT) + { + /* disengage device */ + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(t_ctrl->LockBut), + FALSE); + t_ctrl->engaged = FALSE; + t_ctrl->errcnt = 0; + sat_log_log(SAT_LOG_LEVEL_ERROR, + _ + ("%s:%s: MAX_ERROR_COUNT (%d) reached. Disengaging device!"), + __FILE__, __func__, MAX_ERROR_COUNT); + + //g_print ("ERROR. WROPS = %d\n", ctrl->wrops); + } + + //g_print (" WROPS = %d\n", ctrl->wrops); + } + + /* let's have a clean exit: */ + if (t_ctrl->sock > 0) + { + rigctrl_close(t_ctrl); + } + + if (t_ctrl->timerid) + { + remove_timer(t_ctrl); + } + + return NULL; +} + +void start_timer(GtkRigCtrl * data) +{ + GtkRigCtrl *ctrl = GTK_RIG_CTRL(data); + + /* start timeout timer here ("Cycle")! */ + if (ctrl->timerid > 0) + g_source_remove(ctrl->timerid); + + ctrl->timerid = + gdk_threads_add_timeout(ctrl->delay, rig_ctrl_timeout_cb, ctrl); +} + +void remove_timer(GtkRigCtrl * data) +{ + GtkRigCtrl *ctrl = GTK_RIG_CTRL(data); + + /* stop timer */ + if (ctrl->timerid > 0) + g_source_remove(ctrl->timerid); + ctrl->timerid = 0; +} + +void setconfig(gpointer data) +{ + /* something has changed... */ + GtkRigCtrl *ctrl = GTK_RIG_CTRL(data); + + if (ctrl != NULL) + { + g_async_queue_push(ctrl->rigctlq, ctrl); + } +} diff --git a/src/gtk-rig-ctrl.h b/src/gtk-rig-ctrl.h index d8cae94..1445323 100644 --- a/src/gtk-rig-ctrl.h +++ b/src/gtk-rig-ctrl.h @@ -108,6 +108,16 @@ struct _gtk_rig_ctrl { /* debug related */ guint wrops; guint rdops; + + /* DL4PD */ + /* threads related stuff */ + /* add mutexes etc, to make threads reentrant! */ + GMutex writelock; /*!< Mutex for blocking write operation */ + GMutex rig_ctrl_updatelock; /*!< Mutex wile updating widgets etc */ + GMutex widgetsync; /*!< Mutex used while leaving (sync stuff) */ + GCond widgetready; /*!< Condition when work is done (sync stuff) */ + GAsyncQueue *rigctlq; /*!< Message queue to indicate something has changed */ + GThread *rigctl_thread; /*!< Pointer to current rigctl-thread */ }; struct _GtkRigCtrlClass {