}
int ext_mox_update(void *data) {
-g_print("ext_mox_update: %d\n",GPOINTER_TO_INT(data));
mox_update(GPOINTER_TO_INT(data));
return 0;
}
int pos=GPOINTER_TO_INT(data);
double value;
value=(double)pos;
- if(value<0.0) {
- value=0.0;
- } else if(value>100.0) {
- value=100.0;
+ if(value<-12.0) {
+ value=-12.0;
+ } else if(value>48.0) {
+ value=48.0;
}
set_rf_gain(active_receiver->id,value);
return 0;
return 0;
}
+int ext_anf_update(void *data) {
+ if(active_receiver->anf==0) {
+ active_receiver->anf=1;
+ mode_settings[vfo[active_receiver->id].mode].anf=1;
+ } else {
+ active_receiver->snb=0;
+ mode_settings[vfo[active_receiver->id].mode].anf=0;
+ }
+ SetRXAANFRun(active_receiver->id, active_receiver->anf);
+ g_idle_add(ext_vfo_update, NULL);
+ return 0;
+}
+
int ext_mute_update(void *data) {
active_receiver->mute_radio=!active_receiver->mute_radio;
return 0;
extern int ext_nr_update(void *data);
extern int ext_nb_update(void *data);
extern int ext_snb_update(void *data);
+extern int ext_anf_update(void *data);
extern int ext_band_plus(void *data);
extern int ext_band_minus(void *data);
extern int ext_bandstack_plus(void *data);
"A TO B",
"A SWAP B",
"AGC",
+ "ANF",
"B TO A",
"BAND -",
"BAND +",
#ifdef PTT
sprintf(value,"%d",ENABLE_PTT_GPIO);
- setProperty("ENABLE_PPT_GPIO",value);
+ setProperty("ENABLE_PTT_GPIO",value);
sprintf(value,"%d",PTT_GPIO);
- setProperty("PPT_GPIO",value);
+ setProperty("PTT_GPIO",value);
sprintf(value,"%d",PTT_ACTIVE_LOW);
- setProperty("PPT_ACTIVE_LOW",value);
+ setProperty("PTT_ACTIVE_LOW",value);
#endif
saveProperties("gpio.props");
A_TO_B,
A_SWAP_B,
AGC,
+ ANF,
B_TO_A,
BAND_MINUS,
BAND_PLUS,
MIDI_AF_GAIN, // AFGAIN: AF gain
AGCATTACK, // AGCATTACK: AGC ATTACK (cycle fast/med/slow etc.)
MIDI_AGC, // AGCVAL: AGC level
+ ANF, // ANF: toggel ANF on/off
ATT, // ATT: Step attenuator or Programmable attenuator
VFO_B2A, // B2A: VFO B -> A
BAND_DOWN, // BANDDOWN: cycle through bands downwards
RIT_TOGGLE, // RITTOGGLE: toggle RIT on/off
RIT_VAL, // RITVAL: change RIT value
MIDI_SAT, // SAT: cycle through SAT modes off/SAT/RSAT
+ SNB, // SNB: toggle SNB on/off
MIDI_SPLIT, // SPLIT: Split on/off
SWAP_RX, // SWAPRX: swap active receiver (if there are two receivers)
SWAP_VFO, // SWAPVFO: swap VFO A/B frequency
{ MIDI_AF_GAIN, "AFGAIN"},
{ AGCATTACK, "AGCATTACK"},
{ MIDI_AGC, "AGCVAL"},
+ { ANF, "ANF"},
{ ATT, "ATT"},
{ VFO_B2A, "B2A"},
{ BAND_DOWN, "BANDDOWN"},
{ RIT_TOGGLE, "RITTOGGLE"},
{ RIT_VAL, "RITVAL"},
{ MIDI_SAT, "SAT"},
+ { SNB, "SNB"},
{ MIDI_SPLIT, "SPLIT"},
{ SWAP_RX, "SWAPRX"},
{ SWAP_VFO, "SWAPVFO"},
*dp=dnew;
g_idle_add(ext_set_agc_gain, (gpointer) dp);
break;
+ /////////////////////////////////////////////////////////// "ANF"
+ case ANF: // only key supported
+ if (type == MIDI_KEY) {
+ g_idle_add(ext_anf_update, NULL);
+ }
+ break;
/////////////////////////////////////////////////////////// "ATT"
case ATT: // Key for ALEX attenuator, wheel or knob for slider
switch(type) {
} else if (type == MIDI_WHEEL) {
new=(int)active_receiver->rf_gain+val;
}
- g_idle_add(ext_set_rf_gain, GINT_TO_POINTER((int)val));
+ g_idle_add(ext_set_rf_gain, GINT_TO_POINTER((int)new));
break;
/////////////////////////////////////////////////////////// "RFPOWER"
case TX_DRIVE: // knob or wheel supported
}
g_idle_add(ext_vfo_update, NULL);
break;
+ /////////////////////////////////////////////////////////// "SNB"
+ case SNB: // only key supported
+ if (type == MIDI_KEY) {
+ g_idle_add(ext_snb_update, NULL);
+ }
+ break;
/////////////////////////////////////////////////////////// "SPLIT"
case MIDI_SPLIT: // only key supported
// toggle split mode
switch((control_in[0]>>3)&0x1F) {
case 0:
adc_overload=control_in[1]&0x01;
- IO1=(control_in[1]&0x02)?0:1;
- IO2=(control_in[1]&0x04)?0:1;
- IO3=(control_in[1]&0x08)?0:1;
- if(mercury_software_version!=control_in[2]) {
- mercury_software_version=control_in[2];
- g_print(" Mercury Software version: %d (0x%0X)\n",mercury_software_version,mercury_software_version);
- }
- if(penelope_software_version!=control_in[3]) {
- penelope_software_version=control_in[3];
- g_print(" Penelope Software version: %d (0x%0X)\n",penelope_software_version,penelope_software_version);
+ if (device != DEVICE_HERMES_LITE2) {
+ //
+ // HL2 uses these bits of the protocol for a different purpose:
+ // C1 unused except the ADC overload bit
+ // C2/C3 contains underflow/overflow and TX FIFO count
+ //
+ IO1=(control_in[1]&0x02)?0:1;
+ IO2=(control_in[1]&0x04)?0:1;
+ IO3=(control_in[1]&0x08)?0:1;
+ if(mercury_software_version!=control_in[2]) {
+ mercury_software_version=control_in[2];
+ g_print(" Mercury Software version: %d (0x%0X)\n",mercury_software_version,mercury_software_version);
+ }
+ if(penelope_software_version!=control_in[3]) {
+ penelope_software_version=control_in[3];
+ g_print(" Penelope Software version: %d (0x%0X)\n",penelope_software_version,penelope_software_version);
+ }
}
if(ozy_software_version!=control_in[4]) {
ozy_software_version=control_in[4];
}
break;
case 1:
- exciter_power=((control_in[1]&0xFF)<<8)|(control_in[2]&0xFF); // from Penelope or Hermes
+ if (device != DEVICE_HERMES_LITE_2) {
+ //
+ // HL2 uses C1/C2 for measuring the temperature
+ //
+ exciter_power=((control_in[1]&0xFF)<<8)|(control_in[2]&0xFF); // from Penelope or Hermes
+ } else {
+ exciter_power=0;
+ }
alex_forward_power=((control_in[3]&0xFF)<<8)|(control_in[4]&0xFF); // from Alex or Apollo
break;
case 2:
row++;
temp_row=row;
+ col=0;
if(radio->info.soapy.rx_has_automatic_gain) {
GtkWidget *agc=gtk_check_button_new_with_label("Hardware AGC: ");
gtk_grid_attach(GTK_GRID(grid),agc,col,row,1,1);
if(rx->displaying) {
if(rx->pixels>0) {
+ g_mutex_lock(&rx->display_mutex);
GetPixels(rx->id,0,rx->pixel_samples,&rc);
if(rc) {
if(rx->display_panadapter) {
if(rx->display_waterfall) {
waterfall_update(rx);
}
- }
-
+ }
+ g_mutex_unlock(&rx->display_mutex);
if(active_receiver==rx) {
double m=GetRXAMeter(rx->id,smeter)+meter_calibration;
meter_update(rx,SMETER,m,0.0,0.0,0.0);
rx->pixels = 8*width;
}
}
+
+ // need mutex for zoom/pan
+ g_mutex_init(&rx->display_mutex);
+
// allocate buffers
rx->iq_input_buffer=g_new(double,2*rx->buffer_size);
//rx->audio_buffer=NULL;
RECEIVER *rx=malloc(sizeof(RECEIVER));
rx->id=id;
g_mutex_init(&rx->mutex);
+ g_mutex_init(&rx->display_mutex);
+fprintf(stderr,"create_receiver: g_mutex_init: %p\n",&rx->mutex);
switch(id) {
case 0:
rx->adc=0;
//
g_mutex_lock(&rx->mutex);
+fprintf(stderr,"receiver_change_sample_rate: g_mutex_lock: %p\n",&rx->mutex);
rx->sample_rate=sample_rate;
int scale=rx->sample_rate/48000;
init_analyzer(rx);
fprintf(stderr,"PS FEEDBACK change sample rate:id=%d rate=%d buffer_size=%d output_samples=%d\n",
rx->id, rx->sample_rate, rx->buffer_size, rx->output_samples);
+fprintf(stderr,"receiver_change_sample_rate: g_mutex_unlock: %p\n",&rx->mutex);
g_mutex_unlock(&rx->mutex);
return;
}
SetChannelState(rx->id,1,0);
+fprintf(stderr,"receiver_change_sample_rate: g_mutex_unlock: %p\n",&rx->mutex);
g_mutex_unlock(&rx->mutex);
fprintf(stderr,"receiver_change_sample_rate: id=%d rate=%d buffer_size=%d output_samples=%d\n",rx->id, rx->sample_rate, rx->buffer_size, rx->output_samples);
void full_rx_buffer(RECEIVER *rx) {
int error;
- g_mutex_lock(&rx->mutex);
-
// noise blanker works on original IQ samples
if(rx->nb) {
xanbEXT (rx->id, rx->iq_input_buffer, rx->iq_input_buffer);
//g_print("full_rx_buffer: rx=%d buffer_size=%d samples=%d\n",rx->id,rx->buffer_size,rx->samples);
process_rx_buffer(rx);
- g_mutex_unlock(&rx->mutex);
}
static int rx_buffer_seen=0;
}
void receiver_change_zoom(RECEIVER *rx,double zoom) {
- g_mutex_lock(&rx->mutex);
+ g_mutex_lock(&rx->display_mutex);
if(rx->pixel_samples!=NULL) {
g_free(rx->pixel_samples);
}
}
rx->zoom=(int)zoom;
init_analyzer(rx);
- g_mutex_unlock(&rx->mutex);
+ g_mutex_unlock(&rx->display_mutex);
}
void receiver_change_pan(RECEIVER *rx,double pan) {
- g_mutex_lock(&rx->mutex);
+ g_mutex_lock(&rx->display_mutex);
rx->pan=(int)pan;
- g_mutex_unlock(&rx->mutex);
+ g_mutex_unlock(&rx->display_mutex);
}
typedef struct _receiver {
gint id;
GMutex mutex;
+ GMutex display_mutex;
gint ddc;
gint adc;
break;
}
break;
- case 1048576:
+ case 1024000:
case 1536000:
case 2097152:
divisor=200000L;
}
#endif
if(display_sliders) {
- gtk_range_set_value (GTK_RANGE(rf_gain_scale),receiver[rx]->rf_gain);
+ gtk_range_set_value (GTK_RANGE(attenuation_scale),receiver[rx]->rf_gain);
} else {
if(scale_status!=RF_GAIN || scale_rx!=rx) {
if(scale_status!=NO_FUNCTION) {
if(strcmp(driver,"lime")==0) {
sample_rate=768000;
+ } else if(strcmp(driver,"plutosdr")==0) {
+ sample_rate=768000;
} else if(strcmp(driver,"rtlsdr")==0) {
sample_rate=1024000;
- } else if(strcmp(driver,"plutosdr")==0) {
- sample_rate=2048000;
} else {
sample_rate=1024000;
}
fprintf(stderr,"soapy_discovery\n");
rtlsdr_count=0;
SoapySDRKwargs *results = SoapySDRDevice_enumerate(NULL, &length);
-fprintf(stderr,"soapy_discovery: length=%d\n",(int)length);
+fprintf(stderr,"soapy_discovery: length=%d\n",length);
for (i = 0; i < length; i++) {
for (size_t j = 0; j < results[i].size; j++) {
if(strcmp(results[i].keys[j],"driver")==0 && strcmp(results[i].vals[j],"audio")!=0) {
}
void soapy_protocol_change_sample_rate(RECEIVER *rx) {
+// rx->mutex already locked
g_print("soapy_protocol_change_sample_rate: %d\n",rx->sample_rate);
if(rx->sample_rate==radio_sample_rate) {
if(rx->resample_buffer!=NULL) {
while(running) {
elements=SoapySDRDevice_readStream(soapy_device,rx_stream,buffs,max_samples,&flags,&timeNs,timeoutUs);
if(elements<0) {
- fprintf(stderr,"soapy_protocol_receive_thread: SoapySDRDevice_readStream failed: %s max_samples=%d\n",SoapySDR_errToStr(elements),max_samples);
+ fprintf(stderr,"soapy_protocol_receive_thread: SoapySDRDevice_readStream failed: %s max_samples=%d read=%d\n",SoapySDR_errToStr(elements),max_samples,elements);
+ continue;
}
for(i=0;i<elements;i++) {
rx->buffer[i*2]=(double)buffer[i*2];
void soapy_protocol_set_rx_antenna(RECEIVER *rx,int ant) {
int rc;
if(soapy_device!=NULL) {
-// fprintf(stderr,"soapy_protocol: set_rx_antenna: %s\n",radio->info.soapy.rx_antenna[ant]);
+ g_print("soapy_protocol: set_rx_antenna: %s\n",radio->info.soapy.rx_antenna[ant]);
rc=SoapySDRDevice_setAntenna(soapy_device,SOAPY_SDR_RX,rx->adc,radio->info.soapy.rx_antenna[ant]);
if(rc!=0) {
fprintf(stderr,"soapy_protocol: SoapySDRDevice_setAntenna RX failed: %s\n",SoapySDR_errToStr(rc));
void soapy_protocol_set_tx_antenna(TRANSMITTER *tx,int ant) {
int rc;
if(soapy_device!=NULL) {
-// fprintf(stderr,"soapy_protocol: set_tx_antenna: %s\n",radio->info.soapy.tx_antenna[ant]);
+ g_print("soapy_protocol: set_tx_antenna: %s\n",radio->info.soapy.tx_antenna[ant]);
rc=SoapySDRDevice_setAntenna(soapy_device,SOAPY_SDR_TX,tx->dac,radio->info.soapy.tx_antenna[ant]);
if(rc!=0) {
fprintf(stderr,"soapy_protocol: SoapySDRDevice_setAntenna TX failed: %s\n",SoapySDR_errToStr(rc));
int zoompan_active_receiver_changed(void *data) {
if(display_zoompan) {
gtk_range_set_value(GTK_RANGE(zoom_scale),active_receiver->zoom);
- gtk_range_set_range(GTK_RANGE(pan_scale),0.0,(double)(active_receiver->pixels-active_receiver->width));
+ gtk_range_set_range(GTK_RANGE(pan_scale),0.0,(double)(active_receiver->zoom==1?active_receiver->pixels:active_receiver->pixels-active_receiver->width));
gtk_range_set_value (GTK_RANGE(pan_scale),active_receiver->pan);
if(active_receiver->zoom == 1) {
gtk_widget_set_sensitive(pan_scale, FALSE);
static void zoom_value_changed_cb(GtkWidget *widget, gpointer data) {
receiver_change_zoom(active_receiver,gtk_range_get_value(GTK_RANGE(zoom_scale)));
- gtk_range_set_range(GTK_RANGE(pan_scale),0.0,(double)(active_receiver->pixels-active_receiver->width));
+ gtk_range_set_range(GTK_RANGE(pan_scale),0.0,(double)(active_receiver->zoom==1?active_receiver->pixels:active_receiver->pixels-active_receiver->width));
gtk_range_set_value (GTK_RANGE(pan_scale),active_receiver->pan);
if(active_receiver->zoom == 1) {
gtk_widget_set_sensitive(pan_scale, FALSE);
}
void set_pan(int rx,double value) {
+g_print("set_pan: %f\n",value);
receiver[rx]->pan=(int)value;
if(display_zoompan) {
gtk_range_set_value (GTK_RANGE(pan_scale),receiver[rx]->pan);
sprintf(title,"Pan RX %d",rx);
scale_dialog=gtk_dialog_new_with_buttons(title,GTK_WINDOW(top_window),GTK_DIALOG_DESTROY_WITH_PARENT,NULL,NULL);
GtkWidget *content=gtk_dialog_get_content_area(GTK_DIALOG(scale_dialog));
- pan_scale=gtk_scale_new_with_range(GTK_ORIENTATION_HORIZONTAL,0.0, active_receiver->zoom==1?active_receiver->pixels:active_receiver->pixels-active_receiver->width, 1.00);
+ pan_scale=gtk_scale_new_with_range(GTK_ORIENTATION_HORIZONTAL,0.0, receiver[rx]->zoom==1?receiver[rx]->pixels:receiver[rx]->pixels-receiver[rx]->width, 1.00);
gtk_widget_set_size_request (pan_scale, 400, 30);
gtk_range_set_value (GTK_RANGE(pan_scale),receiver[rx]->pan);
gtk_widget_show(pan_scale);
}
void update_pan(double pan) {
- int p=active_receiver->pan+(int)pan;
- if(p<0) p=0;
- if(p>(active_receiver->pixels-active_receiver->width)) p=active_receiver->pixels-active_receiver->width;
- set_pan(active_receiver->id,p);
+ if(active_receiver->zoom>1) {
+ int p=active_receiver->pan+(int)pan;
+ if(p<0) p=0;
+ if(p>(active_receiver->pixels-active_receiver->width)) p=active_receiver->pixels-active_receiver->width;
+ set_pan(active_receiver->id,(double)p);
+ }
}
GtkWidget *zoompan_init(int my_width, int my_height) {