Initial commit

This commit is contained in:
Rob French 2020-05-01 11:04:26 -05:00
commit 08ec203dde
3 changed files with 584 additions and 0 deletions

183
cat.ino Normal file
View File

@ -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
//======================================================================

10
ubitx_iop.h Normal file
View File

@ -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

391
ubitx_iop.ino Normal file
View File

@ -0,0 +1,391 @@
#include <Bounce2.h>
#include <Audio.h>
#include <Wire.h>
#include <SPI.h>
#include <SD.h>
#include <SerialFlash.h>
#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
//======================================================================