From 57c97d9f9847a262117cdf148ae6702059aa311e Mon Sep 17 00:00:00 2001 From: Rob French Date: Fri, 8 May 2020 00:19:07 -0500 Subject: [PATCH] Working with Raduino! High pitched whine in RX audio. Goes away when USB unplugged. Not immediate, so not a ground loop... seems to be associated with one of my mixers... --- ubitx_iop/audio.ino | 146 ++++++++++++++++------ ubitx_iop/cat.ino | 34 ++++- ubitx_iop/ubitx_iop.h | 8 ++ ubitx_iop/ubitx_iop.ino | 268 ++++++++++++++++++++++++++++++---------- 4 files changed, 343 insertions(+), 113 deletions(-) diff --git a/ubitx_iop/audio.ino b/ubitx_iop/audio.ino index 8fc4509..2de479d 100644 --- a/ubitx_iop/audio.ino +++ b/ubitx_iop/audio.ino @@ -75,9 +75,10 @@ void audioInit() //audioCtrl.dacVolumeRamp(); // if this seems too slow, might try dacVolumeRampLinear(). //audioCtrl.dacVolume(1.0, 0.0); // we're going to mute TX audio via the DAC unless we're transmitting + audioSelectRxInput(RX_RIG_IN); audioSelectTxInput(TX_MIC_IN); // superfluous I think - audioCWFilterNarrow(); // test + audioCtrl.audioPreProcessorEnable(); } inline void updateRxRigIn() @@ -105,6 +106,16 @@ inline void updateRxUSBIn() } } +inline void muteRxUSBIn() +{ + mixRX.gain(RX_USB_IN, 0.0); +} + +inline void restoreRxUSBIn() +{ + updateRxUSBIn(); +} + inline void updateRxSpkrOut() { calRxSpkr.gain(iopConfig.rxSpkrOutCal); @@ -183,11 +194,32 @@ inline void updateTxUSBOut() } } +void audioSelectRxInput(RxInput input) +{ + if (audioRxInput != input) { + audioRxInput = input; + switch(input) { + case RX_RIG_IN: + muteRxUSBIn(); + restoreRxRigIn(); + break; + + case RX_USB_IN: + muteRxRigIn(); + restoreRxUSBIn(); + break; + } + } +} + void audioSelectTxInput(TxInput input) { if (audioTxInput != input) { audioTxInput = input; - switch(input) { + //muteTxMicIn(); // redundant w/ Line-In + muteTxLineIn(); + muteTxUSBIn(); +/* switch(input) { case TX_MIC_IN: muteTxUSBIn(); restoreTxMicIn(); @@ -202,10 +234,12 @@ void audioSelectTxInput(TxInput input) muteTxLineIn(); restoreTxUSBIn(); break; - } + }*/ } } +//====================================================================== + // audioTransmit() // This should be called anytime transmit mode is entered. It should // in theory be called BEFORE the actual transmit signal (key/PTT) is @@ -213,23 +247,17 @@ void audioSelectTxInput(TxInput input) // transitions occur before transmission begins. void audioTransmit() { - if (rigMode == MODE_SSB || rigMode == MODE_DIGI) { - // First we're going to set the RX and TX audio DAC volumes to - // zero while we change other mixer settings, to try to use the - // DAC's volume ramping to minimize pops. - // NOTE: Might need to add a brief delay? - //audioCtrl.dacVolume(0.0, 0.0); - - // Next mute the incoming RX audio. Can't think of a good reason + switch(rigMode) { + // Nothing special for CW, TX audio inputs are already muted. + //case MODE_CW: + //break; + + case MODE_SSB: + // Mute the incoming RX audio. Can't think of a good reason // to let RX audio in while we're transmitting. muteRxRigIn(); if (audioTxInput == TX_MIC_IN) { - // Mute the TX line in in this case, too, because we need to - // switch over to the mic input. - muteTxLineIn(); - - // Now switch to the mic input, and set the mic gain. audioCtrl.inputSelect(AUDIO_INPUT_MIC); updateTxMicIn(); #if defined(FACTORY_CALIBRATION) @@ -247,14 +275,22 @@ void audioTransmit() USBSERIAL.println(iopConfig.txRigOutCal); USBSERIAL.println("=============================="); #endif + } else if (audioTxInput == TX_LINE_IN) { + updateTxLineIn(); } + break; - // Allow both transmit and receive audio output channels. This is safe - // because the RX input is muted, and we might want to inject something else. - //audioCtrl.dacVolume(1.0, 1.0); + case MODE_DIGI: + // Mute the incoming RX audio. Can't think of a good reason + // to let RX audio in while we're transmitting. + muteRxRigIn(); + updateTxUSBIn(); + break; } } +//====================================================================== + // audioReceive() // This should be called anytime receive mode is entered. It should // in theory be called AFTER the actual transmit signal (key/PTT) is @@ -262,27 +298,24 @@ void audioTransmit() // transitions occur before receive begins. void audioReceive() { - if (rigMode == MODE_SSB || rigMode == MODE_DIGI) { - // First we're going to set the RX and TX audio DAC volumes to - // zero while we switch inputs, because the DAC volumes can be - // smoothly ramped by the SGTL5000 to avoid pops. - //audioCtrl.dacVolume(0.0, 0.0); - - // Mute the mic, since we're going to be switching back to line - // input for RX and TX. + switch(rigMode) { + //case MODE_CW: + //break; + + case MODE_SSB: if (audioTxInput == TX_MIC_IN) { muteTxMicIn(); - - // Now switch to the line input, and restore mixer settings. - audioCtrl.inputSelect(AUDIO_INPUT_LINEIN); - restoreTxLineIn(); + audioCtrl.inputSelect(AUDIO_INPUT_LINEIN); + } else if (audioTxInput == TX_LINE_IN) { + muteTxLineIn(); } - restoreRxRigIn(); + break; - // Now bring back up the DAC volumes. Hopefully this reduced pops... - // When going back to receive, we leave transmit DAC at zero. - //audioCtrl.dacVolume(1.0, 0.0); + case MODE_DIGI: + muteTxUSBIn(); + restoreRxRigIn(); + break; } } @@ -540,15 +573,46 @@ void audioCalibrate(IOPConfig* c, char cmd, char subcmd, char parm, float value, } } -int updateFilter[5]; +int lpFilter[5]; +int hpFilter[5]; -void audioCWFilterNarrow() +void audioSSBFilter() { - audioCtrl.audioPreProcessorEnable(); // calcBiquad(FilterType,FrequencyC,dBgain,Q,QuantizationUnit,SampleRate,int*); - calcBiquad(FILTER_BANDPASS, 700, 0, 2, 524288, 44100, updateFilter); - audioCtrl.eqFilter(0, updateFilter); - audioCtrl.eqFilter(1, updateFilter); + calcBiquad(FILTER_LOPASS, 3100, 0, 0.707, 524288, 44100, lpFilter); + calcBiquad(FILTER_HIPASS, 300, 0, 0.707, 524288, 44100, hpFilter); + audioCtrl.eqFilter(0, lpFilter); + audioCtrl.eqFilter(1, hpFilter); + audioCtrl.eqFilter(2, lpFilter); + audioCtrl.eqFilter(3, hpFilter); + audioCtrl.eqFilter(4, lpFilter); + audioCtrl.eqFilter(5, hpFilter); +} + +void audioCWFilter() +{ + // calcBiquad(FilterType,FrequencyC,dBgain,Q,QuantizationUnit,SampleRate,int*); + calcBiquad(FILTER_LOPASS, 700, 0, 0.707, 524288, 44100, lpFilter); + calcBiquad(FILTER_HIPASS, 300, 0, 0.707, 524288, 44100, hpFilter); + audioCtrl.eqFilter(0, lpFilter); + audioCtrl.eqFilter(1, hpFilter); + audioCtrl.eqFilter(2, lpFilter); + audioCtrl.eqFilter(3, hpFilter); + audioCtrl.eqFilter(4, lpFilter); + audioCtrl.eqFilter(5, hpFilter); +} + +void audioDigiFilter() +{ + // calcBiquad(FilterType,FrequencyC,dBgain,Q,QuantizationUnit,SampleRate,int*); + calcBiquad(FILTER_LOPASS, 3100, 0, 0.707, 524288, 44100, lpFilter); + calcBiquad(FILTER_HIPASS, 300, 0, 0.707, 524288, 44100, hpFilter); + audioCtrl.eqFilter(0, lpFilter); + audioCtrl.eqFilter(1, hpFilter); + audioCtrl.eqFilter(2, lpFilter); + audioCtrl.eqFilter(3, hpFilter); + audioCtrl.eqFilter(4, lpFilter); + audioCtrl.eqFilter(5, hpFilter); } //====================================================================== diff --git a/ubitx_iop/cat.ino b/ubitx_iop/cat.ino index fa37ff2..a07978b 100644 --- a/ubitx_iop/cat.ino +++ b/ubitx_iop/cat.ino @@ -10,10 +10,12 @@ #define EEPROM_READ_PREFIX 0xE0 #define EEPROM_WRITE_PREFIX 0xF0 -#define IOP_MODE_COMMAND 0x00 -#define IOP_MODE_SSB 0x01 -#define IOP_MODE_DIGI 0x02 -#define IOP_MODE_CW 0x03 +#define IOP_MODE_COMMAND 0x00 +#define IOP_START_TX_COMMAND 0x01 +#define IOP_STOP_TX_COMMAND 0x02 +#define IOP_MODE_SSB 0x00 +#define IOP_MODE_DIGI 0x01 +#define IOP_MODE_CW 0x02 //====================================================================== // CAT from PC-to-IOP @@ -55,9 +57,31 @@ void processIOPCommand(const byte* buf, int len) if (len < 2) { return; } else { - rigMode = RigMode(buf[1]); + setRigMode(RigMode(buf[1])); + #if defined(DEBUG) + USBSERIAL.print("DEBUG: mode "); + switch(rigMode) { + case MODE_CW: + USBSERIAL.println("CW"); + break; + case MODE_SSB: + USBSERIAL.println("SSB"); + break; + case MODE_DIGI: + USBSERIAL.println("DIGI"); + break; + } + #endif } break; + + case IOP_START_TX_COMMAND: + catPTTOn(); + break; + + case IOP_STOP_TX_COMMAND: + catPTTOff(); + break; } } } diff --git a/ubitx_iop/ubitx_iop.h b/ubitx_iop/ubitx_iop.h index 06207ac..018e2d1 100644 --- a/ubitx_iop/ubitx_iop.h +++ b/ubitx_iop/ubitx_iop.h @@ -19,6 +19,14 @@ enum RigMode { MODE_CW = 2, }; +enum TxState { + TX_OFF = 0, + TX_MIC, + TX_LINE, + TX_CAT, + TX_KEYER, +}; + extern RigMode rigMode; #endif diff --git a/ubitx_iop/ubitx_iop.ino b/ubitx_iop/ubitx_iop.ino index 3d539f7..af884d0 100644 --- a/ubitx_iop/ubitx_iop.ino +++ b/ubitx_iop/ubitx_iop.ino @@ -17,59 +17,208 @@ IOPConfig iopConfig; Bounce micPTT = Bounce(); Bounce linePTT = Bounce(); -bool micPTT_active = false; -bool linePTT_active = false; +TxState txState = TX_OFF; -void checkPTT() +//====================================================================== +// catPTTOn() +// +// NOTE: Should probably move this to cat.ino. +//====================================================================== + +void catPTTOn() { - // Update the PTT lines. USB/DIGI is not part of this. CW should work, however. - micPTT.update(); - linePTT.update(); - if (rigMode == MODE_SSB || rigMode == MODE_CW) { - if (micPTT_active) { - // ignore line PTT; just wait for release of mic PTT - if (micPTT.rose()) { - digitalWrite(PTT_KEY_OUT_PIN, HIGH); - audioReceive(); - micPTT_active = false; - } - } else if (linePTT_active) { - // ignore mic PTT; just wait for release of line PTT - if (linePTT.rose()) { - digitalWrite(PTT_KEY_OUT_PIN, HIGH); - audioReceive(); - linePTT_active = false; - } - } else { - // Whichever PTT source was last active, will determine the TX audio source. - if (micPTT.fell()) { - audioSelectTxInput(TX_MIC_IN); - micPTT_active = true; - audioTransmit(); - digitalWrite(PTT_KEY_OUT_PIN, LOW); - } else if (linePTT.fell()) { - audioSelectTxInput(TX_LINE_IN); - linePTT_active = true; - audioTransmit(); - digitalWrite(PTT_KEY_OUT_PIN, LOW); - } - } - } - - #if defined(DEBUG) - if (micPTT.fell()) { - USBSERIAL.println("Mic PTT pressed!"); - } else if (micPTT.rose()) { - USBSERIAL.println("Mic PTT released!"); - } - if (linePTT.fell()) { - USBSERIAL.println("Line PTT pressed!"); - } else if (linePTT.rose()) { - USBSERIAL.println("Line PTT released!"); - } - #endif + // Check if we're already transmitting. If so, then this command + // does nothing: existing transmission, from existing source and PTT, + // will continue. + if (txState != TX_OFF) return; + + switch(rigMode) { + // CAT should not start or stop TX in CW mode... we really should + // not even get this command. But maybe the rig control software is + // doing it (but then, we should inhibit this in the Raduino). + //case MODE_CW: + //break; + + case MODE_SSB: + // In SSB mode, CAT-PTT will always (de-)activate the Line-In TX + // audio source. + txState = TX_CAT; + audioSelectTxInput(TX_LINE_IN); // in case Mic-In is selected + audioTransmit(); + digitalWrite(PTT_KEY_OUT_PIN, LOW); + break; + + case MODE_DIGI: + // In Digital (USB) mode, CAT-PTT will always (de-)activate the + // USB-In TX audio source. + txState = TX_CAT; + audioTransmit(); + digitalWrite(PTT_KEY_OUT_PIN, LOW); + break; + } } +//====================================================================== +// catPTTOff() +// +// NOTE: Should probably move this to cat.ino. +//====================================================================== + +void catPTTOff() +{ + // If we're not transmitting, or the active PTT is not CAT, then this + // command does nothing: CAT cannot interrupt other transmissions. + if (txState != TX_CAT) return; + + switch(rigMode) { + // CAT should not start or stop TX in CW mode... we really should + // not even get this command. But maybe the rig control software is + // doing it (but then, we should inhibit this in the Raduino). + //case MODE_CW: + //break; + + case MODE_SSB: + // In SSB mode, CAT-PTT will always (de-)activate the Line-In TX + // audio source. + digitalWrite(PTT_KEY_OUT_PIN, HIGH); + audioReceive(); + txState = TX_OFF; + break; + + case MODE_DIGI: + // In Digital (USB) mode, CAT-PTT will always (de-)activate the + // USB-In TX audio source. + digitalWrite(PTT_KEY_OUT_PIN, HIGH); + audioReceive(); + txState = TX_OFF; + break; + } +} + +//====================================================================== +// checkMicPTT() +//====================================================================== + +void checkMicPTT() +{ + micPTT.update(); + + // If we're transmitting, then we're just going to check if Mic-PTT + // was released--the Mic-PTT can always be used to terminate a + // transmission from another source. + if ((txState != TX_OFF) && micPTT.rose()) { + #if defined(DEBUG) + USBSERIAL.println("DEBUG: mic PTT released"); + #endif + digitalWrite(PTT_KEY_OUT_PIN, HIGH); + // In CW mode, we get a sidetone from the uBITX, so we don't mute + // the receive audio. + if (rigMode != MODE_CW) audioReceive(); + txState = TX_OFF; + return; + } + + if ((txState == TX_OFF) && micPTT.fell()) { + #if defined(DEBUG) + USBSERIAL.println("DEBUG: mic PTT depressed"); + #endif + switch(rigMode) { + case MODE_CW: + txState = TX_MIC; + digitalWrite(PTT_KEY_OUT_PIN, LOW); + break; + + case MODE_SSB: + txState = TX_MIC; + audioSelectTxInput(TX_MIC_IN); + audioTransmit(); + digitalWrite(PTT_KEY_OUT_PIN, LOW); + break; + + case MODE_DIGI: + // Mic PTT actuation during Digital does nothing. + break; + } + } +} + +//====================================================================== +// checkLinePTT() +//====================================================================== + +void checkLinePTT() +{ + linePTT.update(); + + // If we're transmitting, then we're just going to check if Line-PTT + // was released--the Line-PTT can always be used to terminate a + // transmission from another source. + if ((txState != TX_OFF) && linePTT.rose()) { + digitalWrite(PTT_KEY_OUT_PIN, HIGH); + // In CW mode, we get a sidetone from the uBITX, so we don't mute + // the receive audio. + if (rigMode != MODE_CW) audioReceive(); + txState = TX_OFF; + return; + } + + if ((txState == TX_OFF) && linePTT.fell()) { + switch(rigMode) { + case MODE_CW: + txState = TX_LINE; + digitalWrite(PTT_KEY_OUT_PIN, LOW); + break; + + case MODE_SSB: + txState = TX_LINE; + audioSelectTxInput(TX_LINE_IN); + audioTransmit(); + digitalWrite(PTT_KEY_OUT_PIN, LOW); + break; + + case MODE_DIGI: + // Line PTT actuation during Digital does nothing. + break; + } + } +} + +//====================================================================== + +void setRigMode(RigMode m) +{ + rigMode = m; + + switch(rigMode) { + case MODE_SSB: + // SSB sets the TX audio input to line-in. Note that this will be + // automatically overridden by mic-in, if the mic PTT is pressed. + audioSelectTxInput(TX_LINE_IN); + audioSSBFilter(); + break; + + case MODE_DIGI: + // Digi sets the TX audio input to USB-in. Keying in this case must + // be via CAT control. Digital modes can also be used through the + // line-in, but the rig mode should be set to SSB in that case, and + // the rig could be keyed either via the line-in PTT, or via CAT. + // Digimodes could also be used through the mic-in, but in that case, + // the mic PTT line would need to be keyed by the computer rather + // than using CAT for PTT control. + audioSelectTxInput(TX_USB_IN); + audioDigiFilter(); + break; + + case MODE_CW: + // CW just gets the radio off of Mic-In; but it won't use Line-In. + audioSelectTxInput(TX_LINE_IN); + audioCWFilter(); + break; + } +} + +//====================================================================== + void setup() { // put your setup code here, to run once: initCAT(38400, SERIAL_8N1); @@ -85,23 +234,7 @@ void setup() { digitalWrite(PTT_KEY_OUT_PIN, HIGH); audioInit(); -} - -//====================================================================== - -void setRigMode(RigMode m) -{ - rigMode = m; - switch(rigMode) { - case MODE_SSB: - break; - - case MODE_DIGI: - break; - - case MODE_CW: - break; - } + setRigMode(MODE_SSB); } //====================================================================== @@ -109,7 +242,8 @@ void setRigMode(RigMode m) void loop() { elapsedMillis frame_timer = 0; - checkPTT(); + checkMicPTT(); + checkLinePTT(); serviceCAT(); /* #if defined(DEBUG)