From f724142fca68845d13bae75e68c56d8341e45bec Mon Sep 17 00:00:00 2001 From: Rob French Date: Tue, 16 Mar 2021 18:37:14 -0500 Subject: [PATCH] Updated DSP. Compiles, no warnings/errors. Going to do some work on CAT. --- TeensyDSP/DSP.cpp | 181 ++++++++++++++++---------------- TeensyDSP/DSP.h | 249 +++++++++++++++++++++++--------------------- TeensyDSP/TS590.cpp | 10 ++ TeensyDSP/TS590.h | 12 +++ 4 files changed, 244 insertions(+), 208 deletions(-) diff --git a/TeensyDSP/DSP.cpp b/TeensyDSP/DSP.cpp index d35e896..8418dbc 100644 --- a/TeensyDSP/DSP.cpp +++ b/TeensyDSP/DSP.cpp @@ -10,17 +10,6 @@ //#include //#include -const int rxRigInChannel = RX_RIG_IN_CH; - -const int txMicInChannel = TX_MIC_IN_CH; -const int txLineInChannel = TX_LINE_IN_CH; -const int txUSBInChannel = TX_USB_IN_CH; -const int txNumChannels = TX_NUM_CHANNELS; - -UBitxDSP DSP; - -//static struct { - // GUItool: begin automatically generated code AudioInputUSB usbIn; //xy=161,313 AudioInputI2S lineIn; //xy=169,205 @@ -56,10 +45,6 @@ AudioControlSGTL5000 audioCtrl; //xy=435,448 //} audio; -UBitxDSP::UBitxDSP() -: txSrc(MIC_IN), txSrcLatched(MIC_IN) { -} - void UBitxDSP::begin() { // Basic audio setup @@ -98,33 +83,32 @@ void UBitxDSP::update() { if (state.vox[txSrc].enable && txVoxLevel.available()) { if (txVoxLevel.read() > state.vox[txSrc].threshold) { - voxTimeout = millis() + state.voxDelay; - state.voxActive = true; + isVoxActive = true; + sinceVoxActive = 0; } } - if (millis() > voxTimeout) { - state.voxActive = false; + if (isVoxActive && (sinceVoxActive > state.voxDelay)) { + isVoxActive = false; } } void UBitxDSP::end() { } -//====================================================================== -// Transmit/Receive (T/R) Switching -//====================================================================== +/********************************************************************** + * Transmit/Receive switching + **********************************************************************/ /*! - * @brief Revert to receive (RX) mode from transmit (TX) mode. First - * the transmit audio output is muted, to ensure that no more - * audio goes to the rig. Then we check to see if the latched - * TX audio source was different than the selected TX audio - * source; this happens if the radio is currently set for a - * particular input (which determines what is monitored by the - * VOX), but then is commanded to transmit a different source - * (e.g. based on a CAT command). The actual transmit audio - * source is latched during transmit, but upon returning to - * receive, we restore the selected transmit audio. + * Return to receive (RX) mode from transmit (TX) mode. + * First the transmit audio output is muted, to ensure that no more + * audio goes to the rig. Then we check to see if the latched TX audio + * source was different than the selected TX audio source; this happens + * if the radio is currently set for a particular input (which + * determines what is monitored by the VOX), but then is commanded to + * transmit a different source (e.g. based on a CAT command). The + * actual transmit audio source is latched during transmit, but upon + * returning to receive, we restore the selected transmit audio. */ void UBitxDSP::rx() { if (isTx) { @@ -140,6 +124,9 @@ void UBitxDSP::rx() { } } +/*! + * Enter transmit (TX) mode from receive (RX) mode. + */ void UBitxDSP::tx(TxAudioIn src) { if (!isTx) { muteRxIn(RX_AUDIO); @@ -159,9 +146,9 @@ void UBitxDSP::tx(TxAudioIn src) { } } -//====================================================================== -// Receive (RX) Audio Chain -//====================================================================== +/********************************************************************** + * General audio setup -- called via begin() + **********************************************************************/ void UBitxDSP::setupRxAudio() { for (int i = 0; i < NUM_RX_AUDIO_CH; i++) { @@ -185,42 +172,6 @@ void UBitxDSP::setupRxAudio() { usbBypassAmp.gain(1.0); } -void UBitxDSP::setRxInLevel(RxAudioCh ch, float level) { - if (ch < NUM_RX_AUDIO_CH) { - state.rxin[ch].level = level; - rxAudio.gain(ch, state.rxin[ch].mute ? 0.0 : state.rxin[ch].level); - } -} - -void UBitxDSP::muteRxIn() { - for (int i = 0; i < NUM_RX_AUDIO_CH; i++) { - state.rxin[RxAudioCh(i)].mute = true; - rxAudio.gain(i, 0.0); - } -} - -void UBitxDSP::muteRxIn(RxAudioCh ch) { - if (ch < NUM_RX_AUDIO_CH) { - if (!state.rxin[ch].mute) { - state.rxin[ch].mute = true; - rxAudio.gain(ch, 0.0); - } - } -} - -void UBitxDSP::unmuteRxIn(RxAudioCh ch) { - if (ch < NUM_RX_AUDIO_CH) { - if (state.rxin[ch].mute) { - state.rxin[ch].mute = false; - rxAudio.gain(ch, state.rxin[ch].level); - } - } -} - -//====================================================================== -// Transmit (TX) Audio Chain -//====================================================================== - void UBitxDSP::setupTxAudio() { for (int i = 0; i < NUM_TX_AUDIO_CH; i++) { txAudio.gain(i, 0.0); @@ -244,24 +195,64 @@ void UBitxDSP::setupTxAudio() { tone2.frequency(1900); } +/********************************************************************** + * Receive audio chain + **********************************************************************/ + +void UBitxDSP::setRxInLevel(RxAudioCh ch, float level) { + if (ch < NUM_RX_AUDIO_CH) { + state.rxIn[ch].level = level; + rxAudio.gain(ch, state.rxIn[ch].mute ? 0.0 : state.rxIn[ch].level); + } +} + +void UBitxDSP::muteRxIn() { + for (int i = 0; i < NUM_RX_AUDIO_CH; i++) { + state.rxIn[RxAudioCh(i)].mute = true; + rxAudio.gain(i, 0.0); + } +} + +void UBitxDSP::muteRxIn(RxAudioCh ch) { + if (ch < NUM_RX_AUDIO_CH) { + if (!state.rxIn[ch].mute) { + state.rxIn[ch].mute = true; + rxAudio.gain(ch, 0.0); + } + } +} + +void UBitxDSP::unmuteRxIn(RxAudioCh ch) { + if (ch < NUM_RX_AUDIO_CH) { + if (state.rxIn[ch].mute) { + state.rxIn[ch].mute = false; + rxAudio.gain(ch, state.rxIn[ch].level); + } + } +} + +/********************************************************************** + * Transmit audio chain + **********************************************************************/ + void UBitxDSP::setTxInLevel(TxAudioCh ch, float level) { if (ch < NUM_TX_AUDIO_CH) { - state.txin[ch].level = level; - txAudio.gain(ch, state.txin[ch].mute ? 0.0 : state.txin[ch].level); + state.txIn[ch].level = level; + txAudio.gain(ch, state.txIn[ch].mute ? 0.0 : state.txIn[ch].level); } } void UBitxDSP::muteTxIn() { for (int i = 0; i < NUM_TX_AUDIO_CH; i++) { - state.txin[TxAudioCh(i)].mute = true; + state.txIn[TxAudioCh(i)].mute = true; txAudio.gain(i, 0.0); } } void UBitxDSP::muteTxIn(TxAudioCh ch) { if (ch < NUM_TX_AUDIO_CH) { - if (!state.txin[ch].mute) { - state.txin[ch].mute = true; + if (!state.txIn[ch].mute) { + state.txIn[ch].mute = true; txAudio.gain(ch, 0.0); } } @@ -269,29 +260,29 @@ void UBitxDSP::muteTxIn(TxAudioCh ch) { void UBitxDSP::unmuteTxIn(TxAudioCh ch) { if (ch < NUM_TX_AUDIO_CH) { - if (state.txin[ch].mute) { - state.txin[ch].mute = false; - rxAudio.gain(ch, state.txin[ch].level); + if (state.txIn[ch].mute) { + state.txIn[ch].mute = false; + rxAudio.gain(ch, state.txIn[ch].level); } } } void UBitxDSP::setTxOutLevel(float level) { - state.txout.level = level; - txOutAmp.gain(state.txout.mute ? 0.0 : state.txout.level); + state.txOut.level = level; + txOutAmp.gain(state.txOut.mute ? 0.0 : state.txOut.level); } void UBitxDSP::muteTxOut() { - if (!state.txout.mute) { - state.txout.mute = true; + if (!state.txOut.mute) { + state.txOut.mute = true; txOutAmp.gain(0.0); } } void UBitxDSP::unmuteTxOut() { - if (state.txout.mute) { - state.txout.mute = false; - txOutAmp.gain(state.txout.level); + if (state.txOut.mute) { + state.txOut.mute = false; + txOutAmp.gain(state.txOut.level); } } @@ -338,13 +329,14 @@ void UBitxDSP::setTxAudioIn(TxAudioIn src, bool isTemp) { default: // should never happen + break; } } } -//====================================================================== -// RX Audio Filter Settings -//====================================================================== +/********************************************************************** + * Receive audio filter (band pass) + **********************************************************************/ const int minRxFilterLo = MIN_RX_FILTER_LO; const int maxRxFilterHi = MAX_RX_FILTER_HI; @@ -434,6 +426,17 @@ void UBitxDSP::setRxFilterCenter(int center) { setRxFilter(lo, hi); } +/********************************************************************** + * Singleton - the DSP instance + **********************************************************************/ + +#ifndef UBITXDSP_CLASS +#define UBITXDSP_CLASS UBitxDSP +#endif + +UBITXDSP_CLASS theDSP; +UBitxDSP& DSP = theDSP; + /* NOTES diff --git a/TeensyDSP/DSP.h b/TeensyDSP/DSP.h index 9a6e4d5..b3fe031 100644 --- a/TeensyDSP/DSP.h +++ b/TeensyDSP/DSP.h @@ -9,113 +9,105 @@ #include #include "Debug.h" -#define MIN_RX_FILTER_LO 0 -#define MAX_RX_FILTER_HI 5000 -#define MIN_RX_FILTER_WIDTH 0 -#define MAX_RX_FILTER_WIDTH 5000 -#define MIN_RX_FILTER_CENTER 0 -#define MAX_RX_FILTER_CENTER 5000 +/********************************************************************** + * Macros + **********************************************************************/ -#define DSP_MILLIS_PER_UPDATE 100 +#define MIN_RX_FILTER_LO (0) //! Min allowable value of the RX filter low-cut frequency +#define MAX_RX_FILTER_HI (5000) //! Max allowable value of the RX filter hi-cut frequency +#define MIN_RX_FILTER_WIDTH (0) //! Min allowable value of the RX filter bandwidth +#define MAX_RX_FILTER_WIDTH (5000) //! Max allowable value of the RX filter bandwidth +#define MIN_RX_FILTER_CENTER (0) //! Min allowable value of the RX filter center frequency +#define MAX_RX_FILTER_CENTER (5000) //! Max allowable value of the RX filter center frequency -#define RX_RIG_IN_CH 0 +#define DSP_MILLIS_PER_UPDATE (100) //! Number of milliseconds between update of the DSP object -#define TX_MIC_IN_CH 0 -#define TX_LINE_IN_CH 0 -#define TX_USB_IN_CH 1 -#define TX_NUM_CHANNELS 2 +#define TX_VOX_MIC_THRESH (0.0) //! Threshold for mic VOX (not implemented, since mic requires special handling) +#define TX_VOX_LINE_THRESH (0.25) //! Threshold for line in VOX +#define TX_VOX_USB_THRESH (0.25) //! Threshold for USB VOX +#define TX_VOX_TUNE_THRESH (0.0) //! Threshold for tune (single tone) VOX (not expected to be used) +#define TX_VOX_TT_THRESH (0.0) //! Threshold for two-tone VOX (not expected to be used) +#define TX_VOX_DELAY (500) //! VOX delay in milliseconds -#define TX_VOX_MIC_THRESH 0.0 -#define TX_VOX_LINE_THRESH 0.25 -#define TX_VOX_USB_THRESH 0.25 -#define TX_VOX_TUNE_THRESH 0.0 -#define TX_VOX_TT_THRESH 0.0 -#define TX_VOX_DELAY 500 +/********************************************************************** + * Enumerations + **********************************************************************/ -/**********************************************************************/ - -/*! - * @brief Defines the four separate RX audio input channels available. - * Not all are currently used by the implementation. - */ +//! Defines the four separate RX audio input channels available. enum RxAudioCh { - RX_AUDIO = 0, - RX_SPARE1, - RX_SPARE2, - RX_SPARE3, - NUM_RX_AUDIO_CH + RX_AUDIO = 0, // Normal receiver audio input channel + RX_SPARE1, // Not used + RX_SPARE2, // Not used + RX_SPARE3, // Not used + NUM_RX_AUDIO_CH // Total number of channels }; -/*! - * @brief Defines the different RX audio inputs. This is not really - * different than the channels, but in theory could be. See - * the corresponding TX enums for an example of this. - */ +//! Defines the different RX audio inputs (not channels). enum RxAudioIn { - RIG_IN = 0, - NUM_RX_AUDIO_IN + RIG_IN = 0, // Normal rig input (receiver audio) + NUM_RX_AUDIO_IN // Total number of inputs }; -/*! - * @brief Defines the four separate TX audio input channels available. - * They do not directly correlate to TX audio input sources. - * Specifically. both mic and line inputs use TX_LINE, and - * the two-tone input uses both TX_TONE1 and TX_TONE2 at the - * same time. - */ +//! Defines the four separate TX audio input channels available. enum TxAudioCh { - TX_LINE = 0, - TX_USB, - TX_TONE1, - TX_TONE2, - NUM_TX_AUDIO_CH + TX_LINE = 0, // Line and/or mic audio input channel + TX_USB, // USB audio input channel + TX_TONE1, // Audio tone #1 input channel + TX_TONE2, // Audio tone #2 input channel + NUM_TX_AUDIO_CH // Toal number of channels }; -/*! - * @brief Defines the different TX audio input sources (not channels!) - * As noted above, MIC_IN and LINE_IN share channels, and - * TWO_TONE_IN uses multiple channels. - */ +//! Defines the different TX audio input sources (not channels!). enum TxAudioIn { - MIC_IN = 0, - LINE_IN, - USB_IN, - TUNE_IN, - TWO_TONE_IN, - NUM_TX_AUDIO_IN + MIC_IN = 0, // Microphone transmit audio input + LINE_IN, // Line ("AUX") transmit audio input + USB_IN, // USB transmit audio input + TUNE_IN, // Tune input (transmits a single tone) + TWO_TONE_IN, // Two tone audio input (transmits two tones) + NUM_TX_AUDIO_IN // Total number of inputs }; -/*! - * @brief Describes a simple audio channel that can be muted. - */ +/********************************************************************** + * Classes + **********************************************************************/ + +//! Defines parameters for a simple audio channel that can be muted. struct AudioChannel { bool mute = false; float level = 0.0; }; -/**********************************************************************/ - +/*! + * Contains the current 'persistent' state of the DSP. + * This includes all audio-specific state that can be saved to, or + * restored from, EEPROM. It does not include 'transient' state (such + * as whether we're currently transmitting or receiving). + */ struct DSPState { - // RX audio I/O settings - default to muted - AudioChannel rxin[NUM_RX_AUDIO_CH] = { + //! Receiver audio inputs; all default to muted. + AudioChannel rxIn[NUM_RX_AUDIO_CH] = { {true, 1.0}, // audio {true, 0.0}, // spare 1 {true, 0.0}, // spare 2 {true, 0.0} // spare 3 }; - AudioChannel rxout = {true, 1.0}; - // TX audio I/O settings - default to muted - AudioChannel txin[NUM_TX_AUDIO_CH] = { + //! Receiver audio output; defaults to muted. + AudioChannel rxOut = {true, 1.0}; + + //! Transmitter audio inputs; all default to muted. + AudioChannel txIn[NUM_TX_AUDIO_CH] = { {true, 0.1}, // line {true, 0.1}, // USB {true, 0.1}, // tone 1 {true, 0.1} // tone 2 }; - AudioChannel txout = {true, 1.0}; - // TX VOX settings, per audio input (not channel!) + //! Tranmitter audio output; defaults to muted. + AudioChannel txOut = {true, 1.0}; + + //! Transmitter VOX settings, per audio input (not channel). struct { bool enable = false; float threshold = 1.0; @@ -126,44 +118,62 @@ struct DSPState { {false, TX_VOX_TUNE_THRESH}, {false, TX_VOX_TT_THRESH} }; - unsigned voxDelay = TX_VOX_DELAY; - bool voxActive = false; - // RX filter settings + //! VOX delay (regardless of input). + unsigned voxDelay = TX_VOX_DELAY; + + //! Current RX filter settings int rxFilterLo = 300; int rxFilterHi = 3000; }; - +/*! + * Defines the DSP subsystem of the UBitx V5X. + * The DSP subsystem, which relies on the Teensy Audio Library, is + * responsible for setting up the audio inputs and outputs for both + * receive (RX) and transmit (TX) audio, maintaining the correct path + * between inputs and outputs based on current TX/RX state, and setting + * up audio filters and other audio-based modules for the RX and TX + * audio paths. + */ class UBitxDSP { - // Object construction. - public: - UBitxDSP(); + /******************************************************************** + * Object creation/deletion + ********************************************************************/ + + public: + UBitxDSP() {} + + /******************************************************************** + * Basic administration + ********************************************************************/ - // Basic administrative functions. public: void begin(); void update(); void end(); - //==================================================================== - // Transmit/Receive (T/R) Switching - //==================================================================== + /******************************************************************** + * Transmit/Receive switching + ********************************************************************/ public: void rx(); inline void tx() { tx(txSrc); } void tx(TxAudioIn src); - //==================================================================== - // Receive (RX) Audio Chain - //==================================================================== + /******************************************************************** + * General audio setup -- called via begin() + ********************************************************************/ - // General administrative function to setup the initial RX audio - // chain. This should only be called once, via begin(). - private: - void setupRxAudio(); + protected: + virtual void setupRxAudio(); + virtual void setupTxAudio(); + + /******************************************************************** + * Receive audio chain + ********************************************************************/ // Basic control of RX audio inputs and outputs. public: @@ -172,14 +182,9 @@ class UBitxDSP { void muteRxIn(RxAudioCh ch); // Mute a specific RX audio input channel. void unmuteRxIn(RxAudioCh ch); // Un-mute a specific RX audio input channel. - //==================================================================== - // Transmit (TX) Audio Chain - //==================================================================== - - // General administrative function to setup the initial TX audio - // chain. This should only be called once, via begin(). - private: - void setupTxAudio(); + /******************************************************************** + * Transmit audio chain + ********************************************************************/ // Basic control of TX audio inputs and outputs. public: @@ -196,12 +201,14 @@ class UBitxDSP { void setTxAudioIn(TxAudioIn src, bool isTemp = false); // Select a specific TX audio input path, and identify it as permanent or temporary. inline TxAudioIn getTxAudioIn() const { return txSrc; } // Return the current TX audio input. - //==================================================================== - // RX Audio Filter Settings - //==================================================================== + /******************************************************************** + * Receive audio filter (band pass) + ********************************************************************/ public: void bypassRxFilter(); + void updateRxFilter(); + void setRxFilter(int lo, int hi); void setRxFilterLo(int lo); void setRxFilterHi(int hi); @@ -209,53 +216,57 @@ class UBitxDSP { void setRxFilterCenter(int center); /*! - * @brief Get the current low frequency bound of the RX band pass filter. + * Get the current low frequency bound of the RX band pass filter. * @return The low frequency bound. */ inline int getRxFilterLo() { return state.rxFilterLo; } /*! - * @brief Get the current high frequency bound of the RX band pass filter. + * Get the current high frequency bound of the RX band pass filter. * @return The high frequency bound. */ inline int getRxFilterHi() { return state.rxFilterHi; } /*! - * @brief Get the current width of the RX band pass filter. + * Get the current width of the RX band pass filter. * @return The filter width. */ inline int getRxFilterWidth() { return state.rxFilterHi - state.rxFilterLo; } /*! - * @brief Get the current center frequency of the RX band pass filter. + * Get the current center frequency of the RX band pass filter. * @return The center frequency. */ inline int getRxFilterCenter() { return (state.rxFilterHi + state.rxFilterLo) / 2; } - // TX audio input settings - void setTxInputLevel(int ch, float lvl); - void enableTxInput(int ch); - void disableTxInput(int ch); - void startTxInput(int ch); - void stopTxInput(int ch); + /******************************************************************** + * Transmit Voice-Operated-Switch (VOX) + ********************************************************************/ + inline bool voxActive() { return isVoxActive; } + inline bool voxInactive() { return !isVoxActive; } + + /******************************************************************** + * Private state + ********************************************************************/ + private: + DSPState state; bool isTx = false; - - void updateRxFilter(); - - DSPState state; - short coefficients[NUM_COEFFICIENTS]; - elapsedMillis sinceLastUpdate; + TxAudioIn txSrc = MIC_IN; + TxAudioIn txSrcLatched = MIC_IN; - TxAudioIn txSrc, txSrcLatched; + short coefficients[NUM_COEFFICIENTS] = {0}; + + elapsedMillis sinceLastUpdate = 0; float usbVol = 0.0; - unsigned voxTimeout; + bool isVoxActive = false; + elapsedMillis sinceVoxActive = 0; }; -extern UBitxDSP DSP; +extern UBitxDSP& DSP; #endif diff --git a/TeensyDSP/TS590.cpp b/TeensyDSP/TS590.cpp index 3f51806..8149e71 100644 --- a/TeensyDSP/TS590.cpp +++ b/TeensyDSP/TS590.cpp @@ -319,6 +319,16 @@ void TS590_SL::sendResponse(const char* cmd) { /**********************************************************************/ +void TS590_VX::handleCommand(const char* cmd) { + +} + +void TS590_VX::sendResponse(const char* cmd) { + +} + +/**********************************************************************/ + TS590_FA cmdFA; TS590_FB cmdFB; TS590_FR cmdFR; diff --git a/TeensyDSP/TS590.h b/TeensyDSP/TS590.h index 2f1b6a4..833f592 100644 --- a/TeensyDSP/TS590.h +++ b/TeensyDSP/TS590.h @@ -192,6 +192,18 @@ class TS590_SL : public TS590Command { unsigned index; }; +/*! + * CAT command for enabling or disabling the mic VOX. + */ +class TS590_VX : public TS590Command { + public: + TS590_VX(): TS590Command("VX") {} + virtual void handleCommand(const char* cmd); + virtual void sendResponse(const char* cmd); + private: + unsigned index; +}; + /**********************************************************************/ class UBitxTS590 {