From a2054e50167b9b34ae4d4febadd7cb73dd555b57 Mon Sep 17 00:00:00 2001 From: c vw Date: Wed, 15 May 2019 10:26:24 +0200 Subject: [PATCH] Intermediat commit to make it visible to someone asking for this --- discovered.h | 2 +- mac_midi.c | 38 ++++++++++++------ midi2.c | 2 +- midi3.c | 3 +- old_discovery.c | 63 +++++++++++++++++++++++++----- old_protocol.c | 102 +++++++++++++++++++++++++++++++++--------------- ps_menu.c | 42 +++++++++++++++++--- radio.c | 22 ++++++++++- receiver.c | 40 ++++++++++++------- receiver.h | 7 ++++ rx_menu.c | 36 +++++++++-------- sliders.c | 2 - 12 files changed, 264 insertions(+), 95 deletions(-) diff --git a/discovered.h b/discovered.h index 7e66b5b..7c14ec0 100644 --- a/discovered.h +++ b/discovered.h @@ -34,7 +34,7 @@ #define DEVICE_ANGELIA 4 #define DEVICE_ORION 5 #define DEVICE_HERMES_LITE 6 -// 8000DLE uses 10 as the device type in old protocol +// ANAN 7000DLE and 8000DLE uses 10 as the device type in old protocol #define DEVICE_ORION2 10 // Newer STEMlab hpsdr emulators use 100 instead of 1 #define DEVICE_STEMLAB 100 diff --git a/mac_midi.c b/mac_midi.c index ad9885b..06c84ca 100644 --- a/mac_midi.c +++ b/mac_midi.c @@ -5,13 +5,21 @@ * This is the "Layer-1" for Apple Macintosh. * * This file implements the function register_midi_device, - * which is called with the name of a supported MIDI device and - * the number of characters in the name that must be equal to - * the name of the MIDI device as known in the operating system. + * which is called with the name of a supported MIDI device. + * This name may be truncated: For example, the call + * register_midi_device("COMPANY MIDI") + * will accept both "COMPANY MIDI X" and "COMPANY MIDI Y" devices. * - * For example, the call - * register_midi_device("COMPANY MIDI X",13) - * will also use a MIDI device named "COMPANY MIDI Y". + * If more than one MIDI device matches the name, the LAST ONE + * found will be taken. This may not be predictable, so it is + * better to say that one of the matching MIDI devices will be taken. + * It is easy to change the code such that ALL devices matching the + * name will be taken. But who cares? Normally there will only be a + * single MIDI controller connected to the computer running the SDR + * program. + * + * The name is actually specified by the user in the midi.inp file + * (see midi2.c) * * This file must generate calls to Layer-2 NewMidiEvent(). * Some type of messages are not consideres (pressure change, etc.), @@ -23,6 +31,12 @@ #ifdef __APPLE__ +/* + * For MacOS, things are easy: + * The OS takes care of everything, we only have to register a callback + * routine. + */ + #include #include @@ -31,6 +45,9 @@ // // MIDI callback function +// called by MacOSX when data from the specified MIDI device arrives. +// We process *all* data but only generate calls to layer-2 for Note On/Off +// and ControllerChange events. // static void ReadMIDIdevice(const MIDIPacketList *pktlist, void *refCon, void *connRefCon) { int i,j,k,command,chan; @@ -49,12 +66,12 @@ static void ReadMIDIdevice(const MIDIPacketList *pktlist, void *refCon, void *co switch (command & 0xF0) { case 0x80: // Note off NewMidiEvent(MIDI_NOTE, chan, packet->data[i+1], 0); - fprintf(stderr,"NOTE OFF: Note=%d Chan=%d Vel=%d\n", packet->data[i+1], chan, packet->data[i+2]); + //fprintf(stderr,"NOTE OFF: Note=%d Chan=%d Vel=%d\n", packet->data[i+1], chan, packet->data[i+2]); i +=3; break; case 0x90: // Note on NewMidiEvent(MIDI_NOTE, chan, packet->data[i+1], 1); - fprintf(stderr,"NOTE ON : Note=%d Chan=%d Vel=%d\n", packet->data[i+1], chan, packet->data[i+2]); + //fprintf(stderr,"NOTE ON : Note=%d Chan=%d Vel=%d\n", packet->data[i+1], chan, packet->data[i+2]); i +=3; break; case 0xA0: // Polyph. Press. @@ -63,7 +80,7 @@ static void ReadMIDIdevice(const MIDIPacketList *pktlist, void *refCon, void *co break; case 0xB0: // Control change NewMidiEvent(MIDI_CTRL, chan, packet->data[i+1], packet->data[i+2]); - fprintf(stderr,"CtlChang: Ctrl=%d Chan=%d Val=%d\n", packet->data[i+1], chan, packet->data[i+2]); + //fprintf(stderr,"CtlChang: Ctrl=%d Chan=%d Val=%d\n", packet->data[i+1], chan, packet->data[i+2]); i +=3; break; case 0xC0: // Program change @@ -76,7 +93,7 @@ static void ReadMIDIdevice(const MIDIPacketList *pktlist, void *refCon, void *co break; case 0xE0: // Pitch Bend NewMidiEvent(MIDI_PITCH, chan, 0, packet->data[i+1] + 128*packet->data[i+2]); - fprintf(stderr,"Pitch : val =%d Chan=%d\n", packet->data[i+1] + 128*packet->data[i+2], chan); + //fprintf(stderr,"Pitch : val =%d Chan=%d\n", packet->data[i+1] + 128*packet->data[i+2], chan); i +=3; break; case 0xF0: @@ -120,7 +137,6 @@ void register_midi_device(char *myname) { FoundMIDIref=i; fprintf(stderr,"MIDI device found and selected: >>>%s<<<\n", name); } else { - fprintf(stderr,"MIDI device we were looking for : >>>%s<<<\n", myname); fprintf(stderr,"MIDI device found BUT NOT SELECTED: >>>%s<<<\n", name); } } diff --git a/midi2.c b/midi2.c index 1e737c1..377a86e 100644 --- a/midi2.c +++ b/midi2.c @@ -67,7 +67,7 @@ void NewMidiEvent(enum MIDIevent event, int channel, int note, int val) { DoTheMidi(desc->action, desc->type, new); } break; - default: + case EVENT_NONE: break; } break; diff --git a/midi3.c b/midi3.c index f3989d0..8e0c33f 100644 --- a/midi3.c +++ b/midi3.c @@ -226,7 +226,8 @@ void DoTheMidi(enum MIDIaction action, enum MIDItype type, int val) { break; } break; - default: + case COMPRESS: + case ACTION_NONE: fprintf(stderr,"Unimplemented in DoTheMidi: A=%d T=%d val=%d\n", action, type, val); break; } diff --git a/old_discovery.c b/old_discovery.c index 235ca12..3704bb5 100644 --- a/old_discovery.c +++ b/old_discovery.c @@ -32,6 +32,7 @@ #include #include #include +#include #include "discovered.h" #include "discovery.h" @@ -56,6 +57,11 @@ static void discover(struct ifaddrs* iface) { struct sockaddr_in to_addr={0}; int flags; struct timeval tv; + int optval; + socklen_t optlen; + fd_set fds; + unsigned char buffer[1032]; + int i, len; if (iface == NULL) { // @@ -80,20 +86,59 @@ static void discover(struct ifaddrs* iface) { return; } // - // We make a time-out of 3 secs, otherwise we might "hang" in connect() + // Here I tried a bullet-proof approach to connect() such that the program + // does not "hang" under any circumstances. + // - First, one makes the socket non-blocking. Then, the connect() will + // immediately return with error EINPROGRESS. + // - Then, one uses select() to look for *writeability* and check + // the socket error if everything went right. Since one calls select() + // with a time-out, one either succeed within this time or gives up. + // - Do not forget to make the socket blocking again. // + // Step 1. Make socket non-blocking and connect() flags=fcntl(discovery_socket, F_GETFL, 0); fcntl(discovery_socket, F_SETFL, flags | O_NONBLOCK); + rc=connect(discovery_socket, (const struct sockaddr *)&to_addr, sizeof(to_addr)); + if ((errno != EINPROGRESS) && (rc < 0)) { + perror("discover: connect() failed for TCP discovery_socket:"); + close(discovery_socket); + return; + } + // Step 2. Use select to wait for the connection tv.tv_sec=3; tv.tv_usec=0; - setsockopt(discovery_socket, SOL_SOCKET, SO_RCVTIMEO, (void *)&tv, sizeof(tv)); - - - if (connect(discovery_socket, (const struct sockaddr *)&to_addr, sizeof(to_addr)) < 0) { - perror("discover: connect() failed for TCP discovery_socket:"); + FD_ZERO(&fds); + FD_SET(discovery_socket, &fds); + rc=select(discovery_socket+1, NULL, &fds, NULL, &tv); + if (rc < 0) { + perror("discover: select() failed on TCP discovery_socket:"); + close(discovery_socket); + return; + } + // If no connection occured, return + if (rc == 0) { + // select timed out + fprintf(stderr,"discover: select() timed out on TCP discovery socket\n"); close(discovery_socket); return; } + // Step 3. select() succeeded. Check success of connect() + optlen=sizeof(int); + rc=getsockopt(discovery_socket, SOL_SOCKET, SO_ERROR, &optval, &optlen); + if (rc < 0) { + // this should very rarely happen + perror("discover: getsockopt() failed on TCP discovery_socket:"); + close(discovery_socket); + return; + } + if (optval != 0) { + // connect did not succeed + fprintf(stderr,"discover: connect() on TCP socket did not succeed\n"); + close(discovery_socket); + return; + } + // Step 4. reset the socket to normal (blocking) mode + fcntl(discovery_socket, F_SETFL, flags & ~O_NONBLOCK); } else { strcpy(interface_name,iface->ifa_name); @@ -135,7 +180,7 @@ static void discover(struct ifaddrs* iface) { to_addr.sin_port=htons(DISCOVERY_PORT); to_addr.sin_addr.s_addr=htonl(INADDR_BROADCAST); } - int optval = 1; + optval = 1; setsockopt(discovery_socket, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval)); setsockopt(discovery_socket, SOL_SOCKET, SO_REUSEPORT, &optval, sizeof(optval)); @@ -152,13 +197,11 @@ static void discover(struct ifaddrs* iface) { // send discovery packet // If this is a TCP connection, send a "long" packet - unsigned char buffer[1032]; - int len=63; + len=63; if (iface == NULL) len=1032; buffer[0]=0xEF; buffer[1]=0xFE; buffer[2]=0x02; - int i; for(i=3;isample_rate) { @@ -912,7 +917,6 @@ void ozy_send_buffer() { output_buffer[C2]|=band->OCrx<<1; } -// TODO - add Alex Antenna output_buffer[C3] = (receiver[0]->alex_attenuation) & 0x03; // do not set higher bits if(active_receiver->random) { output_buffer[C3]|=LT2208_RANDOM_ON; @@ -933,19 +937,25 @@ void ozy_send_buffer() { output_buffer[C3]|=LT2208_GAIN_ON; } - switch(receiver[0]->alex_antenna) { + i=receiver[0]->alex_antenna; +#ifdef PURESIGNAL + // + // Upon TX, we might have to activate a different RX path for the + // attenuated feedback signal. Use feedback_antenna == 0, if + // the feedback signal is routed automatically/internally (e.g. + // ANAN-7000DLE, when using the internal feedback path). + // + if (isTransmitting() && transmitter->puresignal) i=receiver[PS_RX_FEEDBACK]->feedback_antenna; +#endif + switch(i) { case 0: // ANT 1 - break; case 1: // ANT 2 - break; case 2: // ANT 3 break; - case 3: // EXT 1 - //output_buffer[C3]|=0xA0; + case 3: // Alex: RX2 IN, ANAN: EXT1, ANAN7000: EXT output_buffer[C3]|=0xC0; break; - case 4: // EXT 2 - //output_buffer[C3]|=0xC0; + case 4: // Alex: RX1 IN, ANAN: EXT2, ANAN7000: RX BYPASS output_buffer[C3]|=0xA0; break; case 5: // XVTR @@ -959,8 +969,10 @@ void ozy_send_buffer() { // TODO - add Alex TX relay, duplex, receivers Mercury board frequency output_buffer[C4]=0x04; // duplex #ifdef PURESIGNAL - nreceivers=(RECEIVERS*2)-1; - nreceivers+=1; // for PS TX Feedback + // DL1YCF: see comment on "nreceivers" above. The number is reduced by 1 here + nreceivers=2; + if (device == DEVICE_HERMES) nreceivers=3; + if (device == DEVICE_ANGELIA || device == DEVICE_ORION || device == DEVICE_ORION2) nreceivers=4; #else #ifdef RADIOBERRY nreceivers = receivers-1; @@ -969,6 +981,7 @@ void ozy_send_buffer() { #endif #endif + // 0 ... 7 maps on 1 ... 8 receivers output_buffer[C4]|=nreceivers<<3; if(isTransmitting()) { @@ -1014,6 +1027,10 @@ void ozy_send_buffer() { } } } else { + // + // metis_offset !=8: send "command" C&C packets in round-robin + // using the value of "command" from 1 to 10, + // and "command==2" packets are repeated for each RX switch(command) { case 1: // tx frequency output_buffer[C0]=0x02; @@ -1038,7 +1055,10 @@ void ozy_send_buffer() { break; case 2: // rx frequency #ifdef PURESIGNAL - nreceivers=(RECEIVERS*2)+1; + // DL1YCF: see comment on "nreceivers" above. + nreceivers=3; + if (device == DEVICE_HERMES) nreceivers=4; + if (device == DEVICE_ANGELIA || device == DEVICE_ORION || device == DEVICE_ORION2) nreceivers=5; #else #ifdef RADIOBERRY nreceivers = receivers; @@ -1175,28 +1195,30 @@ void ozy_send_buffer() { } #endif output_buffer[C3]=0x00; + output_buffer[C4]=0x00; if(radio->device==DEVICE_HERMES || radio->device==DEVICE_ANGELIA || radio->device==DEVICE_ORION || radio->device==DEVICE_ORION2) { - output_buffer[C4]=0x20|adc_attenuation[receiver[0]->adc]; + // DL1YCF: if attenuation is zero, then disable attenuator + i = adc_attenuation[receiver[0]->adc] & 0x1F; + if (i >0) output_buffer[C4]=0x20| i; } else { #ifdef RADIOBERRY - int att = 63 - rx_gain_slider[active_receiver->adc]; + int att = 63 - rx_gain_slider[active_receiver->adc]; output_buffer[C4]=0x20|att; -#else - output_buffer[C4]=0x00; #endif } break; case 5: - // need to add adc 2 and 3 attenuation output_buffer[C0]=0x16; output_buffer[C1]=0x00; if(receivers==2) { if(radio->device==DEVICE_HERMES || radio->device==DEVICE_ANGELIA || radio->device==DEVICE_ORION || radio->device==DEVICE_ORION2) { - output_buffer[C1]=0x20|adc_attenuation[receiver[1]->adc]; + // DL1YCF: if attenuation is zero, then disable attenuator + i = adc_attenuation[receiver[1]->adc] & 0x1F; + if (i > 0) output_buffer[C1]=0x20|i; } } - output_buffer[C2]=0x00; + output_buffer[C2]=0x00; // ADC3 attenuator disabled. if(cw_keys_reversed!=0) { output_buffer[C2]|=0x40; } @@ -1208,12 +1230,30 @@ void ozy_send_buffer() { output_buffer[C0]=0x1C; output_buffer[C1]=0x00; #ifdef PURESIGNAL - output_buffer[C1]|=receiver[0]->adc; - output_buffer[C1]|=(receiver[0]->adc<<2); - output_buffer[C1]|=receiver[1]->adc<<4; - output_buffer[C1]|=(receiver[1]->adc<<6); + + // The whole setup here implicitly assumes + // that receiver[0]->adc is 0 and receiver[1]->adc is 1 + + // This is the correct setting for DEVICE_METIS and DEVICE_HERMES + output_buffer[C1]|=receiver[0]->adc; // RX1 bound to ADC0 + output_buffer[C1]|=(receiver[0]->adc<<2); // RX2 bound to ADC0 + output_buffer[C1]|=receiver[1]->adc<<4; // RX3 bound to ADC1 + + // DL1YCF: + // For Orion, Angelia and OrionMk2 RX4 must show the FeedBack signal. + // In most cases this is routed back to RX1 so we need ADC0 for RX4 + // Since I could test this only on my ANAN7000, I changed to code + // to associate RX4 with ADC0 only on Orion2 -- but I guess this will + // be necessary for other SDRs as well. + + if (device == DEVICE_ORION2) { + output_buffer[C1]|=(receiver[0]->adc<<6); // This works on ANAN7000 + } else { + output_buffer[C1]|=(receiver[1]->adc<<6); // Does this work for somebody? + } output_buffer[C2]=0x00; if(transmitter->puresignal) { + // This should not be necessary since RX5 is hard-wired to the TX DAC on TX output_buffer[C2]|=receiver[2]->adc; } #else @@ -1263,14 +1303,14 @@ void ozy_send_buffer() { output_buffer[C0]=0x24; output_buffer[C1]=0x00; if(isTransmitting()) { - output_buffer[C1]|=0x80; // ground RX1 on transmit + output_buffer[C1]|=0x80; // ground RX2 on transmit, bit0-6 are Alex2 filters } output_buffer[C2]=0x00; if(receiver[0]->alex_antenna==5) { // XVTR - output_buffer[C2]=0x02; + output_buffer[C2]=0x02; // Alex2 XVTR enable } - output_buffer[C3]=0x00; - output_buffer[C4]=0x00; + output_buffer[C3]=0x00; // Alex2 filters + output_buffer[C4]=0x00; // Alex2 filters break; } diff --git a/ps_menu.c b/ps_menu.c index d6d5924..9312459 100644 --- a/ps_menu.c +++ b/ps_menu.c @@ -227,11 +227,12 @@ static int info_thread(gpointer arg) { switch(state) { case 0: if(newcal && (info[4]>181 || (info[4]<=128 && transmitter->attenuation>0))) { - ddb= 20.0 * log10((double)info[4]/152.293); - if(isnan(ddb)) { - // this means feedback lvl is < 1, switch OFF attenuation - ddb=-100.0; - } + if (info[4] > 0) { + ddb= 20.0 * log10((double)info[4]/152.293); + } else { + // This happens when the "Drive" slider is moved to zero + ddb= -100.0; + } new_att=transmitter->attenuation + (int)ddb; // keep new value of attenuation in allowed range if (new_att < 0) new_att= 0; @@ -263,6 +264,12 @@ static int info_thread(gpointer arg) { return TRUE; } +static void ps_ant_cb(GtkWidget *widget, gpointer data) { + if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget))) { + receiver[PS_RX_FEEDBACK]->feedback_antenna = (int) (uintptr_t) data; + } +} + static void enable_cb(GtkWidget *widget, gpointer data) { g_idle_add(ext_tx_set_ps,(gpointer)(long)gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget))); } @@ -358,7 +365,6 @@ void ps_menu(GtkWidget *parent) { set_button_text_color(twotone_b,"red"); } - col++; GtkWidget *auto_b=gtk_check_button_new_with_label("Auto Attenuate"); @@ -392,6 +398,30 @@ void ps_menu(GtkWidget *parent) { row++; col=0; + GtkWidget *ps_ant_label=gtk_label_new("PS FeedBk ANT:"); + gtk_widget_show(ps_ant_label); + gtk_grid_attach(GTK_GRID(grid), ps_ant_label, col, row, 1, 1); + col++; + + GtkWidget *ps_ant_auto=gtk_radio_button_new_with_label(NULL,"AUTO"); + gtk_widget_show(ps_ant_auto); + gtk_grid_attach(GTK_GRID(grid), ps_ant_auto, col, row, 1, 1); + g_signal_connect(ps_ant_auto,"toggled", G_CALLBACK(ps_ant_cb), (gpointer) (long) 0); + col++; + + GtkWidget *ps_ant_ext1=gtk_radio_button_new_with_label_from_widget(GTK_RADIO_BUTTON(ps_ant_auto),"EXT1"); + gtk_widget_show(ps_ant_ext1); + gtk_grid_attach(GTK_GRID(grid), ps_ant_ext1, col, row, 1, 1); + g_signal_connect(ps_ant_ext1,"toggled", G_CALLBACK(ps_ant_cb), (gpointer) (long) 3); + col++; + + GtkWidget *ps_ant_ext2=gtk_radio_button_new_with_label_from_widget(GTK_RADIO_BUTTON(ps_ant_auto),"EXT2"); + gtk_widget_show(ps_ant_ext2); + gtk_grid_attach(GTK_GRID(grid), ps_ant_ext2, col, row, 1, 1); + g_signal_connect(ps_ant_ext2,"toggled", G_CALLBACK(ps_ant_cb), (gpointer) (long) 4); + + row++; + col=0; feedback_l=gtk_label_new("Feedback Lvl"); gtk_widget_show(feedback_l); gtk_grid_attach(GTK_GRID(grid),feedback_l,col,row,1,1); diff --git a/radio.c b/radio.c index b47623e..b4ccf88 100644 --- a/radio.c +++ b/radio.c @@ -352,7 +352,7 @@ static gboolean minimize_cb (GtkWidget *widget, GdkEventButton *event, gpointer } static gboolean menu_cb (GtkWidget *widget, GdkEventButton *event, gpointer data) { - new_menu(top_window); + new_menu(); return TRUE; } @@ -1014,6 +1014,21 @@ static int calcLevel(double d) { level=(int)(actual_volts*255.0); +#ifdef __APPLE__ +#ifdef PURESIGNAL +// +// DL1YCF: I do not know exactly why: if the drive level +// is set to zero while PS is active, the program +// reproducably crashes when the drive is set from 1 Watt +// to 0 Watt, possibly a division by zero or the evaluation +// of a logarithm within WDSP. +// QuickAndDirty Fix: use "1" as minimum drive level +// which corresponds to a fraction of a Watt. +// + if (level < 1) level=1; +#endif +#endif + //fprintf(stderr,"calcLevel: %f calib=%f level=%d\n",d, gbb, level); return level; } @@ -1482,6 +1497,11 @@ void radioSaveState() { for(i=0;iwindow, event->device, &x, &y, &state); - // DL1YCF added a pair of () to fix an error - if(((state & GDK_BUTTON1_MASK) == GDK_BUTTON1_MASK) || pressed) { + if(state & GDK_BUTTON1_MASK) { int moved=last_x-x; vfo_move((long long)((float)moved*rx->hz_per_pixel)); last_x=x; @@ -198,6 +199,11 @@ void receiver_save_state(RECEIVER *rx) { sprintf(value,"%d",rx->waterfall_automatic); setProperty(name,value); +#ifdef PURESIGNAL + sprintf(name,"receiver.%d.feedback_antenna",rx->id); + sprintf(value,"%d",rx->feedback_antenna); + setProperty(name,value); +#endif sprintf(name,"receiver.%d.alex_antenna",rx->id); sprintf(value,"%d",rx->alex_antenna); setProperty(name,value); @@ -306,15 +312,9 @@ fprintf(stderr,"receiver_restore_state: id=%d\n",rx->id); sprintf(name,"receiver.%d.sample_rate",rx->id); value=getProperty(name); if(value) rx->sample_rate=atoi(value); -#ifdef STEMLAB_FIX - // HPSDR apps on the RedPitay have hard-wired connections - // that should not be changed - fprintf(stderr,"STEMLAB: ignoring ADC settings for RX%d\n",rx->id); -#else sprintf(name,"receiver.%d.adc",rx->id); value=getProperty(name); if(value) rx->adc=atoi(value); -#endif sprintf(name,"receiver.%d.filter_low",rx->id); value=getProperty(name); if(value) rx->filter_low=atoi(value); @@ -360,6 +360,11 @@ fprintf(stderr,"receiver_restore_state: id=%d\n",rx->id); value=getProperty(name); if(value) rx->waterfall_automatic=atoi(value); +#ifdef PURESIGNAL + sprintf(name,"receiver.%d.feedback_antenna",rx->id); + value=getProperty(name); + if(value) rx->feedback_antenna=atoi(value); +#endif sprintf(name,"receiver.%d.alex_antenna",rx->id); value=getProperty(name); if(value) rx->alex_antenna=atoi(value); @@ -774,6 +779,9 @@ fprintf(stderr,"create_pure_signal_receiver: id=%d buffer_size=%d\n",id,buffer_s rx->volume=0.0; + rx->squelch_enable=0; + rx->squelch=0; + rx->dither=0; rx->random=0; rx->preamp=0; @@ -790,6 +798,7 @@ fprintf(stderr,"create_pure_signal_receiver: id=%d buffer_size=%d\n",id,buffer_s rx->nr2_npe_method=0; rx->nr2_ae=1; + rx->feedback_antenna=0; rx->alex_antenna=0; rx->alex_attenuation=0; @@ -808,6 +817,9 @@ fprintf(stderr,"create_pure_signal_receiver: id=%d buffer_size=%d\n",id,buffer_s rx->low_latency=0; + // not much to be restored, except feedback_antenna + if (id == PS_RX_FEEDBACK) receiver_restore_state(rx); + int result; XCreateAnalyzer(rx->id, &result, 262144, 1, 1, ""); if(result != 0) { @@ -867,12 +879,6 @@ fprintf(stderr,"create_receiver: id=%d buffer_size=%d fft_size=%d pixels=%d fps= } break; } -#ifdef STEMLAB_FIX -// -// RedPitaya based HPSDR apps have hard-wired adc settings -// - if (id == 1) rx->adc=1; -#endif } fprintf(stderr,"create_receiver: id=%d default ddc=%d adc=%d\n",rx->id, rx->ddc, rx->adc); rx->sample_rate=48000; @@ -925,6 +931,10 @@ fprintf(stderr,"create_receiver: id=%d default ddc=%d adc=%d\n",rx->id, rx->ddc, rx->nr2_npe_method=0; rx->nr2_ae=1; +#ifdef PURESIGNAL + rx->feedback_antenna=0; +#endif + BAND *b=band_get_band(vfo[rx->id].band); rx->alex_antenna=b->alexRxAntenna; rx->alex_attenuation=b->alexAttenuation; diff --git a/receiver.h b/receiver.h index 39bf084..52970ca 100644 --- a/receiver.h +++ b/receiver.h @@ -89,6 +89,13 @@ typedef struct _receiver { int alex_antenna; int alex_attenuation; +#ifdef PURESIGNAL + // indicates to which ALEX RX antenna the attenuated feedback + // signal from the PA goes. The coding is the same as for alex_antenna, + // except that this connector is only used when transmitting. + int feedback_antenna; +#endif + int filter_low; int filter_high; diff --git a/rx_menu.c b/rx_menu.c index 528284a..2445bdf 100644 --- a/rx_menu.c +++ b/rx_menu.c @@ -59,7 +59,6 @@ static gboolean delete_event(GtkWidget *widget, GdkEvent *event, gpointer user_d static void dither_cb(GtkWidget *widget, gpointer data) { active_receiver->dither=active_receiver->dither==1?0:1; - update_att_preamp(); } static void random_cb(GtkWidget *widget, gpointer data) { @@ -68,7 +67,6 @@ static void random_cb(GtkWidget *widget, gpointer data) { static void preamp_cb(GtkWidget *widget, gpointer data) { active_receiver->preamp=active_receiver->preamp==1?0:1; - update_att_preamp(); } static void alex_att_cb(GtkWidget *widget, gpointer data) { @@ -238,9 +236,17 @@ void rx_menu(GtkWidget *parent) { break; #endif } - + + // // The CHARLY25 board (with RedPitaya) has no support for dither or random, - // so those are left out. PreAmps and Alex Attenuator are controlled via sliders. + // so those are left out. For Charly25, PreAmps and Alex Attenuator are controlled via + // the sliders menu. + // On SDRs other than CHARLY25, preamps or Alex attenuators may be present or not, and we + // do not try to find out whether they are. This would overload the code, and we then + // also must have a menu to check e.g. which ANAN model is actually present. + // Instead, we offer these checkboxes in either case and must rely on the user + // not playing around with features that are not there. + // if (filter_board != CHARLY25) { switch(protocol) { case ORIGINAL_PROTOCOL: @@ -256,17 +262,11 @@ void rx_menu(GtkWidget *parent) { gtk_grid_attach(GTK_GRID(grid),random_b,x,3,1,1); g_signal_connect(random_b,"toggled",G_CALLBACK(random_cb),NULL); - if((protocol==ORIGINAL_PROTOCOL && device==DEVICE_METIS) || -#ifdef USBOZY - (protocol==ORIGINAL_PROTOCOL && device==DEVICE_OZY) || -#endif - (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); + g_signal_connect(preamp_b,"toggled",G_CALLBACK(preamp_cb),NULL); - 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); - g_signal_connect(preamp_b,"toggled",G_CALLBACK(preamp_cb),NULL); - } GtkWidget *alex_att_label=gtk_label_new("Alex Attenuator"); gtk_grid_attach(GTK_GRID(grid), alex_att_label, x, 5, 1, 1); GtkWidget *last_alex_att_b = NULL; @@ -287,12 +287,13 @@ void rx_menu(GtkWidget *parent) { } } + // Number of ADCs. int n_adc=1; switch(protocol) { case ORIGINAL_PROTOCOL: switch(device) { case DEVICE_METIS: - n_adc=1; // FIX for multiple Mercury cards + n_adc=1; // No support for multiple MERCURY cards on a single ATLAS bus. break; case DEVICE_HERMES: case DEVICE_HERMES_LITE: @@ -306,7 +307,7 @@ void rx_menu(GtkWidget *parent) { case NEW_PROTOCOL: switch(device) { case NEW_DEVICE_ATLAS: - n_adc=1; // FIX for multiple Mercury cards + n_adc=1; // No support for multiple MERCURY cards on a single ATLAS bus. break; case NEW_DEVICE_HERMES: case NEW_DEVICE_HERMES2: @@ -322,6 +323,9 @@ void rx_menu(GtkWidget *parent) { break; } + // If there is more than one ADC, let the user associate an ADC + // with the current receiver. Note: for PURESIGNAL, ADC0 has to + // be associated with the first receiver. if(n_adc>1) { for(i=0;ipreamp + active_receiver->dither); gtk_combo_box_set_active_id(GTK_COMBO_BOX(c25_preamp_combobox), id); - } else { - adc_attenuation[active_receiver->adc] = 10*active_receiver->alex_attenuation; } } -- 2.45.2