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);
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);
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);
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);
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);
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;
}
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:
}
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
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);
// 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) {
//
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) {
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);
}
}
}
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));
}
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));
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);
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
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);
*/
}
+ //
+ // 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);