Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Radio uplink and downlink frequencies are hard-coded, making ground station software automation difficult #275

Open
nsdecicco opened this issue Nov 11, 2021 · 0 comments

Comments

@nsdecicco
Copy link
Contributor

Problem statement

At the Laboratory for Atmospheric and Space Physics (LASP) at the University of Colorado Boulder (CU), we use gpredict to control Doppler shift of our GNU Radio-based UHF transceiver and S-band receiver in our ground station. We also use gpredict for control of our UHF antenna rotator. (Our s-band dish uses its own proprietary software for tracking.) We use a set of home-grown shell and Python scripts to automate launching gpredict and our GNU Radio flowgraph (and some other internal software) a few minutes before each pass, but some human interaction is required to click buttons in the gpredict interface that are not currently managed in the gpredict config files (i.e., those which reset to default values when the software is restarted).

We would like if this automation software could be entirely autonomous—that is to say, not requiring any human interaction whatsoever.

One issue with gpredict as it currently stands is the rig control window default transmit and receive frequencies are initialized to a hard-coded value (145.890 MHz): there is no way to configure this value differently without modifying the source code and building a new executable. Ideally, this would be saved in the per-radio .rig configuration files.

Summary of existing code

The rig control window as of the latest version of gpredict appears as follows:

The widgets for adjusting the radio frequency are implemented in gtk-freq-knob.c and gtk-freq-knob.h. These widgets are instantiated in gtk-rig-ctrl.c in the create_uplink_widgets() and create_downlink_widgets() routines—on the downlink side, this looks like the following:

gpredict/src/gtk-rig-ctrl.c

Lines 463 to 467 in a0a5636

/* satellite downlink frequency */
ctrl->SatFreqDown = gtk_freq_knob_new(145890000.0, TRUE);
g_signal_connect(ctrl->SatFreqDown, "freq-changed",
G_CALLBACK(downlink_changed_cb), ctrl);
gtk_box_pack_start(GTK_BOX(vbox), ctrl->SatFreqDown, TRUE, TRUE, 0);

The uplink side is similar. The currently-in-use frequencies displayed below these widgets is likewise instantiated in said routines, and also uses this 145890000.0 "magic number":

gpredict/src/gtk-rig-ctrl.c

Lines 489 to 496 in a0a5636

/* Radio downlink frequency */
label = gtk_label_new(NULL);
gtk_label_set_markup(GTK_LABEL(label),
"<span size='large'><b>Radio:</b></span>");
g_object_set(label, "xalign", 0.5f, "yalign", 1.0f, NULL);
gtk_box_pack_start(GTK_BOX(hbox2), label, TRUE, TRUE, 0);
ctrl->RigFreqDown = gtk_freq_knob_new(145890000.0, FALSE);
gtk_box_pack_start(GTK_BOX(hbox2), ctrl->RigFreqDown, TRUE, TRUE, 0);

Screenshots of modified program

Here are screenshots showing what the rig list and rig editor windows look like after the changes described below are implemented:

Screenshot from 2021-11-10 18-47-10

Screenshot from 2021-11-10 18-47-15

Summary of proposed code changes

It seems like a useful modification to gpredict would be to add default uplink and downlink frequecies to the rig config file (.rig). This requires the following changes:

  • Add new member variables to the radio_conf_t struct in radio-conf.h to provide runtime storage of the default per-radio uplink and downlink frequencies
  • Add code to radio_conf_read() in radio-conf.c to read default uplink and downlink frequencies from the .rig config files
  • Add code to radio_conf_save() in radio-conf.c to save default uplink and downlink frequencies to the .rig config files
  • Add UI controls to the rig editor window to allow viewing and changing the default uplink and downlink frequencies
  • Add columns to the rig list to display the default uplink and downlink frequencies in their own columns

Implementation

Adding configuration file options

Two new variables are added to the radio_conf_t struct in radio-conf.h, defUpFreq and defDnFreq:

