From 08ec203dde9bd22f12502c20f6ad09b8e3d564a7 Mon Sep 17 00:00:00 2001 From: Rob French Date: Fri, 1 May 2020 11:04:26 -0500 Subject: [PATCH] Initial commit --- cat.ino | 183 +++++++++++++++++++++++ ubitx_iop.h | 10 ++ ubitx_iop.ino | 391 ++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 584 insertions(+) create mode 100644 cat.ino create mode 100644 ubitx_iop.h create mode 100644 ubitx_iop.ino diff --git a/cat.ino b/cat.ino new file mode 100644 index 0000000..8a31550 --- /dev/null +++ b/cat.ino @@ -0,0 +1,183 @@ +#include "ubitx_iop.h" + +#define ACK 0 +#define CAT_PREFIX 0xC0 +#define IOP_PREFIX 0xD0 +#define EEPROM_READ_PREFIX 0xE0 +#define EEPROM_WRITE_PREFIX 0xF0 + +//====================================================================== +// CAT from PC-to-IOP +// +// The general concept for IOP use of CAT is for the IOP to pass thru +// all incoming CAT data (from the PC) to the Raduino. +// +// This might change in the future, if we want to grab CAT data straight +// from the PC. That might apply to things like specific audio filter +// settings or something, but since the Raduino modes are an important +// part of the mix, I think the commands really need to come from the +// Raduino... and besides, what if a PC is not connected? +// +// +// For data coming from the Raduino, the IOP does have to do a minimal +// processing to extra any Raduino-to-IOP commands. +//====================================================================== + +void initCAT(long baud, int portConfig) +{ + // CAT with PC via USB + USBSERIAL.begin(baud); + USBSERIAL.flush(); + + // CAT with Raduino via UART + HWSERIAL.begin(baud, portConfig); + USBSERIAL.flush(); +} + +//====================================================================== + +void processIOPCommand(const byte* buf, int len) +{ +} + +//====================================================================== + +enum serial_mode_t { + NORMAL = 0, + CAT_MODE, + IOP_MODE, + EEPROM_READ, + EEPROM_WRITE, +} serialMode = NORMAL; + +int readLength = 0; + +int cmdLength = 0; +byte cmdBuffer[16]; + +uint16_t eepromStartIndex; +uint16_t eepromReadLength; +int magicFlag = 0; + +//---------------------------------------------------------------------- + +void serviceCAT() +{ + int incomingByte; + + // read from the USB serial, pass through to UART serial + for (int i = 0; i < USBSERIAL.available(); i++) { + incomingByte = USBSERIAL.read(); + HWSERIAL.write(incomingByte); + } + + // read from the UART serial, see what we need to do with it + for (int i = 0; i < HWSERIAL.available(); i++) { + incomingByte = HWSERIAL.read(); + + switch(serialMode) { + case NORMAL: + if (incomingByte == ACK) { + USBSERIAL.write(incomingByte); + } else { + readLength = incomingByte & 0x0F; + if (readLength > 0) { + switch(incomingByte & 0xF0) { + case CAT_PREFIX: + case EEPROM_WRITE_PREFIX: + serialMode = CAT_MODE; + break; + + case IOP_PREFIX: + serialMode = IOP_MODE; + cmdLength = 0; + break; + + case EEPROM_READ_PREFIX: + serialMode = EEPROM_READ; + readLength = 5; + magicFlag = 0; + break; + + default: + // should never happen + break; + } + } + } + break; + + case CAT_MODE: + // In CAT mode, we just pass thru the remaining bytes to the PC. + USBSERIAL.write(incomingByte); + readLength--; + if (readLength == 0) { + serialMode = NORMAL; + } + break; + + case IOP_MODE: + cmdBuffer[cmdLength] = incomingByte; + cmdLength++; + readLength--; + if (readLength == 0) { + processIOPCommand(cmdBuffer, cmdLength); + serialMode = NORMAL; + } + break; + + case EEPROM_READ: + readLength--; + switch(readLength) { + case 4: + eepromStartIndex = incomingByte; + if (incomingByte == 0x16) { + magicFlag++; + } + break; + + case 3: + eepromStartIndex += (256 * incomingByte); + if (incomingByte == 0xe8) { + magicFlag++; + } + break; + + case 2: + eepromReadLength = incomingByte; + break; + + case 1: + eepromReadLength += (256 * incomingByte); + break; + + case 0: + USBSERIAL.write(incomingByte); + if (magicFlag == 2) { + readLength = 126 + 2; + } else { + readLength = eepromReadLength + 2; + } + serialMode = CAT_MODE; + break; + + default: + // should never happen + break; + } + break; + + case EEPROM_WRITE: + // TODO + break; + + default: + // should never happen... + break; + } + } +} + +//====================================================================== +// EOF +//====================================================================== diff --git a/ubitx_iop.h b/ubitx_iop.h new file mode 100644 index 0000000..1f0b164 --- /dev/null +++ b/ubitx_iop.h @@ -0,0 +1,10 @@ +#ifndef __UBITX_IOP_H__ +#define __UBITX_IOP_H__ + +// comment this out to disable debugging code +//#define DEBUG + +#define USBSERIAL Serial +#define HWSERIAL Serial1 + +#endif diff --git a/ubitx_iop.ino b/ubitx_iop.ino new file mode 100644 index 0000000..70b16c7 --- /dev/null +++ b/ubitx_iop.ino @@ -0,0 +1,391 @@ +#include + +#include +#include +#include +#include +#include + +#include "ubitx_iop.h" + +#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(); + +#define MIC_PTT_PIN 21 +#define LINE_PTT_PIN 20 +#define PTT_KEY_OUT_PIN 2 + +Bounce micPTT = Bounce(); +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. + micPTT.update(); + linePTT.update(); + if (trxMode == SSB) { + 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); + } + } 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); + } + } else { + // Whichever PTT source was last active, will determine the TX audio source. Need to incorporate USB into this. + if (micPTT.fell()) { + rxio.setTransmit(true); + txio.setTransmit(true); + micPTT_active = true; + digitalWrite(PTT_KEY_OUT_PIN, LOW); + txio.selectMicIn(); + } else if (linePTT.fell()) { + rxio.setTransmit(true); + txio.setTransmit(true); + linePTT_active = true; + 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!"); + } 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 +} + +void setup() { + // put your setup code here, to run once: + initCAT(38400, SERIAL_8N1); + + AudioMemory(12); + + micPTT.attach(MIC_PTT_PIN, INPUT_PULLUP); + micPTT.interval(25); + linePTT.attach(LINE_PTT_PIN, INPUT_PULLUP); + linePTT.interval(25); + + 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(); +} + +void loop() { + elapsedMillis frame_timer = 0; + + checkPTT(); + serviceCAT(); +/* + #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 + } +*/ +} + +//====================================================================== +// EOF +//======================================================================