From 806895a590e9f2d3a1b392090c35312fae595daf Mon Sep 17 00:00:00 2001 From: c vw Date: Thu, 22 Aug 2019 18:21:57 +0200 Subject: [PATCH] made "CW behaviour" user-selectable --- cw_menu.c | 16 +++++++ new_protocol.c | 103 +++++++++++++++++++-------------------- old_protocol.c | 29 +++++++---- radio.c | 6 +++ radio.h | 1 + rx_panadapter.c | 125 +++++++++++++++++++----------------------------- 6 files changed, 140 insertions(+), 140 deletions(-) diff --git a/cw_menu.c b/cw_menu.c index 4849673..4911b5c 100644 --- a/cw_menu.c +++ b/cw_menu.c @@ -68,6 +68,10 @@ static gboolean delete_event(GtkWidget *widget, GdkEvent *event, gpointer user_d 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(); @@ -209,6 +213,18 @@ void cw_menu(GtkWidget *parent) { 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); diff --git a/new_protocol.c b/new_protocol.c index 0d9f833..62035e5 100644 --- a/new_protocol.c +++ b/new_protocol.c @@ -614,8 +614,9 @@ static void new_protocol_high_priority() { long long rxFrequency; long long txFrequency; long phase; - int mode; + int txmode; int ddc; + int txvfo; if(data_socket==-1) { return; @@ -629,16 +630,30 @@ static void new_protocol_high_priority() { 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()) { @@ -652,7 +667,7 @@ static void new_protocol_high_priority() { 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; @@ -660,17 +675,14 @@ static void new_protocol_high_priority() { 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; @@ -694,54 +706,35 @@ static void new_protocol_high_priority() { 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); diff --git a/old_protocol.c b/old_protocol.c index c38f135..06f3235 100644 --- a/old_protocol.c +++ b/old_protocol.c @@ -709,18 +709,27 @@ static long long channel_freq(int chan) { if (vfonum < 0) { // // indicates that we should use the TX frequency. + // We have to adjust by the offset for CTUN mode // if(active_receiver->id==VFO_A) { - if(split) { - freq=vfo[VFO_B].frequency-vfo[VFO_B].lo+vfo[VFO_B].offset; + if(split) { + vfonum=VFO_B; } else { - freq=vfo[VFO_A].frequency-vfo[VFO_A].lo+vfo[VFO_A].offset; + vfonum=VFO_A; } } else { if(split) { - freq=vfo[VFO_A].frequency-vfo[VFO_A].lo+vfo[VFO_A].offset; + vfonum=VFO_A; } else { - freq=vfo[VFO_B].frequency-vfo[VFO_B].lo+vfo[VFO_B].offset; + vfonum=VFO_B; + } + } + freq=vfo[vfonum].frequency-vfo[vfonum].lo+vfo[vfonum].offset; + if (!cw_is_on_vfo_freq) { + if(vfo[vfonum].mode==modeCWU) { + freq+=(long long)cw_keyer_sidetone_frequency; + } else if(vfo[vfonum].mode==modeCWL) { + freq-=(long long)cw_keyer_sidetone_frequency; } } } else { @@ -731,10 +740,12 @@ static long long channel_freq(int chan) { if(vfo[vfonum].rit_enabled) { freq+=vfo[vfonum].rit; } - if(vfo[vfonum].mode==modeCWU) { - freq-=(long long)cw_keyer_sidetone_frequency; - } else if(vfo[vfonum].mode==modeCWL) { - freq+=(long long)cw_keyer_sidetone_frequency; + if (cw_is_on_vfo_freq) { + if(vfo[vfonum].mode==modeCWU) { + freq-=(long long)cw_keyer_sidetone_frequency; + } else if(vfo[vfonum].mode==modeCWL) { + freq+=(long long)cw_keyer_sidetone_frequency; + } } } return freq; diff --git a/radio.c b/radio.c index 6d82af4..fd183f5 100644 --- a/radio.c +++ b/radio.c @@ -221,6 +221,8 @@ int cw_keyer_hang_time=300; // ms int cw_keyer_sidetone_frequency=400; // Hz int cw_breakin=1; // 0=disabled 1=enabled +int cw_is_on_vfo_freq=1; // 1= signal on VFO freq, 0= signal offset by side tone + int vfo_encoder_divisor=15; int protocol; @@ -1236,6 +1238,8 @@ fprintf(stderr,"radioRestoreState: %s\n",property_path); value=getProperty("step"); if(value) step=atoll(value); + value=getProperty("cw_is_on_vfo_freq"); + if(value) cw_is_on_vfo_freq=atoi(value); value=getProperty("cw_keys_reversed"); if(value) cw_keys_reversed=atoi(value); value=getProperty("cw_keyer_speed"); @@ -1441,6 +1445,8 @@ void radioSaveState() { sprintf(value,"%lld",step); setProperty("step",value); + sprintf(value,"%d",cw_is_on_vfo_freq); + setProperty("cw_is_on_vfo_freq",value); sprintf(value,"%d",cw_keys_reversed); setProperty("cw_keys_reversed",value); sprintf(value,"%d",cw_keyer_speed); diff --git a/radio.h b/radio.h index f1898ae..470eb8d 100644 --- a/radio.h +++ b/radio.h @@ -174,6 +174,7 @@ extern int cw_keyer_ptt_delay; extern int cw_keyer_hang_time; extern int cw_keyer_sidetone_frequency; extern int cw_breakin; +extern int cw_is_on_vfo_freq; extern int vfo_encoder_divisor; diff --git a/rx_panadapter.c b/rx_panadapter.c index 52a2eb8..f810faa 100644 --- a/rx_panadapter.c +++ b/rx_panadapter.c @@ -142,18 +142,45 @@ void rx_panadapter_update(RECEIVER *rx) { 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;ihz_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); @@ -169,71 +196,18 @@ void rx_panadapter_update(RECEIVER *rx) { } } - 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 { @@ -244,7 +218,6 @@ void rx_panadapter_update(RECEIVER *rx) { cairo_line_to(cr,cw_frequency,(double)display_height); cairo_stroke(cr); } -*/ // plot the levels if(active) { @@ -300,9 +273,9 @@ void rx_panadapter_update(RECEIVER *rx) { break; } for(i=0;ihz_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); @@ -329,13 +302,13 @@ void rx_panadapter_update(RECEIVER *rx) { cairo_set_source_rgb (cr, 1.0, 0.0, 0.0); cairo_set_line_width(cr, 2.0); if((min_displayfrequencyMin)&&(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_displayfrequencyMax)&&(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); @@ -403,24 +376,24 @@ void rx_panadapter_update(RECEIVER *rx) { 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;iadc]; + cairo_move_to(cr, 0.0, s1); + for(i=1;iadc]; if (filter_board == ALEX && rx->adc == 0) s2 += (double)(10*rx->alex_attenuation); s2 = floor((rx->panadapter_high - s2) * (double) display_height -- 2.45.2