diff --git a/src/radio-conf.h b/src/radio-conf.h
index a5c3aa5..a8b9578 100644
--- a/src/radio-conf.h
+++ b/src/radio-conf.h
@@ -65,6 +65,8 @@ typedef struct {
     gdouble         lo;         /*!< local oscillator freq in Hz (using double for
                                    compatibility with rest of code). Downlink. */
     gdouble         loup;       /*!< local oscillator freq in Hz for uplink. */
+    gdouble         defUpFreq;  /*!< Default uplink in Hertz */
+    gdouble         defDnFreq;  /*!< Default downlink frequency in Hertz */
     rig_type_t      type;       /*!< Radio type */
     ptt_type_t      ptt;        /*!< PTT type (needed for RX, TX, and TRX) */
     vfo_t           vfoDown;    /*!< Downlink VFO for full-duplex radios */

Next, keys for these options are added to radio-conf.c. These will be used later:

diff --git a/src/radio-conf.c b/src/radio-conf.c
index 46c70c5..2dc3954 100644
--- a/src/radio-conf.c
+++ b/src/radio-conf.c
@@ -39,6 +39,8 @@
 #define KEY_CYCLE       "Cycle"
 #define KEY_LO          "LO"
 #define KEY_LOUP        "LO_UP"
+#define KEY_DEF_UP_FREQ "DefaultUplinkFreqHz"
+#define KEY_DEF_DN_FREQ "DefaultDownlinkFreqHz"
 #define KEY_TYPE        "Type"
 #define KEY_PTT         "PTT"
 #define KEY_VFO_DOWN    "VFO_DOWN"

With the keys defined, parser code for these options is added to radio_conf_read() in the same file:

diff --git a/src/radio-conf.c b/src/radio-conf.c
index 46c70c5..2dc3954 100644
--- a/src/radio-conf.c
+++ b/src/radio-conf.c
@@ -175,6 +177,48 @@ gboolean radio_conf_read(radio_conf_t * conf)
         conf->loup = 0.0;
     }

+    /* KEY_DEF_UP_FREQ is optional */
+    if (g_key_file_has_key(cfg, GROUP, KEY_DEF_UP_FREQ, NULL))
+    {
+        conf->defUpFreq =
+            g_key_file_get_double(cfg, GROUP, KEY_DEF_UP_FREQ, &error);
+        if (error != NULL)
+        {
+            sat_log_log(SAT_LOG_LEVEL_ERROR,
+                        _("%s: Error reading radio conf from %s (%s)."),
+                        __func__, conf->name, error->message);
+            g_clear_error(&error);
+            g_key_file_free(cfg);
+            return FALSE;
+        }
+    }
+    else
+    {
+        conf->defUpFreq = 145890000.0;
+    }

The parser for KEY_DEF_DN_FREQ is similar.

Finally, we must also remember to save these configuration settings in radio_conf_save:

@@ -272,6 +316,8 @@ void radio_conf_save(radio_conf_t * conf)
     g_key_file_set_integer(cfg, GROUP, KEY_PORT, conf->port);
     g_key_file_set_double(cfg, GROUP, KEY_LO, conf->lo);
     g_key_file_set_double(cfg, GROUP, KEY_LOUP, conf->loup);
+    g_key_file_set_double(cfg, GROUP, KEY_DEF_UP_FREQ, conf->defUpFreq);
+    g_key_file_set_double(cfg, GROUP, KEY_DEF_DN_FREQ, conf->defDnFreq);
     g_key_file_set_integer(cfg, GROUP, KEY_TYPE, conf->type);
     g_key_file_set_integer(cfg, GROUP, KEY_PTT, conf->ptt);

Modifying the rig editor dialog window

Adding these options to the rig editor UI involves modifying the following methods in sat-pref-rig-editor.c:

  • clear_widgets(), which initializes widgets to their default values,
  • update_widgets(), which initializes the widgets with values read from a configuration file,
  • create_editor_widgets(), which populates the UI controls, and
  • apply_changes(), which saves changes to a radio_conf_t struct.

Common

First, we must add two global pointers to sat-pref-rig-editor.c for the new widgets that we will be adding:

