Modifications, mainly based on a code walkthrough as well as adding some

debugging output.  Compiles, but untested.
This commit is contained in:
Rob French 2020-05-25 23:08:55 -05:00
parent 9b7095a6e3
commit 564c35f397
8 changed files with 538 additions and 669 deletions

View File

@ -104,13 +104,13 @@ void sendIOPSSBStatus(SSBConfig const &c)
}
//======================================================================
// DIGI STATUS MESSAGE
// DGT STATUS MESSAGE
//======================================================================
void sendIOPDigiStatus(DigiConfig const &c)
void sendIOPDGTStatus(DGTConfig const &c)
{
IOPMessage m;
m.id = IOP_DIGI_STATUS_MSG;
m.id = IOP_DGT_STATUS_MSG;
m.len = 4;
m.data[0] = 'D'; // current mode; redundant w/ Raduino mode, but maybe useful for debugging
m.data[1] = '-'; // placeholder for future digital submodes?

View File

@ -71,7 +71,7 @@ enum MessageID {
// Requests
IOP_MODE_REQUEST,
IOP_SSB_STATUS_MSG,
IOP_DIGI_STATUS_MSG,
IOP_DGT_STATUS_MSG,
IOP_CW_STATUS_MSG,
IOP_TEST_STATUS_MSG,
@ -95,12 +95,16 @@ enum MessageID {
*/
enum RigMode {
RIG_MODE_SSB = 0,
RIG_MODE_DIGI,
RIG_MODE_CW,
RIG_MODE_TEST,
// add any new elements here
NUM_RIG_MODES
RIG_MODE_LSB = 0,
RIG_MODE_USB,
RIG_MODE_CWL,
RIG_MODE_CWU,
RIG_MODE_DGL,
RIG_MODE_DGU,
RIG_MODE_TTL,
RIG_MODE_TTU,
// add new items here
NUM_RIG_MODES
};
/* Keyer modes.
@ -117,15 +121,15 @@ enum KeyerMode {
};
enum RxFilter {
RX_FILTER_NORMAL = 0,
RX_FILTER_WIDE = 0,
RX_FILTER_MEDIUM,
RX_FILTER_NARROW,
RX_FILTER_WIDE,
NUM_RX_FILTERS
};
const unsigned char RIG_MODE_LETTER[NUM_RIG_MODES] = {'S', 'D', 'C', 'T'};
const unsigned char RIG_MODE_LETTER[NUM_RIG_MODES] = {'s', 'S', 'c', 'C', 'd', 'D', 't', 'T'};
const unsigned char KEYER_MODE_LETTER[NUM_KEYER_MODES] = {'S', 'A', 'B'};
const unsigned char RX_FILTER_LETTER[NUM_RX_FILTERS] = {'-', 'N', 'W'};
const unsigned char RX_FILTER_LETTER[NUM_RX_FILTERS] = {'W', 'M', 'N'};
const uint8_t NO_FLAGS = 0;
const uint8_t REVERSED = 1;
@ -137,28 +141,46 @@ struct IOPMessage {
};
//======================================================================
// SSB CONFIGURATION
// IConfig
//
// Interface to a configuration object.
//======================================================================
struct SSBConfig {
// parameters
RxFilter filter = RX_FILTER_NORMAL;
class IConfig {
public:
virtual ~IConfig() {}
};
//======================================================================
// DIGI CONFIGURATION
// SSB CONFIGURATION
//======================================================================
struct DigiConfig {
class SSBConfig : public IConfig {
public:
SSBConfig(RxFilter f): filter(f) {}
// parameters
RxFilter filter = RX_FILTER_NORMAL;
RxFilter filter; // = RX_FILTER_MEDIUM;
};
//======================================================================
// DGT CONFIGURATION
//======================================================================
class DGTConfig : public IConfig {
public:
DGTConfig(RxFilter f): filter(f) {}
// parameters
RxFilter filter = RX_FILTER_MEDIUM;
};
//======================================================================
// CW CONFIGURATION
//======================================================================
struct CWConfig {
class CWConfig : public IConfig {
public:
CWConfig(KeyerMode m, bool rev, uint8_t w, float wt, uint16_t st, RxFilter f):
mode(m), reversed(rev), wpm(w), weight(wt), sidetone(st), filter(f) {}
// mode
KeyerMode mode = KEYER_MODE_IAMBIC_A;
// flags
@ -167,7 +189,18 @@ struct CWConfig {
uint8_t wpm = 15;
float weight = 3.0;
uint16_t sidetone = 700;
RxFilter filter = RX_FILTER_NORMAL;
RxFilter filter = RX_FILTER_MEDIUM;
};
//======================================================================
// TT CONFIGURATION
//======================================================================
class TTConfig : public IConfig {
public:
TTConfig(RxFilter f): filter(f) {}
// parameters
RxFilter filter = RX_FILTER_MEDIUM;
};
//======================================================================
@ -184,7 +217,7 @@ void sendIOPStopTxCommand();
void sendIOPModeRequest();
void sendIOPSSBStatus(SSBConfig const&);
void sendIOPDigiStatus(DigiConfig const&);
void sendIOPDGTStatus(DGTConfig const&);
void sendIOPCWStatus(CWConfig const&);
void sendIOPTestStatus();

View File

@ -1,5 +1,7 @@
//======================================================================
// audio.h
//
// NOTE: Let's change the name of this file to RigAudio.h.
//======================================================================
#ifndef __iop_audio_h__
@ -8,27 +10,41 @@
#include <Audio.h>
#include "config.h"
enum RxInput {
RX_RIG_IN = 0,
RX_USB_IN = 1,
};
class RigAudio
{
public:
RigAudio(AudioConfig& c): _config(c) {}
enum RxOutput {
RX_SPEAKER_OUT = 0,
RX_LINE_OUT = 1,
RX_USB_OUT = 2,
};
void init() const;
enum TxInput {
TX_MIC_IN = -1,
TX_LINE_IN = 0,
TX_USB_IN = 1,
TX_TEST_IN = 2,
};
void muteRx() const;
void unmuteRx() const;
enum TxOutput {
TX_RIG_OUT = 0,
TX_USB_OUT = 1,
void muteAllTx() const;
void muteMicIn() const;
void unmuteMicIn() const;
void muteLineIn() const;
void unmuteLineIn() const;
void muteUSBIn() const;
void unmuteUSBIn() const;
void muteTTIn() const;
void unmuteTTIn() const;
void muteSpkrOut() const;
void unmuteSpkrOut() const;
void muteLineOut() const;
void unmuteLineOut() const;
void muteUSBOut() const;
void unmuteUSBOut() const;
private:
AudioConfig _config;
};
//======================================================================
@ -60,11 +76,13 @@ class BPFilter {
//======================================================================
/*
void audioInit();
void audioSelectTxInput(TxInput);
void audioTransmit();
void audioReceive();
void audioCalibrate(IOPConfig *, char, char, char, float, bool);
void audioCalibrate(AudioConfig *, char, char, char, float, bool);
*/
#endif

View File

@ -1,19 +1,37 @@
//======================================================================
// audio.ino
//
// NOTE: Let's change the name of this file to Rigconfig.cc. Will need
// to ensure that "Arduino-isms" are resolved if it's converted to .cc
// from .ino, however.
//======================================================================
#include <dynamicFilters.h>
#include <effect_compressor_fb.h>
#include "audio.h"
#include "tx_audio_proc.h"
extern IOPConfig iopConfig;
short firActive[NUM_COEFFICIENTS];
#define RX_RIG_IN 0
#define RX_USB_IN 1
#define RX_ST_IN 2 // sidetone
#define TX_MIC_IN 0
#define TX_LINE_IN 0
#define TX_USB_IN 1
#define TX_TEST_IN 2
//extern RigConfig rigConfig;
/*
#define DEFAULT_RX_INPUT RIG
#define DEFAULT_RX_OUTPUT SPKR
#define DEFAULT_TX_INPUT MIC
#define DEFAULT_TX_OUTPUT RIG
*/
#include <Audio.h>
#include <Wire.h>
@ -75,10 +93,167 @@ AudioConnection patchCord26(calTxUSB, 0, outUSB, 1);
AudioControlSGTL5000 audioCtrl; //xy=648,517
// GUItool: end automatically generated code
void RigAudio::init() const {
USBDEBUG("audio initialization started");
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(_config.rxRigInLevel, _config.txLineInLevel); // NOTE: need to see if this persists through input changes (see mic gain...)
audioCtrl.lineOutLevel(_config.rxLineOutLevel, _config.txRigOutLevel); // NOTE: need to see if this persists through input changes (see mic gain...)
audioCtrl.micGain(_config.txMicInGain); // superfluous, as I have to do this anytime I switch to mic for some reason
// configure line input
audioCtrl.lineInLevel(_config.rxRigInLevel, _config.txLineInLevel);
// configure line output
calTxLine.gain(_config.txRigOutCal);
audioCtrl.lineOutLevel(_config.rxLineOutLevel, _config.txRigOutLevel);
// configure "receive" of USB audio input (debug only)
if (_config.rxUSBInEnable) {
mixRX.gain(RX_USB_IN, _config.rxUSBInVol * _config.rxUSBInCal);
} else {
mixRX.gain(RX_USB_IN, 0.0);
}
// configure USB audio output of transmit audio (useful for debug)
if (_config.txUSBOutEnable) {
calTxUSB.gain(_config.txUSBOutCal);
} else {
calTxUSB.gain(0.0);
}
// setup the two-tone generator
sine1.frequency(700);
sine2.frequency(1900);
sine1.amplitude(0);
sine2.amplitude(0);
audioFilter(firActive, NUM_COEFFICIENTS, ID_BANDPASS, W_HAMMING, 300.0, 3100.0); // 2.8 kHz filter
filterRX.begin(firActive, NUM_COEFFICIENTS);
filterAmp.gain(1.0);
// for now, just pass through the compressor
compTX.disable();
compAmp.gain(1.0);
// Hardware should be all setup... now we're going to mute everything
// and let the modes take care of enabling/disabling what they should.
for (int i = 0; i < 4; i++) {
mixRX.gain(i, 0.0);
mixTX.gain(i, 0.0);
}
USBDEBUG("audio initialization completed");
}
void RigAudio::muteRx() const {
mixRX.gain(RX_RIG_IN, 0.0);
USBDEBUG("RX audio muted");
}
void RigAudio::unmuteRx() const {
audioCtrl.inputSelect(AUDIO_INPUT_LINEIN);
mixRX.gain(RX_RIG_IN, _config.rxRigInVol * _config.rxRigInCal);
USBDEBUG("RX audio unmuted");
}
void RigAudio::muteAllTx() const {
muteMicIn();
muteLineIn();
muteUSBIn();
muteTTIn();
USBDEBUG("all TX audio muted");
}
void RigAudio::muteMicIn() const {
mixTX.gain(TX_LINE_IN, 0.0);
USBDEBUG("Mic In audio muted");
}
void RigAudio::unmuteMicIn() const {
audioCtrl.inputSelect(AUDIO_INPUT_MIC);
audioCtrl.micGain(_config.txMicInGain);
mixTX.gain(TX_LINE_IN, _config.txMicInVol * _config.txMicInCal);
USBDEBUG("Mic In audio unmuted");
}
void RigAudio::muteLineIn() const {
mixTX.gain(TX_LINE_IN, 0.0);
USBDEBUG("Line In audio muted");
}
void RigAudio::unmuteLineIn() const {
audioCtrl.inputSelect(AUDIO_INPUT_LINEIN);
mixTX.gain(TX_LINE_IN, _config.txLineInVol * _config.txLineInCal);
USBDEBUG("Line In audio unmuted");
}
void RigAudio::muteUSBIn() const {
mixTX.gain(TX_USB_IN, 0.0);
USBDEBUG("USB In audio muted");
}
void RigAudio::unmuteUSBIn() const {
mixTX.gain(TX_USB_IN, _config.txUSBInVol * _config.txUSBInCal);
USBDEBUG("USB In audio unmuted");
}
void RigAudio::muteTTIn() const {
mixTX.gain(TX_TEST_IN, 0.0);
mixTX.gain(TX_TEST_IN + 1, 0.0);
sine1.amplitude(0.0);
sine2.amplitude(0.0);
USBDEBUG("Two Tone audio muted");
}
void RigAudio::unmuteTTIn() const {
sine1.amplitude(0.5);
sine2.amplitude(0.5);
mixTX.gain(TX_TEST_IN, _config.txSine1Vol);
mixTX.gain(TX_TEST_IN + 1, _config.txSine2Vol);
USBDEBUG("Two Tone audio unmuted");
}
void RigAudio::muteSpkrOut() const {
calRxSpkr.gain(0.0);
USBDEBUG("Speaker Out audio muted");
}
void RigAudio::unmuteSpkrOut() const {
calRxSpkr.gain(_config.rxSpkrOutCal);
USBDEBUG("Speaker Out audio unmuted");
}
void RigAudio::muteLineOut() const {
calRxLine.gain(0.0);
USBDEBUG("Line Out audio muted");
}
void RigAudio::unmuteLineOut() const {
calRxLine.gain(_config.rxLineOutCal);
USBDEBUG("Line Out audio unmuted");
}
void RigAudio::muteUSBOut() const {
calRxUSB.gain(0.0);
USBDEBUG("USB Out audio muted");
}
void RigAudio::unmuteUSBOut() const {
calRxUSB.gain(_config.rxUSBOutCal);
USBDEBUG("USB Out audio unmuted");
}
/*
RxInput audioRxInput;
RxOutput audioRxOutput;
TxInput audioTxInput;
TxOutput audioTxOutput;
*/
//======================================================================
@ -130,20 +305,13 @@ void BPFilter::update(AudioFilterFIR* filter=NULL, short* coefficients=NULL) {
filter->begin(coefficients, NUM_COEFFICIENTS);
}
static AudioFilterFIR* BPFilter::_filter = &filterRX;
static short BPFilter::_coefficients[NUM_COEFFICIENTS];
AudioFilterFIR* BPFilter::_filter = &filterRX;
short BPFilter::_coefficients[NUM_COEFFICIENTS];
//======================================================================
enum FilterWidth {
FILTER_WIDE = 0,
FILTER_NORMAL,
FILTER_NARROW,
NUM_FILTER_WIDTHS
};
/*
// array based on mode right now
BPFilter *rxFilter[NUM_RIG_MODES][NUM_FILTER_WIDTHS];
BPFilter *rxFilter[NUM_RIG_MODES][NUM_RX_FILTERS];
//======================================================================
@ -179,9 +347,9 @@ void audioInit()
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.lineInLevel(rigConfig.rxRigInLevel, rigConfig.txLineInLevel); // NOTE: need to see if this persists through input changes (see mic gain...)
audioCtrl.lineOutLevel(rigConfig.rxLineOutLevel, rigConfig.txRigOutLevel); // NOTE: need to see if this persists through input changes (see mic gain...)
audioCtrl.micGain(rigConfig.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
@ -220,293 +388,14 @@ void audioInit()
speechCompressor.enable();
}
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 muteRxUSBIn()
{
mixRX.gain(RX_USB_IN, 0.0);
}
inline void restoreRxUSBIn()
{
updateRxUSBIn();
}
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 updateTxTwoToneIn()
{
sine1.amplitude(0.5);
sine2.amplitude(0.5);
mixTX.gain(TX_TEST_IN, iopConfig.txSine1Vol);
mixTX.gain(TX_TEST_IN + 1, iopConfig.txSine2Vol);
}
inline void muteTxTwoToneIn()
{
mixTX.gain(TX_TEST_IN, 0.0);
mixTX.gain(TX_TEST_IN + 1, 0.0);
sine1.amplitude(0);
sine2.amplitude(0);
}
inline void restoreTxTwoToneIn()
{
sine1.amplitude(0.5);
sine2.amplitude(0.5);
mixTX.gain(TX_TEST_IN, iopConfig.txSine1Vol);
mixTX.gain(TX_TEST_IN + 1, iopConfig.txSine2Vol);
}
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 audioSelectRxInput(RxInput input)
{
if (audioRxInput != input) {
audioRxInput = input;
switch(input) {
case RX_RIG_IN:
muteRxUSBIn();
restoreRxRigIn();
mixRX.gain(2, 0);
mixRX.gain(3, 0);
break;
case RX_USB_IN:
muteRxRigIn();
restoreRxUSBIn();
mixRX.gain(2, 0);
mixRX.gain(3, 0);
break;
}
}
}
void audioSelectTxInput(TxInput input)
{
if (audioTxInput != input) {
audioTxInput = input;
//muteTxMicIn(); // redundant w/ Line-In
muteTxLineIn();
muteTxUSBIn();
muteTxTwoToneIn();
/* 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()
{
switch(rigMode) {
// Nothing special for CW, TX audio inputs are already muted.
//case RIG_MODE_CW:
//break;
case RIG_MODE_SSB:
// 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) {
audioCtrl.inputSelect(AUDIO_INPUT_MIC);
updateTxMicIn();
#if defined(FACTORY_CALIBRATION)
USBSERIAL.println("==============================");
USBSERIAL.println("Transmitting with Mic input");
USBSERIAL.print("Mic gain: ");
USBSERIAL.println(iopConfig.txMicInGain);
USBSERIAL.print("Mic volume: ");
USBSERIAL.println(iopConfig.txMicInVol);
USBSERIAL.print("Mic calibration: ");
USBSERIAL.println(iopConfig.txMicInCal);
USBSERIAL.print("TX audio level: ");
USBSERIAL.println(iopConfig.txRigOutLevel);
USBSERIAL.print("TX audio calibration: ");
USBSERIAL.println(iopConfig.txRigOutCal);
USBSERIAL.println("==============================");
#endif
} else if (audioTxInput == TX_LINE_IN) {
updateTxLineIn();
}
break;
case RIG_MODE_DIGI:
// Mute the incoming RX audio. Can't think of a good reason
// to let RX audio in while we're transmitting.
muteRxRigIn();
updateTxUSBIn();
break;
case RIG_MODE_TEST:
muteRxRigIn();
updateTxTwoToneIn();
break;
}
}
//======================================================================
// 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()
{
switch(rigMode) {
//case RIG_MODE_CW:
//break;
case RIG_MODE_SSB:
if (audioTxInput == TX_MIC_IN) {
muteTxMicIn();
audioCtrl.inputSelect(AUDIO_INPUT_LINEIN);
} else if (audioTxInput == TX_LINE_IN) {
muteTxLineIn();
}
restoreRxRigIn();
break;
case RIG_MODE_DIGI:
muteTxUSBIn();
restoreRxRigIn();
break;
case RIG_MODE_TEST:
muteTxTwoToneIn();
restoreRxRigIn();
break;
}
}
//======================================================================
void audioUpdate()
{
speechCompressor.update();
}
//======================================================================
void audioCalibrate(IOPConfig* c, char cmd, char subcmd, char parm, float value, bool set_value=true)
void audioCalibrate(AudioConfig* c, char cmd, char subcmd, char parm, float value, bool set_value=true)
{
switch(cmd) {
case 'r':
@ -807,7 +696,7 @@ void audioDigiFilter()
audioCtrl.eqFilter(4, lpFilter);
audioCtrl.eqFilter(5, hpFilter);
}
*/
//======================================================================
// EOF
//======================================================================

View File

@ -3,11 +3,15 @@
//======================================================================
#include "cat.h"
#include "TxSwitch.h"
// make these messages static inside a function
IOPMessage inBuf; // input message buffer
IOPMessage outBuf; // output message buffer
extern CATSwitch catPTT;
extern Rig rig;
//======================================================================
// CAT from PC-to-IOP
//
@ -50,20 +54,32 @@ void processIOPCommand(IOPMessage const& m)
if (m.len < 1) {
return;
} else {
setRigMode(RigMode(m.data[0]));
rig.switchMode(RigMode(m.data[0]));
#if defined(DEBUG)
switch(rigMode) {
case RIG_MODE_CW:
USBDEBUG("new mode - CW");
switch(rig.modeNum()) {
case RIG_MODE_CWL:
USBDEBUG("new mode - CWL");
break;
case RIG_MODE_SSB:
USBDEBUG("new mode - SSB");
case RIG_MODE_CWU:
USBDEBUG("new mode - CWU");
break;
case RIG_MODE_DIGI:
USBDEBUG("new mode - DIGI");
case RIG_MODE_LSB:
USBDEBUG("new mode - LSB");
break;
case RIG_MODE_TEST:
USBDEBUG("new mode - TEST");
case RIG_MODE_USB:
USBDEBUG("new mode - USB");
break;
case RIG_MODE_DGL:
USBDEBUG("new mode - DGL");
break;
case RIG_MODE_DGU:
USBDEBUG("new mode - DGU");
break;
case RIG_MODE_TTL:
USBDEBUG("new mode - TTL");
break;
case RIG_MODE_TTU:
USBDEBUG("new mode - TTU");
break;
}
#endif
@ -71,11 +87,11 @@ void processIOPCommand(IOPMessage const& m)
break;
case IOP_START_TX_COMMAND:
catPTTOn();
catPTT.press(rig.mode());
break;
case IOP_STOP_TX_COMMAND:
catPTTOff();
catPTT.release(rig.mode());
break;
case IOP_CW_CONFIG_MSG:
@ -103,7 +119,7 @@ void processCalCommand(const char* buf)
case 'R':
case 't':
case 'T':
audioCalibrate(&iopConfig, cmd, subcmd, parm, value, (count == 4));
//audioCalibrate(&rigConfig.audio, cmd, subcmd, parm, value, (count == 4));
break;
default:

View File

@ -1,11 +1,14 @@
//======================================================================
// config.h
//
// NOTE: Let's change the name of this file to RigConfig.h.
//======================================================================
#ifndef __iop_config_h__
#define __iop_config_h__
#include <iopcomm.h>
//#include "rig.h"
#define KEYER_LEFT_PADDLE_PIN 16
#define KEYER_RIGHT_PADDLE_PIN 17
@ -15,12 +18,16 @@
// There will be no pass-thru of any CAT.
//#define FACTORY_CALIBRATION
// IOPConfig
// Used to store configuration parameters during runtime, as well as to
// save them to EEPROM.
struct IOPConfig {
//======================================================================
// AudioConfig
//======================================================================
class AudioConfig {
public:
//--------------------------------------------------------------------
// RECEIVE PARAMETERS
//--------------------------------------------------------------------
// rig-in parameters (RX)
uint8_t rxRigInLevel = 5;
@ -38,35 +45,43 @@ struct IOPConfig {
// USB-out parameters (RX)
float rxUSBOutCal = 1.0;
//--------------------------------------------------------------------
// TRANSMIT PARAMETERS
//--------------------------------------------------------------------
// NOTE: Default rig-out parameters are based on trying to hit a 25mVrms output to the
// rig. This is based on some discussion at the following URL:
//--------------------------------------------------------------------
// NOTE: Default rig-out parameters are based on trying to hit a
// 25mVrms output to the rig. This is based on some discussion at the
// following URL:
//
// https://groups.io/g/BITX20/message/58951
//
// This may or may not be totally applicable. I believe it was for IMD/spurs on a pre-V5
// version of the uBITX. So it may be OBE for my V5. It also alludes to modifications
// to the transmit audio chain, which may be something I need to look into (i.e. increasing
// This may or may not be totally applicable. I believe it was for
// IMD/spurs on a pre-V5 version of the uBITX. So it may be OBE for
// my V5. It also alludes to modifications to the transmit audio
// chain, which may be something I need to look into (i.e. increasing
// the gain on the initial mic pre-amp).
//
// Specifically, for the rig-out parameters:
// line out level 31 = 1.16 V p-p
// = 0.58 V peak
// = 0.41 V rms = 410 mV rms
// so output calibration needs to reduce that to 17.5 mV rms (70% of 25 mV rms)
// so output calibration needs to reduce that to 17.5 mV rms (70%
// of 25 mV rms)
// txMicInCal = 0.043 ... seems pretty low...
//
// Likewise, default line-in (TX) parameters assume consumer line level
// input, but with the default audio adaptor line-in level setting (5 = 1.33V p-p).
// Likewise, default line-in (TX) parameters assume consumer line
// level input, but with the default audio adaptor line-in level
// setting (5 = 1.33V p-p).
// line in level 5 = 1.33 V p-p
// signal in = 0.894 V p-p
// = 0.447 V peak
// = 0.316 V rms = 316 mV rms
// so input calibration needs to convert that to the 410 mV noted above (equivalent
// for the microphone), so that when that signal gets to the rig-out, it gets
// treated the same as the mic input.
// so input calibration needs to convert that to the 410 mV noted
// above (equivalent for the microphone), so that when that signal
// gets to the rig-out, it gets treated the same as the mic input.
// txLineInCal = 1.30
//--------------------------------------------------------------------
// microphone-in parameters (TX)
uint8_t txMicInGain = 12;
@ -88,18 +103,54 @@ struct IOPConfig {
// USB-out parameters (TX)- debug/monitor use only
bool txUSBOutEnable = true;
float txUSBOutCal = 1.0;
// SSB configuration
SSBConfig ssb;
// Digi configuration
DigiConfig digi;
// CW configuration
CWConfig cw;
};
extern IOPConfig iopConfig;
//======================================================================
// RigConfig
// Used to store configuration parameters during runtime, as well as to
// save them to EEPROM.
//======================================================================
class RigConfig {
public:
// audio configuration
AudioConfig audio;
// SSB configuration
SSBConfig lsb{RX_FILTER_WIDE};
SSBConfig usb{RX_FILTER_WIDE};
// DGT configuration
DGTConfig dgl{RX_FILTER_WIDE};
DGTConfig dgu{RX_FILTER_WIDE};
// CW configuration
CWConfig cwl{
KEYER_MODE_IAMBIC_A,
false,
15,
3.0,
700,
RX_FILTER_WIDE,
};
CWConfig cwu{
KEYER_MODE_IAMBIC_A,
false,
15,
3.0,
700,
RX_FILTER_WIDE,
};
// TT configuration
TTConfig ttl{RX_FILTER_WIDE};
TTConfig ttu{RX_FILTER_WIDE};
// General rig configuration entries.
RigMode mode = RIG_MODE_LSB;
};
extern RigConfig rigConfig;
#endif

View File

@ -11,8 +11,10 @@
#include "eeprom.h"
#include "keyer.h"
#define PTT_KEY_OUT_PIN 2
// comment this out to disable debugging code
//#define DEBUG
#define DEBUG
#if defined(DEBUG)
#define USBDEBUG(x) USBSERIAL.print("IOP: "); USBSERIAL.println(x);
@ -34,10 +36,35 @@ enum TxState {
TX_KEYER,
};
extern RigMode rigMode;
//extern RigMode rigMode;
extern bool keyerKeyDown;
//======================================================================
// Keying functions.
//
// These are simple functions to assert the key line from the IOP to the
// Raduino.
//======================================================================
inline void initKeyLine()
{
pinMode(PTT_KEY_OUT_PIN, OUTPUT);
digitalWrite(PTT_KEY_OUT_PIN, HIGH);
}
inline void setKeyDown()
{
digitalWrite(PTT_KEY_OUT_PIN, LOW);
}
inline void setKeyUp()
{
digitalWrite(PTT_KEY_OUT_PIN, HIGH);
}
//======================================================================
#endif
//======================================================================

View File

@ -3,340 +3,175 @@
//======================================================================
#include <iopcomm.h>
#include "audio.h"
#include "config.h"
#include "ubitx_iop.h"
#include "keyer.h"
#include "rig.h"
#include "TxSwitch.h"
#include <Bounce2.h>
#define BOUNCE_WITH_PROMPT_DETECTION
Keyer keyer{15, 3.0}; // NOTE: make configurable
RigMode rigMode = RIG_MODE_SSB;
//RxFilter rxFilter = RX_FILTER_NORMAL;
IOPConfig iopConfig;
RigConfig rigConfig;
RigAudio rigAudio{rigConfig.audio};
Rig rig{rigConfig, rigAudio};
#define MIC_PTT_PIN 21
#define LINE_PTT_PIN 20
#define PTT_KEY_OUT_PIN 2
CATSwitch catPTT;
//MicSwitch micPTTHelper;
GPIOSwitch micPTT(true, MIC_PTT_PIN);
//LineSwitch linePTTHelper;
GPIOSwitch linePTT(false, LINE_PTT_PIN);
Bounce micPTT = Bounce();
Bounce linePTT = Bounce();
TxState txState = TX_OFF;
Keyer keyer(15, 3.0); // need to make configurable
//SSBMenu ssbMenu();
//DigiMenu digiMenu();
//CWMenu cwMenu();
//MenuItem* dspMenu = &ssbMenu;
elapsedMillis frameMillis;
unsigned frameCounter;
//======================================================================
// catPTTOn()
//
// NOTE: Should probably move this to cat.ino.
//======================================================================
void catPTTOn()
{
// Check if we're already transmitting. If so, then this command
// does nothing: existing transmission, from existing source and PTT,
// will continue.
if (txState != TX_OFF) return;
switch(rigMode) {
// CAT should not start or stop TX in CW mode... we really should
// not even get this command. But maybe the rig control software is
// doing it (but then, we should inhibit this in the Raduino).
//case RIG_MODE_CW:
//break;
case RIG_MODE_SSB:
// In SSB mode, CAT-PTT will always (de-)activate the Line-In TX
// audio source.
txState = TX_CAT;
audioSelectTxInput(TX_LINE_IN); // in case Mic-In is selected
audioTransmit();
digitalWrite(PTT_KEY_OUT_PIN, LOW);
break;
case RIG_MODE_DIGI:
// In Digital (USB) mode, CAT-PTT will always (de-)activate the
// USB-In TX audio source.
txState = TX_CAT;
audioTransmit();
digitalWrite(PTT_KEY_OUT_PIN, LOW);
break;
}
}
//======================================================================
// catPTTOff()
//
// NOTE: Should probably move this to cat.ino.
//======================================================================
void catPTTOff()
{
// If we're not transmitting, or the active PTT is not CAT, then this
// command does nothing: CAT cannot interrupt other transmissions.
if (txState != TX_CAT) return;
switch(rigMode) {
// CAT should not start or stop TX in CW mode... we really should
// not even get this command. But maybe the rig control software is
// doing it (but then, we should inhibit this in the Raduino).
//case RIG_MODE_CW:
//break;
case RIG_MODE_SSB:
// In SSB mode, CAT-PTT will always (de-)activate the Line-In TX
// audio source.
digitalWrite(PTT_KEY_OUT_PIN, HIGH);
audioReceive();
txState = TX_OFF;
break;
case RIG_MODE_DIGI:
// In Digital (USB) mode, CAT-PTT will always (de-)activate the
// USB-In TX audio source.
digitalWrite(PTT_KEY_OUT_PIN, HIGH);
audioReceive();
txState = TX_OFF;
break;
}
}
//======================================================================
// checkMicPTT()
//======================================================================
void checkMicPTT()
{
micPTT.update();
// If we're transmitting, then we're just going to check if Mic-PTT
// was released--the Mic-PTT can always be used to terminate a
// transmission from another source.
if ((txState != TX_OFF) && micPTT.rose()) {
USBDEBUG("mic PTT released");
digitalWrite(PTT_KEY_OUT_PIN, HIGH);
// In CW mode, we get a sidetone from the uBITX, so we don't mute
// the receive audio.
if (rigMode != RIG_MODE_CW) audioReceive();
txState = TX_OFF;
return;
}
if ((txState == TX_OFF) && micPTT.fell()) {
USBDEBUG("mic PTT depressed");
switch(rigMode) {
case RIG_MODE_CW:
txState = TX_MIC;
digitalWrite(PTT_KEY_OUT_PIN, LOW);
break;
case RIG_MODE_SSB:
txState = TX_MIC;
audioSelectTxInput(TX_MIC_IN);
audioTransmit();
digitalWrite(PTT_KEY_OUT_PIN, LOW);
break;
case RIG_MODE_DIGI:
// Mic PTT actuation during Digital does nothing.
break;
case RIG_MODE_TEST:
txState = TX_MIC;
audioSelectTxInput(TX_TEST_IN);
audioTransmit();
digitalWrite(PTT_KEY_OUT_PIN, LOW);
break;
}
}
}
//======================================================================
// checkLinePTT()
//======================================================================
void checkLinePTT()
{
linePTT.update();
// If we're transmitting, then we're just going to check if Line-PTT
// was released--the Line-PTT can always be used to terminate a
// transmission from another source.
if ((txState != TX_OFF) && linePTT.rose()) {
digitalWrite(PTT_KEY_OUT_PIN, HIGH);
// In CW mode, we get a sidetone from the uBITX, so we don't mute
// the receive audio.
if (rigMode != RIG_MODE_CW) audioReceive();
txState = TX_OFF;
return;
}
if ((txState == TX_OFF) && linePTT.fell()) {
switch(rigMode) {
case RIG_MODE_CW:
txState = TX_LINE;
digitalWrite(PTT_KEY_OUT_PIN, LOW);
break;
case RIG_MODE_SSB:
txState = TX_LINE;
audioSelectTxInput(TX_LINE_IN);
audioTransmit();
digitalWrite(PTT_KEY_OUT_PIN, LOW);
break;
case RIG_MODE_DIGI:
// Line PTT actuation during Digital does nothing.
break;
case RIG_MODE_TEST:
txState = TX_LINE;
audioSelectTxInput(TX_TEST_IN);
audioTransmit();
digitalWrite(PTT_KEY_OUT_PIN, LOW);
break;
}
}
}
//======================================================================
void setRigMode(RigMode m)
{
rigMode = m;
switch(rigMode) {
case RIG_MODE_SSB:
case RIG_MODE_TEST:
// SSB sets the TX audio input to line-in. Note that this will be
// automatically overridden by mic-in, if the mic PTT is pressed.
audioSelectTxInput(TX_LINE_IN);
// audioSSBFilter();
// dspMenu = &ssbMenu;
break;
case RIG_MODE_DIGI:
// Digi sets the TX audio input to USB-in. Keying in this case must
// be via CAT control. Digital modes can also be used through the
// line-in, but the rig mode should be set to SSB in that case, and
// the rig could be keyed either via the line-in PTT, or via CAT.
// Digimodes could also be used through the mic-in, but in that case,
// the mic PTT line would need to be keyed by the computer rather
// than using CAT for PTT control.
audioSelectTxInput(TX_USB_IN);
// audioDigiFilter();
// dspMenu = &digiMenu;
break;
case RIG_MODE_CW:
// CW just gets the radio off of Mic-In; but it won't use Line-In.
audioSelectTxInput(TX_LINE_IN);
// audioCWFilter();
// dspMenu = &cwMenu;
break;
}
}
//======================================================================
//elapsedMillis frame10hz = 0;
void setup() {
// put your setup code here, to run once:
initCAT(38400, SERIAL_8N1);
USBDEBUG("setup started");
AudioMemory(16);
AudioMemory(20); // NOTE: Need to fine tune this. Have had errors due to this being too low.
micPTT.attach(MIC_PTT_PIN, INPUT_PULLUP);
micPTT.interval(25);
linePTT.attach(LINE_PTT_PIN, INPUT_PULLUP);
linePTT.interval(25);
initKeyLine();
rigAudio.init();
pinMode(PTT_KEY_OUT_PIN, OUTPUT);
digitalWrite(PTT_KEY_OUT_PIN, HIGH);
frameCounter = 0;
frameMillis = 0;
audioInit();
USBDEBUG("setup completed");
// audioInit();
/*
#if defined(FACTORY_CALIBRATION)
setRigMode(RIG_MODE_TEST);
#else
setRigMode(RIG_MODE_SSB);
#endif
//frame10Hz = 0;
*/
}
//======================================================================
void loop() {
// elapsedMillis elapsed = 0;
RigMode oldRigMode = rigMode;
//RxFilter oldRxFilter = rxFilter;
void loop()
{
static char frame_status[100];
static bool paddle_loop = false;
switch(rigMode) {
case RIG_MODE_CW:
RigMode oldRigMode;
frameCounter++;
if (rig.isCWMode()) {
if (keyer.do_paddles()) {
if (keyer.is_down()) {
digitalWrite(PTT_KEY_OUT_PIN, LOW);
} else {
digitalWrite(PTT_KEY_OUT_PIN, HIGH);
// Checking for T/R separately from the paddle loop, because it's
// possible we're already transmitting (PTT/Key being held), and
// we don't want to run the tx() actions if we're already in TX.
if (rig.isRx()) {
USBDEBUG("entered TX via paddles");
rig.tx();
}
// No break... if the paddle is not active, I want this to fall
// through to checkMicPTT etc... but return early if the paddle is
// active, to maximize responsiveness. Probably could just use
// 'if' statements here instead of the 'switch'.
return;
}
default:
checkMicPTT();
checkLinePTT();
serviceCAT();
paddle_loop = true;
if (keyer.is_down()) {
setKeyDown();
} else {
setKeyUp();
}
return; // return early for paddle responsiveness
} else {
if (paddle_loop) {
// If we exit the paddle loop (i.e. keyer completes its keying
// sequence), then we'll go back to receive, even if one of the
// PTT/Key lines is still held separately. General principle is
// that if "something" stops transmitting, then the rig will
// stop transmitting.
paddle_loop = false;
rig.rx();
USBDEBUG("exited TX from paddles");
}
}
}
rig.update();
oldRigMode = rig.modeNum();
// Update the mic PTT. We need to tell it if we're in SSB mode, so that
// it knows if it should switch to the mic input if pressed. We also
// need to make it inactive if we're in DGT mode, since only CAT will be
// used to start transmitting in that case.
micPTT.setSSBMode(rig.isSSBMode());
micPTT.update(rig.mode(), !rig.isDGTMode());
// Update the line PTT. We need to tell it if we're in SSB mode, so that
// it knows if it should switch to the line input if pressed. We also
// need to make it inactive if we're in DGT mode, since only CAT will be
// used to start transmitting in that case.
linePTT.setSSBMode(rig.isSSBMode());
linePTT.update(rig.mode(), !rig.isDGTMode());
serviceCAT();
// send current status @ 10 Hz
//if (frame10Hz > 100) {
if ((rigMode != oldRigMode)) { // || (rxFilter != oldRxFilter)) {
switch(rigMode) {
case RIG_MODE_SSB:
sendIOPSSBStatus(iopConfig.ssb);
if ((rig.modeNum() != oldRigMode)) { // || (rxFilter != oldRxFilter)) {
USBDEBUG("mode changed");
switch(rig.modeNum()) {
case RIG_MODE_LSB:
USBDEBUG("sending LSB mode status");
sendIOPSSBStatus(rigConfig.lsb);
break;
case RIG_MODE_DIGI:
sendIOPDigiStatus(iopConfig.digi);
case RIG_MODE_USB:
USBDEBUG("sending USB mode status");
sendIOPSSBStatus(rigConfig.usb);
break;
case RIG_MODE_CW:
sendIOPCWStatus(iopConfig.cw);
case RIG_MODE_DGL:
USBDEBUG("sending DGL mode status");
sendIOPDGTStatus(rigConfig.dgl);
break;
case RIG_MODE_TEST:
case RIG_MODE_DGU:
USBDEBUG("sending DGU mode status");
sendIOPDGTStatus(rigConfig.dgu);
break;
case RIG_MODE_CWL:
USBDEBUG("sending CWL mode status");
sendIOPCWStatus(rigConfig.cwl);
break;
case RIG_MODE_CWU:
USBDEBUG("sending CWU mode status");
sendIOPCWStatus(rigConfig.cwu);
break;
case RIG_MODE_TTL:
USBDEBUG("sending TTL mode status");
sendIOPTestStatus();
break;
case RIG_MODE_TTU:
USBDEBUG("sending TTU mode status");
sendIOPTestStatus();
break;
}
//frame10Hz = 0;
}
audioUpdate();
//dspMenu->update();
/*
#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
if (frameMillis > 1000) {
#if defined(DEBUG)
sprintf(frame_status, "update: %d ms, %d frames\n", frameMillis, frameCounter);
USBDEBUG(frame_status);
#endif
}
*/
//audioUpdate(); // was used to update the speech compressor
}
//======================================================================