}
static void rx_ant_cb(GtkToggleButton *widget, gpointer data) {
- //
- // Note this function is only called for the ORIGINAL and NEW protocol
- //
if(gtk_toggle_button_get_active(widget)) {
int b=(GPOINTER_TO_UINT(data))>>4;
int ant=(GPOINTER_TO_UINT(data))&0xF;
BAND *band=band_get_band(b);
band->alexRxAntenna=ant;
- set_alex_rx_antenna();
+ if(active_receiver->id==0) {
+ set_alex_rx_antenna(ant);
+ }
}
}
static void adc0_antenna_cb(GtkComboBox *widget,gpointer data) {
- //
- // Note this function is only called for the SOAPYSDR protocol
- //
ADC *adc=(ADC *)data;
adc->antenna=gtk_combo_box_get_active(widget);
if(radio->protocol==NEW_PROTOCOL) {
}
static void dac0_antenna_cb(GtkComboBox *widget,gpointer data) {
- //
- // Note this function is only called for the SOAPYSDR protocol
- //
DAC *dac=(DAC *)data;
dac->antenna=gtk_combo_box_get_active(widget);
if(radio->protocol==NEW_PROTOCOL) {
}
static void tx_ant_cb(GtkToggleButton *widget, gpointer data) {
- //
- // Note this function is only called for the ORIGINAL and NEW protocol
- //
if(gtk_toggle_button_get_active(widget)) {
int b=(GPOINTER_TO_UINT(data))>>4;
int ant=(GPOINTER_TO_UINT(data))&0xF;
BAND *band=band_get_band(b);
band->alexTxAntenna=ant;
- set_alex_tx_antenna();
+ if(active_receiver->id==0) {
+ set_alex_tx_antenna(ant);
+ }
}
}
void bandRestoreState() {
char* value;
- int v;
int b;
int stack;
char name[128];
value=getProperty(name);
if(value) strcpy(bands[b].title,value);
- // The number of entries is a compile-time constant,
- // which changes when compiling piHPSDR with different
- // options (e.g. with and without SOAPYSDR)
- // Therefore this number cannot be "restored" from a props file
-
- //sprintf(name,"band.%d.entries",b);
- //lue=getProperty(name);
- //if(value) bands[b].bandstack->entries=atoi(value);
+ sprintf(name,"band.%d.entries",b);
+ value=getProperty(name);
+ if(value) bands[b].bandstack->entries=atoi(value);
sprintf(name,"band.%d.current",b);
value=getProperty(name);
- if(value) {
- //
- // Since the number of bandstack entries is a compile-time constant,
- // we cannot allow "current" to exceed the number of available slots
- //
- v=atoi(value);
- if (v >= bands[b].bandstack->entries) v=0;
- bands[b].bandstack->current_entry=v;
- }
+ if(value) bands[b].bandstack->current_entry=atoi(value);
sprintf(name,"band.%d.preamp",b);
value=getProperty(name);
}
}
-void send_eq(int s, int rxeq, int txeq) {
- // inform client about RX/TX equalizer status
- // NOT-YET
-}
-
void send_noise(int s,int rx,int nb,int nb2,int nr,int nr2,int anf,int snb) {
NOISE_COMMAND command;
g_print("send_noise rx=%d nb=%d nb2=%d nr=%d nr2=%d anf=%d snb=%d\n",rx,nb,nb2,nr,nr2,anf,snb);
extern void send_attenuation(int s,int rx,int attenuation);
extern void send_squelch(int s,int rx,int enable,int squelch);
extern void send_noise(int s,int rx,int nb,int nb2,int nr,int nr2,int anf,int snb);
-extern void send_eq(int s, int rxeq, int txeq);
extern void send_band(int s,int rx,int band);
extern void send_mode(int s,int rx,int mode);
extern void send_filter(int s,int rx,int filter);
break;
#ifdef SOAPYSDR
case SOAPYSDR_PROTOCOL:
- sprintf(text,"%s (Protocol SOAPY_SDR %s) via Soapy lib",d->name,d->info.soapy.version);
+ sprintf(text,"%s (Protocol SOAPY_SDR %s) on USB",d->name,d->info.soapy.version);
break;
#endif
#ifdef STEMLAB_DISCOVERY
if(d->device!=SOAPYSDR_USB_DEVICE) {
#endif
// if not on the same subnet then cannot start it
- //
- // DL1YCF: APIPA modification
- // so-called APIPA addresses are of the numerical form 169.254.xxx.yyy and these addresses are used
- // by many radios if they do not get a DHCP address. These addresses are valid even if outside the
- // netmask of the (physical) interface making the connection - so do not complain in this case!
- //
- if (strncmp(inet_ntoa(d->info.network.address.sin_addr),"169.254.",8)) {
- if((d->info.network.interface_address.sin_addr.s_addr&d->info.network.interface_netmask.sin_addr.s_addr) != (d->info.network.address.sin_addr.s_addr&d->info.network.interface_netmask.sin_addr.s_addr)) {
- gtk_button_set_label(GTK_BUTTON(start_button),"Subnet!");
- gtk_widget_set_sensitive(start_button, FALSE);
- }
- }
+ if((d->info.network.interface_address.sin_addr.s_addr&d->info.network.interface_netmask.sin_addr.s_addr) != (d->info.network.address.sin_addr.s_addr&d->info.network.interface_netmask.sin_addr.s_addr)) {
+ gtk_button_set_label(GTK_BUTTON(start_button),"Subnet!");
+ gtk_widget_set_sensitive(start_button, FALSE);
+ }
#ifdef SOAPYSDR
}
#endif
#include "equalizer_menu.h"
#include "radio.h"
#include "channel.h"
-#include "ext.h"
-#include "vfo.h"
static GtkWidget *parent_window=NULL;
return FALSE;
}
-void set_eq() {
- SetTXAGrphEQ(transmitter->id, tx_equalizer);
- SetTXAEQRun(transmitter->id, enable_tx_equalizer);
- SetRXAGrphEQ(active_receiver->id, rx_equalizer);
- SetRXAEQRun(active_receiver->id, enable_rx_equalizer);
-}
-
-void update_eq() {
-#ifdef CLIENT_SERVER
- if(radio_is_remote) {
- send_eq(client_socket,enable_rx_eq, enable_tx_equalizer);
- } else {
-#endif
- set_eq();
-#ifdef CLIENT_SERVER
- }
-#endif
-}
-
static gboolean enable_cb (GtkWidget *widget, GdkEventButton *event, gpointer data) {
- int m;
if(tx_menu) {
enable_tx_equalizer=gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget));
- m=vfo[get_tx_vfo()].mode;
- mode_settings[m].en_txeq = enable_tx_equalizer;
+ SetTXAEQRun(transmitter->id, enable_tx_equalizer);
} else {
enable_rx_equalizer=gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget));
- m=vfo[active_receiver->id].mode;
- mode_settings[m].en_rxeq = enable_rx_equalizer;
+ SetRXAEQRun(active_receiver->id, enable_rx_equalizer);
}
- update_eq();
- // EQ status is now shown in VFO bar
- g_idle_add(ext_vfo_update, NULL);
return FALSE;
}
static void value_changed_cb (GtkWidget *widget, gpointer data) {
int i=GPOINTER_TO_UINT(data);
- int m;
if(tx_menu) {
tx_equalizer[i]=(int)gtk_range_get_value(GTK_RANGE(widget));
- m=vfo[get_tx_vfo()].mode;
- mode_settings[m].txeq[i]=tx_equalizer[i];
+ SetTXAGrphEQ(transmitter->id, tx_equalizer);
} else {
rx_equalizer[i]=(int)gtk_range_get_value(GTK_RANGE(widget));
- m=vfo[active_receiver->id].mode;
- mode_settings[m].rxeq[i]=rx_equalizer[i];
+ SetRXAGrphEQ(active_receiver->id, rx_equalizer);
}
- update_eq();
}
void equalizer_menu(GtkWidget *parent) {
*/
void equalizer_menu(GtkWidget *parent);
-
-void update_eq();
#endif
#include "ext.h"
#include "zoompan.h"
-#include "equalizer_menu.h"
// The following calls functions can be called usig g_idle_add
int ext_set_alex_attenuation(void *data) {
int val=GPOINTER_TO_INT(data);
- BAND *band=band_get_band(vfo[VFO_A].band);
- // store changed attenuation in "band" info
- band->alexAttenuation=val;
- set_alex_attenuation();
+ set_alex_attenuation(val);
return 0;
}
return 0;
}
-int ext_set_split(void *data) {
- if(can_transmit) {
- split=GPOINTER_TO_INT(data),
- tx_set_mode(transmitter,get_tx_mode());
- set_alex_tx_antenna();
- calcDriveLevel();
- g_idle_add(ext_vfo_update, NULL);
- }
- return 0;
-}
-
int ext_split_toggle(void *data) {
if(can_transmit) {
split=split==1?0:1;
tx_set_mode(transmitter,get_tx_mode());
- set_alex_tx_antenna();
- calcDriveLevel();
g_idle_add(ext_vfo_update, NULL);
}
return 0;
return 0;
}
-int ext_update_eq(void *data) {
- update_eq();
- return 0;
-}
-
int ext_set_duplex(void *data) {
setDuplex();
return 0;
extern int ext_ctun_update(void *data);
extern int ext_agc_update(void *data);
extern int ext_split_toggle(void *data);
-extern int ext_set_split(void *data);
extern int ext_cw_setup();
extern int ext_set_duplex(void *data);
extern int ext_update_noise(void *data);
-extern int ext_update_eq(void *data);
#ifdef PURESIGNAL
extern int ext_start_ps(void *data);
#endif
filter->low=gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(widget));
if(vfo[id].mode==modeCWL || vfo[id].mode==modeCWU) {
- // Note that a 250 Hz filter has high=low=125 in CW
- filter->high=filter->low=filter->low/2;
+ filter->high=filter->low;
}
if(f==vfo[id].filter) {
vfo_filter_changed(f);
g_signal_connect(b,"pressed",G_CALLBACK(filter_select_cb),(gpointer)(long)i);
GtkWidget *var1_spin_low=gtk_spin_button_new_with_range(-8000.0,+8000.0,1.0);
- //
- // in CW, filter_low is HALF of the filter width
- //
- if(vfo[active_receiver->id].mode==modeCWL || vfo[active_receiver->id].mode==modeCWU) {
- gtk_spin_button_set_value(GTK_SPIN_BUTTON(var1_spin_low),(double)band_filter->low * 2.0);
- } else {
- gtk_spin_button_set_value(GTK_SPIN_BUTTON(var1_spin_low),(double)band_filter->low);
- }
+ gtk_spin_button_set_value(GTK_SPIN_BUTTON(var1_spin_low),(double)band_filter->low);
gtk_grid_attach(GTK_GRID(grid),var1_spin_low,1,row,1,1);
g_signal_connect(var1_spin_low,"value-changed",G_CALLBACK(var_spin_low_cb),(gpointer)(long)i);
g_signal_connect(b,"pressed",G_CALLBACK(filter_select_cb),(gpointer)(long)i);
GtkWidget *var2_spin_low=gtk_spin_button_new_with_range(-8000.0,+8000.0,1.0);
- //
- // in CW, filter_low is HALF of the filter width
- //
- if(vfo[active_receiver->id].mode==modeCWL || vfo[active_receiver->id].mode==modeCWU) {
- gtk_spin_button_set_value(GTK_SPIN_BUTTON(var2_spin_low),(double)band_filter->low * 2.0);
- } else {
- gtk_spin_button_set_value(GTK_SPIN_BUTTON(var2_spin_low),(double)band_filter->low);
- }
+ gtk_spin_button_set_value(GTK_SPIN_BUTTON(var2_spin_low),(double)band_filter->low);
gtk_grid_attach(GTK_GRID(grid),var2_spin_low,1,row,1,1);
g_signal_connect(var2_spin_low,"value-changed",G_CALLBACK(var_spin_low_cb),(gpointer)(long)i);
FILTER* band_filters=filters[entry->mode];
FILTER* band_filter=&band_filters[entry->filter];
set_filter(active_receiver,band_filter->low,band_filter->high);
+ if(active_receiver->id==0) {
+ set_alex_rx_antenna(band->alexRxAntenna);
+ set_alex_tx_antenna(band->alexTxAntenna);
+ set_alex_attenuation(band->alexAttenuation);
+ }
}
setFrequency(f);
- // defer set_alex.. until here since setFrequency sets the VFO.band
- set_alex_rx_antenna();
- set_alex_tx_antenna();
- set_alex_attenuation();
g_idle_add(ext_vfo_update,NULL);
}
set = 1;
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
-#ifdef __APPLE__
-#include "MacOS.h" // emulate clock_gettime on old MacOS systems
-#endif
#define NEED_DUMMY_AUDIO 1
buffer[ 6]=0xBB;
buffer[ 7]=0xCC;
buffer[ 8]=0xDD;
- buffer[ 9]=0xEF;
- buffer[10]=0xFE;
+ buffer[ 9]=0xEE;
+ buffer[10]=0xFF;
buffer[11]=NEWDEVICE;
buffer[12]=38;
buffer[13]=19;
buffer[ 6]=0xBB;
buffer[ 7]=0xCC;
buffer[ 8]=0xDD;
- buffer[ 9]=0xEF;
- buffer[10]=0xFE;
+ buffer[ 9]=0xEE;
+ buffer[10]=0xFF;
buffer[11]=NEWDEVICE;
buffer[12]=38;
buffer[13]=103;
buffer[ 6]=0xBB;
buffer[ 7]=0xCC;
buffer[ 8]=0xDD;
- buffer[ 9]=0xEF;
- buffer[10]=0xFE;
+ buffer[ 9]=0xEE;
+ buffer[10]=0xFF;
buffer[11]=103;
buffer[12]=NEWDEVICE;
buffer[13]=(checksum >> 8) & 0xFF;
if (buffer[ 6] != 0xBB) break;
if (buffer[ 7] != 0xCC) break;
if (buffer[ 8] != 0xDD) break;
- if (buffer[ 9] != 0xEF) break;
- if (buffer[10] != 0xFE) break;
+ if (buffer[ 9] != 0xEE) break;
+ if (buffer[10] != 0xFF) break;
memset(buffer, 0, 60);
buffer [4]=0x02+active_thread;
buffer [5]=0xAA;
buffer[ 6]=0xBB;
buffer[ 7]=0xCC;
buffer[ 8]=0xDD;
- buffer[ 9]=0xEF;
- buffer[10]=0xFE;
+ buffer[ 9]=0xEE;
+ buffer[10]=0xFF;
buffer[11]=NEWDEVICE;
buffer[12]=38;
buffer[13]=103;
int16_t ssample;
struct timespec delay;
+#ifdef __APPLE__
+ struct timespec now;
+#endif
long wait;
int noiseIQpt,toneIQpt,divpt,rxptr;
double i1,q1,fac1,fac2,fac3,fac4;
delay.tv_nsec -= 1000000000;
delay.tv_sec++;
}
+#ifdef __APPLE__
+ //
+ // The (so-called) operating system for Mac does not have clock_nanosleep(),
+ // but is has clock_gettime as well as nanosleep.
+ // So, to circumvent this problem, we look at the watch and determine
+ // how long we should sleep now.
+ //
+ clock_gettime(CLOCK_MONOTONIC, &now);
+ now.tv_sec =delay.tv_sec - now.tv_sec;
+ now.tv_nsec=delay.tv_nsec - now.tv_nsec;
+ while (now.tv_nsec < 0) {
+ now.tv_nsec += 1000000000;
+ now.tv_sec--;
+ }
+ nanosleep(&now, NULL);
+#else
clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, &delay, NULL);
+#endif
if (sock_TCP_Client > -1)
{
static int cwvox = 0;
-#ifdef __APPLE__
-#include "MacOS.h" // emulate clock_gettime on old MacOS systems
-#else
-
+#ifndef __APPLE__
// using clock_nanosleep of librt
extern int clock_nanosleep(clockid_t __clock_id, int __flags,
__const struct timespec *__req,
int kdelay;
int old_volume;
int txmode;
+#ifdef __APPLE__
+ struct timespec now;
+#endif
fprintf(stderr,"keyer_thread state running= %d\n", running);
while(running) {
loop_delay.tv_sec++;
}
if (!*kdash) break;
+#ifdef __APPLE__
+ clock_gettime(CLOCK_MONOTONIC, &now);
+ now.tv_sec =loop_delay.tv_sec - now.tv_sec;
+ now.tv_nsec=loop_delay.tv_nsec - now.tv_nsec;
+ while (now.tv_nsec < 0) {
+ now.tv_nsec += 1000000000;
+ now.tv_sec--;
+ }
+ nanosleep(&now, NULL);
+#else
clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, &loop_delay, NULL);
+#endif
}
// dash released.
set_keyer_out(0);
loop_delay.tv_nsec -= NSEC_PER_SEC;
loop_delay.tv_sec++;
}
+#ifdef __APPLE__
+ clock_gettime(CLOCK_MONOTONIC, &now);
+ now.tv_sec =loop_delay.tv_sec - now.tv_sec;
+ now.tv_nsec=loop_delay.tv_nsec - now.tv_nsec;
+ while (now.tv_nsec < 0) {
+ now.tv_nsec += 1000000000;
+ now.tv_sec--;
+ }
+ nanosleep(&now, NULL);
+#else
clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, &loop_delay, NULL);
+#endif
set_keyer_out(0);
key_state = DOTDELAY; // add inter-character spacing of one dot length
kdelay=0;
loop_delay.tv_nsec -= NSEC_PER_SEC;
loop_delay.tv_sec++;
}
+#ifdef __APPLE__
+ clock_gettime(CLOCK_MONOTONIC, &now);
+ now.tv_sec =loop_delay.tv_sec - now.tv_sec;
+ now.tv_nsec=loop_delay.tv_nsec - now.tv_nsec;
+ while (now.tv_nsec < 0) {
+ now.tv_nsec += 1000000000;
+ now.tv_sec--;
+ }
+ nanosleep(&now, NULL);
+#else
clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, &loop_delay, NULL);
+#endif
set_keyer_out(0);
key_state = DASHDELAY; // add inter-character spacing of one dot length
kdelay=0;
loop_delay.tv_nsec -= NSEC_PER_SEC;
loop_delay.tv_sec++;
}
+#ifdef __APPLE__
+ clock_gettime(CLOCK_MONOTONIC, &now);
+ now.tv_sec =loop_delay.tv_sec - now.tv_sec;
+ now.tv_nsec=loop_delay.tv_nsec - now.tv_nsec;
+ while (now.tv_nsec < 0) {
+ now.tv_nsec += 1000000000;
+ now.tv_sec--;
+ }
+ nanosleep(&now, NULL);
+#else
clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, &loop_delay, NULL);
+#endif
}
//
// If we have reduced the side tone volume, restore it!
char name[1024];
-#ifdef __APPLE__
- void MacOSstartup(char *path);
- MacOSstartup(argv[0]);
-#endif
-
sprintf(name,"org.g0orx.pihpsdr.pid%d",getpid());
//fprintf(stderr,"gtk_application_new: %s\n",name);
#include <string.h>
#include <stdlib.h>
#include <time.h>
-#ifdef __APPLE__
-#include "MacOS.h" // emulate clock_gettime on old MacOS systems
-#endif
-
#include "midi.h"
struct cmdtable MidiCommandsTable;
case MIDI_PAN: // wheel and knob
switch (type) {
case MIDI_WHEEL:
- g_idle_add(ext_pan_update,GINT_TO_POINTER(val*10));
+ g_idle_add(ext_pan_update,GINT_TO_POINTER(val));
break;
case MIDI_KNOB:
g_idle_add(ext_pan_set,GINT_TO_POINTER(val));
// Network buffers
#define NET_BUFFER_SIZE 2048
-
-
-//
-// Instead of allocating and free-ing (malloc/free) the network buffers
-// at a very high rate, we do it the "pedestrian" way, which may
-// alleviate the system load a little.
-//
-// Therefore we allocate a pool of network buffers *once*, make
-// them a linked list, and simply maintain a "free" flag.
-//
-// This ONLY applies to the network buffers filled with data in
-// new_protocol_thread(), so this need not be thread-safe.
-//
-
-//
-// One buffer. The fences can be used to detect over-writing them
-//
-//
-
-struct mybuffer_ {
- struct mybuffer_ *next;
- int free;
- long lowfence;
- unsigned char buffer[NET_BUFFER_SIZE];
- long highfence;
-} mybuffer_;
-
-typedef struct mybuffer_ mybuffer;
-
-//
-// number of buffers allocated (for statistics)
-//
-static int num_buf = 0;
-
-//
-// head of buffer list
-//
-static mybuffer *buflist = NULL;
-
-//
-// The buffers used by new_protocol_thread
-//
-static mybuffer *iq_buffer[MAX_DDC];
-static mybuffer *command_response_buffer;
-static mybuffer *high_priority_buffer;
-static mybuffer *mic_line_buffer;
-
+static unsigned char *iq_buffer[MAX_DDC];
+static unsigned char *command_response_buffer;
+static unsigned char *high_priority_buffer;
+static unsigned char *mic_line_buffer;
static int mic_bytes_read;
static unsigned char general_buffer[60];
static unsigned char transmit_specific_buffer[60];
static unsigned char receive_specific_buffer[1444];
-//
+// DL1YCF
// new_protocol_receive_specific and friends are not thread-safe, but called
-// periodically from timer thread *and* asynchronously from everywhere else
+// periodically from timer thread and asynchronously from everywhere else
// therefore we need to implement a critical section for each of these functions.
-// The audio buffer needs a mutex since both RX and TX threads may write to
-// this one (CW side tone).
-//
+// It seems that this is not necessary for the audio and TX-IQ buffers.
static pthread_mutex_t rx_spec_mutex = PTHREAD_MUTEX_INITIALIZER;
static pthread_mutex_t tx_spec_mutex = PTHREAD_MUTEX_INITIALIZER;
static pthread_mutex_t hi_prio_mutex = PTHREAD_MUTEX_INITIALIZER;
static pthread_mutex_t general_mutex = PTHREAD_MUTEX_INITIALIZER;
-static pthread_mutex_t audio_mutex = PTHREAD_MUTEX_INITIALIZER;
static int local_ptt=0;
static void process_high_priority();
static void process_mic_data(int bytes);
-//
-// obtain free buffer, if nothing is left allocate
-// 5 new ones. Note these buffer "live" as long as the
-// program lives. They are never free()d.
-//
-static mybuffer *get_my_buffer() {
- int i;
- mybuffer *bp=buflist;
- while (bp) {
- if (bp->free == 1) {
- // found free buffer. Mark as used and return that one.
- bp->free=0;
- return bp;
- }
- bp=bp->next;
- }
- //
- // no free buffer found, allocate some extra ones
- // and add to the head of the list
- //
- for (i=0; i<5; i++) {
- bp = malloc(sizeof(mybuffer));
- bp->free=1;
- bp->next = buflist;
- buflist=bp;
- num_buf++;
- }
- g_print("NewProtocol: number of buffer increased to %d\n", num_buf);
- // Mark the first buffer in list as used and return that one.
- buflist->free=0;
- return buflist;
-}
-
-
#ifdef INCLUDED
static void new_protocol_calc_buffers() {
switch(sample_rate) {
//g_print("new_protocol_general: %s:%d\n",inet_ntoa(base_addr.sin_addr),ntohs(base_addr.sin_port));
if((rc=sendto(data_socket,general_buffer,sizeof(general_buffer),0,(struct sockaddr*)&base_addr,base_addr_length))<0) {
- g_print("sendto socket failed for general: rc=%d errno=%d\n",rc,errno);
+ g_print("sendto socket failed for general\n");
exit(1);
}
high_priority_buffer_to_radio[3]=high_priority_sequence;
high_priority_buffer_to_radio[4]=running;
//
-// We need not set PTT if doing internal CW with break-in
+// We need not set PTT of doing internal CW with break-in
//
if(txmode==modeCWU || txmode==modeCWL) {
if (isTransmitting() && (!cw_keyer_internal || !cw_breakin || CAT_cw_is_active)) high_priority_buffer_to_radio[4]|=0x02;
case 5: // XVTR with old pa board
alex0 |= ALEX_RX_ANTENNA_XVTR | ALEX_RX_ANTENNA_BYPASS;
break;
- case 104: // EXT2 with ANAN-7000: does not exist, use EXT1
+ case 104: // EXT2 with ANAN-7000: does not exit, use EXT1
case 103: // EXT1 with ANAN-7000
alex0 |= ALEX_RX_ANTENNA_EXT1 | ANAN7000_RX_SELECT;
break;
//g_print("new_protocol_transmit_specific: %s:%d\n",inet_ntoa(transmitter_addr.sin_addr),ntohs(transmitter_addr.sin_port));
if((rc=sendto(data_socket,transmit_specific_buffer,sizeof(transmit_specific_buffer),0,(struct sockaddr*)&transmitter_addr,transmitter_addr_length))<0) {
- g_print("sendto socket failed for tx specific: rc=%d errno=%d\n",rc,errno);
- exit(1);
+ g_print("sendto socket failed for tx specific: %d\n",rc);
+ exit(1);
}
if(rc!=sizeof(transmit_specific_buffer)) {
//g_print("new_protocol_receive_specific: %s:%d enable=%02X\n",inet_ntoa(receiver_addr.sin_addr),ntohs(receiver_addr.sin_port),receive_specific_buffer[7]);
if((rc=sendto(data_socket,receive_specific_buffer,sizeof(receive_specific_buffer),0,(struct sockaddr*)&receiver_addr,receiver_addr_length))<0) {
- g_print("sendto socket failed for receive specific: rc=%d errno=%d\n",rc,errno);
+ g_print("sendto socket failed for receive_specific: %d\n",rc);
exit(1);
}
if( ! new_protocol_timer_thread_id )
{
g_print("g_thread_new failed on new_protocol_timer_thread\n");
- exit( -1 );
+ exit( -1 );
}
g_print( "new_protocol_timer_thread: id=%p\n",new_protocol_timer_thread_id);
short sourceport;
unsigned char *buffer;
int bytesread;
- mybuffer *mybuf;
g_print("new_protocol_thread\n");
while(running) {
- mybuf=get_my_buffer();
- buffer=mybuf->buffer;
+ buffer=malloc(NET_BUFFER_SIZE);
bytesread=recvfrom(data_socket,buffer,NET_BUFFER_SIZE,0,(struct sockaddr*)&addr,&length);
if (!running) {
//
// When leaving piHPSDR, it may happen that the protocol has been stopped while
- // we were doing "recvfrom". In this case, we want to let the main
- // thread terminate gracefully, including writing the props files.
+ // we were doing "recvfrom". In this case, we do not want to "exit" but let the main
+ // thread exit gracefully, including writing the props files.
//
- mybuf->free=1;
+ free(buffer);
break;
}
#else
sem_wait(&iq_sem_ready[ddc]);
#endif
- iq_buffer[ddc]=mybuf;
+ iq_buffer[ddc]=buffer;
#ifdef __APPLE__
sem_post(iq_sem_buffer[ddc]);
#else
#else
sem_wait(&command_response_sem_ready);
#endif
- command_response_buffer=mybuf;
+ command_response_buffer=buffer;
#ifdef __APPLE__
sem_post(command_response_sem_buffer);
#else
#else
sem_wait(&high_priority_sem_ready);
#endif
- high_priority_buffer=mybuf;
+ high_priority_buffer=buffer;
#ifdef __APPLE__
sem_post(high_priority_sem_buffer);
#else
#else
sem_wait(&mic_line_sem_ready);
#endif
- mic_line_buffer=mybuf;
+ mic_line_buffer=buffer;
mic_bytes_read=bytesread;
#ifdef __APPLE__
sem_post(mic_line_sem_buffer);
break;
default:
g_print("new_protocol_thread: Unknown port %d\n",sourceport);
- mybuf->free=1;
+ free(buffer);
break;
}
}
sem_wait(&command_response_sem_buffer);
#endif
process_command_response();
- command_response_buffer->free=1;
+ free(command_response_buffer);
}
}
sem_wait(&high_priority_sem_buffer);
#endif
process_high_priority();
- high_priority_buffer->free=1;
+ free(high_priority_buffer);
}
}
// since this is our pace-maker
//
process_mic_data(mic_bytes_read);
- mic_line_buffer->free=1;
+ free(mic_line_buffer);
}
}
sem_post(&iq_sem_ready[ddc]);
sem_wait(&iq_sem_buffer[ddc]);
#endif
- if (iq_buffer[ddc] == NULL) continue;
- buffer=iq_buffer[ddc]->buffer;
+ buffer=iq_buffer[ddc];
+ if (buffer == NULL) continue;
//
// Perform sequence check HERE for all cases
//
process_div_iq_data(buffer);
break;
}
- iq_buffer[ddc]->free=1;
+ free(buffer);
}
}
static void process_command_response() {
long sequence;
- unsigned char *buffer = command_response_buffer->buffer;
- sequence=((buffer[0]&0xFF)<<24)+((buffer[1]&0xFF)<<16)+((buffer[2]&0xFF)<<8)+(buffer[3]&0xFF);
+ sequence=((command_response_buffer[0]&0xFF)<<24)+((command_response_buffer[1]&0xFF)<<16)+((command_response_buffer[2]&0xFF)<<8)+(command_response_buffer[3]&0xFF);
if (sequence != response_sequence) {
g_print("CommRes SeqErr: expected=%ld seen=%ld\n", response_sequence, sequence);
response_sequence=sequence;
}
response_sequence++;
- response=buffer[4]&0xFF;
+ response=command_response_buffer[4]&0xFF;
g_print("CommandResponse with seq=%ld and command=%d\n",sequence,response);
#ifdef __APPLE__
sem_post(response_sem);
#endif
}
-static void process_high_priority() {
+static void process_high_priority(unsigned char *buffer) {
long sequence;
int previous_ptt;
int previous_dot;
int previous_dash;
- unsigned char *buffer=high_priority_buffer->buffer;
- sequence=((buffer[0]&0xFF)<<24)+((buffer[1]&0xFF)<<16)+((buffer[2]&0xFF)<<8)+(buffer[3]&0xFF);
+ sequence=((high_priority_buffer[0]&0xFF)<<24)+((high_priority_buffer[1]&0xFF)<<16)+((high_priority_buffer[2]&0xFF)<<8)+(high_priority_buffer[3]&0xFF);
if (sequence != highprio_rcvd_sequence) {
g_print("HighPrio SeqErr Expected=%ld Seen=%ld\n", highprio_rcvd_sequence, sequence);
highprio_rcvd_sequence=sequence;
previous_dot=dot;
previous_dash=dash;
- local_ptt=buffer[4]&0x01;
- dot=(buffer[4]>>1)&0x01;
- dash=(buffer[4]>>2)&0x01;
- pll_locked=(buffer[4]>>4)&0x01;
- adc_overload=buffer[5]&0x01;
- exciter_power=((buffer[6]&0xFF)<<8)|(buffer[7]&0xFF);
- alex_forward_power=((buffer[14]&0xFF)<<8)|(buffer[15]&0xFF);
- alex_reverse_power=((buffer[22]&0xFF)<<8)|(buffer[23]&0xFF);
- supply_volts=((buffer[49]&0xFF)<<8)|(buffer[50]&0xFF);
+ local_ptt=high_priority_buffer[4]&0x01;
+ dot=(high_priority_buffer[4]>>1)&0x01;
+ dash=(high_priority_buffer[4]>>2)&0x01;
+ pll_locked=(high_priority_buffer[4]>>4)&0x01;
+ adc_overload=high_priority_buffer[5]&0x01;
+ exciter_power=((high_priority_buffer[6]&0xFF)<<8)|(high_priority_buffer[7]&0xFF);
+ alex_forward_power=((high_priority_buffer[14]&0xFF)<<8)|(high_priority_buffer[15]&0xFF);
+ alex_reverse_power=((high_priority_buffer[22]&0xFF)<<8)|(high_priority_buffer[23]&0xFF);
+ supply_volts=((high_priority_buffer[49]&0xFF)<<8)|(high_priority_buffer[50]&0xFF);
if (cw_keyer_internal) {
// Stops CAT cw transmission if paddle hit in "internal" CW
int i;
short sample;
float fsample;
- unsigned char *buffer=mic_line_buffer->buffer;
- sequence=((buffer[0]&0xFF)<<24)+((buffer[1]&0xFF)<<16)+((buffer[2]&0xFF)<<8)+(buffer[3]&0xFF);
+ sequence=((mic_line_buffer[0]&0xFF)<<24)+((mic_line_buffer[1]&0xFF)<<16)+((mic_line_buffer[2]&0xFF)<<8)+(mic_line_buffer[3]&0xFF);
if (sequence != micsamples_sequence) {
g_print("MicSample SeqErr Expected=%ld Seen=%ld\n", micsamples_sequence, sequence);
micsamples_sequence=sequence;
micsamples_sequence++;
b=4;
for(i=0;i<MIC_SAMPLES;i++) {
- sample=(short)(buffer[b++]<<8);
- sample |= (short) (buffer[b++]&0xFF);
+ sample=(short)(mic_line_buffer[b++]<<8);
+ sample |= (short) (mic_line_buffer[b++]&0xFF);
fsample = transmitter->local_microphone ? audio_get_next_mic_sample() : (float) sample * 0.00003051;
add_mic_sample(transmitter,fsample);
}
}
-//
-// Note that new_protocol_cw_audio_samples() is called by the TX thread, while
-// new_protocol_audio_samples() is called by the RX thread.
-//
-//
-// To avoid race conditions, we need a mutex covering these functions.
-// In 99% if the cases, the check on isTransmitting() controls that only one
-// of the functions becomes active, but at the moment of a RX/TX transition
-// this may fail.
-//
-// So "blocking" can only occur very rarely, such that the lock/unlock
-// should cost only few CPU cycles.
-//
-
void new_protocol_cw_audio_samples(short left_audio_sample,short right_audio_sample) {
int rc;
int txmode=get_tx_mode();
-
+ //
+ // Only process samples if transmitting in CW
if (isTransmitting() && (txmode==modeCWU || txmode==modeCWL)) {
- //
- // Only process samples if transmitting in CW
- //
- pthread_mutex_lock(&audio_mutex);
- // insert the samples
- audiobuffer[audioindex++]=left_audio_sample>>8;
- audiobuffer[audioindex++]=left_audio_sample;
- audiobuffer[audioindex++]=right_audio_sample>>8;
- audiobuffer[audioindex++]=right_audio_sample;
-
- if(audioindex>=sizeof(audiobuffer)) {
- // insert the sequence
- audiobuffer[0]=audiosequence>>24;
- audiobuffer[1]=audiosequence>>16;
- audiobuffer[2]=audiosequence>>8;
- audiobuffer[3]=audiosequence;
-
- // send the buffer
- rc=sendto(data_socket,audiobuffer,sizeof(audiobuffer),0,(struct sockaddr*)&audio_addr,audio_addr_length);
- if(rc!=sizeof(audiobuffer)) {
- g_print("sendto socket failed for %ld bytes of audio: rc=%d errno=%d\n",(long)sizeof(audiobuffer),rc,errno);
- }
- audioindex=4;
- audiosequence++;
+
+ // insert the samples
+ audiobuffer[audioindex++]=left_audio_sample>>8;
+ audiobuffer[audioindex++]=left_audio_sample;
+ audiobuffer[audioindex++]=right_audio_sample>>8;
+ audiobuffer[audioindex++]=right_audio_sample;
+
+ if(audioindex>=sizeof(audiobuffer)) {
+
+ // insert the sequence
+ audiobuffer[0]=audiosequence>>24;
+ audiobuffer[1]=audiosequence>>16;
+ audiobuffer[2]=audiosequence>>8;
+ audiobuffer[3]=audiosequence;
+
+ // send the buffer
+
+ rc=sendto(data_socket,audiobuffer,sizeof(audiobuffer),0,(struct sockaddr*)&audio_addr,audio_addr_length);
+ if(rc!=sizeof(audiobuffer)) {
+ g_print("sendto socket failed for %ld bytes of audio: %d\n",(long)sizeof(audiobuffer),rc);
}
- pthread_mutex_unlock(&audio_mutex);
+ audioindex=4;
+ audiosequence++;
+ }
}
}
int txmode=get_tx_mode();
//
// Only process samples if NOT transmitting in CW
- //
if (isTransmitting() && (txmode==modeCWU || txmode==modeCWL)) return;
- pthread_mutex_lock(&audio_mutex);
// insert the samples
audiobuffer[audioindex++]=left_audio_sample>>8;
audiobuffer[audioindex++]=left_audio_sample;
rc=sendto(data_socket,audiobuffer,sizeof(audiobuffer),0,(struct sockaddr*)&audio_addr,audio_addr_length);
if(rc!=sizeof(audiobuffer)) {
- g_print("sendto socket failed for %ld bytes of audio: rc=%d errno=%d\n",(long)sizeof(audiobuffer),rc,errno);
+ g_print("sendto socket failed for %ld bytes of audio: %d\n",(long)sizeof(audiobuffer),rc);
}
audioindex=4;
audiosequence++;
}
- pthread_mutex_unlock(&audio_mutex);
}
void new_protocol_flush_iq_samples() {
// this is called at the end of a TX phase:
// zero out "rest" of TX IQ buffer and send it
//
- int rc;
while (iqindex < sizeof(iqbuffer)) {
iqbuffer[iqindex++]=0;
}
iqbuffer[3]=tx_iq_sequence;
// send the buffer
- rc=sendto(data_socket,iqbuffer,sizeof(iqbuffer),0,(struct sockaddr*)&iq_addr,iq_addr_length);
- if(rc<0) {
- g_print("sendto socket failed for iq-flush, rc=%d errno=%d\n",rc,errno);
+ if(sendto(data_socket,iqbuffer,sizeof(iqbuffer),0,(struct sockaddr*)&iq_addr,iq_addr_length)<0) {
+ g_print("sendto socket failed for iq\n");
exit(1);
}
iqindex=4;
}
void new_protocol_iq_samples(int isample,int qsample) {
- int rc;
-
iqbuffer[iqindex++]=isample>>16;
iqbuffer[iqindex++]=isample>>8;
iqbuffer[iqindex++]=isample;
iqbuffer[3]=tx_iq_sequence;
// send the buffer
- rc=sendto(data_socket,iqbuffer,sizeof(iqbuffer),0,(struct sockaddr*)&iq_addr,iq_addr_length);
- if(rc<0) {
- g_print("sendto socket failed for iq, rc=%d errno=%d\n",rc,errno);
+ if(sendto(data_socket,iqbuffer,sizeof(iqbuffer),0,(struct sockaddr*)&iq_addr,iq_addr_length)<0) {
+ g_print("sendto socket failed for iq\n");
exit(1);
}
iqindex=4;
void* new_protocol_timer_thread(void* arg) {
//
- // Periodically send HighPriority as well as General packets.
- // A general packet is, for example,
+ // We now sent HighPriority as well as General packets
+ // in addition. General packet re-sending is, for example,
// required if the band changes (band->disblePA), and HighPrio
// packets are necessary at very many instances when changing
// something in the menus, and then a small delay does no harm
#include <time.h>
#include <math.h>
#include <errno.h>
-#ifdef __APPLE__
-#include "MacOS.h" // emulate clock_gettime on old MacOS systems
-#endif
#include <gtk/gtk.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <math.h>
-#ifdef __APPLE__
-#include "MacOS.h" // emulate clock_gettime on old MacOS systems
-#endif
#define EXTERN extern
#include "hpsdrsim.h"
unsigned int seed;
struct timespec delay;
+#ifdef __APPLE__
+ struct timespec now;
+#endif
myddc=(int) (uintptr_t) data;
if (myddc < 0 || myddc >= NUMRECEIVERS) return NULL;
delay.tv_nsec -= 1000000000;
delay.tv_sec++;
}
+#ifdef __APPLE__
+ //
+ // The (so-called) operating system for Mac does not have clock_nanosleep(),
+ // but is has clock_gettime as well as nanosleep.
+ // So, to circumvent this problem, we look at the watch and determine
+ // how long we should sleep now.
+ //
+ clock_gettime(CLOCK_MONOTONIC, &now);
+ now.tv_sec =delay.tv_sec - now.tv_sec;
+ now.tv_nsec=delay.tv_nsec - now.tv_nsec;
+ while (now.tv_nsec < 0) {
+ now.tv_nsec += 1000000000;
+ now.tv_sec--;
+ }
+ nanosleep(&now, NULL);
+#else
clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, &delay, NULL);
+#endif
if (sendto(sock, buffer, 1444, 0, (struct sockaddr*)&addr_new, sizeof(addr_new)) < 0) {
perror("***** ERROR: RX thread sendto");
break;
int rc;
int i;
struct timespec delay;
+#ifdef __APPLE__
+ struct timespec now;
+#endif
sock=socket(AF_INET, SOCK_DGRAM, 0);
delay.tv_nsec -= 1000000000;
delay.tv_sec++;
}
+#ifdef __APPLE__
+ //
+ // The (so-called) operating system for Mac does not have clock_nanosleep(),
+ // but is has clock_gettime as well as nanosleep.
+ // So, to circumvent this problem, we look at the watch and determine
+ // how long we should sleep now.
+ //
+ clock_gettime(CLOCK_MONOTONIC, &now);
+ now.tv_sec =delay.tv_sec - now.tv_sec;
+ now.tv_nsec=delay.tv_nsec - now.tv_nsec;
+ while (now.tv_nsec < 0) {
+ now.tv_nsec += 1000000000;
+ now.tv_sec--;
+ }
+ nanosleep(&now, NULL);
+#else
clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, &delay, NULL);
+#endif
if (sendto(sock, buffer, 132, 0, (struct sockaddr*)&addr_new, sizeof(addr_new)) < 0) {
perror("***** ERROR: Mic thread sendto");
break;
}
}
-//
-// To avoid race conditions, we need a mutex covering the next three functions
-// that are called both by the RX and TX thread, and are filling and sending the
-// output buffer.
-//
-// In 99% if the cases, the check on isTransmitting() controls that only one
-// of the functions becomes active, but at the moment of a RX/TX transition
-// this may fail.
-//
-// So "blocking" can only occur very rarely, such that the lock/unlock
-// should cost only few CPU cycles.
-//
-
-static pthread_mutex_t send_buffer_mutex = PTHREAD_MUTEX_INITIALIZER;
-
void old_protocol_audio_samples(RECEIVER *rx,short left_audio_sample,short right_audio_sample) {
if(!isTransmitting()) {
- pthread_mutex_lock(&send_buffer_mutex);
output_buffer[output_buffer_index++]=left_audio_sample>>8;
output_buffer[output_buffer_index++]=left_audio_sample;
output_buffer[output_buffer_index++]=right_audio_sample>>8;
ozy_send_buffer();
output_buffer_index=8;
}
- pthread_mutex_unlock(&send_buffer_mutex);
}
}
//
void old_protocol_iq_samples_with_sidetone(int isample, int qsample, int side) {
if(isTransmitting()) {
- pthread_mutex_lock(&send_buffer_mutex);
output_buffer[output_buffer_index++]=side >> 8;
output_buffer[output_buffer_index++]=side;
output_buffer[output_buffer_index++]=side >> 8;
ozy_send_buffer();
output_buffer_index=8;
}
- pthread_mutex_unlock(&send_buffer_mutex);
}
}
void old_protocol_iq_samples(int isample,int qsample) {
if(isTransmitting()) {
- pthread_mutex_lock(&send_buffer_mutex);
output_buffer[output_buffer_index++]=0;
output_buffer[output_buffer_index++]=0;
output_buffer[output_buffer_index++]=0;
ozy_send_buffer();
output_buffer_index=8;
}
- pthread_mutex_unlock(&send_buffer_mutex);
}
}
case 5: // XVTR with old pa board
output_buffer[C3] |= 0xE0;
break;
- case 104: // EXT2 with ANAN-7000: does not exist, use EXT1
+ case 104: // EXT2 with ANAN-7000: does not exit, use EXT1
case 103: // EXT1 with ANAN-7000
output_buffer[C3]|= 0x40;
break;
if (rxgain > 60) rxgain=60;
// encode all 6 bits of RXgain in ATT value and set bit6
if (isTransmitting()) {
- //
- // The "TX attenuation" value (0 ... 31 dB) has to be mapped to a
- // a range of preamp settings. This range is very different on the
- // HermesLite when using "internal" feedback (crosstalk from the
- // RX/TX releay) or "external" feedback (attenuator output
- // connected with RF3 input of the HermesLite2).
- // To cope with both situations, the preamp range is
- // +2 ... +33 dB if "Internal" feedback is selected in the
- // PS menu (this is optimal for "crosstalk" feedback) and
- // if external feedback is used (check either EXT1 or ByPass
- // in the PS menu) the preamp range is -12 ... +19 dB.
- //
- //
- output_buffer[C4] = 0x40 | (33 - (transmitter->attenuation & 0x1F));
-#ifdef PURESIGNAL
- if (receiver[PS_RX_FEEDBACK]->alex_antenna == 0) {
- output_buffer[C4] = 0x40 | (45 - (transmitter->attenuation & 0x1F));
- }
-#endif
+ output_buffer[C4] = 0x40 | (31 - (transmitter->attenuation & 0x1F));
} else {
output_buffer[C4] = 0x40 | (rxgain & 0x3F);
}
output_buffer[C1]|=(receiver[1]->adc<<(2*rx2channel));
}
}
- if (have_rx_gain) {
- //
- // On the HermesLite2, we need bit7 set to make this feature active,
- // and need bit6 set to tell HL2 to directly use the lowest 6 bits
- // for the built-in preamp. For the effect of choosing different
- // "alex antennas" see above.
- output_buffer[C3] = 0xC0 | (33 - (transmitter->attenuation & 0x1F));
-#ifdef PURESIGNAL
- if (receiver[PS_RX_FEEDBACK]->alex_antenna == 0) {
- output_buffer[C3] = 0xC0 | (45 - (transmitter->attenuation & 0x1F));
- }
-#endif
- } else {
- output_buffer[C3]=transmitter->attenuation & 0x1F; // Step attenuator of first ADC, value used when TXing
- }
+ output_buffer[C3]=0x00;
+ output_buffer[C3]|=transmitter->attenuation; // Step attenuator of first ADC, value used when TXing
output_buffer[C4]=0x00;
break;
case 7:
switch(protocol) {
case ORIGINAL_PROTOCOL:
case NEW_PROTOCOL:
-#ifdef SOAPYSDR
- case SOAPYSDR_PROTOCOL:
-#endif
//
// put sample into ring buffer
//
}
}
break;
+#ifdef SOAPYSDR
+ case SOAPYSDR_PROTOCOL:
+ // Note that this call ends up deeply in the TX engine
+ soapy_protocol_process_local_mic(sample);
+ break;
+#endif
default:
break;
}
// we have to store the data such that the PA callback function
// can access it.
//
-// Note that the check on isTransmitting() takes care that "blocking"
-// by the mutex can only occur in the moment of a RX/TX transition if
-// both audio_write() and cw_audio_write() get a "go".
-//
-// So mutex locking/unlocking should only cost few CPU cycles in
-// normal operation.
-//
int audio_write (RECEIVER *rx, float left, float right)
{
int mode=modeUSB;
RECEIVER *rx = active_receiver;
float *buffer = rx->local_audio_buffer;
- g_mutex_lock(&rx->local_audio_mutex);
if (rx->playback_handle != NULL && rx->local_audio_buffer != NULL) {
buffer[rx->local_audio_buffer_offset++] = sample;
if (rx->local_audio_buffer_offset == MY_AUDIO_BUFFER_SIZE) {
rx->local_audio_buffer_offset=0;
}
}
- g_mutex_unlock(&rx->local_audio_mutex);
return 0;
}
#ifdef LOCALCW
#include "iambic.h"
#endif
-#include "rigctl_menu.h"
#ifdef MIDI
// rather than including MIDI.h with all its internal stuff
// (e.g. enum components) we just declare the single bit thereof
status_text(text);
- switch (protocol) {
- case ORIGINAL_PROTOCOL:
- case NEW_PROTOCOL:
- sprintf(text,"piHPSDR: %s (%s %s) %s (%s) on %s",
- radio->name,
- p,
- version,
- ip,
- mac,
- iface);
- break;
-#ifdef SOAPYSDR
- case SOAPYSDR_PROTOCOL:
- sprintf(text,"piHPSDR: %s (%s %s)",
- radio->name,
- p,
- version);
- break;
-#endif
- }
+ sprintf(text,"piHPSDR: %s (%s %s) %s (%s) on %s",
+ radio->name,
+ p,
+ version,
+ ip,
+ mac,
+ iface);
gtk_window_set_title (GTK_WINDOW (top_window), text);
if(rigctl_enable) {
launch_rigctl();
- if (serial_enable) {
- launch_serial();
- }
- } else {
- // since we do not spawn the serial thread,
- // disable serial
- serial_enable=0;
}
if(can_transmit) {
void setMox(int state) {
if(!can_transmit) return;
+#ifdef SOAPYSDR
+ if(protocol==SOAPYSDR_PROTOCOL && !transmitter->local_microphone) return;
+#endif
vox_cancel(); // remove time-out
if(mox!=state) {
if (state && vox) {
case NEW_PROTOCOL:
schedule_high_priority();
break;
-#ifdef SOAPYSDR
- case SOAPYSDR_PROTOCOL:
- soapy_protocol_set_gain(active_receiver,value * 1.0);
- break;
-#endif
}
}
-//
-// For HPSDR, only receiver[0]->rx_antenna has an effect
-// The antenna is set according to what is stored in the "band" info
-// We have to call this routine in the HPSDR case each time a band is switched.
-//
-void set_alex_rx_antenna() {
- BAND *band;
- switch (protocol) {
- case ORIGINAL_PROTOCOL:
- band=band_get_band(vfo[VFO_A].band);
- receiver[0]->alex_antenna=band->alexRxAntenna;
- break;
- case NEW_PROTOCOL:
- band=band_get_band(vfo[VFO_A].band);
- receiver[0]->alex_antenna=band->alexRxAntenna;
- schedule_high_priority();
- break;
+void set_alex_rx_antenna(int v) {
+ if(active_receiver->id==0) {
+ active_receiver->alex_antenna=v;
+ if(protocol==NEW_PROTOCOL) {
+ schedule_high_priority();
}
+ }
+#ifdef SOAPYSDR
+ if(protocol==SOAPYSDR_PROTOCOL) {
+ soapy_protocol_set_rx_antenna(active_receiver,v);
+ }
+#endif
}
-//
-// For HPSDR, determine which band control the TX and
-// set TX antenna accordingly
-// We have to call this routine
-// in the HPSDR case each time the TX band is switched,
-// which is for each band switch, each time "split" is
-// changed, and in case of "split", each time the active
-// RX changes!
-//
-void set_alex_tx_antenna() {
- BAND *band;
- if (!can_transmit) return;
- switch (protocol) {
- case ORIGINAL_PROTOCOL:
- band=band_get_band(vfo[get_tx_vfo()].band);
- transmitter->alex_antenna=band->alexTxAntenna;
- break;
- case NEW_PROTOCOL:
- band=band_get_band(vfo[get_tx_vfo()].band);
- transmitter->alex_antenna=band->alexTxAntenna;
+void set_alex_tx_antenna(int v) {
+ transmitter->alex_antenna=v;
+ if(protocol==NEW_PROTOCOL) {
schedule_high_priority();
- break;
}
}
//
-// For HPSDR, only receiver[0]->alex_attenuation has an effect
-// Set this from the attenuation stored "per band"
+// There is an error here.
+// The alex att should not be associated with a receiver,
+// but with an ADC. *all* receivers bound to that ADC
+// will experience the same attenuation.
//
-void set_alex_attenuation() {
- BAND *band;
- switch (protocol) {
- case ORIGINAL_PROTOCOL:
- band=band_get_band(vfo[VFO_A].band);
- receiver[0]->alex_attenuation=band->alexAttenuation;
- break;
- case NEW_PROTOCOL:
- band=band_get_band(vfo[VFO_A].band);
- receiver[0]->alex_attenuation=band->alexAttenuation;
- schedule_high_priority();
- break;
+// This means, alex_attenuation should not be stored in thre
+// receiver, but separately (as is the case with adc_attenuation).
+//
+void set_alex_attenuation(int v) {
+ if(active_receiver->id==0) {
+ active_receiver->alex_attenuation=v;
+ if(protocol==NEW_PROTOCOL) {
+ schedule_high_priority();
}
+ }
}
void radioRestoreState() {
if(value) rigctl_enable=atoi(value);
value=getProperty("rigctl_port_base");
if(value) rigctl_port_base=atoi(value);
- value=getProperty("rigctl_serial_enable");
- if (value) serial_enable=atoi(value);
- value=getProperty("rigctl_serial_baud_rate");
- if (value) serial_baud_rate=atoi(value);
- value=getProperty("rigctl_serial_port");
- if (value) strcpy(ser_port,value);
value=getProperty("adc_0_attenuation");
if(value) adc_attenuation[0]=atoi(value);
setProperty("rigctl_enable",value);
sprintf(value,"%d",rigctl_port_base);
setProperty("rigctl_port_base",value);
- sprintf(value,"%d",serial_enable);
- setProperty("rigctl_serial_enable",value);
- sprintf(value,"%d",serial_baud_rate);
- setProperty("rigctl_serial_baud_rate",value);
- setProperty("rigctl_serial_port",ser_port);
sprintf(value,"%d",display_sequence_errors);
setProperty("radio.display_sequence_errors",value);
extern void setSquelch(RECEIVER *rx);
extern void set_attenuation(int value);
-extern void set_alex_rx_antenna(void);
-extern void set_alex_tx_antenna(void);
-extern void set_alex_attenuation(void);
+extern void set_alex_rx_antenna(int v);
+extern void set_alex_tx_antenna(int v);
+extern void set_alex_attenuation(int v);
extern int isTransmitting();
filter_board_changed();
}
- //
- // This should not be necessary HERE
- //
- if(filter_board==ALEX || filter_board==APOLLO || filter_board==CHARLY25) {
- set_alex_rx_antenna();
- set_alex_tx_antenna();
- set_alex_attenuation();
+ if(filter_board==ALEX || filter_board==APOLLO) {
+ BAND *band=band_get_current_band();
+ // mode and filters have nothing to do with the filter board
+ //BANDSTACK_ENTRY* entry=bandstack_entry_get_current();
+ //setFrequency(entry->frequency);
+ //setMode(entry->mode);
+ //set_mode(active_receiver,entry->mode);
+ //FILTER* band_filters=filters[entry->mode];
+ //FILTER* band_filter=&band_filters[entry->filter];
+ //set_filter(active_receiver,band_filter->low,band_filter->high);
+ if(active_receiver->id==0) {
+ set_alex_rx_antenna(band->alexRxAntenna);
+ set_alex_tx_antenna(band->alexTxAntenna);
+ set_alex_attenuation(band->alexAttenuation);
+ }
}
att_type_changed();
}
g_idle_add(sliders_active_receiver_changed,NULL);
// setup the transmitter mode and filter
if(can_transmit) {
- // TX band has possibly changed
tx_set_mode(transmitter,get_tx_mode());
- set_alex_tx_antenna();
- calcDriveLevel();
}
}
char *command;
} COMMAND;
+int fd; // Serial port file descriptor
+
static CLIENT client[MAX_CLIENTS];
int squelch=-160; //local sim of squelch level
// CW sending stuff
//
-static char cw_buf[25];
+static char cw_buf[30];
static int cw_busy=0;
static int cat_cw_seen=0;
char *read_buf =ring_buf;
char *p;
int num_buf=0;
- int txmode;
while (server_running) {
// wait for CW data (periodically look every 100 msec)
continue;
}
- //
- // if a message arrives and the TX mode is not CW, silently ignore
- //
- txmode=get_tx_mode();
- if (cw_busy && txmode != modeCWU && txmode != modeCWL) {
- cw_busy=0;
- continue;
- }
// if new data is available and fits into the buffer, copy-in.
// If there are several adjacent spaces, take only the first one.
// This also swallows the "tails" of the KY commands which
CAT_cw_is_active=1;
if (!mox) {
// activate PTT
- g_idle_add(ext_mox_update ,GINT_TO_POINTER(1));
+ g_idle_add(ext_mox_update ,(gpointer)1);
// have to wait until it is really there
// Note that if out-of-band, we would wait
// forever here, so allow at most 200 msec
// If a CW key has been hit, we continue in TX mode.
// Otherwise, switch PTT off.
if (!cw_key_hit && mox) {
- g_idle_add(ext_mox_update ,GINT_TO_POINTER(0));
+ g_idle_add(ext_mox_update ,(gpointer)0);
}
// Let the CAT system swallow incoming CW commands by setting cw_busy to -1.
// Do so until no CAT CW message has arrived for 1 second
if (cw_busy || num_buf > 0) continue;
CAT_cw_is_active=0;
if (!cw_key_hit) {
- g_idle_add(ext_mox_update ,GINT_TO_POINTER(0));
+ g_idle_add(ext_mox_update ,(gpointer)0);
// wait up to 500 msec for MOX having gone
// otherwise there might be a race condition when sending
// the next character really soon
cw_busy=0;
if (CAT_cw_is_active) {
CAT_cw_is_active=0;
- g_idle_add(ext_mox_update ,GINT_TO_POINTER(0));
+ g_idle_add(ext_mox_update ,(gpointer)0);
}
return NULL;
}
// returns the command string
//
void send_resp (int fd,char * msg) {
- if(rigctl_debug) g_print("RIGCTL: fd=%d RESP=%s\n",fd, msg);
+ if(rigctl_debug) g_print("RIGCTL: RESP=%s\n",msg);
int length=strlen(msg);
- int rc;
- int count=0;
+ int written=0;
-//
-// Possibly, the channel is already closed. In this case
-// give up (rc < 0) or at most try a few times (rc == 0)
-// since we are in the GTK idle loop
-//
- while(length>0) {
- rc=write(fd,msg,length);
- if (rc < 0) return;
- if (rc == 0) {
- count++;
- if (count > 10) return;
- }
- length -= rc;
- msg += rc;
+ while(written<length) {
+ written+=write(fd,&msg[written],length-written);
}
+
}
//
setsockopt(server_socket, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
setsockopt(server_socket, SOL_SOCKET, SO_REUSEPORT, &on, sizeof(on));
- setsockopt(server_socket, SOL_SOCKET, SO_KEEPALIVE, &on, sizeof(on));
// bind to listening port
memset(&server_address,0,sizeof(server_address));
for(i=0;i<MAX_CLIENTS;i++) {
client[i].fd=-1;
}
- // listen with a max queue of 3
- if(listen(server_socket,3)<0) {
- perror("rigctl_server: listen failed");
- close(server_socket);
- return NULL;
- }
server_running=1;
// must start the thread here in order NOT to inherit a lock
if (!rigctl_cw_thread_id) rigctl_cw_thread_id = g_thread_new("RIGCTL cw", rigctl_cw_thread, NULL);
while(server_running) {
- int spare;
+ // listen with a max queue of 3
+ if(listen(server_socket,3)<0) {
+ perror("rigctl_server: listen failed");
+ close(server_socket);
+ return NULL;
+ }
// find a spare thread
- spare = -1;
for(i=0;i<MAX_CLIENTS;i++) {
- if(client[i].fd == -1) {
- spare=i;
- break;
- }
- }
- // if all threads are busy, wait and continue
- if (spare < 0) {
- usleep(100000L);
- continue;
- }
- // A thread is available, try to get connection
+ if(client[i].fd==-1) {
- g_print("Using client: %d\n",spare);
+ g_print("Using client: %d\n",i);
- client[spare].fd=accept(server_socket,(struct sockaddr*)&client[spare].address,&client[spare].address_length);
- if(client[spare].fd<0) {
- perror("rigctl_server: client accept failed");
- client[spare].fd = -1;
- continue;
- }
+ client[i].fd=accept(server_socket,(struct sockaddr*)&client[i].address,&client[i].address_length);
+ if(client[i].fd<0) {
+ perror("rigctl_server: client accept failed");
+ continue;
+ }
- client[spare].thread_id = g_thread_new("rigctl client", rigctl_client, (gpointer)&client[spare]);
- // no check on return value since g_thread_new succeeds or program aborts
+ client[i].thread_id = g_thread_new("rigctl client", rigctl_client, (gpointer)&client[i]);
+ if(client[i].thread_id==NULL) {
+ g_print("g_thread_new failed (n rigctl_client\n");
+ g_print("setting SO_LINGER to 0 for client_socket: %d\n",client[i].fd);
+ struct linger linger = { 0 };
+ linger.l_onoff = 1;
+ linger.l_linger = 0;
+ if(setsockopt(client[i].fd,SOL_SOCKET,SO_LINGER,(const char *)&linger,sizeof(linger))==-1) {
+ perror("setsockopt(...,SO_LINGER,...) failed for client");
+ }
+ close(client[i].fd);
+ }
+ }
+ }
}
close(server_socket);
command_index++;
if(cmd_input[i]==';') {
command[command_index]='\0';
- if(rigctl_debug) g_print("RIGCTL: fd=%d command=%s\n",client->fd,command);
+ if(rigctl_debug) g_print("RIGCTL: command=%s\n",command);
COMMAND *info=g_new(COMMAND,1);
info->client=client;
info->command=command;
}
}
}
-g_print("RIGCTL: Leaving rigctl_client thread\n");
+g_print("RIGCTL: Leaving rigctl_client thread");
if(client->fd!=-1) {
g_print("setting SO_LINGER to 0 for client_socket: %d\n",client->fd);
struct linger linger = { 0 };
sprintf(reply,"ZZSP%d;",split);
send_resp(client->fd,reply) ;
} else if(command[5]==';') {
- int val=atoi(&command[4]);
- ext_set_split(GINT_TO_POINTER(val));
+ split=atoi(&command[4]);
+ tx_set_mode(transmitter,get_tx_mode());
+ vfo_update();
}
break;
case 'R': //ZZSR
sprintf(reply,"ZZSW%d;",split);
send_resp(client->fd,reply) ;
} else if(command[5]==';') {
- int val=atoi(&command[4]);
- ext_set_split(GINT_TO_POINTER(val));
+ split=atoi(&command[4]);
+ tx_set_mode(transmitter,get_tx_mode());
+ vfo_update();
}
break;
case 'Y': //ZZSY
break;
case 'I': //AI
// set/read Auto Information
- // many clients start the connection with an "AI0" command.
- // piHPSDR is constantly in an "AI0" state, therefore
- // silently ignore AI0 commands and flag an error for
- // all other possiblities
- if (command[2] == '0' && command[3] == ';') {
- // do nothing
- } else {
- implemented=FALSE;
- }
+ implemented=FALSE;
break;
case 'L': // AL
// set/read Auto Notch level
sprintf(reply,"FT%d;",split);
send_resp(client->fd,reply) ;
} else if(command[3]==';') {
- int val=atoi(&command[2]);
- ext_set_split(GINT_TO_POINTER(val));
+ split=atoi(&command[2]);
+ tx_set_mode(transmitter,get_tx_mode());
+ vfo_update();
}
break;
case 'W': //FW
} else if(command[27]==';') {
if(cw_busy==0) {
strncpy(cw_buf,&command[3],24);
- // if command is too long, strncpy does not terminate destination
- cw_buf[24]='\0';
cw_busy=1;
}
} else {
case 'A': //SA
// set/read stallite mode status
if(command[2]==';') {
- sprintf(reply,"SA%d%d%d%d%d%d%dSAT? ;",sat_mode==SAT_MODE|sat_mode==RSAT_MODE,0,0,0,sat_mode==SAT_MODE,sat_mode==RSAT_MODE,0);
+ sprintf(reply,"SA%d%d%d%d%d%d%dSAT? ;",sat_mode==SAT_MODE|sat_mode==RSAT_MODE,0,0,0,sat_mode=SAT_MODE,sat_mode=RSAT_MODE,0);
send_resp(client->fd,reply);
} else if(command[9]==';') {
if(command[2]=='0') {
int command_index=0;
int numbytes;
int i;
- g_mutex_lock(&mutex_a->m);
cat_control++;
- if(rigctl_debug) g_print("RIGCTL: SER INC cat_contro=%d\n",cat_control);
- g_mutex_unlock(&mutex_a->m);
- g_idle_add(ext_vfo_update,NULL);
serial_running=TRUE;
while(serial_running) {
- numbytes = read (client->fd, cmd_input, sizeof cmd_input);
+ numbytes = read (fd, cmd_input, sizeof cmd_input);
if(numbytes>0) {
for(i=0;i<numbytes;i++) {
command[command_index]=cmd_input[i];
command_index++;
if(cmd_input[i]==';') {
command[command_index]='\0';
- if(rigctl_debug) g_print("RIGCTL: fd=%d command=%s\n",client->fd,command);
+ if(rigctl_debug) g_print("RIGCTL: command=%s\n",command);
COMMAND *info=g_new(COMMAND,1);
info->client=client;
info->command=command;
//usleep(100L);
}
close(client->fd);
- g_mutex_lock(&mutex_a->m);
cat_control--;
- if(rigctl_debug) g_print("RIGCTL: SER DEC - cat_control=%d\n",cat_control);
- g_mutex_unlock(&mutex_a->m);
- g_idle_add(ext_vfo_update,NULL);
- g_free(client); // this is the serial_client allocated in launch_serial
- return NULL;
}
int launch_serial () {
- int fd;
g_print("RIGCTL: Launch Serial port %s\n",ser_port);
if(mutex_b_exists == 0) {
mutex_b = g_new(GT_MUTEX,1);
g_print("serial port fd=%d\n",fd);
set_interface_attribs (fd, serial_baud_rate, serial_parity);
- set_blocking (fd, 0); // set no blocking
+ set_blocking (fd, 1); // set no blocking
CLIENT *serial_client=g_new(CLIENT,1);
serial_client->fd=fd;
serial_server_thread_id = g_thread_new( "Serial server", serial_server, serial_client);
if(!serial_server_thread_id )
{
- // NOTREACHED, since program aborts if g_thread_new fails
g_free(serial_client);
g_print("g_thread_new failed on serial_server\n");
return 0;
void disable_serial () {
g_print("RIGCTL: Disable Serial port %s\n",ser_port);
serial_running=FALSE;
- // wait for the serial server actually terminating
- if (serial_server_thread_id) {
- g_thread_join(serial_server_thread_id);
- }
- serial_server_thread_id=NULL;
}
//
g_mutex_init(&mutex_busy->m);
// This routine encapsulates the thread call
- rigctl_server_thread_id = g_thread_new( "rigctl server", rigctl_server, GINT_TO_POINTER(rigctl_port_base));
+ rigctl_server_thread_id = g_thread_new( "rigctl server", rigctl_server, (gpointer)(long)rigctl_port_base);
if( ! rigctl_server_thread_id )
{
- // NOTREACHED, since program aborts if g_thread_new fails
g_print("g_thread_new failed on rigctl_server\n");
}
}
#include "vfo.h"
int serial_enable;
-static GtkWidget *serial_enable_b;
char ser_port[64]="/dev/ttyACM0";
int serial_baud_rate = B9600;
int serial_parity = 0; // 0=none, 1=even, 2=odd
if(rigctl_enable) {
launch_rigctl();
} else {
- //
- // If serial server is running, terminate it.
- // Disable serial and clear check-box
- //
- if (serial_enable) {
- disable_serial();
- }
- serial_enable=0;
- gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON(serial_enable_b),0);
disable_rigctl();
}
}
static void serial_enable_cb(GtkWidget *widget, gpointer data) {
- //
- // If rigctl is not running, serial cannot be enabled
- //
- if (!rigctl_enable) {
- serial_enable=0;
- gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(widget),0);
- return;
- }
strcpy(ser_port,gtk_entry_get_text(GTK_ENTRY(serial_port_entry)));
serial_enable=gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget));
if(serial_enable) {
if(launch_serial() == 0) {
- gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(widget),FALSE) ;
+ gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON(widget),FALSE) ;
}
} else {
disable_serial();
// Set Baud Rate
static void baud_rate_cb(GtkWidget *widget, gpointer data) {
- int active=gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget));
- fprintf(stderr,"ACTIVE=%d BAUD=%d\n", active, GPOINTER_TO_INT(data));
- if (active) {
- serial_baud_rate = GPOINTER_TO_INT(data);
- fprintf(stderr,"RIGCTL_MENU: Baud rate changed: %d\n",serial_baud_rate);
- }
+ serial_baud_rate = GPOINTER_TO_INT(data);
+ fprintf(stderr,"RIGCTL_MENU: Baud rate changed: %d\n",serial_baud_rate);
}
// Set Parity 0=None, 1=Even, 2=0dd
g_signal_connect(rigctl_port_spinner,"value_changed",G_CALLBACK(rigctl_value_changed_cb),NULL);
/* Put the Serial Port stuff here */
- serial_enable_b=gtk_check_button_new_with_label("Serial Port Enable");
+ GtkWidget *serial_enable_b=gtk_check_button_new_with_label("Serial Port Enable");
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (serial_enable_b), serial_enable);
gtk_widget_show(serial_enable_b);
gtk_grid_attach(GTK_GRID(grid),serial_enable_b,0,3,1,1);
extern int serial_baud_rate;
extern int serial_parity;
-extern int serial_enable;
extern gboolean rigctl_debug;
#include "receiver.h"
#include "sliders.h"
#include "new_protocol.h"
-#include "vfo.h"
static GtkWidget *parent_window=NULL;
static GtkWidget *menu_b=NULL;
}
static void alex_att_cb(GtkWidget *widget, gpointer data) {
- BAND *band;
if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget))) {
- // store value in the "band" info
- band=band_get_band(vfo[VFO_A].band);
- band->alexAttenuation=GPOINTER_TO_INT(data);
- set_alex_attenuation();
+ set_alex_attenuation((intptr_t) data);
update_att_preamp();
}
}
#ifdef USBOZY
(protocol==ORIGINAL_PROTOCOL && device == DEVICE_OZY) ||
#endif
- (protocol==NEW_PROTOCOL && device == NEW_DEVICE_ATLAS)) {
+ (protocol==NEW_PROTOCOL && device == NEW_DEVICE_ATLAS)) {
GtkWidget *preamp_b=gtk_check_button_new_with_label("Preamp");
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (preamp_b), active_receiver->preamp);
gtk_grid_attach(GTK_GRID(grid),preamp_b,x,4,1,1);
static void c25_att_combobox_changed(GtkWidget *widget, gpointer data) {
int val = atoi(gtk_combo_box_get_active_id(GTK_COMBO_BOX(widget)));
- if (active_receiver->id == 0) {
+ if (active_receiver->adc == 0) {
// this button is only valid for the first receiver
// store attenuation, such that in meter.c the correct level is displayed
adc_attenuation[active_receiver->adc] = 12*val;
- BAND* band = band_get_band(vfo[VFO_A].band);
- band->alexAttenuation=val;
- set_alex_attenuation();
+ set_alex_attenuation(val);
} else {
// always show "0 dB" on the button if the second RX is active
if (val != 0) {
sample_rate=768000;
} else if(strcmp(driver,"rtlsdr")==0) {
sample_rate=1048576;
- } else if(strcmp(driver,"radioberry")==0) {
- sample_rate=48000;
} else {
sample_rate=1048576;
}
}
if(strcmp(driver,"lime")==0) {
sprintf(discovered[devices].info.soapy.version,"fw=%s gw=%s hw=%s p=%s", fw_version, gw_version, hw_version, p_version);
- } else if (strcmp(driver,"radioberry")==0) {
- sprintf(discovered[devices].info.soapy.version,"fw=%s gw=%s", fw_version, gw_version);
} else {
strcpy(discovered[devices].info.soapy.version,"");
}
#include <stdlib.h>
#include <stdbool.h>
#include <ifaddrs.h>
-#include <sys/socket.h>
#include <net/if.h>
#include <arpa/inet.h>
#include <string.h>
#include <gdk/gdk.h>
#include <glib.h>
#include <errno.h>
+#include <ifaddrs.h>
#include <stdint.h>
#include <string.h>
int start = (full-width) /2; // Copy from start ... (end-1)
float *tfp=tx->pixel_samples;
float *rfp=rx_feedback->pixel_samples+start;
- float offset;
int i;
//
// The TX panadapter shows a RELATIVE signal strength. A CW or single-tone signal at
// on the attenuation effective in the feedback path.
// We try to normalize the feeback signal such that is looks like a "normal" TX
// panadapter if the feedback is optimal for PURESIGNAL (that is, if the attenuation
- // is optimal). The correction (offset) depends on the protocol (different peak levels in the TX
- // feedback channel.
+ // is optimal). The correction depends on the protocol (different peak levels in the TX
+ // feedback channel, old=0.407, new=0.2899, difference is 3 dB).
switch (protocol) {
case ORIGINAL_PROTOCOL:
- // TX dac feedback peak = 0.406, on HermesLite2 0.230
- offset = (device == DEVICE_HERMES_LITE2) ? 17.0 : 12.0;
+ for (i=0; i<width; i++) {
+ *tfp++ =*rfp++ + 12.0;
+ }
break;
case NEW_PROTOCOL:
- // TX dac feedback peak = 0.2899
- offset = 15.0;
+ for (i=0; i<width; i++) {
+ *tfp++ =*rfp++ + 15.0;
+ }
break;
default:
- // we probably never come here
- offset = 0.0;
+ memcpy(tfp, rfp, width*sizeof(float));
break;
}
- for (i=0; i<width; i++) {
- *tfp++ =*rfp++ + offset;
- }
g_mutex_unlock(&rx_feedback->mutex);
} else {
#endif
}
break;
-#ifdef SOAPYSDR
- case SOAPYSDR_PROTOCOL:
+#ifdef SOAPY_SDR
+ case SOAPY_PROTOCOL:
transmitter->fwd=0.0;
transmitter->exciter=0.0;
transmitter->rev=0.0;
tx->pixel_samples=g_new(float,tx->pixels);
if (cw_shape_buffer48) g_free(cw_shape_buffer48);
if (cw_shape_buffer192) g_free(cw_shape_buffer192);
- switch (protocol) {
- case ORIGINAL_PROTOCOL:
- //
- // We need no buffer for the IQ sample amplitudes because
- // we make dual use of the buffer for the audio amplitudes
- // (TX sample rate == mic sample rate)
- //
- cw_shape_buffer48=g_new(double,tx->buffer_size);
- break;
- case NEW_PROTOCOL:
-#ifdef SOAPYSDR
- case SOAPYSDR_PROTOCOL:
-#endif
- //
- // We need two buffers: one for the audio sample amplitudes
- // and another one for the TX IQ amplitudes
- // (TX and mic sample rate are usually different).
- //
- cw_shape_buffer48=g_new(double,tx->buffer_size);
- cw_shape_buffer192=g_new(double,tx->output_samples);
- break;
+ //
+ // We need this one both for old and new protocol, since
+ // is is also used to shape the audio samples
+ cw_shape_buffer48=g_new(double,tx->buffer_size);
+ if (protocol == NEW_PROTOCOL) {
+ // We need this buffer for the new protocol only, where it is only
+ // used to shape the TX envelope
+ cw_shape_buffer192=g_new(double,tx->output_samples);
}
- g_print("transmitter: allocate buffers: mic_input_buffer=%p iq_output_buffer=%p pixels=%p\n",
- tx->mic_input_buffer,tx->iq_output_buffer,tx->pixel_samples);
+fprintf(stderr,"transmitter: allocate buffers: mic_input_buffer=%p iq_output_buffer=%p pixels=%p\n",tx->mic_input_buffer,tx->iq_output_buffer,tx->pixel_samples);
- g_print("create_transmitter: OpenChannel id=%d buffer_size=%d fft_size=%d sample_rate=%d dspRate=%d outputRate=%d\n",
- tx->id,
- tx->buffer_size,
- 2048, // tx->fft_size,
- tx->mic_sample_rate,
- tx->mic_dsp_rate,
- tx->iq_output_rate);
+ fprintf(stderr,"create_transmitter: OpenChannel id=%d buffer_size=%d fft_size=%d sample_rate=%d dspRate=%d outputRate=%d\n",
+ tx->id,
+ tx->buffer_size,
+ 2048, // tx->fft_size,
+ tx->mic_sample_rate,
+ tx->mic_dsp_rate,
+ tx->iq_output_rate);
OpenChannel(tx->id,
tx->buffer_size,
if (isTransmitting()) {
- if( ( (protocol == NEW_PROTOCOL && radio->device==NEW_DEVICE_ATLAS)
- || (protocol==ORIGINAL_PROTOCOL && radio->device==DEVICE_METIS)
- ) && atlas_penelope) {
+ if(radio->device==NEW_DEVICE_ATLAS && atlas_penelope) {
//
// On these boards, drive level changes are performed by
// scaling the TX IQ samples. In the other cases, DriveLevel
break;
case NEW_PROTOCOL:
//
- // tx->output_samples is four times tx->buffer_size
+ // tx->output_samples if four times tx->buffer_size
// Take TX envelope from the 192kHz shape buffer
//
isample=0;
new_protocol_iq_samples(isample,qsample);
}
break;
-#ifdef SOAPYSDR
- case SOAPYSDR_PROTOCOL:
- //
- // the only difference to the P2 treatment is that we do not
- // generate audio samples to be sent to the radio
- //
- isample=0;
- for(j=0;j<tx->output_samples;j++) {
- ramp=cw_shape_buffer192[j]; // between 0.0 and 1.0
- qsample=floor(gain*ramp+0.5); // always non-negative, isample is just the pulse envelope
- soapy_protocol_iq_samples((float)isample,(float)qsample);
- }
- break;
-#endif
}
} else {
//
cw_shape_buffer192[i+3]=cwramp192[s+0];
}
}
-#ifdef SOAPYSDR
- if (protocol == SOAPYSDR_PROTOCOL) {
- //
- // The ratio between the TX and microphone sample rate can be any value, so
- // it is difficult to construct a general ramp here. We may at least *assume*
- // that the ratio is integral. We can extrapolate from the shapes calculated
- // for 48 and 192 kHz sample rate.
- //
- // At any rate, we *must* produce tx->outputsamples IQ samples from an input
- // buffer of size tx->buffer_size.
- //
- int ratio = tx->output_samples / tx->buffer_size;
- int j;
- i=ratio*tx->samples; // current position in TX IQ buffer
- if (updown) {
- //
- // Climb up the ramp
- //
- if (ratio % 4 == 0) {
- // simple adaptation from the 192 kHz ramp
- ratio = ratio / 4;
- s=4*cw_shape;
- for (j=0; j<ratio; j++) cw_shape_buffer192[i++]=cwramp192[s+0];
- for (j=0; j<ratio; j++) cw_shape_buffer192[i++]=cwramp192[s+1];
- for (j=0; j<ratio; j++) cw_shape_buffer192[i++]=cwramp192[s+2];
- for (j=0; j<ratio; j++) cw_shape_buffer192[i++]=cwramp192[s+3];
- } else {
- // simple adaptation from the 48 kHz ramp
- for (j=0; j<ratio; j++) cw_shape_buffer192[i++]=cwramp48[cw_shape];
- }
- } else {
- //
- // Walk down the ramp
- //
- if (ratio % 4 == 0) {
- // simple adaptation from the 192 kHz ramp
- ratio = ratio / 4;
- s=4*cw_shape;
- for (j=0; j<ratio; j++) cw_shape_buffer192[i++]=cwramp192[s+3];
- for (j=0; j<ratio; j++) cw_shape_buffer192[i++]=cwramp192[s+2];
- for (j=0; j<ratio; j++) cw_shape_buffer192[i++]=cwramp192[s+1];
- for (j=0; j<ratio; j++) cw_shape_buffer192[i++]=cwramp192[s+0];
- } else {
- // simple adaptation from the 48 kHz ramp
- for (j=0; j<ratio; j++) cw_shape_buffer192[i++]=cwramp48[cw_shape];
- }
- }
- }
-#endif
} else {
//
// If no longer transmitting, or no longer doing CW: reset pulse shaper.
cw_key_up=0;
cw_key_down=0;
cw_shape=0;
- // insert "silence" in CW audio and TX IQ buffers
cw_shape_buffer48[tx->samples]=0.0;
if (protocol == NEW_PROTOCOL) {
cw_shape_buffer192[4*tx->samples+0]=0.0;
cw_shape_buffer192[4*tx->samples+2]=0.0;
cw_shape_buffer192[4*tx->samples+3]=0.0;
}
-#ifdef SOAPYSDR
- if (protocol == SOAPYSDR_PROTOCOL) {
- //
- // this essentially the P2 code, where the ratio
- // is fixed to 4
- //
- int ratio = tx->output_samples / tx->buffer_size;
- int i=ratio*tx->samples;
- int j;
- for (j=0; j<ratio; j++) cw_shape_buffer192[i++]=0.0;
- }
-#endif
}
tx->mic_input_buffer[tx->samples*2]=mic_sample_double;
tx->mic_input_buffer[(tx->samples*2)+1]=0.0; //mic_sample_double;
gtk_spin_button_set_value(GTK_SPIN_BUTTON(ctcss_spin),(double)transmitter->ctcss_frequency);
gtk_grid_attach(GTK_GRID(grid),ctcss_spin,col,row,1,1);
g_signal_connect(ctcss_spin,"value-changed",G_CALLBACK(ctcss_spin_cb),NULL);
-*/
+
row++;
col=0;
-
+*/
GtkWidget *tune_use_drive_b=gtk_check_button_new_with_label("Tune use drive");
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (tune_use_drive_b), transmitter->tune_use_drive);
gtk_widget_show(tune_use_drive_b);
gtk_grid_attach(GTK_GRID(grid),tune_use_drive_b,col,row,1,1);
g_signal_connect(tune_use_drive_b,"toggled",G_CALLBACK(tune_use_drive_cb),NULL);
- //row++;
- //col=0;
- col++;
+ row++;
+ col=0;
GtkWidget *tune_percent_label=gtk_label_new(NULL);
gtk_label_set_markup(GTK_LABEL(tune_percent_label), "<b>Tune Percent:</b>");
sprintf(name,"modeset.%d.snb", i);
sprintf(value,"%d", mode_settings[i].snb);
setProperty(name,value);
- sprintf(name,"modeset.%d.en_txeq", i);
- sprintf(value,"%d", mode_settings[i].en_txeq);
- setProperty(name,value);
- sprintf(name,"modeset.%d.txeq.0", i);
- sprintf(value,"%d", mode_settings[i].txeq[0]);
- setProperty(name,value);
- sprintf(name,"modeset.%d.txeq.1", i);
- sprintf(value,"%d", mode_settings[i].txeq[1]);
- setProperty(name,value);
- sprintf(name,"modeset.%d.txeq.2", i);
- sprintf(value,"%d", mode_settings[i].txeq[2]);
- setProperty(name,value);
- sprintf(name,"modeset.%d.txeq.3", i);
- sprintf(value,"%d", mode_settings[i].txeq[3]);
- setProperty(name,value);
- sprintf(name,"modeset.%d.en_rxeq", i);
- sprintf(value,"%d", mode_settings[i].en_rxeq);
- setProperty(name,value);
- sprintf(name,"modeset.%d.rxeq.0", i);
- sprintf(value,"%d", mode_settings[i].rxeq[0]);
- setProperty(name,value);
- sprintf(name,"modeset.%d.rxeq.1", i);
- sprintf(value,"%d", mode_settings[i].rxeq[1]);
- setProperty(name,value);
- sprintf(name,"modeset.%d.rxeq.2", i);
- sprintf(value,"%d", mode_settings[i].rxeq[2]);
- setProperty(name,value);
- sprintf(name,"modeset.%d.rxeq.3", i);
- sprintf(value,"%d", mode_settings[i].rxeq[3]);
- setProperty(name,value);
}
}
mode_settings[i].nb2=0;
mode_settings[i].anf=0;
mode_settings[i].snb=0;
- mode_settings[i].en_txeq=0;
- mode_settings[i].txeq[0]=0;
- mode_settings[i].txeq[1]=0;
- mode_settings[i].txeq[2]=0;
- mode_settings[i].txeq[3]=0;
- mode_settings[i].en_rxeq=0;
- mode_settings[i].rxeq[0]=0;
- mode_settings[i].rxeq[1]=0;
- mode_settings[i].rxeq[2]=0;
- mode_settings[i].rxeq[3]=0;
sprintf(name,"modeset.%d.filter",i);
value=getProperty(name);
sprintf(name,"modeset.%d.snb",i);
value=getProperty(name);
if(value) mode_settings[i].snb=atoi(value);
- sprintf(name,"modeset.%d.en_txeq",i);
- value=getProperty(name);
- if(value) mode_settings[i].en_txeq=atoi(value);
- sprintf(name,"modeset.%d.txeq.0",i);
- value=getProperty(name);
- if(value) mode_settings[i].txeq[0]=atoi(value);
- sprintf(name,"modeset.%d.txeq.1",i);
- value=getProperty(name);
- if(value) mode_settings[i].txeq[1]=atoi(value);
- sprintf(name,"modeset.%d.txeq.2",i);
- value=getProperty(name);
- if(value) mode_settings[i].txeq[2]=atoi(value);
- sprintf(name,"modeset.%d.txeq.3",i);
- value=getProperty(name);
- if(value) mode_settings[i].txeq[3]=atoi(value);
- sprintf(name,"modeset.%d.en_rxeq",i);
- value=getProperty(name);
- if(value) mode_settings[i].en_rxeq=atoi(value);
- sprintf(name,"modeset.%d.rxeq.0",i);
- value=getProperty(name);
- if(value) mode_settings[i].rxeq[0]=atoi(value);
- sprintf(name,"modeset.%d.rxeq.1",i);
- value=getProperty(name);
- if(value) mode_settings[i].rxeq[1]=atoi(value);
- sprintf(name,"modeset.%d.rxeq.2",i);
- value=getProperty(name);
- if(value) mode_settings[i].rxeq[2]=atoi(value);
- sprintf(name,"modeset.%d.rxeq.3",i);
- value=getProperty(name);
- if(value) mode_settings[i].rxeq[3]=atoi(value);
}
}
void vfo_band_changed(int id,int b) {
BANDSTACK *bandstack;
- int m;
#ifdef CLIENT_SERVER
if(radio_is_remote) {
vfo[id].filter=entry->filter;
vfo[id].lo=band->frequencyLO+band->errorLO;
-//
-// Change to the filter/NR combination stored for this mode
-//
- m=vfo[id].mode;
-
- vfo[id].filter =mode_settings[m].filter;
- active_receiver->nr =mode_settings[m].nr;
- active_receiver->nr2=mode_settings[m].nr2;
- active_receiver->nb =mode_settings[m].nb;
- active_receiver->nb2=mode_settings[m].nb2;
- active_receiver->anf=mode_settings[m].anf;
- active_receiver->snb=mode_settings[m].snb;
- enable_rx_equalizer =mode_settings[m].en_rxeq;
- rx_equalizer[0] =mode_settings[m].rxeq[0];
- rx_equalizer[1] =mode_settings[m].rxeq[1];
- rx_equalizer[2] =mode_settings[m].rxeq[2];
- rx_equalizer[3] =mode_settings[m].rxeq[3];
- enable_tx_equalizer =mode_settings[m].en_txeq;
- tx_equalizer[0] =mode_settings[m].txeq[0];
- tx_equalizer[1] =mode_settings[m].txeq[1];
- tx_equalizer[2] =mode_settings[m].txeq[2];
- tx_equalizer[3] =mode_settings[m].txeq[3];
-
- // make changes effective
- g_idle_add(ext_update_noise, NULL);
- g_idle_add(ext_update_eq , NULL);
-
// turn off ctun
vfo[id].ctun=0;
vfo[id].ctun_frequency=0LL;
switch(id) {
case 0:
bandstack->current_entry=vfo[id].bandstack;
+ receiver_vfo_changed(receiver[id]);
+ BAND *band=band_get_band(vfo[id].band);
+ set_alex_rx_antenna(band->alexRxAntenna);
+ if(can_transmit) {
+ set_alex_tx_antenna(band->alexTxAntenna);
+ }
+ set_alex_attenuation(band->alexAttenuation);
receiver_vfo_changed(receiver[0]);
break;
case 1:
}
break;
}
- set_alex_attenuation();
- set_alex_rx_antenna();
if(can_transmit) {
- set_alex_tx_antenna();
tx_set_mode(transmitter,get_tx_mode());
//
// If the band has changed, it is necessary to re-calculate
switch(id) {
case 0:
bandstack->current_entry=vfo[id].bandstack;
+ receiver_vfo_changed(receiver[id]);
+ BAND *band=band_get_band(vfo[id].band);
+ set_alex_rx_antenna(band->alexRxAntenna);
+ if(can_transmit) {
+ set_alex_tx_antenna(band->alexTxAntenna);
+ }
+ set_alex_attenuation(band->alexAttenuation);
receiver_vfo_changed(receiver[0]);
break;
case 1:
break;
}
- set_alex_rx_antenna();
- set_alex_attenuation();
if(can_transmit) {
- set_alex_tx_antenna();
tx_set_mode(transmitter,get_tx_mode());
//
// I do not think the band can change within this function.
active_receiver->nb2=mode_settings[m].nb2;
active_receiver->anf=mode_settings[m].anf;
active_receiver->snb=mode_settings[m].snb;
- enable_rx_equalizer =mode_settings[m].en_rxeq;
- rx_equalizer[0] =mode_settings[m].rxeq[0];
- rx_equalizer[1] =mode_settings[m].rxeq[1];
- rx_equalizer[2] =mode_settings[m].rxeq[2];
- rx_equalizer[3] =mode_settings[m].rxeq[3];
- enable_tx_equalizer =mode_settings[m].en_txeq;
- tx_equalizer[0] =mode_settings[m].txeq[0];
- tx_equalizer[1] =mode_settings[m].txeq[1];
- tx_equalizer[2] =mode_settings[m].txeq[2];
- tx_equalizer[3] =mode_settings[m].txeq[3];
// make changes effective
g_idle_add(ext_update_noise, NULL);
- g_idle_add(ext_update_eq , NULL);
switch(id) {
case 0:
receiver_mode_changed(receiver[0]);
if(receivers==2) {
receiver_vfo_changed(receiver[1]);
}
- set_alex_rx_antenna();
- set_alex_attenuation();
if(can_transmit) {
- set_alex_tx_antenna();
tx_set_mode(transmitter,get_tx_mode());
- calcDriveLevel(); // sends HighPrio packet if in new protocol
}
g_idle_add(ext_vfo_update,NULL);
}
vfo[VFO_A].rit_enabled=vfo[VFO_B].rit_enabled;
vfo[VFO_A].rit=vfo[VFO_B].rit;
receiver_vfo_changed(receiver[0]);
- set_alex_rx_antenna();
- set_alex_attenuation();
if(can_transmit) {
- set_alex_tx_antenna();
tx_set_mode(transmitter,get_tx_mode());
- calcDriveLevel(); // sends HighPrio packet if in new protocol
}
g_idle_add(ext_vfo_update,NULL);
}
if(receivers==2) {
receiver_vfo_changed(receiver[1]);
}
- set_alex_rx_antenna();
- set_alex_attenuation();
if(can_transmit) {
- set_alex_tx_antenna();
tx_set_mode(transmitter,get_tx_mode());
- calcDriveLevel(); // sends HighPrio packet if in new protocol
}
g_idle_add(ext_vfo_update,NULL);
}
if(can_transmit) {
cairo_move_to(cr, 330, 50);
if (transmitter->compressor) {
- sprintf(temp_text,"CMPR %d",(int) transmitter->compressor_level);
+ sprintf(temp_text,"CMPR %d dB",(int) transmitter->compressor_level);
cairo_set_source_rgb(cr, 1.0, 1.0, 0.0);
cairo_show_text(cr, temp_text);
} else {
cairo_show_text(cr, "CMPR OFF");
}
}
- //
- // Indicate whether an equalizer is active
- //
- cairo_move_to(cr, 400, 50);
- if ((isTransmitting() && enable_tx_equalizer) || (!isTransmitting() && enable_rx_equalizer)) {
- cairo_set_source_rgb(cr, 1.0, 1.0, 0.0);
- } else {
- cairo_set_source_rgb(cr, 0.7, 0.7, 0.7);
- }
- cairo_show_text(cr, "EQ");
cairo_move_to(cr, 500, 50);
if(diversity_enabled) {
//
// Store filter and NR settings on a per-mode basis
-// all elements are "on/off"
//
struct _mode_settings {
int filter;
- int nb; // Noise blanker #1
- int nb2; // Noise blanker #2
- int nr; // Noise reduction #1
- int nr2; // Noise reduction #2
- int anf; // Automatic notch filter
- int snb; // Spectral noise blanker
- int en_txeq; // TX equalizer on/off
- int en_rxeq; // RX equalizer on/off
- int txeq[4]; // TX equalizer settings
- int rxeq[4]; // RX equalizer settings
+ int nb;
+ int nb2;
+ int nr;
+ int nr2;
+ int anf;
+ int snb;
};
extern struct _mode_settings mode_settings[];