diff --git a/src/sat-pref-rig-editor.c b/src/sat-pref-rig-editor.c
index 0f278fc..27d726a 100644
--- a/src/sat-pref-rig-editor.c
+++ b/src/sat-pref-rig-editor.c
@@ -41,6 +41,8 @@ static GtkWidget *ptt;          /* PTT */
 static GtkWidget *vfo;          /* VFO Up/Down selector */
 static GtkWidget *lo;           /* local oscillator of downconverter */
 static GtkWidget *loup;         /* local oscillator of upconverter */
+static GtkWidget *defDnFreq;    /* Default downlink frequency */
+static GtkWidget *defUpFreq;    /* Default uplink frequency */
 static GtkWidget *sigaos;       /* AOS signalling */
 static GtkWidget *siglos;       /* LOS signalling */

create_editor_widgets()

Controls are added for adjusting downlink frequency to create_editor_widgets():

diff --git a/src/sat-pref-rig-editor.c b/src/sat-pref-rig-editor.c
index 0f278fc..27d726a 100644
--- a/src/sat-pref-rig-editor.c
+++ b/src/sat-pref-rig-editor.c
@@ -421,18 +431,50 @@ static GtkWidget *create_editor_widgets(radio_conf_t * conf)
     g_object_set(label, "xalign", 0.0, "yalign", 0.5, NULL);
     gtk_grid_attach(GTK_GRID(table), label, 3, 7, 1, 1);
 
+    /* Default downlink frequency */
+    label = gtk_label_new(_("Default downlink"));
+    g_object_set(label, "xalign", 1.0, "yalign", 0.5, NULL);
+    gtk_grid_attach(GTK_GRID(table), label, 0, 8, 1, 1);
+
+    defDnFreq = gtk_spin_button_new_with_range(0, 10000, 0.001);
+    gtk_spin_button_set_value(GTK_SPIN_BUTTON(defDnFreq), 0);
+    gtk_spin_button_set_digits(GTK_SPIN_BUTTON(defDnFreq), 3);
+    gtk_widget_set_tooltip_text(defDnFreq,
+                                _("Enter the default downlink frequency"));
+    gtk_grid_attach(GTK_GRID(table), defDnFreq, 1, 8, 2, 1);
+
+    label = gtk_label_new(_("MHz"));
+    g_object_set(label, "xalign", 0.0, "yalign", 0.5, NULL);
+    gtk_grid_attach(GTK_GRID(table), label, 3, 8, 1, 1);

The code which adds uplink frequency adjustment is similar.

As two new rows are inserted in the widget table above AOS/LOS signaling, these controls must be shifted down by one:

     /* AOS / LOS signalling */
     label = gtk_label_new(_("Signalling"));
     g_object_set(label, "xalign", 1.0, "yalign", 0.5, NULL);
-    gtk_grid_attach(GTK_GRID(table), label, 0, 8, 1, 1);
+    gtk_grid_attach(GTK_GRID(table), label, 0, 10, 1, 1);
 
     sigaos = gtk_check_button_new_with_label(_("AOS"));
-    gtk_grid_attach(GTK_GRID(table), sigaos, 1, 8, 1, 1);
+    gtk_grid_attach(GTK_GRID(table), sigaos, 1, 10, 1, 1);
     gtk_widget_set_tooltip_text(sigaos,
                                 _("Enable AOS signalling for this radio."));
 
     siglos = gtk_check_button_new_with_label(_("LOS"));
-    gtk_grid_attach(GTK_GRID(table), siglos, 2, 8, 1, 1);
+    gtk_grid_attach(GTK_GRID(table), siglos, 2, 10, 1, 1);
     gtk_widget_set_tooltip_text(siglos,
                                 _("Enable LOS signalling for this radio."));

clear_editor_widgets()

Changes to this method are very simple:

@@ -52,6 +54,8 @@ static void clear_widgets()
     gtk_spin_button_set_value(GTK_SPIN_BUTTON(port), 4532);     /* hamlib default? */
     gtk_spin_button_set_value(GTK_SPIN_BUTTON(lo), 0);
     gtk_spin_button_set_value(GTK_SPIN_BUTTON(loup), 0);
