soapy_protocol_set_gain(rx);
if(vfo[0].ctun) {
- setFrequency(vfo[0].ctun_frequency);
+ receiver_set_frequency(rx,vfo[0].ctun_frequency);
}
soapy_protocol_start_receiver(rx);
return mox | vox | tune;
}
-void setFrequency(long long f) {
- int v=active_receiver->id;
- vfo[v].band=get_band_from_frequency(f);
-
- if(vfo[v].ctun) {
- //
- // If new frequency is within "window", change the CTUN frequency and
- // update the offset. If it is outside, deactivate CTUN and fall
- // through
- //
- long long minf=vfo[v].frequency-(long long)(active_receiver->sample_rate/2);
- long long maxf=vfo[v].frequency+(long long)(active_receiver->sample_rate/2);
- if(f > minf && f < maxf) {
- vfo[v].ctun_frequency=f;
- vfo[v].offset=f-vfo[v].frequency;
- set_offset(active_receiver,vfo[v].offset);
- return;
- }
- vfo[v].ctun=0;
- vfo[v].ctun_frequency=0;
- vfo[v].offset=0;
- set_offset(active_receiver,vfo[v].offset);
- }
- vfo[v].frequency=f;
-
- switch(protocol) {
- case NEW_PROTOCOL:
- schedule_high_priority();
- break;
- case ORIGINAL_PROTOCOL:
- break;
-#ifdef SOAPYSDR
- case SOAPYSDR_PROTOCOL:
- if(!vfo[v].ctun) {
- soapy_protocol_set_rx_frequency(active_receiver,v);
- vfo[v].offset=0;
- }
- break;
-#endif
- }
-}
-
-long long getFrequency() {
- return vfo[active_receiver->id].frequency;
-}
-
double getDrive() {
return transmitter->drive;
}
}
}
+void radio_split_toggle() {
+ radio_set_split(!split);
+}
+
void radio_set_split(int val) {
//
// "split" *must only* be set through this interface,
extern void radio_change_sample_rate(int rate);
extern void set_alex_antennas(void);
extern void tx_vfo_changed(void);
+extern void radio_split_toggle();
extern void radio_set_split(int v);
extern void setMox(int state);
extern int getMox(void);
extern int isTransmitting(void);
-extern void setFrequency(long long f);
-extern long long getFrequency(void);
-
extern void radioRestoreState(void);
extern void radioSaveState(void);
g_print("%s: id=%d rate=%d buffer_size=%d output_samples=%d\n",__FUNCTION__,rx->id, rx->sample_rate, rx->buffer_size, rx->output_samples);
}
+void receiver_set_frequency(RECEIVER *rx, long long f) {
+ int id=rx->id;
+
+ //
+ // update VFO, and let receiver_frequency_changed do the rest
+ //
+ vfo[id].band=get_band_from_frequency(f);
+ if(vfo[id].ctun) {
+ vfo[id].ctun_frequency=f;
+ } else {
+ vfo[id].frequency=f;
+ }
+ receiver_frequency_changed(rx);
+}
+
void receiver_frequency_changed(RECEIVER *rx) {
int id=rx->id;
if(vfo[id].ctun) {
+ int ctun_ok=1;
+ long long frequency=vfo[id].frequency;
+ long long half=(long long)rx->sample_rate/2LL;
+ long long rx_low=vfo[id].ctun_frequency+rx->filter_low;
+ long long rx_high=vfo[id].ctun_frequency+rx->filter_high;
+ if (rx_low < frequency - half || rx_high > frequency+half) {
+ //
+ // Perhaps this is paranoia, but a "legal" VFO might turn
+ // into an "illegal" when when reducing the sample rate,
+ // thus narrowing the CTUN window
+ //
+ g_print("%s: CTUN freq out of range\n", __FUNCTION__);
+ vfo[id].frequency=vfo[id].ctun_frequency;
+ ctun_ok=0;
+ }
if(rx->zoom>1) {
//
// Adjust PAN if new filter width has moved out of
// current display range
//
- long long frequency=vfo[id].frequency;
- long long half=(long long)rx->sample_rate/2LL;
- long long rx_low=vfo[id].ctun_frequency+rx->filter_low;
- long long rx_high=vfo[id].ctun_frequency+rx->filter_high;
long long min_display=frequency-half+(long long)((double)rx->pan*rx->hz_per_pixel);
long long max_display=min_display+(long long)((double)rx->width*rx->hz_per_pixel);
if(rx_low<=min_display) {
}
//
- // The (HPSDR) frequency does not change in CTUN,
- // so simply compute new offset and tell WDSP about it
+ // Compute new offset and tell WDSP about it
//
vfo[id].offset=vfo[id].ctun_frequency-vfo[id].frequency;
if(vfo[id].rit_enabled) {
vfo[id].offset+=vfo[id].rit;
}
set_offset(rx,vfo[id].offset);
- } else {
- switch(protocol) {
- case ORIGINAL_PROTOCOL:
- // P1 does this automatically
- break;
- case NEW_PROTOCOL:
- schedule_high_priority(); // send new frequency
- break;
+ //
+ // If we have changed the CTUN center frequency,
+ // we cannot return but must tell the radio about it
+ //
+ if (ctun_ok) return;
+ }
+ switch(protocol) {
+ case ORIGINAL_PROTOCOL:
+ // P1 does this automatically
+ break;
+ case NEW_PROTOCOL:
+ schedule_high_priority(); // send new frequency
+ break;
#if SOAPYSDR
- case SOAPYSDR_PROTOCOL:
- soapy_protocol_set_rx_frequency(rx,id);
- break;
+ case SOAPYSDR_PROTOCOL:
+ soapy_protocol_set_rx_frequency(rx,id);
+ break;
#endif
- }
}
}
}
void receiver_vfo_changed(RECEIVER *rx) {
+ //
+ // Called when the VFO controlling rx has changed,
+ // e.g. after a "swap VFO" action
+ //
receiver_frequency_changed(rx);
receiver_mode_changed(rx);
- //receiver_filter_changed(rx);
}
static void process_rx_buffer(RECEIVER *rx) {
extern RECEIVER *create_receiver(int id, int buffer_size, int fft_size, int pixels, int fps, int width, int height);
extern void receiver_change_sample_rate(RECEIVER *rx,int sample_rate);
extern void receiver_change_adc(RECEIVER *rx,int adc);
+extern void receiver_set_frequency(RECEIVER *rx, long long frequency);
extern void receiver_frequency_changed(RECEIVER *rx);
extern void receiver_mode_changed(RECEIVER *rx);
extern void receiver_filter_changed(RECEIVER *rx);
if (b != vfo[v].band) {
vfo_band_changed(v, b);
}
- if(active_receiver->id==v) {
- setFrequency(f);
- } else {
- // change VFO frequency of the non-active receiver
- vfo[v].frequency=f;
- if (vfo[v].ctun) {
- vfo[v].ctun=FALSE;
- vfo[v].offset=0;
- vfo[v].ctun_frequency=vfo[v].frequency;
- }
+ if (v == VFO_A) receiver_set_frequency(receiver[0], f);
+ if (v == VFO_B) {
+ //
+ // If there is only one receiver, there is no RX running that
+ // is controlled by VFO_B, so just update the frequency of the
+ // VFO without telling WDSP about it.
+ // If VFO_B controls a (running) receiver, do the "full job".
+ //
if (receivers == 2) {
- // VFO v controls a running WDSP receiver,
- // need to "manually change" it.
- // DO NOT DO IT HERE. Better add a "RECEIVER *rx" argument
- // to setFrequency in radio.c
+ receiver_set_frequency(receiver[1], f);
+ } else {
+ vfo[v].frequency=f;
+ if (vfo[v].ctun) {
+ vfo[v].ctun=FALSE;
+ vfo[v].offset=0;
+ vfo[v].ctun_frequency=vfo[v].frequency;
+ }
}
}
g_idle_add(ext_vfo_update, NULL);
}
+
+//
+// Set CTUN state of a VFO
+//
+void vfo_ctun_update(int id,int state) {
+ long long f;
+ if (vfo[id].ctun == state) return; // no-op if no change
+ vfo[id].ctun=state;
+ if(vfo[id].ctun) {
+ // CTUN turned OFF->ON
+ vfo[id].ctun_frequency=vfo[id].frequency;
+ vfo[id].offset=0;
+ if (id < receivers) receiver_set_frequency(receiver[id],vfo[id].ctun_frequency);
+ } else {
+ // CTUN turned ON->OFF: keep frequency
+ vfo[id].frequency=vfo[id].ctun_frequency;
+ vfo[id].offset=0;
+ if (id < receivers) receiver_set_frequency(receiver[id],vfo[id].ctun_frequency);
+ }
+}
+
+//
+// helper function for numerically entering a new VFO frequency
+//
+void num_pad(int val) {
+ //
+ // The numpad may be difficult to use since the frequency has to be given in Hz
+ // TODO: add a multiplier button like "kHz"
+ // TODO: display the current "entered_frequency" somewhere
+ // (not all of us are good in typing blind)
+ //
+ RECEIVER *rx=active_receiver;
+ if(!vfo[rx->id].entering_frequency) {
+ vfo[rx->id].entered_frequency=0;
+ vfo[rx->id].entering_frequency=TRUE;
+ }
+ switch(val) {
+ case -1: // clear
+ vfo[rx->id].entered_frequency=0;
+ vfo[rx->id].entering_frequency=FALSE;
+ break;
+ case -2: // enter
+ if(vfo[rx->id].entered_frequency!=0) {
+ receiver_set_frequency(rx, vfo[rx->id].entered_frequency);
+ g_idle_add(ext_vfo_update, NULL);
+ }
+ vfo[rx->id].entering_frequency=FALSE;
+ break;
+ default:
+ vfo[rx->id].entered_frequency=(vfo[rx->id].entered_frequency*10)+val;
+ break;
+ }
+}
+
extern struct _mode_settings mode_settings[];
-typedef struct _set_frequency {
- int vfo;
- long long frequency;
-} SET_FREQUENCY;
-
#define STEPS 15
extern char *step_labels[];
extern void vfo_rit(int rx,int i);
extern void vfo_set_frequency(int vfo, long long f);
+extern void vfo_ctun_update(int id, int state);
+
+extern void num_pad(int val);
+
#endif