diff --git a/audio.h b/audio.h new file mode 100644 index 0000000..d3ff33a --- /dev/null +++ b/audio.h @@ -0,0 +1,39 @@ +//====================================================================== +// audio.h +//====================================================================== + +#ifndef __iop_audio_h__ +#define __iop_audio_h__ + +enum RxInput { + RX_RIG_IN = 0, + RX_USB_IN, +}; + +enum RxOutput { + RX_SPEAKER_OUT = 0, + RX_LINE_OUT, + RX_USB_OUT, +}; + +enum TxInput { + TX_MIC_IN = -1, + TX_LINE_IN = 0, + TX_USB_IN, +}; + +enum TxOutput { + TX_RIG_OUT = 0, + TX_USB_OUT, +}; + +void audioInit(); +void audioSelectTxInput(TxInput); +void audioTransmit(); +void audioReceive(); + +#endif + +//====================================================================== +// EOF +//====================================================================== diff --git a/audio.ino b/audio.ino new file mode 100644 index 0000000..8ba3466 --- /dev/null +++ b/audio.ino @@ -0,0 +1,274 @@ +//====================================================================== +// audio.ino +//====================================================================== + +#include "audio.h" + +extern IOPConfig iopConfig; + +#define DEFAULT_RX_INPUT RIG +#define DEFAULT_RX_OUTPUT SPKR +#define DEFAULT_TX_INPUT MIC +#define DEFAULT_TX_OUTPUT RIG + +#include +#include +#include +#include +#include + +// GUItool: begin automatically generated code +AudioInputI2S inLine; //xy=224,194 +AudioInputUSB inUSB; //xy=224,303 +AudioAnalyzeRMS rmsRX; //xy=399,71 +AudioAnalyzePeak peakRX; //xy=403,122 +AudioMixer4 mixRX; //xy=460,187 +AudioMixer4 mixTX; //xy=460,303 +AudioAmplifier calRxUSB; //xy=650,189 +AudioAmplifier calRxSpkr; //xy=654,79 +AudioAmplifier calRxLine; //xy=657,136 +AudioAmplifier calTxLine; //xy=669,272 +AudioAmplifier calTxUSB; //xy=670,329 +AudioAnalyzePeak peakTX; //xy=685,402 +AudioAnalyzeRMS rmsTX; //xy=699,457 +AudioOutputAnalog outSpkr; //xy=830,79 +AudioOutputUSB outUSB; //xy=839,279 +AudioOutputI2S outLine; //xy=842,228 +AudioConnection patchCord1(inLine, 0, rmsRX, 0); +AudioConnection patchCord2(inLine, 0, peakRX, 0); +AudioConnection patchCord3(inLine, 0, mixRX, 0); +AudioConnection patchCord4(inLine, 1, mixTX, 0); +AudioConnection patchCord5(inUSB, 0, mixRX, 1); +AudioConnection patchCord6(inUSB, 1, mixTX, 1); +AudioConnection patchCord7(mixRX, calRxSpkr); +AudioConnection patchCord8(mixRX, calRxLine); +AudioConnection patchCord9(mixRX, calRxUSB); +AudioConnection patchCord10(mixTX, calTxLine); +AudioConnection patchCord11(mixTX, calTxUSB); +AudioConnection patchCord12(mixTX, peakTX); +AudioConnection patchCord13(mixTX, rmsTX); +AudioConnection patchCord14(calRxUSB, 0, outUSB, 0); +AudioConnection patchCord15(calRxSpkr, outSpkr); +AudioConnection patchCord16(calRxLine, 0, outLine, 0); +AudioConnection patchCord17(calTxLine, 0, outLine, 1); +AudioConnection patchCord18(calTxUSB, 0, outUSB, 1); +AudioControlSGTL5000 audioCtrl; //xy=407,467 +// GUItool: end automatically generated code + +RxInput audioRxInput; +RxOutput audioRxOutput; +TxInput audioTxInput; +TxOutput audioTxOutput; + +// audioInit() +// Setup the audio subsystem. +void audioInit() +{ + 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(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.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 + + // selectTxInput(TX_LINE_IN); +} + +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 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 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 audioSelectTxInput(TxInput input) +{ + if (audioTxInput != input) { + audioTxInput = input; + 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() +{ + 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 + // 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(); + } + + // 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); + } +} + +// 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() +{ + 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. + if (audioTxInput == TX_MIC_IN) { + muteTxMicIn(); + + // Now switch to the line input, and restore mixer settings. + audioCtrl.inputSelect(AUDIO_INPUT_LINEIN); + restoreTxLineIn(); + } + + restoreRxRigIn(); + + // 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); + } +} + +//====================================================================== +// EOF +//====================================================================== diff --git a/cat.h b/cat.h new file mode 100644 index 0000000..a7fc5ca --- /dev/null +++ b/cat.h @@ -0,0 +1,18 @@ +//====================================================================== +// cat.h +//====================================================================== + +#ifndef __iop_cat_h__ +#define __iop_cat_h__ + +#define USBSERIAL Serial +#define HWSERIAL Serial1 + +void initCAT(long, int); +void serviceCAT(); + +#endif + +//====================================================================== +// EOF +//====================================================================== diff --git a/cat.ino b/cat.ino index 8a31550..d36fe05 100644 --- a/cat.ino +++ b/cat.ino @@ -1,4 +1,8 @@ -#include "ubitx_iop.h" +//====================================================================== +// cat.ino +//====================================================================== + +#include "cat.h" #define ACK 0 #define CAT_PREFIX 0xC0 diff --git a/eeprom.h b/eeprom.h new file mode 100644 index 0000000..4e17341 --- /dev/null +++ b/eeprom.h @@ -0,0 +1,12 @@ +//====================================================================== +// eeprom.h +//====================================================================== + +#ifndef __iop_eeprom_h__ +#define __iop_eeprom_h__ + +#endif + +//====================================================================== +// EOF +//====================================================================== diff --git a/eeprom.ino b/eeprom.ino new file mode 100644 index 0000000..f669a69 --- /dev/null +++ b/eeprom.ino @@ -0,0 +1,9 @@ +//====================================================================== +// eeprom.ino +//====================================================================== + +#include "eeprom.h" + +//====================================================================== +// EOF +//====================================================================== diff --git a/ubitx_iop.h b/ubitx_iop.h index 1f0b164..71d8922 100644 --- a/ubitx_iop.h +++ b/ubitx_iop.h @@ -1,10 +1,74 @@ -#ifndef __UBITX_IOP_H__ -#define __UBITX_IOP_H__ +//====================================================================== +// ubitx_iop.h +//====================================================================== + +#ifndef __ubitx_iop_h__ +#define __ubitx_iop_h__ + +#include "audio.h" +#include "cat.h" +#include "eeprom.h" // comment this out to disable debugging code //#define DEBUG -#define USBSERIAL Serial -#define HWSERIAL Serial1 +enum RigMode { + MODE_SSB = 0, + MODE_DIGI, + MODE_CW, +}; + +// IOPConfig +// Used to store configuration parameters during runtime, as well as to +// save them to EEPROM. +// +// NOTE: Need to put version info and a version check here. +struct IOPConfig { + + // RECEIVE PARAMETERS + + // rig-in parameters (RX) + uint8_t rxRigInLevel = 5; + float rxRigInVol = 1.0; + float rxRigInCal = 1.0; + // USB-in parameters (RX) - debug/monitor use only + bool rxUSBInEnable = false; + float rxUSBInVol = 1.0; + float rxUSBInCal = 1.0; + // speaker-out (DAC) parameters (RX) + float rxSpkrOutCal = 1.0; + // line-out parameters (RX) + uint8_t rxLineOutLevel = 29; + float rxLineOutCal = 1.0; + // USB-out parameters (RX) + float rxUSBOutCal = 1.0; + + // TRANSMIT PARAMETERS + + // microphone-in parameters (TX) + uint8_t txMicInGain = 32; + float txMicInVol = 1.0; + float txMicInCal = 1.0; + // line-in parameters (TX) + uint8_t txLineInLevel = 5; + float txLineInVol = 1.0; + float txLineInCal = 1.0; + // USB-in parameters (TX) + float txUSBInVol = 1.0; + float txUSBInCal = 1.0; + // rig-out parameters (TX) + uint8_t txRigOutLevel = 29; + float txRigOutCal = 1.0; + // USB-out parameters (TX)- debug/monitor use only + bool txUSBOutEnable = true; + float txUSBOutCal = 1.0; +}; + +extern RigMode rigMode; +extern IOPConfig iopConfig; #endif + +//====================================================================== +// EOF +//====================================================================== diff --git a/ubitx_iop.ino b/ubitx_iop.ino index 70b16c7..8faac1e 100644 --- a/ubitx_iop.ino +++ b/ubitx_iop.ino @@ -1,259 +1,14 @@ -#include - -#include -#include -#include -#include -#include +//====================================================================== +// ubitx_iop.ino +//====================================================================== #include "ubitx_iop.h" +#include #define BOUNCE_WITH_PROMPT_DETECTION -// GUItool: begin automatically generated code -AudioInputI2S inI2S; //xy=224,194 -AudioInputUSB inUSB; //xy=224,303 -AudioAnalyzeRMS rmsRX; //xy=399,71 -AudioAnalyzePeak peakRX; //xy=403,122 -AudioMixer4 mixRX; //xy=460,187 -AudioMixer4 mixTX; //xy=460,303 -AudioAmplifier ampTX; //xy=601,302 -AudioAmplifier ampRX; //xy=602,176 -AudioAnalyzeRMS rmsTX; //xy=788,424 -AudioAnalyzePeak peakTX; //xy=789,378 -AudioOutputAnalog outDAC; //xy=836,110 -AudioOutputI2S outI2S; //xy=836,183 -AudioOutputUSB outUSB; //xy=836,300 -AudioConnection patchCord1(inI2S, 0, rmsRX, 0); -AudioConnection patchCord2(inI2S, 0, peakRX, 0); -AudioConnection patchCord3(inI2S, 0, mixRX, 0); -AudioConnection patchCord4(inI2S, 1, mixTX, 0); -AudioConnection patchCord5(inUSB, 0, mixRX, 1); -AudioConnection patchCord6(inUSB, 1, mixTX, 1); -AudioConnection patchCord7(mixRX, ampRX); -AudioConnection patchCord8(mixTX, ampTX); -AudioConnection patchCord9(ampTX, 0, outI2S, 1); -AudioConnection patchCord10(ampTX, peakTX); -AudioConnection patchCord11(ampTX, rmsTX); -AudioConnection patchCord12(ampTX, 0, outUSB, 1); -AudioConnection patchCord13(ampRX, 0, outUSB, 0); -AudioConnection patchCord14(ampRX, 0, outI2S, 0); -AudioConnection patchCord15(ampRX, outDAC); -AudioControlSGTL5000 audioCtrl; //xy=517,485 -// GUItool: end automatically generated code - - -//AudioStream* tx_inputs[4] = { -// NULL, NULL, NULL, NULL -//}; - -enum io_t { - IO_NONE = 0, - IO_RIG = 1, - IO_LINE = 2, - IO_USB = 3, - IO_MIC = 4, - IO_SPKR = 5, -}; - -#define DEFAULT_RX_SRC IO_RIG -#define DEFAULT_RX_DST IO_SPKR -#define DEFAULT_TX_SRC IO_MIC -#define DEFAULT_TX_DST IO_RIG - -class RXAudio { - public: - RXAudio() - { } - - void init() - { - mix.gain(0, 0.0); - mix.gain(1, 0.0); - mix.gain(2, 0.0); - mix.gain(3, 0.0); - } - - void selectRigIn() - { - // disable other input(s) - mix.gain(1, 0.0); - - // enable the rig's receiver input - mix.gain(0, 1.0); - } - - void selectUSBIn() - { - // disable other input(s) - mix.gain(0, 0.0); - - // enable the USB input - mix.gain(1, 1.0); - } - - void setTransmit(bool tx) - { - if (tx) { - mix.gain(0, 0.0); - } else { - mix.gain(0, 1.0); - } - } - - private: - static constexpr AudioMixer4& mix = mixRX; - static constexpr AudioControlSGTL5000& ctrl = audioCtrl; -}; - -class TXAudio { - public: - TXAudio() - { } - - void init() - { - mix.gain(0, 0.0); - mix.gain(1, 0.0); - mix.gain(2, 0.0); - mix.gain(3, 0.0); - - ctrl.micGain(0); - //ctrl.dacVolume(1.0, 0.0); - } - - void selectMicIn() - { - if (src != IO_MIC) { - src = IO_MIC; - - // disable other input(s) - mix.gain(1, 0.0); - - // enable the I2C input - mix.gain(0, 1.0); - } - } - - void selectLineIn() - { - if (src != IO_LINE) { - src = IO_LINE; - - // disable other input(s) - mix.gain(1, 0.0); - - // enable the I2C input - mix.gain(0, 1.0); - } - } - - void selectUSBIn() - { - if (src != IO_USB) { - src = IO_USB; - - // disable other input(s) - mix.gain(0, 0.0); - - // enable USB input - mix.gain(1, 1.0); - } - } - - void setTransmit(bool tx) - { - if (src == IO_MIC) { - if (tx) { - // drop the gain down, switch to Mic, bring it back up - mix.gain(0, 0.0); - ctrl.inputSelect(AUDIO_INPUT_MIC); - mix.gain(0, 1.0); - } else { - // drop the gain down, switch to Line, bring it back up - mix.gain(0, 0.0); - ctrl.inputSelect(AUDIO_INPUT_LINEIN); - mix.gain(0, 1.0); - } - } - } - - private: - io_t src = DEFAULT_TX_SRC; - static constexpr AudioMixer4& mix = mixTX; - static constexpr AudioControlSGTL5000& ctrl = audioCtrl; -}; - -/* -enum io_mode_t { - MODE_KEY = 0, - MODE_MIC = 1, // use AUDIO_INPUT_MIC; switches it in based on the PTT - MODE_LINE = 2, // use AUDIO_INPUT_LINEIN - MODE_USB = 3, // use AUDIO_INPUT_LINEIN, but mute it and use USB audio instead -} io_mode = MODE_USB; - -enum tr_mode_t { - MODE_RX = 0, - MODE_TX = 1, -} tr_mode = MODE_RX; - -int setIOMode(io_mode_t m) { - // Check for error conditions, return -1 if we can't set the mode. - if (tr_mode == MODE_TX) { // Don't allow mode changes while transmitting. - return -1; - } - - io_mode = m; - - switch (io_mode) { - case MODE_KEY: - break; - - case MODE_MIC: - break; - - case MODE_LINE: - break; - - case MODE_USB: - break; - - default: - break; - } - - return 0; -} - -int setTRMode(tr_mode_t m) { - // Check for error conditions, return -1 if we can't set the mode. - // NONE - - tr_mode = m; - - switch (tr_mode) { - case MODE_RX: - if (io_mode == MODE_MIC) { - audioCtrl.inputSelect(AUDIO_INPUT_LINEIN); - } - break; - - case MODE_TX: - if (io_mode == MODE_MIC) { - audioCtrl.inputSelect(AUDIO_INPUT_MIC); - } - break; - - default: - break; - } - - return 0; -} -*/ - -RXAudio rxio = RXAudio(); -TXAudio txio = TXAudio(); +RigMode rigMode; +IOPConfig iopConfig; #define MIC_PTT_PIN 21 #define LINE_PTT_PIN 20 @@ -265,63 +20,42 @@ Bounce linePTT = Bounce(); bool micPTT_active = false; bool linePTT_active = false; -enum key_state_t { - NONE = 0, - KEY = 1, - MIC_PTT = 2, - LINE_PTT = 3, -} keyState = NONE; - -enum trx_mode_t { - SSB = 0, - CW = 1, -} trxMode = SSB; - void checkPTT() { - // Update the PTT lines. + // Update the PTT lines. USB/DIGI is not part of this. CW should work, however. micPTT.update(); linePTT.update(); - if (trxMode == SSB) { + if (rigMode == MODE_SSB || rigMode == MODE_CW) { if (micPTT_active) { // ignore line PTT; just wait for release of mic PTT if (micPTT.rose()) { - txio.setTransmit(false); - micPTT_active = false; digitalWrite(PTT_KEY_OUT_PIN, HIGH); - rxio.setTransmit(false); + audioReceive(); + micPTT_active = false; } } else if (linePTT_active) { // ignore mic PTT; just wait for release of line PTT if (linePTT.rose()) { - txio.setTransmit(false); - linePTT_active = false; digitalWrite(PTT_KEY_OUT_PIN, HIGH); - rxio.setTransmit(false); + audioReceive(); + linePTT_active = false; } } else { - // Whichever PTT source was last active, will determine the TX audio source. Need to incorporate USB into this. + // Whichever PTT source was last active, will determine the TX audio source. if (micPTT.fell()) { - rxio.setTransmit(true); - txio.setTransmit(true); + audioSelectTxInput(TX_MIC_IN); micPTT_active = true; + audioTransmit(); digitalWrite(PTT_KEY_OUT_PIN, LOW); - txio.selectMicIn(); } else if (linePTT.fell()) { - rxio.setTransmit(true); - txio.setTransmit(true); + audioSelectTxInput(TX_LINE_IN); linePTT_active = true; + audioTransmit(); digitalWrite(PTT_KEY_OUT_PIN, LOW); - txio.selectLineIn(); } } - } else if (trxMode == CW) { - // ignoring for now... } - // For now, if either PTT line goes low (active), we're simply going to set the PTT/key line to the Raduino. - // In the future, we'll plan on changing audio inputs depending on what button is pressed. - digitalWrite(PTT_KEY_OUT_PIN, (micPTT.read() && linePTT.read() ? HIGH : LOW)); #if defined(DEBUG) if (micPTT.fell()) { USBSERIAL.println("Mic PTT pressed!"); @@ -350,17 +84,7 @@ void setup() { pinMode(PTT_KEY_OUT_PIN, OUTPUT); digitalWrite(PTT_KEY_OUT_PIN, HIGH); - // Enable the audio shield, enable I/O. - audioCtrl.enable(); - audioCtrl.muteHeadphone(); - audioCtrl.unmuteLineout(); - audioCtrl.volume(1.0); - - rxio.init(); - rxio.selectRigIn(); - - txio.init(); - txio.selectMicIn(); + audioInit(); } void loop() {