]> git.rkrishnan.org Git - pihpsdr.git/commitdiff
SWR alarm and protection (mostly from Davide)
authorc vw <dl1ycf@darc.de>
Thu, 29 Apr 2021 16:35:46 +0000 (18:35 +0200)
committerc vw <dl1ycf@darc.de>
Thu, 29 Apr 2021 16:35:46 +0000 (18:35 +0200)
meter.c
meter.h
radio.c
radio.h
transmitter.c
transmitter.h
tx_menu.c
tx_panadapter.c

diff --git a/meter.c b/meter.c
index ce0a6d7a440b0fc06b400915be716c10d01ab788..462a334dee400c61692a1f829a30fec3ff9cfc41 100644 (file)
--- a/meter.c
+++ b/meter.c
@@ -445,10 +445,16 @@ if(analog_meter) {
       cairo_move_to(cr, 80, meter_height-22);
       cairo_show_text(cr, sf);
 
+      if (swr > transmitter->swr_alarm) {
+        cairo_set_source_rgb(cr, 1.0, 0.2, 0.0);  // display SWR in red color
+      } else {
+        cairo_set_source_rgb (cr, 1.0, 1.0, 1.0); // display SWR in white color
+      }
       sprintf(sf,"SWR: %1.1f:1",swr);
       cairo_move_to(cr, 60, meter_height-12);
       cairo_show_text(cr, sf);
 
+      cairo_set_source_rgb (cr, 1.0, 1.0, 1.0);
       sprintf(sf,"ALC: %2.1f dB",alc);
       cairo_move_to(cr, 60, meter_height-2);
       cairo_show_text(cr, sf);
@@ -680,6 +686,13 @@ if(analog_meter) {
       cairo_move_to(cr, 10, 35);
       cairo_show_text(cr, sf);
 
+      if (swr > transmitter->swr_alarm) {
+        cairo_set_source_rgb(cr, 1.0, 0.2, 0.0);  // display SWR in red color
+      } else {
+        cairo_set_source_rgb (cr, 1.0, 1.0, 1.0); // display SWR in white color
+      }
+
+
       cairo_select_font_face(cr, DISPLAY_FONT,
             CAIRO_FONT_SLANT_NORMAL,
             CAIRO_FONT_WEIGHT_BOLD);
@@ -688,6 +701,8 @@ if(analog_meter) {
       cairo_move_to(cr, 10, 55);
       cairo_show_text(cr, sf);
 
+      cairo_set_source_rgb (cr, 1.0, 1.0, 1.0);  // revert to white color
+
       sprintf(sf,"ALC: %2.1f dB",alc);
       cairo_move_to(cr, meter_width/2, 35);
       cairo_show_text(cr, sf);
diff --git a/meter.h b/meter.h
index 7c3bfd285f5de592c2a4743e5584adbf3c332a37..212b479eb9cd41dae5022b020f1c4ae7f52003d2 100644 (file)
--- a/meter.h
+++ b/meter.h
@@ -26,6 +26,6 @@
 #define POWER 1
 
 extern GtkWidget* meter_init(int width,int height,GtkWidget *parent);
-extern void meter_update(RECEIVER *rx,int meter_type,double value,double reverse,double exciter,double alc);
+extern void meter_update(RECEIVER *rx,int meter_type,double value,double reverse,double alc,double swr);
 
 #endif
diff --git a/radio.c b/radio.c
index 4e4b511c0b06b73d3b6230e7e506a8375d71f4f6..c86aa7d86baad36c63d6cf5237a3a82652c379fa 100644 (file)
--- a/radio.c
+++ b/radio.c
@@ -339,6 +339,7 @@ gboolean mute_rx_while_transmitting=FALSE;
 double drive_max=100;
 
 gboolean display_sequence_errors=TRUE;
+gboolean display_swr_protection=FALSE;
 gint sequence_errors=0;
 
 gint rx_height;
diff --git a/radio.h b/radio.h
index 9b322cc92083ba0a5c34dd109e24f29db1921105..82f1491bd12199d371ae1ee754233dd94cda895c 100644 (file)
--- a/radio.h
+++ b/radio.h
@@ -320,6 +320,7 @@ extern int rx_gain_calibration;  // position of the RX gain slider that
 extern double drive_max;
 
 extern gboolean display_sequence_errors;
+extern gboolean display_swr_protection;
 extern gint sequence_errors;
 extern GMutex property_mutex;
 
index d0f49ee15f32a856288264971c20ba90d8035e9e..62329268394d6737a052daf7e94b1c7adb844704 100644 (file)
@@ -236,6 +236,12 @@ void transmitter_save_state(TRANSMITTER *tx) {
   sprintf(name,"transmitter.%d.tune_use_drive",tx->id);
   sprintf(value,"%d",tx->tune_use_drive);
   setProperty(name,value);
+  sprintf(name,"transmitter.%d.swr_protection",tx->id);
+  sprintf(value,"%d",tx->swr_protection);
+  setProperty(name,value);
+  sprintf(name,"transmitter.%d.swr_alarm",tx->id);
+  sprintf(value,"%f",tx->swr_alarm);
+  setProperty(name,value);
   sprintf(name,"transmitter.%d.drive_level",tx->id);
   sprintf(value,"%d",tx->drive_level);
   setProperty(name,value);
@@ -337,6 +343,12 @@ void transmitter_restore_state(TRANSMITTER *tx) {
   sprintf(name,"transmitter.%d.tune_use_drive",tx->id);
   value=getProperty(name);
   if(value) tx->tune_use_drive=atoi(value);
+  sprintf(name,"transmitter.%d.swr_protection",tx->id);
+  value=getProperty(name);
+  if(value) tx->swr_protection=atoi(value);
+  sprintf(name,"transmitter.%d.swr_alarm",tx->id);
+  value=getProperty(name);
+  if(value) tx->swr_alarm=atof(value);
   sprintf(name,"transmitter.%d.drive_level",tx->id);
   value=getProperty(name);
   if(value) tx->drive_level=atoi(value);
@@ -467,7 +479,7 @@ static gboolean update_display(gpointer data) {
       tx_panadapter_update(tx);
     }
 
-    transmitter->alc=GetTXAMeter(tx->id, alc);
+    tx->alc=GetTXAMeter(tx->id, alc);
     double constant1=3.3;
     double constant2=0.095;
     int fwd_cal_offset=6;
@@ -528,20 +540,20 @@ static gboolean update_display(gpointer data) {
         }
         fwd_power=fwd_power-fwd_cal_offset;
         v1=((double)fwd_power/4095.0)*constant1;
-        transmitter->fwd=(v1*v1)/constant2;
+        tx->fwd=(v1*v1)/constant2;
 
         if(device==DEVICE_HERMES_LITE || device==DEVICE_HERMES_LITE2) {
-          transmitter->exciter=0.0;
+          tx->exciter=0.0;
         } else {
           ex_power=ex_power-fwd_cal_offset;
           v1=((double)ex_power/4095.0)*constant1;
-          transmitter->exciter=(v1*v1)/constant2;
+          tx->exciter=(v1*v1)/constant2;
         }
 
-        transmitter->rev=0.0;
+        tx->rev=0.0;
         if(fwd_power!=0) {
           v1=((double)rev_power/4095.0)*constant1;
-          transmitter->rev=(v1*v1)/constant2;
+          tx->rev=(v1*v1)/constant2;
         }
         break;
       case NEW_PROTOCOL:
@@ -585,60 +597,77 @@ static gboolean update_display(gpointer data) {
         }
         fwd_power=fwd_power-fwd_cal_offset;
         v1=((double)fwd_power/4095.0)*constant1;
-        transmitter->fwd=(v1*v1)/constant2;
+        tx->fwd=(v1*v1)/constant2;
 
         ex_power=exciter_power;
         ex_power=ex_power-fwd_cal_offset;
         v1=((double)ex_power/4095.0)*constant1;
-        transmitter->exciter=(v1*v1)/constant2;
+        tx->exciter=(v1*v1)/constant2;
 
-        transmitter->rev=0.0;
+        tx->rev=0.0;
         if(alex_forward_power!=0) {
           rev_power=alex_reverse_power;
           v1=((double)rev_power/4095.0)*constant1;
-          transmitter->rev=(v1*v1)/constant2;
+          tx->rev=(v1*v1)/constant2;
         }
         break;
 
 #ifdef SOAPYSDR
       case SOAPYSDR_PROTOCOL:
-        transmitter->fwd=0.0;
-        transmitter->exciter=0.0;
-        transmitter->rev=0.0;
+        tx->fwd=0.0;
+        tx->exciter=0.0;
+        tx->rev=0.0;
         break;
 #endif
     }
 
-    double fwd=compute_power(transmitter->fwd);
-    double rev=compute_power(transmitter->rev);
+    //
+    // compute_power applies the interpolation table
+    // that corrects the power meter if it has been
+    // calibrated
+    //
+    double fwd=compute_power(tx->fwd);
+    double rev=compute_power(tx->rev);
+
+//g_print("transmitter: meter_update: fwd:%f->%f rev:%f->%f ex_fwd=%d alex_fwd=%d alex_rev=%d\n",tx->fwd,fwd,tx->rev,rev,exciter_power,alex_forward_power,alex_reverse_power);
+
+    tx->fwd=fwd;
+    tx->rev=rev;
 
     //
     // Calculate SWR here such that it is available in DUPLEX mode
-    // transmitter->swr can be used in other parts of the program to
+    // tx->swr can be used in other parts of the program to
     // implement SWR protection etc.
     //
-    if (fwd > 0.01 && fwd > 1.01*rev) {
+    if (tx->fwd > 0.01 && tx->fwd > 1.01*tx->rev) {
         //
         // SWR means VSWR (voltage based) but we have the forward and
         // reflected power, so correct for that
         //
-        double gamma=sqrt(rev/fwd);
-        transmitter->swr=0.7*(1+gamma)/(1-gamma) + 0.3*transmitter->swr;
+        double gamma=sqrt(tx->rev/tx->fwd);
+        tx->swr=0.7*(1+gamma)/(1-gamma) + 0.3*tx->swr;
     } else {
         //
         // This value may be used for auto SWR protection, so move towards 1.0
         //
-        transmitter->swr = 0.7 + 0.3*transmitter->swr;
-    }
-    if (fwd == 0.0) {
-      fwd = transmitter->exciter;
+        tx->swr = 0.7 + 0.3*tx->swr;
     }
+    if (tx->fwd <= 0.0) tx->fwd = tx->exciter;
 
 
-//g_print("transmitter: meter_update: fwd:%f->%f rev:%f->%f ex_fwd=%d alex_fwd=%d alex_rev=%d\n",transmitter->fwd,fwd,transmitter->rev,rev,exciter_power,alex_forward_power,alex_reverse_power);
+//
+//  If SWR is above threshold and SWR protection is enabled,
+//  set the drive slider to zero. Do not do this while tuning
+//
+    if (tx->swr_protection && !getTune() && tx->swr >= tx->swr_alarm) {
+      double *dp = malloc(sizeof(double));
+      *dp = 0.0;
+      g_idle_add(ext_set_drive, (gpointer) dp);
+      display_swr_protection = TRUE;
+    }
 
     if(!duplex) {
-      meter_update(active_receiver,POWER,fwd,rev,transmitter->alc,transmitter->swr);
+      meter_update(active_receiver,POWER,tx->fwd,tx->rev,tx->alc,tx->swr);
     }
 
     return TRUE; // keep going
@@ -828,6 +857,8 @@ fprintf(stderr,"create_transmitter: id=%d buffer_size=%d mic_sample_rate=%d mic_
   tx->dialog_x=-1;
   tx->dialog_y=-1;
   tx->swr = 1.0;
+  tx->swr_protection = FALSE;
+  tx->swr_alarm=3.0;       // default value for SWR protection
 
   transmitter_restore_state(tx);
 
@@ -1159,11 +1190,11 @@ static void full_tx_buffer(TRANSMITTER *tx) {
       // samples are sent with full amplitude.
       // DL1YCF: include factor 0.00392 since DriveLevel == 255 means full amplitude
       //
-      if(tune && !transmitter->tune_use_drive) {
-        double fac=sqrt((double)transmitter->tune_percent * 0.01);
-        gain=gain*(double)transmitter->drive_level*fac*0.00392;
+      if(tune && !tx->tune_use_drive) {
+        double fac=sqrt((double)tx->tune_percent * 0.01);
+        gain=gain*(double)tx->drive_level*fac*0.00392;
       } else {
-        gain=gain*(double)transmitter->drive_level*0.00392;
+        gain=gain*(double)tx->drive_level*0.00392;
       }
     }
     if (protocol == ORIGINAL_PROTOCOL && radio->device == DEVICE_HERMES_LITE2) {
@@ -1180,11 +1211,11 @@ static void full_tx_buffer(TRANSMITTER *tx) {
       //
       int power;
       double f,g;
-      if(tune && !transmitter->tune_use_drive) {
-        f=sqrt((double)transmitter->tune_percent * 0.01);
-        power=(int)((double)transmitter->drive_level*f);
+      if(tune && !tx->tune_use_drive) {
+        f=sqrt((double)tx->tune_percent * 0.01);
+        power=(int)((double)tx->drive_level*f);
       } else {
-        power=transmitter->drive_level;
+        power=tx->drive_level;
       }
       g=-15.0;
       if (power > 0) {
@@ -1525,8 +1556,8 @@ void add_ps_iq_samples(TRANSMITTER *tx, double i_sample_tx,double q_sample_tx, d
 
   if(rx_feedback->samples>=rx_feedback->buffer_size) {
     if(isTransmitting()) {
-      pscc(transmitter->id, rx_feedback->buffer_size, tx_feedback->iq_input_buffer, rx_feedback->iq_input_buffer);
-      if(transmitter->displaying && transmitter->feedback) {
+      pscc(tx->id, rx_feedback->buffer_size, tx_feedback->iq_input_buffer, rx_feedback->iq_input_buffer);
+      if(tx->displaying && tx->feedback) {
         Spectrum0(1, rx_feedback->id, 0, 0, rx_feedback->iq_input_buffer);
       }
     }
@@ -1596,24 +1627,24 @@ void tx_set_ps(TRANSMITTER *tx,int state) {
 }
 
 void tx_set_twotone(TRANSMITTER *tx,int state) {
-  transmitter->twotone=state;
+  tx->twotone=state;
   if(state) {
     // set frequencies and levels
     switch(tx->mode) {
       case modeCWL:
       case modeLSB:
       case modeDIGL:
-       SetTXAPostGenTTFreq(transmitter->id, -900.0, -1700.0);
+       SetTXAPostGenTTFreq(tx->id, -900.0, -1700.0);
         break;
       default:
-       SetTXAPostGenTTFreq(transmitter->id, 900.0, 1700.0);
+       SetTXAPostGenTTFreq(tx->id, 900.0, 1700.0);
        break;
     }
-    SetTXAPostGenTTMag (transmitter->id, 0.49, 0.49);
-    SetTXAPostGenMode(transmitter->id, 1);
-    SetTXAPostGenRun(transmitter->id, 1);
+    SetTXAPostGenTTMag (tx->id, 0.49, 0.49);
+    SetTXAPostGenMode(tx->id, 1);
+    SetTXAPostGenRun(tx->id, 1);
   } else {
-    SetTXAPostGenRun(transmitter->id, 0);
+    SetTXAPostGenRun(tx->id, 0);
   }
   g_idle_add(ext_mox_update,GINT_TO_POINTER(state));
 }
index 7327013276d9a3349b9a87a8875c88453f949fcc..fb5fc908a1f3b602843c0adca43380025cd675bc 100644 (file)
@@ -103,6 +103,8 @@ typedef struct _transmitter {
   double rev;
   double alc;
   double swr;
+  gboolean swr_protection;
+  double swr_alarm;
 
   gint xit_enabled;
   long long xit;
index ef7e4780b555c40aede51f52a2ab9db70b169533..a7f30a80ca329fa29a0acdfa393b6a33ba88b4af 100644 (file)
--- a/tx_menu.c
+++ b/tx_menu.c
@@ -126,6 +126,14 @@ static void tune_percent_cb (GtkWidget *widget, gpointer data) {
   transmitter->tune_percent=gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(widget));
 }
 
+static void swr_protection_cb (GtkWidget *widget, gpointer data) {
+  transmitter->swr_protection=gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget));
+}
+
+static void swr_alarm_cb (GtkWidget *widget, gpointer data) {
+  transmitter->swr_alarm=(double)gtk_spin_button_get_value(GTK_SPIN_BUTTON(widget));
+}
+
 static void use_rx_filter_cb(GtkWidget *widget, gpointer data) {
   transmitter->use_rx_filter=gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget));
 
@@ -539,6 +547,30 @@ void tx_menu(GtkWidget *parent) {
   gtk_grid_attach(GTK_GRID(grid),tune_percent,col,row,1,1);
   g_signal_connect(tune_percent,"value-changed",G_CALLBACK(tune_percent_cb),NULL);
 
+  row++;
+  col=0;
+
+  GtkWidget *swr_protection_b=gtk_check_button_new_with_label("SWR Protection");
+  gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (swr_protection_b), transmitter->swr_protection);
+  gtk_widget_show(swr_protection_b);
+  gtk_grid_attach(GTK_GRID(grid),swr_protection_b,col,row,1,1);
+  g_signal_connect(swr_protection_b,"toggled",G_CALLBACK(swr_protection_cb),NULL);
+
+  col++;
+
+  GtkWidget *swr_alarm_label=gtk_label_new(NULL);
+  gtk_label_set_markup(GTK_LABEL(swr_alarm_label), "<b>SWR alarm at:</b>");
+#ifdef GTK316
+  gtk_label_set_xalign(GTK_LABEL(swr_alarm_label),0);
+#endif
+  gtk_widget_show(swr_alarm_label);
+  gtk_grid_attach(GTK_GRID(grid),swr_alarm_label,col,row,1,1);
+
+  col++;
+  GtkWidget *swr_alarm=gtk_spin_button_new_with_range(1.0,10.0,0.1);
+  gtk_spin_button_set_value(GTK_SPIN_BUTTON(swr_alarm),(double)transmitter->swr_alarm);
+  gtk_grid_attach(GTK_GRID(grid),swr_alarm,col,row,1,1);
+  g_signal_connect(swr_alarm,"value-changed",G_CALLBACK(swr_alarm_cb),NULL);
 
   gtk_container_add(GTK_CONTAINER(content),grid);
 
index 4ca7870d752ead8ac1557b769ed13f48c0f0f3c9..8d1d9cb5aa58bda440514c98f2f75f72326772c0 100644 (file)
@@ -49,7 +49,8 @@ static gdouble hz_per_pixel;
 static gdouble filter_left=0.0;
 static gdouble filter_right=0.0;
 
-static gint tx_fifo_count=0;
+static gint tx_fifo_count=0;        // timer for FIFO underrun message
+static gint swr_protection_count=0; // timer for SWR protection message
 
 /* Create a new surface of the appropriate size to store our scribbles */
 static gboolean
@@ -399,22 +400,26 @@ void tx_panadapter_update(TRANSMITTER *tx) {
 
   if(duplex) {
     char text[64];
-    cairo_set_source_rgb(cr,1.0,0.0,0.0);
+    cairo_set_source_rgb(cr,1.0,0.2,0.0);
     cairo_set_font_size(cr, DISPLAY_FONT_SIZE3);
 
     if(transmitter->fwd<0.0001) {
-      sprintf(text,"FWD: %0.3f",transmitter->exciter);
+      sprintf(text,"FWD %0.3f W",transmitter->exciter);
     } else {
-      sprintf(text,"FWD: %0.3f",transmitter->fwd);
+      sprintf(text,"FWD %0.1f W",transmitter->fwd);
     }
     cairo_move_to(cr,10,15);
     cairo_show_text(cr, text);
 
-    sprintf(text,"REV: %0.3f",transmitter->rev);
+    //
+    // Since colour is already red, no special
+    // action for "high SWR" warning
+    //
+    sprintf(text,"SWR 1:%1.1f",transmitter->swr);
     cairo_move_to(cr,10,30);
     cairo_show_text(cr, text);
 
-    sprintf(text,"ALC: %0.3f",transmitter->alc);
+    sprintf(text,"ALC %2.1f dB",transmitter->alc);
     cairo_move_to(cr,10,45);
     cairo_show_text(cr, text);
 
@@ -429,6 +434,25 @@ void tx_panadapter_update(TRANSMITTER *tx) {
 */
   }
 
+  //
+  // If the SWR protection has been triggered, display message for three seconds
+  //
+  if (tx->dialog==NULL && display_swr_protection) {
+    char text[64];
+    cairo_set_source_rgb(cr,1.0,0.2,0.0);
+    cairo_set_font_size(cr,DISPLAY_FONT_SIZE3);
+    cairo_move_to(cr, 260.0, 30.0);
+    sprintf(text,"! High SWR > %2.1f", tx->swr_alarm);
+    cairo_show_text(cr, text);
+    cairo_move_to(cr, 260.0, 50.0);
+    cairo_show_text(cr, "! Drive set to zero");
+    swr_protection_count++;
+    if (swr_protection_count >= 3*tx->fps) {
+      display_swr_protection = FALSE;
+      swr_protection_count=0;
+    }
+  }
+
   if(tx->dialog==NULL && protocol==ORIGINAL_PROTOCOL && device==DEVICE_HERMES_LITE2) {
     char text[64];
     cairo_set_source_rgb(cr,1.0,1.0,0.0);