return FALSE;
}
+static void cw_vfo_cb(GtkWidget *widget, gpointer data) {
+ cw_is_on_vfo_freq=(uintptr_t)data;
+}
+
static void cw_keyer_internal_cb(GtkWidget *widget, gpointer data) {
cw_keyer_internal=cw_keyer_internal==1?0:1;
cw_changed();
gtk_grid_attach(GTK_GRID(grid),cw_keyer_mode_b,0,5,1,1);
g_signal_connect(cw_keyer_mode_b,"pressed",G_CALLBACK(cw_keyer_mode_cb),(gpointer *)KEYER_MODE_B);
+ GtkWidget *cw_vfo=gtk_radio_button_new_with_label(NULL,"CW on VFO freq");
+ gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (cw_vfo), cw_is_on_vfo_freq);
+ gtk_widget_show(cw_vfo);
+ gtk_grid_attach(GTK_GRID(grid),cw_vfo,1,3,1,1);
+ g_signal_connect(cw_vfo,"pressed",G_CALLBACK(cw_vfo_cb),(gpointer *)1);
+
+ GtkWidget *cw_vfo_pm=gtk_radio_button_new_with_label_from_widget(GTK_RADIO_BUTTON(cw_vfo),"CW on VFO +/- sidetone");
+ gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (cw_vfo_pm), cw_is_on_vfo_freq==0);
+ gtk_widget_show(cw_vfo_pm);
+ gtk_grid_attach(GTK_GRID(grid),cw_vfo_pm,1,4,1,1);
+ g_signal_connect(cw_vfo_pm,"pressed",G_CALLBACK(cw_vfo_cb),(gpointer *)0);
+
GtkWidget *cw_keys_reversed_b=gtk_check_button_new_with_label("Keys reversed");
//gtk_widget_override_font(cw_keys_reversed_b, pango_font_description_from_string("Arial 18"));
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (cw_keys_reversed_b), cw_keys_reversed);
long long rxFrequency;
long long txFrequency;
long phase;
- int mode;
+ int txmode;
int ddc;
+ int txvfo;
if(data_socket==-1) {
return;
high_priority_buffer_to_radio[2]=high_priority_sequence>>8;
high_priority_buffer_to_radio[3]=high_priority_sequence;
- if(split) {
- mode=vfo[1].mode;
+ //
+ // Determine VFO controlling the TX frequency
+ // and the associated mode
+ //
+ if(active_receiver->id==VFO_A) {
+ if(split) {
+ txvfo=VFO_B;
+ } else {
+ txvfo=VFO_A;
+ }
} else {
- mode=vfo[0].mode;
+ if(split) {
+ txvfo=VFO_A;
+ } else {
+ txvfo=VFO_B;
+ }
}
+ txmode=vfo[txvfo].mode;
+
high_priority_buffer_to_radio[4]=running;
//
// We need not set PTT of doing internal CW with break-in
//
- if(mode==modeCWU || mode==modeCWL) {
+ if(txmode==modeCWU || txmode==modeCWL) {
if (isTransmitting() && (!cw_keyer_internal || !cw_breakin || CAT_cw_is_active)) high_priority_buffer_to_radio[4]|=0x02;
} else {
if(isTransmitting()) {
if (diversity_enabled) {
//
- // Use frequency of RX1 for both DDC0 and DDC1
+ // Use frequency of first receiver for both DDC0 and DDC1
// This is overridden later if we do PURESIGNAL TX
//
rxFrequency=vfo[0].frequency-vfo[0].lo;
rxFrequency+=vfo[0].rit;
}
- switch(vfo[0].mode) {
- case modeCWU:
- rxFrequency-=cw_keyer_sidetone_frequency;
- break;
- case modeCWL:
- rxFrequency+=cw_keyer_sidetone_frequency;
- break;
- default:
- break;
+ if (cw_is_on_vfo_freq) {
+ if(vfo[0].mode==modeCWU) {
+ rxFrequency-=(long long)cw_keyer_sidetone_frequency;
+ } else if(vfo[0].mode==modeCWL) {
+ rxFrequency+=(long long)cw_keyer_sidetone_frequency;
+ }
}
-
+
phase=(long)((4294967296.0*(double)rxFrequency)/122880000.0);
high_priority_buffer_to_radio[ 9]=phase>>24;
high_priority_buffer_to_radio[10]=phase>>16;
if(vfo[v].rit_enabled) {
rxFrequency+=vfo[v].rit;
}
+ if (cw_is_on_vfo_freq) {
+ if(vfo[v].mode==modeCWU) {
+ rxFrequency-=(long long)cw_keyer_sidetone_frequency;
+ } else if(vfo[v].mode==modeCWL) {
+ rxFrequency+=(long long)cw_keyer_sidetone_frequency;
+ }
+ }
- switch(vfo[v].mode) {
- case modeCWU:
- rxFrequency-=cw_keyer_sidetone_frequency;
- break;
- case modeCWL:
- rxFrequency+=cw_keyer_sidetone_frequency;
- break;
- default:
- break;
- }
-
- phase=(long)((4294967296.0*(double)rxFrequency)/122880000.0);
- high_priority_buffer_to_radio[9+(ddc*4)]=phase>>24;
- high_priority_buffer_to_radio[10+(ddc*4)]=phase>>16;
- high_priority_buffer_to_radio[11+(ddc*4)]=phase>>8;
- high_priority_buffer_to_radio[12+(ddc*4)]=phase;
- }
+ phase=(long)((4294967296.0*(double)rxFrequency)/122880000.0);
+ high_priority_buffer_to_radio[9+(ddc*4)]=phase>>24;
+ high_priority_buffer_to_radio[10+(ddc*4)]=phase>>16;
+ high_priority_buffer_to_radio[11+(ddc*4)]=phase>>8;
+ high_priority_buffer_to_radio[12+(ddc*4)]=phase;
+ }
}
//
// Set DUC frequency
//
- if(active_receiver->id==VFO_A) {
- txFrequency=vfo[VFO_A].frequency-vfo[VFO_A].lo+vfo[VFO_A].offset;
- if(split) {
- txFrequency=vfo[VFO_B].frequency-vfo[VFO_B].lo+vfo[VFO_B].offset;
- }
- } else {
- txFrequency=vfo[VFO_B].frequency-vfo[VFO_B].lo+vfo[VFO_B].offset;
- if(split) {
- txFrequency=vfo[VFO_A].frequency-vfo[VFO_A].lo+vfo[VFO_A].offset;
- }
- }
+ txFrequency=vfo[txvfo].frequency-vfo[txvfo].lo+vfo[txvfo].offset;
-/*
- switch(vfo[active_receiver->id].mode) {
- case modeCWU:
- txFrequency+=cw_keyer_sidetone_frequency;
- break;
- case modeCWL:
- txFrequency-=cw_keyer_sidetone_frequency;
- break;
- default:
- break;
+ if (!cw_is_on_vfo_freq) {
+ if(txmode==modeCWU) {
+ txFrequency+=(long long)cw_keyer_sidetone_frequency;
+ } else if(txmode==modeCWL) {
+ txFrequency-=(long long)cw_keyer_sidetone_frequency;
}
-*/
+ }
phase=(long)((4294967296.0*(double)txFrequency)/122880000.0);
cairo_fill(cr);
//cairo_paint (cr);
+ double HzPerPixel = rx->hz_per_pixel; // need this many times
+
+ int mode=vfo[rx->id].mode;
long long frequency=vfo[rx->id].frequency;
long half=(long)rx->sample_rate/2L;
+ BAND *band=band_get_band(vfo[rx->id].band);
+ double vfofreq=(double) display_width * 0.5;
+
+ //
+ // There are two options here in CW mode, depending on cw_is_on_vfo_freq.
+ //
+ // If true, the CW frequency is the VFO frequency and the center of the spectrum
+ // then is at the VFO frequency plus or minus the sidetone frequency. However we
+ // will keep the center of the PANADAPTER at the VFO frequency and shift the
+ // pixels of the spectrum.
+ //
+ // If false, the center of the spectrum is at the VFO frequency and the TX
+ // frequency is VFO freq +/- sidetone frequency. In this case we mark this
+ // freq by a yellow line.
+ //
+
+ if (cw_is_on_vfo_freq) {
+ if (mode == modeCWU) {
+ frequency -= cw_keyer_sidetone_frequency;
+ vfofreq += (double) cw_keyer_sidetone_frequency / HzPerPixel;
+ } else if (mode == modeCWL) {
+ frequency += cw_keyer_sidetone_frequency;
+ vfofreq -= (double) cw_keyer_sidetone_frequency / HzPerPixel;
+ }
+ }
long long min_display=frequency-half;
long long max_display=frequency+half;
- BAND *band=band_get_band(vfo[rx->id].band);
if(vfo[rx->id].band==band60) {
for(i=0;i<channel_entries;i++) {
long long low_freq=band_channels_60m[i].frequency-(band_channels_60m[i].width/(long long)2);
long long hi_freq=band_channels_60m[i].frequency+(band_channels_60m[i].width/(long long)2);
- x1=(low_freq-min_display)/(long long)rx->hz_per_pixel;
- x2=(hi_freq-min_display)/(long long)rx->hz_per_pixel;
+ x1=(low_freq-min_display)/(long long)HzPerPixel;
+ x2=(hi_freq-min_display)/(long long)HzPerPixel;
cairo_set_source_rgb (cr, 0.6, 0.3, 0.3);
cairo_rectangle(cr, x1, 0.0, x2-x1, (double)display_height);
cairo_fill(cr);
}
}
- double cwshift;
- int begin,end,icwshift;
-
- //
- // In this program, when using CW, we will always transmit on exactly
- // the frequency which is the "VFO display" frequency, not 800 Hz above
- // or below. Therfore, the RX center frequency sent to the SDR is shifted
- // by the sidetone frequency.
- // Previous versions showed a "shifted" RX spectrum where the CW signal that
- // was received exactly on the VFO frequency was shifted to the right (CWU)
- // or to the left (CWL), the exact position shown by a yellow line.
- //
- // Alternatively, one could arrange things such that the RX spectrum is
- // shown correctly and that in CWU you "hear" a CW signal at 7000,0 kHz
- // when the VFO display frequency is 7000.0 kHz. Then, the TX signal must
- // have an offset, that is, you send a CW signal at 7000.8 kHz when the
- // VFO display shows 7000.0 kHz, and the yellow line is at 7000.8 kHz.
- //
- // Instead of drawing a "yellow line" to show where the received CW
- // signal is, we shift the displayed spectrum by the side tone such
- // that the received signals occur at the nominal frequencies
- // That is, in CW we TX at the VFO display frequency which is marked by
- // a red line, and we also receive CW signals from exactly that position in
- // the RX spectrum. Furthermore, when switching between CWU and CWL, the
- // displayed RX spectrum remains unchanged except for the part at the right
- // or left margin of the display.
- //
- // For me (DL1YCF) this seems more logical.
- //
- switch (vfo[rx->id].mode) {
- case modeCWU:
- // spectrum must be shifted to the left
- cwshift=(double) cw_keyer_sidetone_frequency / rx->hz_per_pixel;
- icwshift=(int) cwshift;
- begin=0;
- end=display_width-icwshift;
- break;
- case modeCWL:
- // spectrum must shifted to the right
- cwshift=-(double) cw_keyer_sidetone_frequency / rx->hz_per_pixel;
- icwshift=(int) cwshift;
- begin=-cwshift;
- end=display_width;
- break;
- default:
- cwshift=0.0;
- icwshift=0;
- begin=0;
- end=display_width;
- break;
- }
-
-
// filter
cairo_set_source_rgba (cr, 0.25, 0.25, 0.25, 0.75);
- filter_left =-cwshift+(double)display_width/2.0+(((double)rx->filter_low+vfo[rx->id].offset)/rx->hz_per_pixel);
- filter_right=-cwshift+(double)display_width/2.0+(((double)rx->filter_high+vfo[rx->id].offset)/rx->hz_per_pixel);
+ filter_left =(double)display_width*0.5 +(((double)rx->filter_low+vfo[rx->id].offset)/HzPerPixel);
+ filter_right=(double)display_width*0.5 +(((double)rx->filter_high+vfo[rx->id].offset)/HzPerPixel);
cairo_rectangle(cr, filter_left, 0.0, filter_right-filter_left, (double)display_height);
cairo_fill(cr);
-/*
- do not draw the "yellow line". Instead, shift the spectrum
- such that the rx frequency offset is compensated
-
- if(vfo[rx->id].mode==modeCWU || vfo[rx->id].mode==modeCWL) {
+ //
+ // Draw the "yellow line" indicating the CW frequency when
+ // it is not the VFO freq
+ //
+ if (!cw_is_on_vfo_freq && (vfo[rx->id].mode==modeCWU || vfo[rx->id].mode==modeCWL)) {
if(active) {
cairo_set_source_rgb (cr, 1.0, 1.0, 0.0);
} else {
cairo_line_to(cr,cw_frequency,(double)display_height);
cairo_stroke(cr);
}
-*/
// plot the levels
if(active) {
break;
}
for(i=0;i<display_width;i++) {
- f = frequency - half + (long) (rx->hz_per_pixel * i);
+ f = frequency - half + (long) (HzPerPixel * i);
if (f > 0) {
- if ((f % divisor) < (long) rx->hz_per_pixel) {
+ if ((f % divisor) < (long) HzPerPixel) {
cairo_set_line_width(cr, 1.0);
//cairo_move_to(cr,(double)i,0.0);
cairo_move_to(cr,(double)i,10.0);
cairo_set_source_rgb (cr, 1.0, 0.0, 0.0);
cairo_set_line_width(cr, 2.0);
if((min_display<band->frequencyMin)&&(max_display>band->frequencyMin)) {
- i=(band->frequencyMin-min_display)/(long long)rx->hz_per_pixel;
+ i=(band->frequencyMin-min_display)/(long long)HzPerPixel;
cairo_move_to(cr,(double)i,0.0);
cairo_line_to(cr,(double)i,(double)display_height);
cairo_stroke(cr);
}
if((min_display<band->frequencyMax)&&(max_display>band->frequencyMax)) {
- i=(band->frequencyMax-min_display)/(long long)rx->hz_per_pixel;
+ i=(band->frequencyMax-min_display)/(long long)HzPerPixel;
cairo_move_to(cr,(double)i,0.0);
cairo_line_to(cr,(double)i,(double)display_height);
cairo_stroke(cr);
cairo_set_source_rgb (cr, 0.5, 0.0, 0.0);
}
cairo_set_line_width(cr, 1.0);
- cairo_move_to(cr,(double)(display_width/2.0)+(vfo[rx->id].offset/rx->hz_per_pixel),0.0);
- cairo_line_to(cr,(double)(display_width/2.0)+(vfo[rx->id].offset/rx->hz_per_pixel),(double)display_height);
+ cairo_move_to(cr,vfofreq+(vfo[rx->id].offset/HzPerPixel),0.0);
+ cairo_line_to(cr,vfofreq+(vfo[rx->id].offset/HzPerPixel),(double)display_height);
cairo_stroke(cr);
// signal
double s1,s2;
- samples[begin+icwshift]=-200.0;
- samples[end-1+icwshift]=-200.0;
- s1=(double)samples[begin+icwshift]+(double)adc_attenuation[rx->adc];
+ samples[0]=-200.0;
+ samples[display_width-1]=-200.0;
+ s1=(double)samples[0]+(double)adc_attenuation[rx->adc];
if (filter_board == ALEX && rx->adc == 0) s1 += (double)(10*rx->alex_attenuation);
s1 = floor((rx->panadapter_high - s1)
* (double) display_height
/ (rx->panadapter_high - rx->panadapter_low));
- cairo_move_to(cr, (double) begin, s1);
- for(i=begin+1;i<end;i++) {
- s2=(double)samples[i+icwshift]+(double)adc_attenuation[rx->adc];
+ cairo_move_to(cr, 0.0, s1);
+ for(i=1;i<display_width;i++) {
+ s2=(double)samples[i]+(double)adc_attenuation[rx->adc];
if (filter_board == ALEX && rx->adc == 0) s2 += (double)(10*rx->alex_attenuation);
s2 = floor((rx->panadapter_high - s2)
* (double) display_height