+    gtk_spin_button_set_value(GTK_SPIN_BUTTON(defDnFreq), 145.89);
+    gtk_spin_button_set_value(GTK_SPIN_BUTTON(defUpFreq), 145.89);
     gtk_combo_box_set_active(GTK_COMBO_BOX(type), RIG_TYPE_RX);
     gtk_combo_box_set_active(GTK_COMBO_BOX(ptt), PTT_TYPE_NONE);
     gtk_combo_box_set_active(GTK_COMBO_BOX(vfo), 0);

update_widgets()

@@ -100,6 +104,12 @@ static void update_widgets(radio_conf_t * conf)
     /* lo up in MHz */
     gtk_spin_button_set_value(GTK_SPIN_BUTTON(loup), conf->loup / 1000000.0);
 
+     /* Default downlink frequency in MHz */
+     gtk_spin_button_set_value(GTK_SPIN_BUTTON(defDnFreq),
+                               conf->defDnFreq * 1.0e-6);

+     /* Default uplink frequency in Mhz */
+     gtk_spin_button_set_value(GTK_SPIN_BUTTON(defUpFreq),
+                               conf->defUpFreq * 1.0e-6);

     /* AOS / LOS signalling */
     gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(sigaos), conf->signal_aos);
     gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(siglos), conf->signal_los);

apply_changes()

@@ -468,6 +512,14 @@ static gboolean apply_changes(radio_conf_t * conf)
     /* lo up freq */
     conf->loup = 1000000.0 * gtk_spin_button_get_value(GTK_SPIN_BUTTON(loup));
 
+    /* default downlink freq */
+    conf->defDnFreq = 1000000.0 *
+                      gtk_spin_button_get_value(GTK_SPIN_BUTTON(defDnFreq));
+
+    /* default uplink freq */
+    conf->defUpFreq = 1000000.0 *
+                      gtk_spin_button_get_value(GTK_SPIN_BUTTON(defUpFreq));
+
     /* rig type */
     conf->type = gtk_combo_box_get_active(GTK_COMBO_BOX(type));

Modifying the rig list

sat-pref-rig-data.h

First, we add enumeration values representing the two columns we will be adding to the rig list (default uplink and downlink frequency):

diff --git a/src/sat-pref-rig-data.h b/src/sat-pref-rig-data.h
index eea4e56..1330e07 100644
--- a/src/sat-pref-rig-data.h
+++ b/src/sat-pref-rig-data.h
@@ -38,6 +38,8 @@ typedef enum {
     RIG_LIST_COL_VFODOWN,       /*!< VFO down */
     RIG_LIST_COL_LO,            /*!< Local oscillator freq (downlink) */
     RIG_LIST_COL_LOUP,          /*!< Local oscillato freq (uplink) */
+    RIG_LIST_COL_DEF_UP_FREQ,   /*!< Default uplink frequency */
+    RIG_LIST_COL_DEF_DN_FREQ,   /*!< Default downlink frequency */
     RIG_LIST_COL_SIGAOS,        /*!< Signal AOS */
     RIG_LIST_COL_SIGLOS,        /*!< Signal LOS */
     RIG_LIST_COL_NUM            /*!< The number of fields in the list. */

sat-pref-rig.c

The data model

The list store (data model) must be modified to include the new columns:

@@ -53,13 +53,15 @@ static GtkTreeModel *create_and_fill_model()
      /* create a new list store */
      liststore = gtk_list_store_new(RIG_LIST_COL_NUM, G_TYPE_STRING,     // name
                                     G_TYPE_STRING,       // host
                                     G_TYPE_INT,  // port
                                     G_TYPE_INT,  // type
                                     G_TYPE_INT,  // PTT
                                     G_TYPE_INT,  // VFO Up
                                     G_TYPE_INT,  // VFO Down
                                     G_TYPE_DOUBLE,       // LO DOWN
                                     G_TYPE_DOUBLE,       // LO UO
+                                    G_TYPE_DOUBLE,       // Default down freq.
+                                    G_TYPE_DOUBLE,       // Default up freq.
                                     G_TYPE_BOOLEAN,      // AOS signalling
                                     G_TYPE_BOOLEAN       // LOS signalling
          );

Likewise every instance of gtk_list_store_set and gtk_tree_model_get must be modified to include these new columns:

                    gtk_list_store_set(liststore, &item,
                                         RIG_LIST_COL_NAME, conf.name,
                                         RIG_LIST_COL_HOST, conf.host,
                                         RIG_LIST_COL_PORT, conf.port,
                                         RIG_LIST_COL_TYPE, conf.type,
                                         RIG_LIST_COL_PTT, conf.ptt,
                                         RIG_LIST_COL_VFOUP, conf.vfoUp,
                                         RIG_LIST_COL_VFODOWN, conf.vfoDown,
                                         RIG_LIST_COL_LO, conf.lo,
                                         RIG_LIST_COL_LOUP, conf.loup,
+                                        RIG_LIST_COL_DEF_UP_FREQ, conf.defUpFreq,
+                                        RIG_LIST_COL_DEF_DN_FREQ, conf.defDnFreq,
                                         RIG_LIST_COL_SIGAOS, conf.signal_aos,
                                         RIG_LIST_COL_SIGLOS, conf.signal_los,
                                         -1);
     }

