diff --git a/iopcomm/iopcomm.cpp b/iopcomm/iopcomm.cpp index 6931a95..ed2ff3a 100644 --- a/iopcomm/iopcomm.cpp +++ b/iopcomm/iopcomm.cpp @@ -104,13 +104,13 @@ void sendIOPSSBStatus(SSBConfig const &c) } //====================================================================== -// DIGI STATUS MESSAGE +// DGT STATUS MESSAGE //====================================================================== -void sendIOPDigiStatus(DigiConfig const &c) +void sendIOPDGTStatus(DGTConfig const &c) { IOPMessage m; - m.id = IOP_DIGI_STATUS_MSG; + m.id = IOP_DGT_STATUS_MSG; m.len = 4; m.data[0] = 'D'; // current mode; redundant w/ Raduino mode, but maybe useful for debugging m.data[1] = '-'; // placeholder for future digital submodes? diff --git a/iopcomm/iopcomm.h b/iopcomm/iopcomm.h index b40dd52..3721230 100644 --- a/iopcomm/iopcomm.h +++ b/iopcomm/iopcomm.h @@ -71,7 +71,7 @@ enum MessageID { // Requests IOP_MODE_REQUEST, IOP_SSB_STATUS_MSG, - IOP_DIGI_STATUS_MSG, + IOP_DGT_STATUS_MSG, IOP_CW_STATUS_MSG, IOP_TEST_STATUS_MSG, @@ -95,12 +95,16 @@ enum MessageID { */ enum RigMode { - RIG_MODE_SSB = 0, - RIG_MODE_DIGI, - RIG_MODE_CW, - RIG_MODE_TEST, - // add any new elements here - NUM_RIG_MODES + RIG_MODE_LSB = 0, + RIG_MODE_USB, + RIG_MODE_CWL, + RIG_MODE_CWU, + RIG_MODE_DGL, + RIG_MODE_DGU, + RIG_MODE_TTL, + RIG_MODE_TTU, + // add new items here + NUM_RIG_MODES }; /* Keyer modes. @@ -117,15 +121,15 @@ enum KeyerMode { }; enum RxFilter { - RX_FILTER_NORMAL = 0, + RX_FILTER_WIDE = 0, + RX_FILTER_MEDIUM, RX_FILTER_NARROW, - RX_FILTER_WIDE, NUM_RX_FILTERS }; -const unsigned char RIG_MODE_LETTER[NUM_RIG_MODES] = {'S', 'D', 'C', 'T'}; +const unsigned char RIG_MODE_LETTER[NUM_RIG_MODES] = {'s', 'S', 'c', 'C', 'd', 'D', 't', 'T'}; const unsigned char KEYER_MODE_LETTER[NUM_KEYER_MODES] = {'S', 'A', 'B'}; -const unsigned char RX_FILTER_LETTER[NUM_RX_FILTERS] = {'-', 'N', 'W'}; +const unsigned char RX_FILTER_LETTER[NUM_RX_FILTERS] = {'W', 'M', 'N'}; const uint8_t NO_FLAGS = 0; const uint8_t REVERSED = 1; @@ -137,28 +141,46 @@ struct IOPMessage { }; //====================================================================== -// SSB CONFIGURATION +// IConfig +// +// Interface to a configuration object. //====================================================================== -struct SSBConfig { - // parameters - RxFilter filter = RX_FILTER_NORMAL; +class IConfig { + public: + virtual ~IConfig() {} }; //====================================================================== -// DIGI CONFIGURATION +// SSB CONFIGURATION //====================================================================== -struct DigiConfig { +class SSBConfig : public IConfig { + public: + SSBConfig(RxFilter f): filter(f) {} // parameters - RxFilter filter = RX_FILTER_NORMAL; + RxFilter filter; // = RX_FILTER_MEDIUM; +}; + +//====================================================================== +// DGT CONFIGURATION +//====================================================================== + +class DGTConfig : public IConfig { + public: + DGTConfig(RxFilter f): filter(f) {} + // parameters + RxFilter filter = RX_FILTER_MEDIUM; }; //====================================================================== // CW CONFIGURATION //====================================================================== -struct CWConfig { +class CWConfig : public IConfig { + public: + CWConfig(KeyerMode m, bool rev, uint8_t w, float wt, uint16_t st, RxFilter f): + mode(m), reversed(rev), wpm(w), weight(wt), sidetone(st), filter(f) {} // mode KeyerMode mode = KEYER_MODE_IAMBIC_A; // flags @@ -167,7 +189,18 @@ struct CWConfig { uint8_t wpm = 15; float weight = 3.0; uint16_t sidetone = 700; - RxFilter filter = RX_FILTER_NORMAL; + RxFilter filter = RX_FILTER_MEDIUM; +}; + +//====================================================================== +// TT CONFIGURATION +//====================================================================== + +class TTConfig : public IConfig { + public: + TTConfig(RxFilter f): filter(f) {} + // parameters + RxFilter filter = RX_FILTER_MEDIUM; }; //====================================================================== @@ -184,7 +217,7 @@ void sendIOPStopTxCommand(); void sendIOPModeRequest(); void sendIOPSSBStatus(SSBConfig const&); -void sendIOPDigiStatus(DigiConfig const&); +void sendIOPDGTStatus(DGTConfig const&); void sendIOPCWStatus(CWConfig const&); void sendIOPTestStatus(); diff --git a/ubitx_iop/audio.h b/ubitx_iop/audio.h index be26d78..e26b811 100644 --- a/ubitx_iop/audio.h +++ b/ubitx_iop/audio.h @@ -1,5 +1,7 @@ //====================================================================== // audio.h +// +// NOTE: Let's change the name of this file to RigAudio.h. //====================================================================== #ifndef __iop_audio_h__ @@ -8,27 +10,41 @@ #include #include "config.h" -enum RxInput { - RX_RIG_IN = 0, - RX_USB_IN = 1, -}; +class RigAudio +{ + public: + RigAudio(AudioConfig& c): _config(c) {} -enum RxOutput { - RX_SPEAKER_OUT = 0, - RX_LINE_OUT = 1, - RX_USB_OUT = 2, -}; + void init() const; -enum TxInput { - TX_MIC_IN = -1, - TX_LINE_IN = 0, - TX_USB_IN = 1, - TX_TEST_IN = 2, -}; + void muteRx() const; + void unmuteRx() const; -enum TxOutput { - TX_RIG_OUT = 0, - TX_USB_OUT = 1, + void muteAllTx() const; + + void muteMicIn() const; + void unmuteMicIn() const; + + void muteLineIn() const; + void unmuteLineIn() const; + + void muteUSBIn() const; + void unmuteUSBIn() const; + + void muteTTIn() const; + void unmuteTTIn() const; + + void muteSpkrOut() const; + void unmuteSpkrOut() const; + + void muteLineOut() const; + void unmuteLineOut() const; + + void muteUSBOut() const; + void unmuteUSBOut() const; + + private: + AudioConfig _config; }; //====================================================================== @@ -60,11 +76,13 @@ class BPFilter { //====================================================================== +/* void audioInit(); void audioSelectTxInput(TxInput); void audioTransmit(); void audioReceive(); -void audioCalibrate(IOPConfig *, char, char, char, float, bool); +void audioCalibrate(AudioConfig *, char, char, char, float, bool); +*/ #endif diff --git a/ubitx_iop/audio.ino b/ubitx_iop/audio.ino index d6aab7e..13d8fb2 100644 --- a/ubitx_iop/audio.ino +++ b/ubitx_iop/audio.ino @@ -1,19 +1,37 @@ //====================================================================== // audio.ino +// +// NOTE: Let's change the name of this file to Rigconfig.cc. Will need +// to ensure that "Arduino-isms" are resolved if it's converted to .cc +// from .ino, however. //====================================================================== #include #include + #include "audio.h" #include "tx_audio_proc.h" -extern IOPConfig iopConfig; +short firActive[NUM_COEFFICIENTS]; +#define RX_RIG_IN 0 +#define RX_USB_IN 1 +#define RX_ST_IN 2 // sidetone + +#define TX_MIC_IN 0 +#define TX_LINE_IN 0 +#define TX_USB_IN 1 +#define TX_TEST_IN 2 + +//extern RigConfig rigConfig; + +/* #define DEFAULT_RX_INPUT RIG #define DEFAULT_RX_OUTPUT SPKR #define DEFAULT_TX_INPUT MIC #define DEFAULT_TX_OUTPUT RIG +*/ #include #include @@ -75,10 +93,167 @@ AudioConnection patchCord26(calTxUSB, 0, outUSB, 1); AudioControlSGTL5000 audioCtrl; //xy=648,517 // GUItool: end automatically generated code +void RigAudio::init() const { + USBDEBUG("audio initialization started"); + + audioCtrl.enable(); + audioCtrl.muteHeadphone(); // not using the headphone output + audioCtrl.volume(0.0); // not using the headphone output + audioCtrl.inputSelect(AUDIO_INPUT_LINEIN); // required for RX audio + audioCtrl.unmuteLineout(); // required for RX audio + + audioCtrl.lineInLevel(_config.rxRigInLevel, _config.txLineInLevel); // NOTE: need to see if this persists through input changes (see mic gain...) + audioCtrl.lineOutLevel(_config.rxLineOutLevel, _config.txRigOutLevel); // NOTE: need to see if this persists through input changes (see mic gain...) + audioCtrl.micGain(_config.txMicInGain); // superfluous, as I have to do this anytime I switch to mic for some reason + + // configure line input + audioCtrl.lineInLevel(_config.rxRigInLevel, _config.txLineInLevel); + + // configure line output + calTxLine.gain(_config.txRigOutCal); + audioCtrl.lineOutLevel(_config.rxLineOutLevel, _config.txRigOutLevel); + + // configure "receive" of USB audio input (debug only) + if (_config.rxUSBInEnable) { + mixRX.gain(RX_USB_IN, _config.rxUSBInVol * _config.rxUSBInCal); + } else { + mixRX.gain(RX_USB_IN, 0.0); + } + + // configure USB audio output of transmit audio (useful for debug) + if (_config.txUSBOutEnable) { + calTxUSB.gain(_config.txUSBOutCal); + } else { + calTxUSB.gain(0.0); + } + + // setup the two-tone generator + sine1.frequency(700); + sine2.frequency(1900); + sine1.amplitude(0); + sine2.amplitude(0); + + audioFilter(firActive, NUM_COEFFICIENTS, ID_BANDPASS, W_HAMMING, 300.0, 3100.0); // 2.8 kHz filter + filterRX.begin(firActive, NUM_COEFFICIENTS); + filterAmp.gain(1.0); + + // for now, just pass through the compressor + compTX.disable(); + compAmp.gain(1.0); + + // Hardware should be all setup... now we're going to mute everything + // and let the modes take care of enabling/disabling what they should. + for (int i = 0; i < 4; i++) { + mixRX.gain(i, 0.0); + mixTX.gain(i, 0.0); + } + + USBDEBUG("audio initialization completed"); +} + +void RigAudio::muteRx() const { + mixRX.gain(RX_RIG_IN, 0.0); + USBDEBUG("RX audio muted"); +} + +void RigAudio::unmuteRx() const { + audioCtrl.inputSelect(AUDIO_INPUT_LINEIN); + mixRX.gain(RX_RIG_IN, _config.rxRigInVol * _config.rxRigInCal); + USBDEBUG("RX audio unmuted"); +} + +void RigAudio::muteAllTx() const { + muteMicIn(); + muteLineIn(); + muteUSBIn(); + muteTTIn(); + USBDEBUG("all TX audio muted"); +} + +void RigAudio::muteMicIn() const { + mixTX.gain(TX_LINE_IN, 0.0); + USBDEBUG("Mic In audio muted"); +} + +void RigAudio::unmuteMicIn() const { + audioCtrl.inputSelect(AUDIO_INPUT_MIC); + audioCtrl.micGain(_config.txMicInGain); + mixTX.gain(TX_LINE_IN, _config.txMicInVol * _config.txMicInCal); + USBDEBUG("Mic In audio unmuted"); +} + +void RigAudio::muteLineIn() const { + mixTX.gain(TX_LINE_IN, 0.0); + USBDEBUG("Line In audio muted"); +} + +void RigAudio::unmuteLineIn() const { + audioCtrl.inputSelect(AUDIO_INPUT_LINEIN); + mixTX.gain(TX_LINE_IN, _config.txLineInVol * _config.txLineInCal); + USBDEBUG("Line In audio unmuted"); +} + +void RigAudio::muteUSBIn() const { + mixTX.gain(TX_USB_IN, 0.0); + USBDEBUG("USB In audio muted"); +} +void RigAudio::unmuteUSBIn() const { + mixTX.gain(TX_USB_IN, _config.txUSBInVol * _config.txUSBInCal); + USBDEBUG("USB In audio unmuted"); +} + +void RigAudio::muteTTIn() const { + mixTX.gain(TX_TEST_IN, 0.0); + mixTX.gain(TX_TEST_IN + 1, 0.0); + sine1.amplitude(0.0); + sine2.amplitude(0.0); + USBDEBUG("Two Tone audio muted"); +} + +void RigAudio::unmuteTTIn() const { + sine1.amplitude(0.5); + sine2.amplitude(0.5); + mixTX.gain(TX_TEST_IN, _config.txSine1Vol); + mixTX.gain(TX_TEST_IN + 1, _config.txSine2Vol); + USBDEBUG("Two Tone audio unmuted"); +} + +void RigAudio::muteSpkrOut() const { + calRxSpkr.gain(0.0); + USBDEBUG("Speaker Out audio muted"); +} + +void RigAudio::unmuteSpkrOut() const { + calRxSpkr.gain(_config.rxSpkrOutCal); + USBDEBUG("Speaker Out audio unmuted"); +} + +void RigAudio::muteLineOut() const { + calRxLine.gain(0.0); + USBDEBUG("Line Out audio muted"); +} + +void RigAudio::unmuteLineOut() const { + calRxLine.gain(_config.rxLineOutCal); + USBDEBUG("Line Out audio unmuted"); +} + +void RigAudio::muteUSBOut() const { + calRxUSB.gain(0.0); + USBDEBUG("USB Out audio muted"); +} + +void RigAudio::unmuteUSBOut() const { + calRxUSB.gain(_config.rxUSBOutCal); + USBDEBUG("USB Out audio unmuted"); +} + +/* RxInput audioRxInput; RxOutput audioRxOutput; TxInput audioTxInput; TxOutput audioTxOutput; +*/ //====================================================================== @@ -130,20 +305,13 @@ void BPFilter::update(AudioFilterFIR* filter=NULL, short* coefficients=NULL) { filter->begin(coefficients, NUM_COEFFICIENTS); } -static AudioFilterFIR* BPFilter::_filter = &filterRX; -static short BPFilter::_coefficients[NUM_COEFFICIENTS]; +AudioFilterFIR* BPFilter::_filter = &filterRX; +short BPFilter::_coefficients[NUM_COEFFICIENTS]; //====================================================================== - -enum FilterWidth { - FILTER_WIDE = 0, - FILTER_NORMAL, - FILTER_NARROW, - NUM_FILTER_WIDTHS -}; - +/* // array based on mode right now -BPFilter *rxFilter[NUM_RIG_MODES][NUM_FILTER_WIDTHS]; +BPFilter *rxFilter[NUM_RIG_MODES][NUM_RX_FILTERS]; //====================================================================== @@ -179,9 +347,9 @@ void audioInit() audioCtrl.volume(0.0); // not using the headphone output audioCtrl.inputSelect(AUDIO_INPUT_LINEIN); // required for RX audio audioCtrl.unmuteLineout(); // required for RX audio - audioCtrl.lineInLevel(iopConfig.rxRigInLevel, iopConfig.txLineInLevel); // NOTE: need to see if this persists through input changes (see mic gain...) - audioCtrl.lineOutLevel(iopConfig.rxLineOutLevel, iopConfig.txRigOutLevel); // NOTE: need to see if this persists through input changes (see mic gain...) - audioCtrl.micGain(iopConfig.txMicInGain); // superfluous, as I have to do this anytime I switch to mic for some reason + audioCtrl.lineInLevel(rigConfig.rxRigInLevel, rigConfig.txLineInLevel); // NOTE: need to see if this persists through input changes (see mic gain...) + audioCtrl.lineOutLevel(rigConfig.rxLineOutLevel, rigConfig.txRigOutLevel); // NOTE: need to see if this persists through input changes (see mic gain...) + audioCtrl.micGain(rigConfig.txMicInGain); // superfluous, as I have to do this anytime I switch to mic for some reason //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 @@ -220,293 +388,14 @@ void audioInit() speechCompressor.enable(); } -inline void updateRxRigIn() -{ - audioCtrl.lineInLevel(iopConfig.rxRigInLevel, iopConfig.txLineInLevel); - mixRX.gain(RX_RIG_IN, iopConfig.rxRigInVol * iopConfig.rxRigInCal); -} -inline void muteRxRigIn() -{ - mixRX.gain(RX_RIG_IN, 0.0); -} - -inline void restoreRxRigIn() -{ - mixRX.gain(RX_RIG_IN, iopConfig.rxRigInVol * iopConfig.rxRigInCal); -} - -inline void updateRxUSBIn() -{ - if (iopConfig.rxUSBInEnable) { - mixRX.gain(RX_USB_IN, iopConfig.rxUSBInVol * iopConfig.rxUSBInCal); - } else { - mixRX.gain(RX_USB_IN, 0.0); - } -} - -inline void muteRxUSBIn() -{ - mixRX.gain(RX_USB_IN, 0.0); -} - -inline void restoreRxUSBIn() -{ - updateRxUSBIn(); -} - -inline void updateRxSpkrOut() -{ - calRxSpkr.gain(iopConfig.rxSpkrOutCal); -} - -inline void updateRxLineOut() -{ - calRxLine.gain(iopConfig.rxLineOutCal); - audioCtrl.lineOutLevel(iopConfig.rxLineOutLevel, iopConfig.txRigOutLevel); -} - -inline void updateRxUSBOut() -{ - calRxUSB.gain(iopConfig.rxUSBOutCal); -} - -inline void updateTxMicIn() -{ - audioCtrl.micGain(iopConfig.txMicInGain); - mixTX.gain(TX_LINE_IN, iopConfig.txMicInVol * iopConfig.txMicInCal); -} - -inline void muteTxMicIn() -{ - mixTX.gain(TX_LINE_IN, 0.0); -} - -inline void restoreTxMicIn() -{ - mixTX.gain(TX_LINE_IN, iopConfig.txMicInVol * iopConfig.txMicInCal); -} - -inline void updateTxLineIn() -{ - audioCtrl.lineInLevel(iopConfig.rxRigInLevel, iopConfig.txLineInLevel); - mixTX.gain(TX_LINE_IN, iopConfig.txLineInVol * iopConfig.txLineInCal); -} - -inline void muteTxLineIn() -{ - mixTX.gain(TX_LINE_IN, 0.0); -} - -inline void restoreTxLineIn() -{ - mixTX.gain(TX_LINE_IN, iopConfig.txLineInVol * iopConfig.txLineInCal); -} - -inline void updateTxUSBIn() -{ - mixTX.gain(TX_USB_IN, iopConfig.txUSBInVol * iopConfig.txUSBInCal); -} - -inline void muteTxUSBIn() -{ - mixTX.gain(TX_USB_IN, 0.0); -} - -inline void restoreTxUSBIn() -{ - mixTX.gain(TX_USB_IN, iopConfig.txUSBInVol * iopConfig.txUSBInCal); -} - -inline void updateTxTwoToneIn() -{ - sine1.amplitude(0.5); - sine2.amplitude(0.5); - mixTX.gain(TX_TEST_IN, iopConfig.txSine1Vol); - mixTX.gain(TX_TEST_IN + 1, iopConfig.txSine2Vol); -} - -inline void muteTxTwoToneIn() -{ - mixTX.gain(TX_TEST_IN, 0.0); - mixTX.gain(TX_TEST_IN + 1, 0.0); - sine1.amplitude(0); - sine2.amplitude(0); -} - -inline void restoreTxTwoToneIn() -{ - sine1.amplitude(0.5); - sine2.amplitude(0.5); - mixTX.gain(TX_TEST_IN, iopConfig.txSine1Vol); - mixTX.gain(TX_TEST_IN + 1, iopConfig.txSine2Vol); -} - -inline void updateTxRigOut() -{ - calTxLine.gain(iopConfig.txRigOutCal); - audioCtrl.lineOutLevel(iopConfig.rxLineOutLevel, iopConfig.txRigOutLevel); -} - -inline void updateTxUSBOut() -{ - if (iopConfig.txUSBOutEnable) { - calTxUSB.gain(iopConfig.txUSBOutCal); - } else { - calTxUSB.gain(0.0); - } -} - -void audioSelectRxInput(RxInput input) -{ - if (audioRxInput != input) { - audioRxInput = input; - switch(input) { - case RX_RIG_IN: - muteRxUSBIn(); - restoreRxRigIn(); - mixRX.gain(2, 0); - mixRX.gain(3, 0); - break; - - case RX_USB_IN: - muteRxRigIn(); - restoreRxUSBIn(); - mixRX.gain(2, 0); - mixRX.gain(3, 0); - break; - } - } -} - -void audioSelectTxInput(TxInput input) -{ - if (audioTxInput != input) { - audioTxInput = input; - //muteTxMicIn(); // redundant w/ Line-In - muteTxLineIn(); - muteTxUSBIn(); - muteTxTwoToneIn(); -/* switch(input) { - case TX_MIC_IN: - muteTxUSBIn(); - restoreTxMicIn(); - break; - - case TX_LINE_IN: - muteTxUSBIn(); - restoreTxLineIn(); - break; - - case TX_USB_IN: - 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 -// sent to the Raduino, in order to ensure that any audio source -// transitions occur before transmission begins. -void audioTransmit() -{ - switch(rigMode) { - // Nothing special for CW, TX audio inputs are already muted. - //case RIG_MODE_CW: - //break; - - case RIG_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) { - audioCtrl.inputSelect(AUDIO_INPUT_MIC); - updateTxMicIn(); -#if defined(FACTORY_CALIBRATION) - USBSERIAL.println("=============================="); - USBSERIAL.println("Transmitting with Mic input"); - USBSERIAL.print("Mic gain: "); - USBSERIAL.println(iopConfig.txMicInGain); - USBSERIAL.print("Mic volume: "); - USBSERIAL.println(iopConfig.txMicInVol); - USBSERIAL.print("Mic calibration: "); - USBSERIAL.println(iopConfig.txMicInCal); - USBSERIAL.print("TX audio level: "); - USBSERIAL.println(iopConfig.txRigOutLevel); - USBSERIAL.print("TX audio calibration: "); - USBSERIAL.println(iopConfig.txRigOutCal); - USBSERIAL.println("=============================="); -#endif - } else if (audioTxInput == TX_LINE_IN) { - updateTxLineIn(); - } - break; - - case RIG_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; - - case RIG_MODE_TEST: - muteRxRigIn(); - updateTxTwoToneIn(); - 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 -// removed from the Raduino, in order to ensure that any audio source -// transitions occur before receive begins. -void audioReceive() -{ - switch(rigMode) { - //case RIG_MODE_CW: - //break; - - case RIG_MODE_SSB: - if (audioTxInput == TX_MIC_IN) { - muteTxMicIn(); - audioCtrl.inputSelect(AUDIO_INPUT_LINEIN); - } else if (audioTxInput == TX_LINE_IN) { - muteTxLineIn(); - } - restoreRxRigIn(); - break; - - case RIG_MODE_DIGI: - muteTxUSBIn(); - restoreRxRigIn(); - break; - - case RIG_MODE_TEST: - muteTxTwoToneIn(); - restoreRxRigIn(); - break; - } -} - -//====================================================================== - -void audioUpdate() -{ - speechCompressor.update(); -} - -//====================================================================== - -void audioCalibrate(IOPConfig* c, char cmd, char subcmd, char parm, float value, bool set_value=true) +void audioCalibrate(AudioConfig* c, char cmd, char subcmd, char parm, float value, bool set_value=true) { switch(cmd) { case 'r': @@ -807,7 +696,7 @@ void audioDigiFilter() audioCtrl.eqFilter(4, lpFilter); audioCtrl.eqFilter(5, hpFilter); } - +*/ //====================================================================== // EOF //====================================================================== diff --git a/ubitx_iop/cat.ino b/ubitx_iop/cat.ino index e4b4223..e4b709c 100644 --- a/ubitx_iop/cat.ino +++ b/ubitx_iop/cat.ino @@ -3,11 +3,15 @@ //====================================================================== #include "cat.h" +#include "TxSwitch.h" // make these messages static inside a function IOPMessage inBuf; // input message buffer IOPMessage outBuf; // output message buffer +extern CATSwitch catPTT; +extern Rig rig; + //====================================================================== // CAT from PC-to-IOP // @@ -50,20 +54,32 @@ void processIOPCommand(IOPMessage const& m) if (m.len < 1) { return; } else { - setRigMode(RigMode(m.data[0])); + rig.switchMode(RigMode(m.data[0])); #if defined(DEBUG) - switch(rigMode) { - case RIG_MODE_CW: - USBDEBUG("new mode - CW"); + switch(rig.modeNum()) { + case RIG_MODE_CWL: + USBDEBUG("new mode - CWL"); break; - case RIG_MODE_SSB: - USBDEBUG("new mode - SSB"); + case RIG_MODE_CWU: + USBDEBUG("new mode - CWU"); break; - case RIG_MODE_DIGI: - USBDEBUG("new mode - DIGI"); + case RIG_MODE_LSB: + USBDEBUG("new mode - LSB"); break; - case RIG_MODE_TEST: - USBDEBUG("new mode - TEST"); + case RIG_MODE_USB: + USBDEBUG("new mode - USB"); + break; + case RIG_MODE_DGL: + USBDEBUG("new mode - DGL"); + break; + case RIG_MODE_DGU: + USBDEBUG("new mode - DGU"); + break; + case RIG_MODE_TTL: + USBDEBUG("new mode - TTL"); + break; + case RIG_MODE_TTU: + USBDEBUG("new mode - TTU"); break; } #endif @@ -71,11 +87,11 @@ void processIOPCommand(IOPMessage const& m) break; case IOP_START_TX_COMMAND: - catPTTOn(); + catPTT.press(rig.mode()); break; case IOP_STOP_TX_COMMAND: - catPTTOff(); + catPTT.release(rig.mode()); break; case IOP_CW_CONFIG_MSG: @@ -103,7 +119,7 @@ void processCalCommand(const char* buf) case 'R': case 't': case 'T': - audioCalibrate(&iopConfig, cmd, subcmd, parm, value, (count == 4)); + //audioCalibrate(&rigConfig.audio, cmd, subcmd, parm, value, (count == 4)); break; default: diff --git a/ubitx_iop/config.h b/ubitx_iop/config.h index 90fefd2..4eeae57 100644 --- a/ubitx_iop/config.h +++ b/ubitx_iop/config.h @@ -1,11 +1,14 @@ //====================================================================== // config.h +// +// NOTE: Let's change the name of this file to RigConfig.h. //====================================================================== #ifndef __iop_config_h__ #define __iop_config_h__ #include +//#include "rig.h" #define KEYER_LEFT_PADDLE_PIN 16 #define KEYER_RIGHT_PADDLE_PIN 17 @@ -15,12 +18,16 @@ // There will be no pass-thru of any CAT. //#define FACTORY_CALIBRATION -// IOPConfig -// Used to store configuration parameters during runtime, as well as to -// save them to EEPROM. -struct IOPConfig { +//====================================================================== +// AudioConfig +//====================================================================== +class AudioConfig { + public: + + //-------------------------------------------------------------------- // RECEIVE PARAMETERS + //-------------------------------------------------------------------- // rig-in parameters (RX) uint8_t rxRigInLevel = 5; @@ -38,35 +45,43 @@ struct IOPConfig { // USB-out parameters (RX) float rxUSBOutCal = 1.0; + //-------------------------------------------------------------------- // TRANSMIT PARAMETERS + //-------------------------------------------------------------------- - // NOTE: Default rig-out parameters are based on trying to hit a 25mVrms output to the - // rig. This is based on some discussion at the following URL: + //-------------------------------------------------------------------- + // NOTE: Default rig-out parameters are based on trying to hit a + // 25mVrms output to the rig. This is based on some discussion at the + // following URL: // // https://groups.io/g/BITX20/message/58951 // - // This may or may not be totally applicable. I believe it was for IMD/spurs on a pre-V5 - // version of the uBITX. So it may be OBE for my V5. It also alludes to modifications - // to the transmit audio chain, which may be something I need to look into (i.e. increasing + // This may or may not be totally applicable. I believe it was for + // IMD/spurs on a pre-V5 version of the uBITX. So it may be OBE for + // my V5. It also alludes to modifications to the transmit audio + // chain, which may be something I need to look into (i.e. increasing // the gain on the initial mic pre-amp). // // Specifically, for the rig-out parameters: // line out level 31 = 1.16 V p-p // = 0.58 V peak // = 0.41 V rms = 410 mV rms - // so output calibration needs to reduce that to 17.5 mV rms (70% of 25 mV rms) + // so output calibration needs to reduce that to 17.5 mV rms (70% + // of 25 mV rms) // txMicInCal = 0.043 ... seems pretty low... // - // Likewise, default line-in (TX) parameters assume consumer line level - // input, but with the default audio adaptor line-in level setting (5 = 1.33V p-p). + // Likewise, default line-in (TX) parameters assume consumer line + // level input, but with the default audio adaptor line-in level + // setting (5 = 1.33V p-p). // line in level 5 = 1.33 V p-p // signal in = 0.894 V p-p // = 0.447 V peak // = 0.316 V rms = 316 mV rms - // so input calibration needs to convert that to the 410 mV noted above (equivalent - // for the microphone), so that when that signal gets to the rig-out, it gets - // treated the same as the mic input. + // so input calibration needs to convert that to the 410 mV noted + // above (equivalent for the microphone), so that when that signal + // gets to the rig-out, it gets treated the same as the mic input. // txLineInCal = 1.30 + //-------------------------------------------------------------------- // microphone-in parameters (TX) uint8_t txMicInGain = 12; @@ -88,18 +103,54 @@ struct IOPConfig { // USB-out parameters (TX)- debug/monitor use only bool txUSBOutEnable = true; float txUSBOutCal = 1.0; - - // SSB configuration - SSBConfig ssb; - - // Digi configuration - DigiConfig digi; - - // CW configuration - CWConfig cw; }; -extern IOPConfig iopConfig; +//====================================================================== +// RigConfig +// Used to store configuration parameters during runtime, as well as to +// save them to EEPROM. +//====================================================================== + +class RigConfig { + public: + // audio configuration + AudioConfig audio; + + // SSB configuration + SSBConfig lsb{RX_FILTER_WIDE}; + SSBConfig usb{RX_FILTER_WIDE}; + + // DGT configuration + DGTConfig dgl{RX_FILTER_WIDE}; + DGTConfig dgu{RX_FILTER_WIDE}; + + // CW configuration + CWConfig cwl{ + KEYER_MODE_IAMBIC_A, + false, + 15, + 3.0, + 700, + RX_FILTER_WIDE, + }; + CWConfig cwu{ + KEYER_MODE_IAMBIC_A, + false, + 15, + 3.0, + 700, + RX_FILTER_WIDE, + }; + + // TT configuration + TTConfig ttl{RX_FILTER_WIDE}; + TTConfig ttu{RX_FILTER_WIDE}; + + // General rig configuration entries. + RigMode mode = RIG_MODE_LSB; +}; + +extern RigConfig rigConfig; #endif diff --git a/ubitx_iop/ubitx_iop.h b/ubitx_iop/ubitx_iop.h index 6769ad6..efbd3ce 100644 --- a/ubitx_iop/ubitx_iop.h +++ b/ubitx_iop/ubitx_iop.h @@ -11,8 +11,10 @@ #include "eeprom.h" #include "keyer.h" +#define PTT_KEY_OUT_PIN 2 + // comment this out to disable debugging code -//#define DEBUG +#define DEBUG #if defined(DEBUG) #define USBDEBUG(x) USBSERIAL.print("IOP: "); USBSERIAL.println(x); @@ -34,10 +36,35 @@ enum TxState { TX_KEYER, }; -extern RigMode rigMode; +//extern RigMode rigMode; extern bool keyerKeyDown; +//====================================================================== +// Keying functions. +// +// These are simple functions to assert the key line from the IOP to the +// Raduino. +//====================================================================== + +inline void initKeyLine() +{ + pinMode(PTT_KEY_OUT_PIN, OUTPUT); + digitalWrite(PTT_KEY_OUT_PIN, HIGH); +} + +inline void setKeyDown() +{ + digitalWrite(PTT_KEY_OUT_PIN, LOW); +} + +inline void setKeyUp() +{ + digitalWrite(PTT_KEY_OUT_PIN, HIGH); +} + +//====================================================================== + #endif //====================================================================== diff --git a/ubitx_iop/ubitx_iop.ino b/ubitx_iop/ubitx_iop.ino index 0c74b62..097c871 100644 --- a/ubitx_iop/ubitx_iop.ino +++ b/ubitx_iop/ubitx_iop.ino @@ -3,340 +3,175 @@ //====================================================================== #include +#include "audio.h" +#include "config.h" #include "ubitx_iop.h" +#include "keyer.h" +#include "rig.h" +#include "TxSwitch.h" -#include -#define BOUNCE_WITH_PROMPT_DETECTION +Keyer keyer{15, 3.0}; // NOTE: make configurable -RigMode rigMode = RIG_MODE_SSB; -//RxFilter rxFilter = RX_FILTER_NORMAL; -IOPConfig iopConfig; +RigConfig rigConfig; +RigAudio rigAudio{rigConfig.audio}; +Rig rig{rigConfig, rigAudio}; -#define MIC_PTT_PIN 21 -#define LINE_PTT_PIN 20 -#define PTT_KEY_OUT_PIN 2 +CATSwitch catPTT; +//MicSwitch micPTTHelper; +GPIOSwitch micPTT(true, MIC_PTT_PIN); +//LineSwitch linePTTHelper; +GPIOSwitch linePTT(false, LINE_PTT_PIN); -Bounce micPTT = Bounce(); -Bounce linePTT = Bounce(); - -TxState txState = TX_OFF; - -Keyer keyer(15, 3.0); // need to make configurable - -//SSBMenu ssbMenu(); -//DigiMenu digiMenu(); -//CWMenu cwMenu(); -//MenuItem* dspMenu = &ssbMenu; +elapsedMillis frameMillis; +unsigned frameCounter; //====================================================================== -// catPTTOn() -// -// NOTE: Should probably move this to cat.ino. -//====================================================================== - -void catPTTOn() -{ - // 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 RIG_MODE_CW: - //break; - - case RIG_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 RIG_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 RIG_MODE_CW: - //break; - - case RIG_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 RIG_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()) { - USBDEBUG("mic PTT released"); - 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 != RIG_MODE_CW) audioReceive(); - txState = TX_OFF; - return; - } - - if ((txState == TX_OFF) && micPTT.fell()) { - USBDEBUG("mic PTT depressed"); - switch(rigMode) { - case RIG_MODE_CW: - txState = TX_MIC; - digitalWrite(PTT_KEY_OUT_PIN, LOW); - break; - - case RIG_MODE_SSB: - txState = TX_MIC; - audioSelectTxInput(TX_MIC_IN); - audioTransmit(); - digitalWrite(PTT_KEY_OUT_PIN, LOW); - break; - - case RIG_MODE_DIGI: - // Mic PTT actuation during Digital does nothing. - break; - - case RIG_MODE_TEST: - txState = TX_MIC; - audioSelectTxInput(TX_TEST_IN); - audioTransmit(); - digitalWrite(PTT_KEY_OUT_PIN, LOW); - 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 != RIG_MODE_CW) audioReceive(); - txState = TX_OFF; - return; - } - - if ((txState == TX_OFF) && linePTT.fell()) { - switch(rigMode) { - case RIG_MODE_CW: - txState = TX_LINE; - digitalWrite(PTT_KEY_OUT_PIN, LOW); - break; - - case RIG_MODE_SSB: - txState = TX_LINE; - audioSelectTxInput(TX_LINE_IN); - audioTransmit(); - digitalWrite(PTT_KEY_OUT_PIN, LOW); - break; - - case RIG_MODE_DIGI: - // Line PTT actuation during Digital does nothing. - break; - - case RIG_MODE_TEST: - txState = TX_LINE; - audioSelectTxInput(TX_TEST_IN); - audioTransmit(); - digitalWrite(PTT_KEY_OUT_PIN, LOW); - break; - } - } -} - -//====================================================================== - -void setRigMode(RigMode m) -{ - rigMode = m; - - switch(rigMode) { - case RIG_MODE_SSB: - case RIG_MODE_TEST: - // 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(); -// dspMenu = &ssbMenu; - break; - - case RIG_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(); -// dspMenu = &digiMenu; - break; - - case RIG_MODE_CW: - // CW just gets the radio off of Mic-In; but it won't use Line-In. - audioSelectTxInput(TX_LINE_IN); -// audioCWFilter(); -// dspMenu = &cwMenu; - break; - } -} - -//====================================================================== - -//elapsedMillis frame10hz = 0; void setup() { // put your setup code here, to run once: initCAT(38400, SERIAL_8N1); + USBDEBUG("setup started"); - AudioMemory(16); + AudioMemory(20); // NOTE: Need to fine tune this. Have had errors due to this being too low. - micPTT.attach(MIC_PTT_PIN, INPUT_PULLUP); - micPTT.interval(25); - linePTT.attach(LINE_PTT_PIN, INPUT_PULLUP); - linePTT.interval(25); + initKeyLine(); + rigAudio.init(); - pinMode(PTT_KEY_OUT_PIN, OUTPUT); - digitalWrite(PTT_KEY_OUT_PIN, HIGH); + frameCounter = 0; + frameMillis = 0; - audioInit(); + USBDEBUG("setup completed"); +// audioInit(); +/* #if defined(FACTORY_CALIBRATION) setRigMode(RIG_MODE_TEST); #else setRigMode(RIG_MODE_SSB); #endif - - //frame10Hz = 0; +*/ } //====================================================================== -void loop() { -// elapsedMillis elapsed = 0; - RigMode oldRigMode = rigMode; - //RxFilter oldRxFilter = rxFilter; +void loop() +{ + static char frame_status[100]; + static bool paddle_loop = false; - switch(rigMode) { - case RIG_MODE_CW: + RigMode oldRigMode; + + frameCounter++; + + if (rig.isCWMode()) { if (keyer.do_paddles()) { - if (keyer.is_down()) { - digitalWrite(PTT_KEY_OUT_PIN, LOW); - } else { - digitalWrite(PTT_KEY_OUT_PIN, HIGH); + + // Checking for T/R separately from the paddle loop, because it's + // possible we're already transmitting (PTT/Key being held), and + // we don't want to run the tx() actions if we're already in TX. + if (rig.isRx()) { + USBDEBUG("entered TX via paddles"); + rig.tx(); } - // No break... if the paddle is not active, I want this to fall - // through to checkMicPTT etc... but return early if the paddle is - // active, to maximize responsiveness. Probably could just use - // 'if' statements here instead of the 'switch'. - return; - } - default: - checkMicPTT(); - checkLinePTT(); - serviceCAT(); + paddle_loop = true; + + if (keyer.is_down()) { + setKeyDown(); + } else { + setKeyUp(); + } + + return; // return early for paddle responsiveness + } else { + if (paddle_loop) { + // If we exit the paddle loop (i.e. keyer completes its keying + // sequence), then we'll go back to receive, even if one of the + // PTT/Key lines is still held separately. General principle is + // that if "something" stops transmitting, then the rig will + // stop transmitting. + paddle_loop = false; + rig.rx(); + USBDEBUG("exited TX from paddles"); + } + } } + rig.update(); + + oldRigMode = rig.modeNum(); + + // Update the mic PTT. We need to tell it if we're in SSB mode, so that + // it knows if it should switch to the mic input if pressed. We also + // need to make it inactive if we're in DGT mode, since only CAT will be + // used to start transmitting in that case. + micPTT.setSSBMode(rig.isSSBMode()); + micPTT.update(rig.mode(), !rig.isDGTMode()); + + // Update the line PTT. We need to tell it if we're in SSB mode, so that + // it knows if it should switch to the line input if pressed. We also + // need to make it inactive if we're in DGT mode, since only CAT will be + // used to start transmitting in that case. + linePTT.setSSBMode(rig.isSSBMode()); + linePTT.update(rig.mode(), !rig.isDGTMode()); + + serviceCAT(); + // send current status @ 10 Hz //if (frame10Hz > 100) { - if ((rigMode != oldRigMode)) { // || (rxFilter != oldRxFilter)) { - switch(rigMode) { - case RIG_MODE_SSB: - sendIOPSSBStatus(iopConfig.ssb); + if ((rig.modeNum() != oldRigMode)) { // || (rxFilter != oldRxFilter)) { + USBDEBUG("mode changed"); + switch(rig.modeNum()) { + case RIG_MODE_LSB: + USBDEBUG("sending LSB mode status"); + sendIOPSSBStatus(rigConfig.lsb); break; - case RIG_MODE_DIGI: - sendIOPDigiStatus(iopConfig.digi); + case RIG_MODE_USB: + USBDEBUG("sending USB mode status"); + sendIOPSSBStatus(rigConfig.usb); break; - case RIG_MODE_CW: - sendIOPCWStatus(iopConfig.cw); + case RIG_MODE_DGL: + USBDEBUG("sending DGL mode status"); + sendIOPDGTStatus(rigConfig.dgl); break; - case RIG_MODE_TEST: + case RIG_MODE_DGU: + USBDEBUG("sending DGU mode status"); + sendIOPDGTStatus(rigConfig.dgu); + break; + + case RIG_MODE_CWL: + USBDEBUG("sending CWL mode status"); + sendIOPCWStatus(rigConfig.cwl); + break; + + case RIG_MODE_CWU: + USBDEBUG("sending CWU mode status"); + sendIOPCWStatus(rigConfig.cwu); + break; + + case RIG_MODE_TTL: + USBDEBUG("sending TTL mode status"); sendIOPTestStatus(); + break; + + case RIG_MODE_TTU: + USBDEBUG("sending TTU mode status"); + sendIOPTestStatus(); + break; } //frame10Hz = 0; } - audioUpdate(); - //dspMenu->update(); - -/* - #if defined(DEBUG) - int frame_skews = 0; // for debugging; see how often we skew frames - #endif - - // put your main code here, to run repeatedly: - - // Run at a nominal 20 Hz frame rate. - #if defined(DEBUG) - if (frame_timer > 50) { - frame_skews += 1; - } - #endif - while (frame_timer < 50) { // this doesn't seem like a good way to do this + if (frameMillis > 1000) { + #if defined(DEBUG) + sprintf(frame_status, "update: %d ms, %d frames\n", frameMillis, frameCounter); + USBDEBUG(frame_status); + #endif } -*/ + + //audioUpdate(); // was used to update the speech compressor } //======================================================================