Initial commit
This commit is contained in:
commit
08ec203dde
183
cat.ino
Normal file
183
cat.ino
Normal 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
10
ubitx_iop.h
Normal 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
391
ubitx_iop.ino
Normal 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
|
||||
//======================================================================
|
Loading…
Reference in New Issue
Block a user