The edit, add, and ok button callbacks must be changed:

@@ -393,6 +397,8 @@ static void edit_cb(GtkWidget * button, gpointer data)
         .vfoDown = 0,
         .lo = 0.0,
         .loup = 0.0,
+        .defUpFreq = 0.0,
+        .defDnFreq = 0.0,
         .signal_aos = FALSE,
         .signal_los = FALSE
     };
@@ -688,6 +719,8 @@ static void add_cb(GtkWidget * button, gpointer data)
         .vfoDown = 0,
         .lo = 0.0,
         .loup = 0.0,
+        .defDnFreq = 14589000.0,
+        .defUpFreq = 14589000.0,
         .signal_aos = FALSE,
         .signal_los = FALSE,
     };
@@ -812,6 +847,8 @@ void sat_pref_rig_ok()
         .vfoDown = 0,
         .lo = 0.0,
         .loup = 0.0,
+        .defDnFreq = 14589000.0,
+        .defUpFreq = 14589000.0,
         .signal_aos = FALSE,
         .signal_los = FALSE
     };

Adding UI controls

@@ -587,6 +597,27 @@ static void create_rig_list()
                                             (RIG_LIST_COL_LOUP), NULL);
     gtk_tree_view_insert_column(GTK_TREE_VIEW(riglist), column, -1);
 
+    /* Default downlink frequency */
+    renderer = gtk_cell_renderer_text_new();
+    column = gtk_tree_view_column_new_with_attributes(_("Downlink"), renderer,
+                                                      "text", RIG_LIST_COL_DEF_DN_FREQ,
+                                                      NULL);
+    gtk_tree_view_column_set_cell_data_func(column, renderer,
+                                            render_lo,
+                                            GUINT_TO_POINTER(RIG_LIST_COL_DEF_DN_FREQ),
+                                            NULL);
+    gtk_tree_view_insert_column(GTK_TREE_VIEW(riglist), column, -1);
+
+    /* Default uplink frequency */
+    renderer = gtk_cell_renderer_text_new();
+    column = gtk_tree_view_column_new_with_attributes(_("Uplink"), renderer,
+                                                      "text",
+                                                      RIG_LIST_COL_DEF_UP_FREQ, NULL);
+    gtk_tree_view_column_set_cell_data_func(column, renderer, render_lo,
+                                            GUINT_TO_POINTER
+                                            (RIG_LIST_COL_DEF_UP_FREQ), NULL);
+    gtk_tree_view_insert_column(GTK_TREE_VIEW(riglist), column, -1);
+
     /* AOS signalling */
     renderer = gtk_cell_renderer_text_new();
     column =

Lastly, the number of digits printed after the decimal point in the rig list columns is increased from 0 to 3:

@@ -293,7 +297,7 @@ static void render_lo(GtkTreeViewColumn * col,
 
     /* convert to MHz */
     number /= 1000000.0;
-    buff = g_strdup_printf("%.0f MHz", number);
+    buff = g_strdup_printf("%.3f MHz", number);
     g_object_set(renderer, "text", buff, NULL);
     g_free(buff);
 }

Pull request

A pull request implementing these changes has been opened: see #274.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant