Compare commits
9 Commits
mode-based
...
new-main-d
Author | SHA1 | Date | |
---|---|---|---|
295b99ef36 | |||
|
e6009989db | ||
|
1f3585d8e4 | ||
|
c8aecdfb0d | ||
|
f724142fca | ||
|
869e47d430 | ||
|
20b475dace | ||
|
962a3ce80f | ||
|
86ae1ddb2f |
@@ -1 +0,0 @@
|
|||||||
../TeensyDSP/Debug.h
|
|
0
Raduino/Debug.h
Executable file
0
Raduino/Debug.h
Executable file
@@ -1 +0,0 @@
|
|||||||
../TeensyDSP/RigState.cpp
|
|
0
Raduino/RigState.cpp
Executable file
0
Raduino/RigState.cpp
Executable file
@@ -1 +0,0 @@
|
|||||||
../TeensyDSP/RigState.h
|
|
0
Raduino/RigState.h
Executable file
0
Raduino/RigState.h
Executable file
BIN
References/B5A-0180-20.pdf
Normal file
BIN
References/B5A-0180-20.pdf
Normal file
Binary file not shown.
BIN
References/ts_590_g_pc_command_e.pdf
Normal file
BIN
References/ts_590_g_pc_command_e.pdf
Normal file
Binary file not shown.
@@ -10,216 +10,351 @@
|
|||||||
//#include <SD.h>
|
//#include <SD.h>
|
||||||
//#include <SerialFlash.h>
|
//#include <SerialFlash.h>
|
||||||
|
|
||||||
#define RX_AUDIO_CH 0
|
|
||||||
|
|
||||||
const int txMicInChannel = TX_MIC_IN_CH;
|
|
||||||
const int txLineInChannel = TX_LINE_IN_CH;
|
|
||||||
const int txUSBInChannel = TX_USB_IN_CH;
|
|
||||||
const int txNumChannels = TX_NUM_CHANNELS;
|
|
||||||
|
|
||||||
const int txLineInVOX = TX_LINE_IN_VOX;
|
|
||||||
const int txUSBInLVOX = TX_USB_IN_L_VOX;
|
|
||||||
const int txUSBInRVOX = TX_USB_IN_R_VOX;
|
|
||||||
const int txNumVOX = TX_NUM_VOX;
|
|
||||||
|
|
||||||
|
|
||||||
UBitxDSP DSP;
|
|
||||||
|
|
||||||
//static struct {
|
|
||||||
|
|
||||||
// GUItool: begin automatically generated code
|
// GUItool: begin automatically generated code
|
||||||
AudioInputUSB usbIn; //xy=153,341
|
AudioInputUSB usbIn; //xy=63,305
|
||||||
AudioInputI2S lineIn; //xy=161,233
|
AudioInputI2S lineIn; //xy=71,197
|
||||||
AudioAnalyzeRMS usbInRMS_R; //xy=276,431
|
AudioSynthWaveformSine tone1; //xy=111,369
|
||||||
AudioAnalyzeRMS usbInRMS_L; //xy=335,392
|
AudioSynthWaveformSine tone2; //xy=111,410
|
||||||
AudioAnalyzeRMS lineInRMS; //xy=387,273
|
AudioMixer4 rxAudio; //xy=328,111
|
||||||
AudioMixer4 rxAudio; //xy=418,147
|
AudioMixer4 txAudio; //xy=332,299
|
||||||
AudioMixer4 txAudio; //xy=422,335
|
AudioAnalyzeRMS txVoxLevel; //xy=490,340
|
||||||
AudioFilterFIR rxFilter; //xy=583,139
|
AudioFilterFIR rxFilter; //xy=493,103
|
||||||
AudioAmplifier usbOutAmp; //xy=748,135
|
AudioAmplifier usbOutAmp; //xy=658,99
|
||||||
AudioAmplifier lineOutAmp; //xy=749,198
|
AudioAmplifier lineOutAmp; //xy=659,162
|
||||||
AudioAmplifier usbBypassAmp; //xy=756,261
|
AudioAmplifier usbBypassAmp; //xy=666,225
|
||||||
AudioOutputI2S lineOut; //xy=966,330
|
AudioAmplifier txOutAmp; //xy=713,301
|
||||||
AudioOutputUSB usbOut; //xy=968,291
|
AudioOutputI2S lineOut; //xy=876,294
|
||||||
|
AudioOutputUSB usbOut; //xy=878,255
|
||||||
AudioConnection patchCord1(usbIn, 0, txAudio, 1);
|
AudioConnection patchCord1(usbIn, 0, txAudio, 1);
|
||||||
AudioConnection patchCord2(usbIn, 0, usbInRMS_L, 0);
|
AudioConnection patchCord2(lineIn, 0, rxAudio, 0);
|
||||||
AudioConnection patchCord3(usbIn, 1, usbInRMS_R, 0);
|
AudioConnection patchCord3(lineIn, 1, txAudio, 0);
|
||||||
AudioConnection patchCord4(lineIn, 0, rxAudio, 0);
|
AudioConnection patchCord4(tone1, 0, txAudio, 2);
|
||||||
AudioConnection patchCord5(lineIn, 1, txAudio, 0);
|
AudioConnection patchCord5(tone1, 0, rxAudio, 2);
|
||||||
AudioConnection patchCord6(lineIn, 1, lineInRMS, 0);
|
AudioConnection patchCord6(tone2, 0, txAudio, 3);
|
||||||
AudioConnection patchCord7(rxAudio, rxFilter);
|
AudioConnection patchCord7(tone2, 0, rxAudio, 3);
|
||||||
AudioConnection patchCord8(rxAudio, usbBypassAmp);
|
AudioConnection patchCord8(rxAudio, rxFilter);
|
||||||
AudioConnection patchCord9(txAudio, 0, lineOut, 1);
|
AudioConnection patchCord9(rxAudio, usbBypassAmp);
|
||||||
AudioConnection patchCord10(rxFilter, usbOutAmp);
|
AudioConnection patchCord10(txAudio, txVoxLevel);
|
||||||
AudioConnection patchCord11(rxFilter, lineOutAmp);
|
AudioConnection patchCord11(txAudio, txOutAmp);
|
||||||
AudioConnection patchCord12(usbOutAmp, 0, usbOut, 0);
|
AudioConnection patchCord12(rxFilter, usbOutAmp);
|
||||||
AudioConnection patchCord13(lineOutAmp, 0, lineOut, 0);
|
AudioConnection patchCord13(rxFilter, lineOutAmp);
|
||||||
AudioConnection patchCord14(usbBypassAmp, 0, usbOut, 1);
|
AudioConnection patchCord14(usbOutAmp, 0, usbOut, 0);
|
||||||
AudioControlSGTL5000 audioCtrl; //xy=427,476
|
AudioConnection patchCord15(lineOutAmp, 0, lineOut, 0);
|
||||||
|
AudioConnection patchCord16(usbBypassAmp, 0, usbOut, 1);
|
||||||
|
AudioConnection patchCord17(txOutAmp, 0, lineOut, 1);
|
||||||
|
AudioControlSGTL5000 audioCtrl; //xy=337,440
|
||||||
// GUItool: end automatically generated code
|
// GUItool: end automatically generated code
|
||||||
|
|
||||||
//} audio;
|
|
||||||
|
|
||||||
UBitxDSP::UBitxDSP() {
|
|
||||||
voxRMS[txLineInVOX] = &lineInRMS;
|
|
||||||
voxRMS[txUSBInLVOX] = &usbInRMS_L;
|
|
||||||
voxRMS[txUSBInRVOX] = &usbInRMS_R;
|
|
||||||
}
|
|
||||||
|
|
||||||
void UBitxDSP::begin() {
|
void UBitxDSP::begin() {
|
||||||
AudioMemory(16);
|
|
||||||
|
// Basic audio setup
|
||||||
|
AudioMemory(16); // TODO: optimize this
|
||||||
audioCtrl.enable();
|
audioCtrl.enable();
|
||||||
audioCtrl.volume(0.0); // headphone volume...
|
audioCtrl.volume(0.0); // headphone volume...
|
||||||
audioCtrl.muteHeadphone(); // ...not used by UBitxDSP
|
audioCtrl.muteHeadphone(); // ...not used by UBitxDSP
|
||||||
|
|
||||||
for (int i = 0; i < 4; i++) {
|
setupRxAudio();
|
||||||
if (i == RX_AUDIO_CH)
|
setupTxAudio();
|
||||||
rxAudio.gain(i, 1.0);
|
|
||||||
else
|
|
||||||
rxAudio.gain(i, 0.0);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int i = 0; i < 4; i++) {
|
|
||||||
txAudio.gain(i, 0.0);
|
|
||||||
}
|
|
||||||
|
|
||||||
// SETUP THE AUDIO INPUTS
|
|
||||||
|
|
||||||
// Rig (Line) Input (RX)
|
|
||||||
audioCtrl.inputSelect(AUDIO_INPUT_LINEIN);
|
|
||||||
audioCtrl.unmuteLineout();
|
|
||||||
audioCtrl.lineInLevel(9, 5); // RX, TX
|
|
||||||
audioCtrl.lineOutLevel(29, 31); //RX, TX
|
|
||||||
|
|
||||||
// Mic Input (TX)
|
|
||||||
audioCtrl.micGain(0); // TODO: set value
|
|
||||||
|
|
||||||
// Line Input (TX)
|
|
||||||
|
|
||||||
// USB Input (TX)
|
|
||||||
|
|
||||||
// SETUP THE AUDIO OUTPUTS
|
|
||||||
|
|
||||||
// Line Output (RX)
|
|
||||||
lineOutAmp.gain(1.0);
|
|
||||||
|
|
||||||
// USB Output (RX)
|
|
||||||
usbOutAmp.gain(1.0);
|
|
||||||
usbBypassAmp.gain(1.0);
|
|
||||||
|
|
||||||
// Rig (Line) Output (TX)
|
|
||||||
|
|
||||||
// Default to RX.
|
// Default to RX.
|
||||||
|
muteRxIn(); // redundant?
|
||||||
|
muteTxIn(); // redundant?
|
||||||
|
isTx = true; // so that rx() call works
|
||||||
rx();
|
rx();
|
||||||
|
|
||||||
// Setup the VOX - clean this up
|
// Setup the VOX - TBD
|
||||||
state.voxActive[TX_LINE_IN_VOX] = false;
|
|
||||||
state.voxThresh[TX_LINE_IN_VOX] = TX_LINE_IN_VOX_THRESH;
|
|
||||||
state.voxDelay[TX_LINE_IN_VOX] = TX_LINE_IN_VOX_DELAY;
|
|
||||||
state.voxTimeout[TX_LINE_IN_VOX] = 0;
|
|
||||||
state.voxActive[TX_USB_IN_L_VOX] = false;
|
|
||||||
state.voxThresh[TX_USB_IN_L_VOX] = TX_USB_IN_L_VOX_THRESH;
|
|
||||||
state.voxDelay[TX_USB_IN_L_VOX] = TX_USB_IN_L_VOX_DELAY;
|
|
||||||
state.voxTimeout[TX_USB_IN_L_VOX] = 0;
|
|
||||||
state.voxActive[TX_USB_IN_R_VOX] = false;
|
|
||||||
state.voxThresh[TX_USB_IN_R_VOX] = TX_USB_IN_R_VOX_THRESH;
|
|
||||||
state.voxDelay[TX_USB_IN_R_VOX] = TX_USB_IN_R_VOX_DELAY;
|
|
||||||
state.voxTimeout[TX_USB_IN_R_VOX] = 0;
|
|
||||||
|
|
||||||
// Setup the RX Filter.
|
// Setup the RX Filter.
|
||||||
setRxFilter(300, 3000);
|
setRxFilter(300.0, 3000.0);
|
||||||
|
|
||||||
sinceLastUpdate = 0;
|
sinceLastUpdate = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void UBitxDSP::update() {
|
void UBitxDSP::update() {
|
||||||
// Only going to adjust the USB volume periodically.
|
// Update the USB volume (level of TX USB output) periodically.
|
||||||
if (sinceLastUpdate > DSP_MILLIS_PER_UPDATE) {
|
if (sinceLastUpdate > DSP_MILLIS_PER_UPDATE) {
|
||||||
float vol = usbIn.volume();
|
float vol = usbIn.volume();
|
||||||
setTxInputLevel(txUSBInChannel, vol);
|
if (vol != usbVol) {
|
||||||
|
setTxInLevel(TX_USB, vol);
|
||||||
|
usbVol = vol;
|
||||||
|
}
|
||||||
sinceLastUpdate = 0;
|
sinceLastUpdate = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update the VOX switches.
|
|
||||||
// TODO: Move the enable logic in here, so we don't process unnecessarily.
|
|
||||||
for (int i = 0; i < txNumVOX; i++) {
|
|
||||||
if (voxRMS[i]->available()) {
|
|
||||||
float lvl = voxRMS[i]->read();
|
|
||||||
if (lvl > state.voxThresh[i]) {
|
|
||||||
state.voxTimeout[i] = millis() + state.voxDelay[i];
|
|
||||||
state.voxActive[i] = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (millis() > state.voxTimeout[i]) {
|
|
||||||
state.voxActive[i] = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void UBitxDSP::end() {
|
void UBitxDSP::end() {
|
||||||
|
bypassRxFilter();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**********************************************************************
|
||||||
|
* Transmit/Receive switching
|
||||||
|
**********************************************************************/
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Return to receive (RX) mode from transmit (TX) mode.
|
||||||
|
* First the transmit audio output is muted, to ensure that no more
|
||||||
|
* audio goes to the rig. Then we check to see if the latched TX audio
|
||||||
|
* source was different than the selected TX audio source; this happens
|
||||||
|
* if the radio is currently set for a particular input (which
|
||||||
|
* determines what is monitored by the VOX), but then is commanded to
|
||||||
|
* transmit a different source (e.g. based on a CAT command). The
|
||||||
|
* actual transmit audio source is latched during transmit, but upon
|
||||||
|
* returning to receive, we restore the selected transmit audio.
|
||||||
|
*/
|
||||||
void UBitxDSP::rx() {
|
void UBitxDSP::rx() {
|
||||||
// mute all tx audio
|
if (isTx) {
|
||||||
audioCtrl.micGain(0);
|
muteTxOut();
|
||||||
for (int i = 0; i < 4; i++) {
|
if (txSrcLatched != txSrc) {
|
||||||
txAudio.gain(i, 0.0);
|
setTxAudioIn(txSrc);
|
||||||
}
|
}
|
||||||
// select line in for rx
|
if (txSrcLatched == MIC_IN) {
|
||||||
audioCtrl.inputSelect(AUDIO_INPUT_LINEIN);
|
audioCtrl.inputSelect(AUDIO_INPUT_LINEIN);
|
||||||
// restore rx audio
|
}
|
||||||
rxAudio.gain(RX_AUDIO_CH, 1.0); // restore the RX audio
|
unmuteRxIn(RX_AUDIO);
|
||||||
|
isTx = false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void UBitxDSP::txMicIn() {
|
/*!
|
||||||
// mute the rx audio
|
* Enter transmit (TX) mode from receive (RX) mode.
|
||||||
rxAudio.gain(RX_AUDIO_CH, 0.0);
|
*/
|
||||||
// restore the tx mic audio
|
void UBitxDSP::tx(TxAudioIn src) {
|
||||||
|
if (!isTx) {
|
||||||
|
muteRxIn(RX_AUDIO);
|
||||||
|
|
||||||
|
txSrcLatched = src;
|
||||||
|
if (txSrcLatched != txSrc) {
|
||||||
|
setTxAudioIn(txSrcLatched, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (txSrcLatched == MIC_IN) {
|
||||||
audioCtrl.inputSelect(AUDIO_INPUT_MIC);
|
audioCtrl.inputSelect(AUDIO_INPUT_MIC);
|
||||||
audioCtrl.micGain(12);
|
audioCtrl.micGain(micGain);
|
||||||
for (int i = 0; i < 4; i++) {
|
}
|
||||||
if (i == TX_MIC_IN_CH)
|
|
||||||
txAudio.gain(i, 0.1);
|
unmuteTxOut();
|
||||||
else
|
isTx = true;
|
||||||
txAudio.gain(i, 0.0);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void UBitxDSP::txLineIn() {
|
/**********************************************************************
|
||||||
// mute the rx audio
|
* General audio setup -- called via begin()
|
||||||
rxAudio.gain(RX_AUDIO_CH, 0.0);
|
**********************************************************************/
|
||||||
// restore the tx line in audio
|
|
||||||
|
void UBitxDSP::setupRxAudio() {
|
||||||
|
for (int i = 0; i < NUM_RX_AUDIO_CH; i++) {
|
||||||
|
if (i == RX_AUDIO)
|
||||||
|
rxAudio.gain(i, 1.0);
|
||||||
|
else
|
||||||
|
rxAudio.gain(i, 0.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Rig (Line) Input (RX)
|
||||||
audioCtrl.inputSelect(AUDIO_INPUT_LINEIN);
|
audioCtrl.inputSelect(AUDIO_INPUT_LINEIN);
|
||||||
for (int i = 0; i < 4; i++) {
|
audioCtrl.unmuteLineout();
|
||||||
if (i == TX_LINE_IN_CH)
|
audioCtrl.lineInLevel(9, 5); // RX, TX
|
||||||
txAudio.gain(i, 0.1);
|
audioCtrl.lineOutLevel(29, 31); // RX, TX
|
||||||
else
|
|
||||||
|
// Line Output (RX)
|
||||||
|
setLineOutLevel(1.0);
|
||||||
|
|
||||||
|
// USB Output (RX)
|
||||||
|
setUSBOutLevel(1.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void UBitxDSP::setupTxAudio() {
|
||||||
|
for (int i = 0; i < NUM_TX_AUDIO_CH; i++) {
|
||||||
|
txAudio.gain(i, 0.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Mic Input (TX)
|
||||||
|
audioCtrl.micGain(0); // TODO: set value
|
||||||
|
// Line Input (TX)
|
||||||
|
|
||||||
|
// USB Input (TX)
|
||||||
|
|
||||||
|
// Rig (Line) Output (TX)
|
||||||
|
txOutAmp.gain(1.0);
|
||||||
|
|
||||||
|
tone1.amplitude(1.0); // TODO - just do this once.
|
||||||
|
tone1.frequency(1500); // TODO: Make this dynamic based on CW (sidetone freq) versus data (1500 Hz)
|
||||||
|
|
||||||
|
tone1.amplitude(1.0); // TODO - just do this once.
|
||||||
|
tone1.amplitude(1.0); // TODO - just do this once.
|
||||||
|
tone1.frequency(700);
|
||||||
|
tone2.frequency(1900);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**********************************************************************
|
||||||
|
* Receive audio chain
|
||||||
|
**********************************************************************/
|
||||||
|
|
||||||
|
void UBitxDSP::setRxInLevel(RxAudioCh ch, float level) {
|
||||||
|
if (ch < NUM_RX_AUDIO_CH) {
|
||||||
|
state.rxIn[ch].level = level;
|
||||||
|
rxAudio.gain(ch, state.rxIn[ch].mute ? 0.0 : state.rxIn[ch].level);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void UBitxDSP::muteRxIn() {
|
||||||
|
for (int i = 0; i < NUM_RX_AUDIO_CH; i++) {
|
||||||
|
state.rxIn[RxAudioCh(i)].mute = true;
|
||||||
|
rxAudio.gain(i, 0.0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void UBitxDSP::muteRxIn(RxAudioCh ch) {
|
||||||
|
if (ch < NUM_RX_AUDIO_CH) {
|
||||||
|
if (!state.rxIn[ch].mute) {
|
||||||
|
state.rxIn[ch].mute = true;
|
||||||
|
rxAudio.gain(ch, 0.0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void UBitxDSP::unmuteRxIn(RxAudioCh ch) {
|
||||||
|
if (ch < NUM_RX_AUDIO_CH) {
|
||||||
|
if (state.rxIn[ch].mute) {
|
||||||
|
state.rxIn[ch].mute = false;
|
||||||
|
rxAudio.gain(ch, state.rxIn[ch].level);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void UBitxDSP::setLineOutLevel(float level) {
|
||||||
|
state.rxOut[LINE_OUT].level = level;
|
||||||
|
lineOutAmp.gain(state.rxOut[LINE_OUT].mute ? 0.0 : state.rxOut[LINE_OUT].level);
|
||||||
|
}
|
||||||
|
|
||||||
|
void UBitxDSP::setUSBOutLevel(float level) {
|
||||||
|
state.rxOut[USB_OUT].level = level;
|
||||||
|
usbOutAmp.gain(state.rxOut[USB_OUT].mute ? 0.0 : state.rxOut[USB_OUT].level);
|
||||||
|
usbBypassAmp.gain(state.rxOut[USB_OUT].mute ? 0.0 : state.rxOut[USB_OUT].level);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**********************************************************************
|
||||||
|
* Transmit audio chain
|
||||||
|
**********************************************************************/
|
||||||
|
|
||||||
|
void UBitxDSP::setTxInLevel(TxAudioCh ch, float level) {
|
||||||
|
if (ch < NUM_TX_AUDIO_CH) {
|
||||||
|
state.txIn[ch].level = level;
|
||||||
|
txAudio.gain(ch, state.txIn[ch].mute ? 0.0 : state.txIn[ch].level);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void UBitxDSP::muteTxIn() {
|
||||||
|
for (int i = 0; i < NUM_TX_AUDIO_CH; i++) {
|
||||||
|
state.txIn[TxAudioCh(i)].mute = true;
|
||||||
txAudio.gain(i, 0.0);
|
txAudio.gain(i, 0.0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void UBitxDSP::txUSBIn() {
|
void UBitxDSP::muteTxIn(TxAudioCh ch) {
|
||||||
// mute the rx audio
|
if (ch < NUM_TX_AUDIO_CH) {
|
||||||
rxAudio.gain(RX_AUDIO_CH, 0.0);
|
if (!state.txIn[ch].mute) {
|
||||||
// restore the tx usb in audio
|
state.txIn[ch].mute = true;
|
||||||
audioCtrl.inputSelect(AUDIO_INPUT_LINEIN);
|
txAudio.gain(ch, 0.0);
|
||||||
for (int i = 0; i < 4; i++) {
|
}
|
||||||
if (i == TX_USB_IN_CH)
|
|
||||||
txAudio.gain(i, 0.1);
|
|
||||||
else
|
|
||||||
txAudio.gain(i, 0.0);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**********************************************************************/
|
void UBitxDSP::unmuteTxIn(TxAudioCh ch) {
|
||||||
// RX filter settings
|
if (ch < NUM_TX_AUDIO_CH) {
|
||||||
|
if (state.txIn[ch].mute) {
|
||||||
|
state.txIn[ch].mute = false;
|
||||||
|
rxAudio.gain(ch, state.txIn[ch].level);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const float minRxFilterLo = MIN_RX_FILTER_LO;
|
void UBitxDSP::setTxOutLevel(float level) {
|
||||||
const float maxRxFilterHi = MAX_RX_FILTER_HI;
|
state.txOut.level = level;
|
||||||
const float minRxFilterWidth = MIN_RX_FILTER_WIDTH;
|
txOutAmp.gain(state.txOut.mute ? 0.0 : state.txOut.level);
|
||||||
const float maxRxFilterWidth = MAX_RX_FILTER_WIDTH;
|
}
|
||||||
const float minRxFilterCenter = MIN_RX_FILTER_CENTER;
|
|
||||||
const float maxRxFilterCenter = MAX_RX_FILTER_CENTER;
|
void UBitxDSP::muteTxOut() {
|
||||||
|
if (!state.txOut.mute) {
|
||||||
|
state.txOut.mute = true;
|
||||||
|
txOutAmp.gain(0.0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void UBitxDSP::unmuteTxOut() {
|
||||||
|
if (state.txOut.mute) {
|
||||||
|
state.txOut.mute = false;
|
||||||
|
txOutAmp.gain(state.txOut.level);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void UBitxDSP::setLineInLevel(float level) {
|
||||||
|
state.txIn[TX_LINE].level = level;
|
||||||
|
txAudio.gain(TX_LINE, state.txIn[TX_LINE].mute ? 0.0 : state.txIn[TX_LINE].level);
|
||||||
|
}
|
||||||
|
|
||||||
|
void UBitxDSP::setUSBInLevel(float level) {
|
||||||
|
state.txIn[TX_USB].level = level;
|
||||||
|
txAudio.gain(TX_USB, state.txIn[TX_USB].mute ? 0.0 : state.txIn[TX_USB].level);
|
||||||
|
}
|
||||||
|
|
||||||
|
void UBitxDSP::setTxAudioIn(TxAudioIn src, bool isTemp) {
|
||||||
|
if (!isTemp) {
|
||||||
|
txSrc = src;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isTx) {
|
||||||
|
muteTxIn(); // Mute all channels, then unmute the desired ones.
|
||||||
|
switch (src) { // Don't switch inputs while transmitting.
|
||||||
|
case MIC_IN:
|
||||||
|
// Note that we can't actually use the VOX code on the mic input,
|
||||||
|
// because we can't make the actual mic input active without
|
||||||
|
// losing our receive audio. So, mic input is never actually
|
||||||
|
// selected until it is time for it to transmit, which makes the
|
||||||
|
// VOX moot. The caller must make use of an external, analog VOX
|
||||||
|
// circuit driving a GPIO pin, or something similar (or the PTT of
|
||||||
|
// course) to begin actually using the mic input. So this case
|
||||||
|
// just falls through to the line input.
|
||||||
|
|
||||||
|
case LINE_IN:
|
||||||
|
unmuteTxIn(TX_LINE);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case USB_IN:
|
||||||
|
unmuteTxIn(TX_USB);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case TUNE_IN:
|
||||||
|
tone1.amplitude(1.0); // TODO - just do this once.
|
||||||
|
tone1.frequency(1500); // TODO: Make this dynamic based on CW (sidetone freq) versus data (1500 Hz)
|
||||||
|
unmuteTxIn(TX_TONE1);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case TWO_TONE_IN:
|
||||||
|
tone1.amplitude(1.0); // TODO - just do this once.
|
||||||
|
tone1.amplitude(1.0); // TODO - just do this once.
|
||||||
|
tone1.frequency(700);
|
||||||
|
tone2.frequency(1900);
|
||||||
|
unmuteTxIn(TX_TONE1);
|
||||||
|
unmuteTxIn(TX_TONE2);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
// should never happen
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**********************************************************************
|
||||||
|
* Receive audio filter (band pass)
|
||||||
|
**********************************************************************/
|
||||||
|
|
||||||
|
const int minRxFilterLo = MIN_RX_FILTER_LO;
|
||||||
|
const int maxRxFilterHi = MAX_RX_FILTER_HI;
|
||||||
|
const int minRxFilterWidth = MIN_RX_FILTER_WIDTH;
|
||||||
|
const int maxRxFilterWidth = MAX_RX_FILTER_WIDTH;
|
||||||
|
const int minRxFilterCenter = MIN_RX_FILTER_CENTER;
|
||||||
|
const int maxRxFilterCenter = MAX_RX_FILTER_CENTER;
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* @brief Bypass the RX audio filter.
|
* @brief Bypass the RX audio filter.
|
||||||
@@ -229,16 +364,16 @@ void UBitxDSP::bypassRxFilter() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* @brief Update the RX audio filter using the currently set low and
|
@brief Update the RX audio filter using the currently set low and
|
||||||
* high frequencies. This is called by each of the public
|
high frequencies. This is called by each of the public
|
||||||
* filter methods to update the filter with new frequencies.
|
filter methods to update the filter with new frequencies.
|
||||||
*/
|
*/
|
||||||
void UBitxDSP::updateRxFilter() {
|
void UBitxDSP::updateRxFilter() {
|
||||||
audioFilter(coefficients, NUM_COEFFICIENTS, ID_BANDPASS, W_HAMMING, double(state.rxFilterLo), double(state.rxFilterHi));
|
audioFilter(coefficients, NUM_COEFFICIENTS, ID_BANDPASS, W_HAMMING, double(state.rxFilterLo), double(state.rxFilterHi));
|
||||||
rxFilter.begin(coefficients, NUM_COEFFICIENTS);
|
rxFilter.begin(coefficients, NUM_COEFFICIENTS);
|
||||||
}
|
}
|
||||||
|
|
||||||
void UBitxDSP::setRxFilter(float lo, float hi) {
|
void UBitxDSP::setRxFilter(int lo, int hi) {
|
||||||
if (hi < lo + minRxFilterWidth) {
|
if (hi < lo + minRxFilterWidth) {
|
||||||
hi = lo + minRxFilterWidth;
|
hi = lo + minRxFilterWidth;
|
||||||
}
|
}
|
||||||
@@ -256,7 +391,7 @@ void UBitxDSP::setRxFilter(float lo, float hi) {
|
|||||||
updateRxFilter();
|
updateRxFilter();
|
||||||
}
|
}
|
||||||
|
|
||||||
void UBitxDSP::setRxFilterLo(float lo) {
|
void UBitxDSP::setRxFilterLo(int lo) {
|
||||||
if (lo > state.rxFilterHi - minRxFilterWidth) {
|
if (lo > state.rxFilterHi - minRxFilterWidth) {
|
||||||
lo = state.rxFilterHi - minRxFilterWidth;
|
lo = state.rxFilterHi - minRxFilterWidth;
|
||||||
}
|
}
|
||||||
@@ -267,7 +402,7 @@ void UBitxDSP::setRxFilterLo(float lo) {
|
|||||||
updateRxFilter();
|
updateRxFilter();
|
||||||
}
|
}
|
||||||
|
|
||||||
void UBitxDSP::setRxFilterHi(float hi) {
|
void UBitxDSP::setRxFilterHi(int hi) {
|
||||||
if (hi < state.rxFilterLo + minRxFilterWidth) {
|
if (hi < state.rxFilterLo + minRxFilterWidth) {
|
||||||
hi = state.rxFilterLo + minRxFilterWidth;
|
hi = state.rxFilterLo + minRxFilterWidth;
|
||||||
}
|
}
|
||||||
@@ -278,82 +413,67 @@ void UBitxDSP::setRxFilterHi(float hi) {
|
|||||||
updateRxFilter();
|
updateRxFilter();
|
||||||
}
|
}
|
||||||
|
|
||||||
void UBitxDSP::setRxFilterWidth(float width) {
|
void UBitxDSP::setRxFilterWidth(int width) {
|
||||||
if (width < minRxFilterWidth) {
|
if (width < minRxFilterWidth) {
|
||||||
width = minRxFilterWidth;
|
width = minRxFilterWidth;
|
||||||
} else if (width > maxRxFilterWidth) {
|
} else if (width > maxRxFilterWidth) {
|
||||||
width = maxRxFilterWidth;
|
width = maxRxFilterWidth;
|
||||||
}
|
}
|
||||||
float center = (state.rxFilterHi + state.rxFilterLo) / 2;
|
int center = (state.rxFilterHi + state.rxFilterLo) / 2;
|
||||||
float lo = center - (width / 2);
|
int lo = center - (width / 2);
|
||||||
float hi = center + (width / 2);
|
int hi = center + (width / 2);
|
||||||
setRxFilter(lo, hi);
|
setRxFilter(lo, hi);
|
||||||
}
|
}
|
||||||
|
|
||||||
void UBitxDSP::setRxFilterCenter(float center) {
|
void UBitxDSP::setRxFilterCenter(int center) {
|
||||||
if (center < minRxFilterCenter) {
|
if (center < minRxFilterCenter) {
|
||||||
center = minRxFilterCenter;
|
center = minRxFilterCenter;
|
||||||
} else if (center > maxRxFilterCenter) {
|
} else if (center > maxRxFilterCenter) {
|
||||||
center = maxRxFilterCenter;
|
center = maxRxFilterCenter;
|
||||||
}
|
}
|
||||||
float width = state.rxFilterHi - state.rxFilterLo;
|
int width = state.rxFilterHi - state.rxFilterLo;
|
||||||
float lo = center - (width / 2);
|
int lo = center - (width / 2);
|
||||||
float hi = center + (width / 2);
|
int hi = center + (width / 2);
|
||||||
setRxFilter(lo, hi);
|
setRxFilter(lo, hi);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**********************************************************************
|
||||||
|
* Transmit Voice-Operated-Switch (VOX)
|
||||||
|
**********************************************************************/
|
||||||
|
|
||||||
/**********************************************************************/
|
float UBitxDSP::getVoxLevel() const {
|
||||||
// TX audio input settings
|
if (return txVoxLevel.available()) {
|
||||||
|
prevVox = txVoxLevel.read();
|
||||||
void UBitxDSP::setTxInputLevel(int ch, float lvl) {
|
|
||||||
if ((ch > -1) && (ch < txNumChannels)) {
|
|
||||||
state.txInLvl[ch] = lvl;
|
|
||||||
float vol = lvl * float(state.txInEnable[ch] * state.txInTx[ch]);
|
|
||||||
txAudio.gain(ch, vol);
|
|
||||||
}
|
}
|
||||||
|
return prevVox;
|
||||||
}
|
}
|
||||||
|
|
||||||
void UBitxDSP::enableTxInput(int ch) {
|
/**********************************************************************
|
||||||
if ((ch > -1) && (ch < txNumChannels)) {
|
* Singleton - the DSP instance
|
||||||
state.txInEnable[ch] = 1;
|
**********************************************************************/
|
||||||
float vol = state.txInLvl[ch] * float(state.txInEnable[ch] * state.txInTx[ch]);
|
|
||||||
txAudio.gain(ch, vol);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void UBitxDSP::disableTxInput(int ch) {
|
// TODO: Fix this. This won't work... this compilation unit won't be
|
||||||
if ((ch > -1) && (ch < txNumChannels)) {
|
// able to instantiate a class it doesn't know about.
|
||||||
state.txInEnable[ch] = 0;
|
|
||||||
float vol = state.txInLvl[ch] * float(state.txInEnable[ch] * state.txInTx[ch]);
|
|
||||||
txAudio.gain(ch, vol);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void UBitxDSP::startTxInput(int ch) {
|
#ifndef UBITXDSP_CLASS
|
||||||
if ((ch > -1) && (ch < txNumChannels)) {
|
#define UBITXDSP_CLASS UBitxDSP
|
||||||
state.txInTx[ch] = 1;
|
#endif
|
||||||
float vol = state.txInLvl[ch] * float(state.txInEnable[ch] * state.txInTx[ch]);
|
|
||||||
txAudio.gain(ch, vol);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void UBitxDSP::stopTxInput(int ch) {
|
UBITXDSP_CLASS theDSP;
|
||||||
if ((ch > -1) && (ch < txNumChannels)) {
|
UBitxDSP& DSP = theDSP;
|
||||||
state.txInTx[ch] = 0;
|
|
||||||
float vol = state.txInLvl[ch] * float(state.txInEnable[ch] * state.txInTx[ch]);
|
|
||||||
txAudio.gain(ch, vol);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// VOX settings
|
/*
|
||||||
bool UBitxDSP::isVoxActive(int vox) {
|
NOTES
|
||||||
if ((vox > -1) && (vox < 3)) {
|
|
||||||
return state.voxActive[vox];
|
Major functions:
|
||||||
} else {
|
- tx() - start transmitting / pause receiving
|
||||||
return false;
|
- rx() - stop transmitting / resume receiving
|
||||||
}
|
- setTxSource() - set the TX audio source to MIC_IN, LINE_IN, or USB_IN
|
||||||
}
|
- also sets the relevant VOX source/parameters (as applicable)
|
||||||
|
|
||||||
|
Receive audio chain:
|
||||||
|
-
|
||||||
|
*/
|
||||||
|
|
||||||
//======================================================================
|
//======================================================================
|
||||||
// EOF
|
// EOF
|
||||||
|
292
TeensyDSP/DSP.h
292
TeensyDSP/DSP.h
@@ -9,83 +9,213 @@
|
|||||||
#include <dynamicFilters.h>
|
#include <dynamicFilters.h>
|
||||||
#include "Debug.h"
|
#include "Debug.h"
|
||||||
|
|
||||||
#define MIN_RX_FILTER_LO 0.0
|
/**********************************************************************
|
||||||
#define MAX_RX_FILTER_HI 5000.0
|
* Macros
|
||||||
#define MIN_RX_FILTER_WIDTH 0.0
|
**********************************************************************/
|
||||||
#define MAX_RX_FILTER_WIDTH 5000.0
|
|
||||||
#define MIN_RX_FILTER_CENTER 0.0
|
|
||||||
#define MAX_RX_FILTER_CENTER 5000.0
|
|
||||||
|
|
||||||
#define DSP_MILLIS_PER_UPDATE 100
|
#define MIN_RX_FILTER_LO (0.0) //! Min allowable value of the RX filter low-cut frequency
|
||||||
|
#define MAX_RX_FILTER_HI (5000.0) //! Max allowable value of the RX filter hi-cut frequency
|
||||||
|
#define MIN_RX_FILTER_WIDTH (0.0) //! Min allowable value of the RX filter bandwidth
|
||||||
|
#define MAX_RX_FILTER_WIDTH (5000.0) //! Max allowable value of the RX filter bandwidth
|
||||||
|
#define MIN_RX_FILTER_CENTER (0.0) //! Min allowable value of the RX filter center frequency
|
||||||
|
#define MAX_RX_FILTER_CENTER (5000.0) //! Max allowable value of the RX filter center frequency
|
||||||
|
|
||||||
#define TX_MIC_IN_CH 0
|
#define DSP_MILLIS_PER_UPDATE (100) //! Number of milliseconds between update of the DSP object
|
||||||
#define TX_LINE_IN_CH 0
|
|
||||||
#define TX_USB_IN_CH 1
|
|
||||||
#define TX_NUM_CHANNELS 2
|
|
||||||
|
|
||||||
#define TX_LINE_IN_VOX 0
|
#define TX_VOX_MIC_THRESH (0.0) //! Threshold for mic VOX (not implemented, since mic requires special handling)
|
||||||
#define TX_USB_IN_L_VOX 1
|
#define TX_VOX_LINE_THRESH (0.25) //! Threshold for line in VOX
|
||||||
#define TX_USB_IN_R_VOX 2
|
#define TX_VOX_USB_THRESH (0.25) //! Threshold for USB VOX
|
||||||
#define TX_NUM_VOX 3
|
#define TX_VOX_TUNE_THRESH (0.0) //! Threshold for tune (single tone) VOX (not expected to be used)
|
||||||
|
#define TX_VOX_TT_THRESH (0.0) //! Threshold for two-tone VOX (not expected to be used)
|
||||||
|
#define TX_VOX_DELAY (500) //! VOX delay in milliseconds
|
||||||
|
|
||||||
#define TX_LINE_IN_VOX_THRESH 0.25
|
/**********************************************************************
|
||||||
#define TX_USB_IN_L_VOX_THRESH 0.25
|
* Enumerations
|
||||||
#define TX_USB_IN_R_VOX_THRESH 0.25
|
**********************************************************************/
|
||||||
|
|
||||||
#define TX_LINE_IN_VOX_DELAY 500
|
//! Defines the four separate RX audio input channels available.
|
||||||
#define TX_USB_IN_L_VOX_DELAY 500
|
enum RxAudioCh {
|
||||||
#define TX_USB_IN_R_VOX_DELAY 500
|
RX_AUDIO = 0, // Normal receiver audio input channel
|
||||||
|
RX_SPARE, // Not used
|
||||||
|
RX_TONE1 , // Optional tone #1 input channel (currently not used)
|
||||||
|
RX_TONE2, // Optional tone #2 input channel (currently not used)
|
||||||
|
NUM_RX_AUDIO_CH // Total number of channels
|
||||||
|
};
|
||||||
|
|
||||||
|
//! Defines the different RX audio inputs (not channels).
|
||||||
|
enum RxAudioIn {
|
||||||
|
RIG_IN = 0, // Normal rig input (receiver audio)
|
||||||
|
NUM_RX_AUDIO_IN // Total number of inputs
|
||||||
|
};
|
||||||
|
|
||||||
|
//! Defines the different RX audio outputs.
|
||||||
|
enum RxAudioOut {
|
||||||
|
LINE_OUT = 0, // Line audio out (and speaker)
|
||||||
|
USB_OUT, // USB audio out
|
||||||
|
NUM_RX_AUDIO_OUT
|
||||||
|
};
|
||||||
|
|
||||||
|
//! Defines the four separate TX audio input channels available.
|
||||||
|
enum TxAudioCh {
|
||||||
|
TX_LINE = 0, // Line and/or mic audio input channel
|
||||||
|
TX_USB, // USB audio input channel
|
||||||
|
TX_TONE1, // Audio tone #1 input channel
|
||||||
|
TX_TONE2, // Audio tone #2 input channel
|
||||||
|
NUM_TX_AUDIO_CH // Toal number of channels
|
||||||
|
};
|
||||||
|
|
||||||
|
//! Defines the different TX audio input sources (not channels!).
|
||||||
|
enum TxAudioIn {
|
||||||
|
MIC_IN = 0, // Microphone transmit audio input
|
||||||
|
LINE_IN, // Line ("AUX") transmit audio input
|
||||||
|
USB_IN, // USB transmit audio input
|
||||||
|
TUNE_IN, // Tune input (transmits a single tone)
|
||||||
|
TWO_TONE_IN, // Two tone audio input (transmits two tones)
|
||||||
|
NUM_TX_AUDIO_IN // Total number of inputs
|
||||||
|
};
|
||||||
|
|
||||||
|
/**********************************************************************
|
||||||
|
* Classes
|
||||||
|
**********************************************************************/
|
||||||
|
|
||||||
|
//! Defines parameters for a simple audio channel that can be muted.
|
||||||
|
struct AudioChannel {
|
||||||
|
bool mute = false;
|
||||||
|
float level = 0.0;
|
||||||
|
};
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Contains the current 'persistent' state of the DSP.
|
||||||
|
* This includes all audio-specific state that can be saved to, or
|
||||||
|
* restored from, EEPROM. It does not include 'transient' state (such
|
||||||
|
* as whether we're currently transmitting or receiving).
|
||||||
|
*/
|
||||||
struct DSPState {
|
struct DSPState {
|
||||||
|
|
||||||
// RX audio output settings
|
//! Receiver audio inputs; all default to muted.
|
||||||
|
AudioChannel rxIn[NUM_RX_AUDIO_CH] = {
|
||||||
|
{true, 1.0}, // audio
|
||||||
|
{true, 0.0}, // spare 1
|
||||||
|
{true, 0.0}, // spare 2
|
||||||
|
{true, 0.0} // spare 3
|
||||||
|
};
|
||||||
|
|
||||||
// RX filter settings
|
//! Receiver audio output; defaults to un
|
||||||
|
muted.
|
||||||
|
AudioChannel rxOut[NUM_RX_AUDIO_OUT] = {
|
||||||
|
{false, 1.0}, // line
|
||||||
|
{false, 1.0} // USB
|
||||||
|
};
|
||||||
|
|
||||||
|
//! Transmitter audio inputs; all default to muted.
|
||||||
|
AudioChannel txIn[NUM_TX_AUDIO_CH] = {
|
||||||
|
{true, 0.1}, // line
|
||||||
|
{true, 0.1}, // USB
|
||||||
|
{true, 0.1}, // tone 1
|
||||||
|
{true, 0.1} // tone 2
|
||||||
|
};
|
||||||
|
|
||||||
|
//! Tranmitter audio output; defaults to muted.
|
||||||
|
AudioChannel txOut = {true, 1.0};
|
||||||
|
|
||||||
|
//! Current RX filter settings
|
||||||
float rxFilterLo = 300.0;
|
float rxFilterLo = 300.0;
|
||||||
float rxFilterHi = 3000.0;
|
float rxFilterHi = 3000.0;
|
||||||
|
|
||||||
// TX audio input settings
|
|
||||||
float txInLvl[4] = {0.5, 0.5, 0.0, 0.0};
|
|
||||||
int txInEnable[4] = {1, 1, 0, 0};
|
|
||||||
int txInTx[4] = {0, 0, 0, 0};
|
|
||||||
|
|
||||||
// VOX settings
|
|
||||||
bool voxActive[3];
|
|
||||||
float voxThresh[3];
|
|
||||||
unsigned voxDelay[3];
|
|
||||||
unsigned voxTimeout[3];
|
|
||||||
};
|
|
||||||
|
|
||||||
enum TRState {
|
|
||||||
TRANSMIT,
|
|
||||||
RECEIVE
|
|
||||||
};
|
|
||||||
|
|
||||||
enum RxAudioIn {
|
|
||||||
RIG_AUDIO
|
|
||||||
};
|
|
||||||
|
|
||||||
enum TxAudioIn {
|
|
||||||
MIC_IN,
|
|
||||||
LINE_IN,
|
|
||||||
USB_IN
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Defines the DSP subsystem of the UBitx V5X.
|
||||||
|
* The DSP subsystem, which relies on the Teensy Audio Library, is
|
||||||
|
* responsible for setting up the audio inputs and outputs for both
|
||||||
|
* receive (RX) and transmit (TX) audio, maintaining the correct path
|
||||||
|
* between inputs and outputs based on current TX/RX state, and setting
|
||||||
|
* up audio filters and other audio-based modules for the RX and TX
|
||||||
|
* audio paths.
|
||||||
|
*/
|
||||||
class UBitxDSP {
|
class UBitxDSP {
|
||||||
|
|
||||||
|
/********************************************************************
|
||||||
|
* Object creation/deletion
|
||||||
|
********************************************************************/
|
||||||
|
|
||||||
|
public:
|
||||||
|
UBitxDSP() {}
|
||||||
|
|
||||||
|
/********************************************************************
|
||||||
|
* Basic administration
|
||||||
|
********************************************************************/
|
||||||
|
|
||||||
public:
|
public:
|
||||||
UBitxDSP();
|
|
||||||
void begin();
|
void begin();
|
||||||
void update();
|
void update();
|
||||||
void end();
|
void end();
|
||||||
|
|
||||||
|
/********************************************************************
|
||||||
|
* Transmit/Receive switching
|
||||||
|
********************************************************************/
|
||||||
|
|
||||||
|
public:
|
||||||
void rx();
|
void rx();
|
||||||
void txMicIn();
|
inline void tx() { tx(txSrc); }
|
||||||
void txLineIn();
|
void tx(TxAudioIn src);
|
||||||
void txUSBIn();
|
|
||||||
|
|
||||||
// RX audio output settings
|
/********************************************************************
|
||||||
|
* General audio setup -- called via begin()
|
||||||
|
********************************************************************/
|
||||||
|
|
||||||
// RX filter settings
|
protected:
|
||||||
|
virtual void setupRxAudio();
|
||||||
|
virtual void setupTxAudio();
|
||||||
|
|
||||||
|
/********************************************************************
|
||||||
|
* Receive audio chain
|
||||||
|
********************************************************************/
|
||||||
|
|
||||||
|
// Basic control of RX audio inputs and outputs.
|
||||||
|
public:
|
||||||
|
void setRxInLevel(RxAudioCh ch, float level); // Set the audio input level for a given channel.
|
||||||
|
void muteRxIn(); // Mute all RX audio input channels.
|
||||||
|
void muteRxIn(RxAudioCh ch); // Mute a specific RX audio input channel.
|
||||||
|
void unmuteRxIn(RxAudioCh ch); // Un-mute a specific RX audio input channel.
|
||||||
|
|
||||||
|
void setLineOutLevel(float level); // Set the line output level (0.0 - 1.0).
|
||||||
|
void setUSBOutLevel(float level); // Set the USB output level (0.0 - 1.0).
|
||||||
|
|
||||||
|
/********************************************************************
|
||||||
|
* Transmit audio chain
|
||||||
|
********************************************************************/
|
||||||
|
|
||||||
|
// Basic control of TX audio inputs and outputs.
|
||||||
|
public:
|
||||||
|
void setTxInLevel(TxAudioCh ch, float level); // Set the audio input level for a given channel.
|
||||||
|
void muteTxIn(); // Mute all TX audio input channels.
|
||||||
|
void muteTxIn(TxAudioCh ch); // Mute a specific TX audio input channel.
|
||||||
|
void unmuteTxIn(TxAudioCh ch); // Un-mute a specific TX audio input channel.
|
||||||
|
|
||||||
|
void setTxOutLevel(float level); // Set the TX audio output level.
|
||||||
|
void muteTxOut(); // Mute the TX audio output.
|
||||||
|
void unmuteTxOut(); // Un-mute the TX audio output.
|
||||||
|
|
||||||
|
void setLineInLevel(float level); // Set the line input level (0.0 - 1.0).
|
||||||
|
void setUSBInLevel(float level); // Set the USB input level (0.0 - 1.0).
|
||||||
|
|
||||||
|
// Transmit audio selection (may be overriden at actual transmit time).
|
||||||
|
public:
|
||||||
|
void setTxAudioIn(TxAudioIn src, bool isTemp = false); // Select a specific TX audio input path, and identify it as permanent or temporary.
|
||||||
|
inline TxAudioIn getTxAudioIn() const { return txSrc; } // Return the current TX audio input.
|
||||||
|
|
||||||
|
// Mic input controls.
|
||||||
|
public:
|
||||||
|
inline void setMicGain(float level) { micGain = static_cast<unsigned>(level * 63.0); } // Set the mic gain.
|
||||||
|
|
||||||
|
/********************************************************************
|
||||||
|
* Receive audio filter (band pass)
|
||||||
|
********************************************************************/
|
||||||
|
|
||||||
|
public:
|
||||||
void bypassRxFilter();
|
void bypassRxFilter();
|
||||||
|
void updateRxFilter();
|
||||||
|
|
||||||
void setRxFilter(float lo, float hi);
|
void setRxFilter(float lo, float hi);
|
||||||
void setRxFilterLo(float lo);
|
void setRxFilterLo(float lo);
|
||||||
void setRxFilterHi(float hi);
|
void setRxFilterHi(float hi);
|
||||||
@@ -93,50 +223,58 @@ class UBitxDSP {
|
|||||||
void setRxFilterCenter(float center);
|
void setRxFilterCenter(float center);
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* @brief Get the current low frequency bound of the RX band pass filter.
|
* Get the current low frequency bound of the RX band pass filter.
|
||||||
* @return The low frequency bound.
|
* @return The low frequency bound.
|
||||||
*/
|
*/
|
||||||
inline int getRxFilterLo() { return state.rxFilterLo; }
|
inline float getRxFilterLo() const { return state.rxFilterLo; }
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* @brief Get the current high frequency bound of the RX band pass filter.
|
* Get the current high frequency bound of the RX band pass filter.
|
||||||
* @return The high frequency bound.
|
* @return The high frequency bound.
|
||||||
*/
|
*/
|
||||||
inline int getRxFilterHi() { return state.rxFilterHi; }
|
inline float getRxFilterHi() const { return state.rxFilterHi; }
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* @brief Get the current width of the RX band pass filter.
|
* Get the current width of the RX band pass filter.
|
||||||
* @return The filter width.
|
* @return The filter width.
|
||||||
*/
|
*/
|
||||||
inline int getRxFilterWidth() { return state.rxFilterHi - state.rxFilterLo; }
|
inline float getRxFilterWidth() const { return state.rxFilterHi - state.rxFilterLo; }
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* @brief Get the current center frequency of the RX band pass filter.
|
* Get the current center frequency of the RX band pass filter.
|
||||||
* @return The center frequency.
|
* @return The center frequency.
|
||||||
*/
|
*/
|
||||||
inline int getRxFilterCenter() { return (state.rxFilterHi + state.rxFilterLo) / 2; }
|
inline float getRxFilterCenter() const { return (state.rxFilterHi + state.rxFilterLo) / 2.0; }
|
||||||
|
|
||||||
// TX audio input settings
|
/********************************************************************
|
||||||
void setTxInputLevel(int ch, float lvl);
|
* Transmit Voice-Operated-Switch (VOX)
|
||||||
void enableTxInput(int ch);
|
********************************************************************/
|
||||||
void disableTxInput(int ch);
|
|
||||||
void startTxInput(int ch);
|
|
||||||
void stopTxInput(int ch);
|
|
||||||
|
|
||||||
// VOX settings
|
public:
|
||||||
bool isVoxActive(int vox);
|
float getVoxLevel() const;
|
||||||
|
|
||||||
|
/********************************************************************
|
||||||
|
* Private state
|
||||||
|
********************************************************************/
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void updateRxFilter();
|
|
||||||
|
|
||||||
DSPState state;
|
DSPState state;
|
||||||
short coefficients[NUM_COEFFICIENTS];
|
|
||||||
elapsedMillis sinceLastUpdate;
|
|
||||||
|
|
||||||
AudioAnalyzeRMS* voxRMS[3];
|
bool isTx = false;
|
||||||
|
TxAudioIn txSrc = MIC_IN;
|
||||||
|
TxAudioIn txSrcLatched = MIC_IN;
|
||||||
|
|
||||||
|
short coefficients[NUM_COEFFICIENTS] = {0};
|
||||||
|
|
||||||
|
elapsedMillis sinceLastUpdate = 0;
|
||||||
|
float usbVol = 0.0;
|
||||||
|
|
||||||
|
unsigned micGain = 0;
|
||||||
|
|
||||||
|
float prevVox = 0.0;
|
||||||
};
|
};
|
||||||
|
|
||||||
extern UBitxDSP DSP;
|
extern UBitxDSP& DSP;
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@@ -61,7 +61,7 @@ speed(wpm), symWeight(weight)
|
|||||||
// Calculate the length of dot, dash and silence
|
// Calculate the length of dot, dash and silence
|
||||||
void UBitxKeyer::calcRatio()
|
void UBitxKeyer::calcRatio()
|
||||||
{
|
{
|
||||||
float w = (1.0 + symWeight) / (symWeight - 1.0);
|
float w = (1 + symWeight) / (symWeight -1);
|
||||||
spaceLen = (1200 / speed);
|
spaceLen = (1200 / speed);
|
||||||
dotLen = spaceLen * (w - 1);
|
dotLen = spaceLen * (w - 1);
|
||||||
dashLen = (1 + w) * spaceLen;
|
dashLen = (1 + w) * spaceLen;
|
||||||
@@ -73,12 +73,6 @@ void UBitxKeyer::setWPM(int wpm)
|
|||||||
calcRatio();
|
calcRatio();
|
||||||
}
|
}
|
||||||
|
|
||||||
void UBitxKeyer::setWeight(float weight)
|
|
||||||
{
|
|
||||||
symWeight = weight;
|
|
||||||
calcRatio();
|
|
||||||
}
|
|
||||||
|
|
||||||
//======================================================================
|
//======================================================================
|
||||||
// Latch paddle press
|
// Latch paddle press
|
||||||
//======================================================================
|
//======================================================================
|
||||||
@@ -113,10 +107,11 @@ bool UBitxKeyer::doPaddles()
|
|||||||
if ((digitalRead(LP_in) == LOW) || (digitalRead(RP_in) == LOW) || (keyerControl & 0x03)) {
|
if ((digitalRead(LP_in) == LOW) || (digitalRead(RP_in) == LOW) || (keyerControl & 0x03)) {
|
||||||
updatePaddleLatch();
|
updatePaddleLatch();
|
||||||
keyerState = CHK_DIT;
|
keyerState = CHK_DIT;
|
||||||
return true;
|
// letting this fall through // return true;
|
||||||
}
|
} else {
|
||||||
return false;
|
return false;
|
||||||
//break;
|
}
|
||||||
|
// break;
|
||||||
|
|
||||||
case CHK_DIT: // See if the dit paddle was pressed
|
case CHK_DIT: // See if the dit paddle was pressed
|
||||||
if (keyerControl & DIT_L) {
|
if (keyerControl & DIT_L) {
|
||||||
@@ -124,20 +119,20 @@ bool UBitxKeyer::doPaddles()
|
|||||||
ktimer = dotLen;
|
ktimer = dotLen;
|
||||||
keyerState = KEYED_PREP;
|
keyerState = KEYED_PREP;
|
||||||
return true;
|
return true;
|
||||||
}
|
} else { // fall through
|
||||||
// fall through
|
|
||||||
keyerState = CHK_DAH;
|
keyerState = CHK_DAH;
|
||||||
|
}
|
||||||
|
|
||||||
case CHK_DAH: // See if dah paddle was pressed
|
case CHK_DAH: // See if dah paddle was pressed
|
||||||
if (keyerControl & DAH_L) {
|
if (keyerControl & DAH_L) {
|
||||||
ktimer = dashLen;
|
ktimer = dashLen;
|
||||||
keyerState = KEYED_PREP;
|
keyerState = KEYED_PREP;
|
||||||
return true;
|
// letting this fall through // return true;
|
||||||
} else {
|
} else {
|
||||||
keyerState = IDLE;
|
keyerState = IDLE;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
//break;
|
// break;
|
||||||
|
|
||||||
case KEYED_PREP: // Assert key down, start timing
|
case KEYED_PREP: // Assert key down, start timing
|
||||||
// state shared for dit or dah
|
// state shared for dit or dah
|
||||||
@@ -145,20 +140,21 @@ bool UBitxKeyer::doPaddles()
|
|||||||
ktimer += millis(); // set ktimer to interval end time
|
ktimer += millis(); // set ktimer to interval end time
|
||||||
keyerControl &= ~(DIT_L + DAH_L); // clear both paddle latch bits
|
keyerControl &= ~(DIT_L + DAH_L); // clear both paddle latch bits
|
||||||
keyerState = KEYED; // next state
|
keyerState = KEYED; // next state
|
||||||
return true;
|
// letting this fall through // return true;
|
||||||
//break;
|
// break;
|
||||||
|
|
||||||
case KEYED: // Wait for timer to expire
|
case KEYED: // Wait for timer to expire
|
||||||
if (millis() > ktimer) { // are we at end of key down ?
|
if (millis() > ktimer) { // are we at end of key down ?
|
||||||
keyDown = false;
|
keyDown = false;
|
||||||
ktimer = millis() + spaceLen; // inter-element time
|
ktimer = millis() + spaceLen; // inter-element time
|
||||||
keyerState = INTER_ELEMENT; // next state
|
keyerState = INTER_ELEMENT; // next state
|
||||||
return true;
|
// letting this fall through // return true;
|
||||||
} else if (keyMode == IAMBICB) { // Iambic B Mode ?
|
} else if (keyMode == IAMBICB) { // Iambic B Mode ?
|
||||||
updatePaddleLatch(); // yes, early paddle latch in Iambic B mode
|
updatePaddleLatch(); // yes, early paddle latch in Iambic B mode
|
||||||
}
|
} else {
|
||||||
return true;
|
return true;
|
||||||
// break;
|
}
|
||||||
|
// break;
|
||||||
|
|
||||||
case INTER_ELEMENT: // Insert time between dits/dahs
|
case INTER_ELEMENT: // Insert time between dits/dahs
|
||||||
updatePaddleLatch(); // latch paddle state
|
updatePaddleLatch(); // latch paddle state
|
||||||
@@ -172,9 +168,10 @@ bool UBitxKeyer::doPaddles()
|
|||||||
keyerState = IDLE; // go idle
|
keyerState = IDLE; // go idle
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
return true;
|
return true;
|
||||||
//break;
|
}
|
||||||
|
// break;
|
||||||
}
|
}
|
||||||
|
|
||||||
return false; // resolve compiler warning; do we ever get here?
|
return false; // resolve compiler warning; do we ever get here?
|
||||||
|
@@ -44,12 +44,10 @@ public:
|
|||||||
//void cw_pin(int pin);
|
//void cw_pin(int pin);
|
||||||
//void ptt_pin(int pin);
|
//void ptt_pin(int pin);
|
||||||
void setWPM(int wpm);
|
void setWPM(int wpm);
|
||||||
inline int getWPM() { return speed; }
|
|
||||||
void setWeight(float weight);
|
|
||||||
inline float getWeight() { return symWeight; }
|
|
||||||
inline void setMode(int mode) { keyMode = mode; }
|
inline void setMode(int mode) { keyMode = mode; }
|
||||||
inline int getMode() { return keyMode; }
|
inline int getMode() { return keyMode; }
|
||||||
inline bool isDown() { return keyDown; }
|
inline bool isDown() { return keyDown; }
|
||||||
|
// void setWeight();
|
||||||
|
|
||||||
bool doPaddles();
|
bool doPaddles();
|
||||||
|
|
||||||
|
@@ -3,56 +3,18 @@
|
|||||||
|
|
||||||
#include "RigState.h"
|
#include "RigState.h"
|
||||||
|
|
||||||
#define DEFAULT_SSB_LO_CUT 300.0
|
struct RigState {
|
||||||
#define DEFAULT_SSB_HI_CUT 3000.0
|
|
||||||
#define DEFAULT_CW_WIDTH 500.0
|
|
||||||
#define DEFAULT_LOW_USB false
|
|
||||||
#define DEFAULT_LOW_CWU true
|
|
||||||
#define DEFAULT_HIGH_USB true
|
|
||||||
#define DEFAULT_HIGH_CWU true
|
|
||||||
|
|
||||||
enum HamBand {
|
|
||||||
BAND_80M = 0,
|
|
||||||
BAND_60M,
|
|
||||||
BAND_40M,
|
|
||||||
BAND_30M,
|
|
||||||
BAND_20M,
|
|
||||||
BAND_17M,
|
|
||||||
BAND_15M,
|
|
||||||
BAND_12M,
|
|
||||||
BAND_10M,
|
|
||||||
NUM_BANDS
|
|
||||||
};
|
|
||||||
|
|
||||||
struct ModeConfig {
|
|
||||||
bool isUpper;
|
|
||||||
float dspLo;
|
|
||||||
float dspHi;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct BandConfig {
|
|
||||||
ModeConfig cw;
|
|
||||||
ModeConfig ssb;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct RigConfig {
|
|
||||||
//bool isData = false;
|
|
||||||
bool useUSBInput = true; // whether or not to use the USB input for data
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class UBitxRig {
|
class UBitxRig {
|
||||||
public:
|
public:
|
||||||
UBitxRig();
|
|
||||||
|
|
||||||
inline void begin() {}
|
inline void begin() {}
|
||||||
inline void update() {}
|
inline void update() {}
|
||||||
|
|
||||||
inline unsigned getFreqA() const { return radState.getFreqA(); }
|
inline unsigned getFreqA() const { return radState.getFreqA(); }
|
||||||
inline unsigned getFreqB() const { return radState.getFreqB(); }
|
inline unsigned getFreqB() const { return radState.getFreqB(); }
|
||||||
|
|
||||||
inline int getRIT() const { return radState.getRIT(); }
|
inline int getRIT() const { return radState.getRIT(); }
|
||||||
inline int getXIT() const { return radState.getXIT(); }
|
inline int getXIT() const { return radState.getXIT(); }
|
||||||
|
|
||||||
inline bool isVFOA() const { return radState.isVFOA(); }
|
inline bool isVFOA() const { return radState.isVFOA(); }
|
||||||
inline bool isVFOB() const { return radState.isVFOB(); }
|
inline bool isVFOB() const { return radState.isVFOB(); }
|
||||||
inline bool isSplit() const { return radState.isSplit(); }
|
inline bool isSplit() const { return radState.isSplit(); }
|
||||||
@@ -63,20 +25,12 @@ class UBitxRig {
|
|||||||
inline bool isModeCWR() const { return radState.isModeCWR(); }
|
inline bool isModeCWR() const { return radState.isModeCWR(); }
|
||||||
inline bool isModeUSB() const { return radState.isModeUSB(); }
|
inline bool isModeUSB() const { return radState.isModeUSB(); }
|
||||||
inline bool isModeLSB() const { return radState.isModeLSB(); }
|
inline bool isModeLSB() const { return radState.isModeLSB(); }
|
||||||
|
|
||||||
inline float getCWSidetone() const { return static_cast<float>(radState.getSidetone()); }
|
|
||||||
|
|
||||||
inline bool isUSBInput() const { return conf.useUSBInput; }
|
|
||||||
inline bool isLineInput() const { return !conf.useUSBInput; }
|
|
||||||
|
|
||||||
inline bool isAI() const { return autoInfo; }
|
inline bool isAI() const { return autoInfo; }
|
||||||
|
|
||||||
inline void setFreqA(unsigned freq) { catState.setFreqA(freq); }
|
inline void setFreqA(unsigned freq) { catState.setFreqA(freq); }
|
||||||
inline void setFreqB(unsigned freq) { catState.setFreqB(freq); }
|
inline void setFreqB(unsigned freq) { catState.setFreqB(freq); }
|
||||||
|
|
||||||
inline void setRIT(int freq) { catState.setRIT(freq); }
|
inline void setRIT(int freq) { catState.setRIT(freq); }
|
||||||
inline void setXIT(int freq) { catState.setXIT(freq); }
|
inline void setXIT(int freq) { catState.setXIT(freq); }
|
||||||
|
|
||||||
inline void setVFOA() { catState.setVFOA(); }
|
inline void setVFOA() { catState.setVFOA(); }
|
||||||
inline void setVFOB() { catState.setVFOB(); }
|
inline void setVFOB() { catState.setVFOB(); }
|
||||||
inline void setSplitOn() { catState.setSplitOn(); }
|
inline void setSplitOn() { catState.setSplitOn(); }
|
||||||
@@ -85,16 +39,12 @@ class UBitxRig {
|
|||||||
inline void setRITOff() { catState.setRITOff(); }
|
inline void setRITOff() { catState.setRITOff(); }
|
||||||
inline void setXITOn() { catState.setXITOn(); }
|
inline void setXITOn() { catState.setXITOn(); }
|
||||||
inline void setXITOff() { catState.setXITOff(); }
|
inline void setXITOff() { catState.setXITOff(); }
|
||||||
inline void setModeCW() { catState.setModeCW(); }
|
inline void setCW() { catState.setCW(); }
|
||||||
inline void setModeCWR() { catState.setModeCWR(); }
|
inline void setCWR() { catState.setCWR(); }
|
||||||
inline void setModeUSB() { catState.setModeUSB(); }
|
inline void setUSB() { catState.setUSB(); }
|
||||||
inline void setModeLSB() { catState.setModeLSB(); }
|
inline void setLSB() { catState.setLSB(); }
|
||||||
|
|
||||||
inline void setCWSidetone(float f) { catState.setSidetone(static_cast<uint16_t>(f)); }
|
|
||||||
|
|
||||||
inline void setUSBInput() { conf.useUSBInput = true; }
|
|
||||||
inline void setLineInput() { conf.useUSBInput = false; }
|
|
||||||
|
|
||||||
|
inline void setAI(bool on) { autoInfo = on; }
|
||||||
inline void aiOn() { autoInfo = true; }
|
inline void aiOn() { autoInfo = true; }
|
||||||
inline void aiOff() { autoInfo = false; }
|
inline void aiOff() { autoInfo = false; }
|
||||||
|
|
||||||
@@ -113,12 +63,9 @@ class UBitxRig {
|
|||||||
//void getBand();
|
//void getBand();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
RigConfig conf;
|
|
||||||
UBitxRigState catState;
|
UBitxRigState catState;
|
||||||
UBitxRigState radState;
|
UBitxRigState radState;
|
||||||
bool autoInfo = false;
|
bool autoInfo = false; // TODO: Move this to rig state struct
|
||||||
|
|
||||||
BandConfig band[NUM_BANDS];
|
|
||||||
};
|
};
|
||||||
|
|
||||||
extern UBitxRig Rig;
|
extern UBitxRig Rig;
|
||||||
|
@@ -56,7 +56,7 @@ void UBitxRigState::begin() {
|
|||||||
#include "ubitx.h"
|
#include "ubitx.h"
|
||||||
#include "ubitx_eemap.h"
|
#include "ubitx_eemap.h"
|
||||||
|
|
||||||
extern unsigned long frequency, ritRxFrequency, ritTxFrequency, sideTone;
|
extern unsigned long frequency, ritRxFrequency, ritTxFrequency;
|
||||||
extern unsigned long vfoA;
|
extern unsigned long vfoA;
|
||||||
extern unsigned long vfoB;
|
extern unsigned long vfoB;
|
||||||
extern char cwMode;
|
extern char cwMode;
|
||||||
@@ -169,10 +169,8 @@ void UBitxRigState::writeDirty() {
|
|||||||
// XIT - TODO
|
// XIT - TODO
|
||||||
}
|
}
|
||||||
|
|
||||||
// Various flags
|
|
||||||
if (isDirty(FLAGS_WORD)) {
|
|
||||||
|
|
||||||
// VFO A/B selection
|
// VFO A/B selection
|
||||||
|
if (isDirty(FLAGS_WORD)) {
|
||||||
char prev = vfoActive;
|
char prev = vfoActive;
|
||||||
vfoActive = isVFOA() ? VFO_A : VFO_B;
|
vfoActive = isVFOA() ? VFO_A : VFO_B;
|
||||||
if (vfoActive != prev) {
|
if (vfoActive != prev) {
|
||||||
@@ -216,13 +214,6 @@ void UBitxRigState::writeDirty() {
|
|||||||
setFrequency(frequency);
|
setFrequency(frequency);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Keyer information
|
|
||||||
if (isDirty(KEYER_WORD)) {
|
|
||||||
|
|
||||||
// Sidetone frequency
|
|
||||||
sideTone = static_cast<unsigned long>(getSidetone());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@@ -293,22 +284,17 @@ void UBitxRigState::readDirty() {
|
|||||||
char curr = (cwMode << 1) | isUSB;
|
char curr = (cwMode << 1) | isUSB;
|
||||||
if (curr != prev) {
|
if (curr != prev) {
|
||||||
if (cwMode == 2) {
|
if (cwMode == 2) {
|
||||||
setModeCW();
|
setCW();
|
||||||
} else if (cwMode == 1) {
|
} else if (cwMode == 1) {
|
||||||
setModeCWR();
|
setCWR();
|
||||||
} else {
|
} else {
|
||||||
if (isUSB) {
|
if (isUSB) {
|
||||||
setModeUSB();
|
setUSB();
|
||||||
} else {
|
} else {
|
||||||
setModeLSB();
|
setLSB();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sidetone
|
|
||||||
if (getSidetone() != static_cast<uint16_t>(sideTone)) {
|
|
||||||
setSidetone(static_cast<uint16_t>(sideTone));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/***********************************************************************
|
/***********************************************************************
|
||||||
@@ -346,16 +332,6 @@ void UBitxRigState::receive_RIGINF(int numBytes) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//--------------------------------------------------------------------
|
|
||||||
// Do anything that needs to happen when something is updated by the
|
|
||||||
// Raduino... this would be due to e.g. changes through the menu.
|
|
||||||
// Current (as of 2/19/2021) things that DON'T need to have any
|
|
||||||
// updates: frequency (those just get requested by CAT as needed).
|
|
||||||
// Current things that do need to get updated: sidetone (used to
|
|
||||||
// update CW filter values).
|
|
||||||
//--------------------------------------------------------------------
|
|
||||||
processDirty();
|
|
||||||
|
|
||||||
IFDEBUG( serialHexState("Rcvd") );
|
IFDEBUG( serialHexState("Rcvd") );
|
||||||
IFDEBUG( serialPrettyState("Rcvd") );
|
IFDEBUG( serialPrettyState("Rcvd") );
|
||||||
}
|
}
|
||||||
@@ -396,13 +372,6 @@ void UBitxRigState::send_RIGINF() {
|
|||||||
//--------------------------------------------------------------------
|
//--------------------------------------------------------------------
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
|
||||||
* @brief Perform required actions based on any dirty bits set.
|
|
||||||
*/
|
|
||||||
void UBitxRigState::processDirty() {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
|
@@ -15,9 +15,6 @@
|
|||||||
#define UBITX_USB_FLAG 0x00000020
|
#define UBITX_USB_FLAG 0x00000020
|
||||||
#define UBITX_TX_FLAG 0x00000040
|
#define UBITX_TX_FLAG 0x00000040
|
||||||
|
|
||||||
#define UBITX_SIDETONE_MASK 0x000007FF
|
|
||||||
#define UBITX_KEYER_MODE_MASK 0x00003800
|
|
||||||
|
|
||||||
#ifdef TEENSYDUINO
|
#ifdef TEENSYDUINO
|
||||||
#define DISABLEINTS(CMD) do { noInterrupts(); CMD; interrupts(); } while (0)
|
#define DISABLEINTS(CMD) do { noInterrupts(); CMD; interrupts(); } while (0)
|
||||||
#else
|
#else
|
||||||
@@ -30,7 +27,6 @@ enum RigStateWord {
|
|||||||
VFOB_WORD,
|
VFOB_WORD,
|
||||||
OFFSETS_WORD,
|
OFFSETS_WORD,
|
||||||
FLAGS_WORD,
|
FLAGS_WORD,
|
||||||
KEYER_WORD,
|
|
||||||
NUM_WORDS
|
NUM_WORDS
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -259,25 +255,25 @@ struct UBitxRigState {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void setModeUSB(bool mark = true) {
|
inline void setUSB(bool mark = true) {
|
||||||
DISABLEINTS( data[FLAGS_WORD] |= UBITX_USB_FLAG;
|
DISABLEINTS( data[FLAGS_WORD] |= UBITX_USB_FLAG;
|
||||||
data[FLAGS_WORD] &= ~UBITX_CW_FLAG;
|
data[FLAGS_WORD] &= ~UBITX_CW_FLAG;
|
||||||
if (mark) setDirty(FLAGS_WORD) );
|
if (mark) setDirty(FLAGS_WORD) );
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void setModeLSB(bool mark = true) {
|
inline void setLSB(bool mark = true) {
|
||||||
DISABLEINTS( data[FLAGS_WORD] &= ~UBITX_USB_FLAG;
|
DISABLEINTS( data[FLAGS_WORD] &= ~UBITX_USB_FLAG;
|
||||||
data[FLAGS_WORD] &= ~UBITX_CW_FLAG;
|
data[FLAGS_WORD] &= ~UBITX_CW_FLAG;
|
||||||
if (mark) setDirty(FLAGS_WORD) );
|
if (mark) setDirty(FLAGS_WORD) );
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void setModeCW(bool mark = true) {
|
inline void setCW(bool mark = true) {
|
||||||
DISABLEINTS( data[FLAGS_WORD] |= UBITX_USB_FLAG;
|
DISABLEINTS( data[FLAGS_WORD] |= UBITX_USB_FLAG;
|
||||||
data[FLAGS_WORD] |= UBITX_CW_FLAG;
|
data[FLAGS_WORD] |= UBITX_CW_FLAG;
|
||||||
if (mark) setDirty(FLAGS_WORD) );
|
if (mark) setDirty(FLAGS_WORD) );
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void setModeCWR(bool mark = true) {
|
inline void setCWR(bool mark = true) {
|
||||||
DISABLEINTS( data[FLAGS_WORD] &= ~UBITX_USB_FLAG;
|
DISABLEINTS( data[FLAGS_WORD] &= ~UBITX_USB_FLAG;
|
||||||
data[FLAGS_WORD] |= UBITX_CW_FLAG;
|
data[FLAGS_WORD] |= UBITX_CW_FLAG;
|
||||||
if (mark) setDirty(FLAGS_WORD) );
|
if (mark) setDirty(FLAGS_WORD) );
|
||||||
@@ -313,18 +309,6 @@ struct UBitxRigState {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void setSidetone(uint16_t f, bool mark = true) {
|
|
||||||
DISABLEINTS( data[KEYER_WORD] &= ~UBITX_SIDETONE_MASK;
|
|
||||||
data[KEYER_WORD] |= (uint32_t(f) & UBITX_SIDETONE_MASK);
|
|
||||||
if (mark) setDirty(KEYER_WORD) );
|
|
||||||
}
|
|
||||||
|
|
||||||
inline uint16_t getSidetone() {
|
|
||||||
uint32_t result;
|
|
||||||
DISABLEINTS( result = data[KEYER_WORD] & UBITX_SIDETONE_MASK );
|
|
||||||
return uint16_t(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
void serialHexState(const char* label);
|
void serialHexState(const char* label);
|
||||||
void serialPrettyState(const char* label);
|
void serialPrettyState(const char* label);
|
||||||
@@ -335,9 +319,6 @@ struct UBitxRigState {
|
|||||||
// RigState, not in the TeensyDSP (Teensy) case.
|
// RigState, not in the TeensyDSP (Teensy) case.
|
||||||
void writeDirty(); // write fields FROM RigState TO Raduino
|
void writeDirty(); // write fields FROM RigState TO Raduino
|
||||||
void readDirty(); // read variables FROM Raduino TO RigState
|
void readDirty(); // read variables FROM Raduino TO RigState
|
||||||
#else
|
|
||||||
// These methods are only defined (currently) in the TeensyDSP case.
|
|
||||||
void processDirty();
|
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@@ -5,11 +5,10 @@
|
|||||||
#include <Arduino.h>
|
#include <Arduino.h>
|
||||||
#include "TR.h"
|
#include "TR.h"
|
||||||
|
|
||||||
UBitxTR _tr(DSP);
|
UBitxTR TR(DSP);
|
||||||
UBitxTR& TR = _tr;
|
|
||||||
|
|
||||||
void UBitxTR::update(bool cw, bool extKey) {
|
void UBitxTR::update(bool cw, bool extKey) {
|
||||||
updateKey();
|
updateLinePTT();
|
||||||
|
|
||||||
if (cw) {
|
if (cw) {
|
||||||
if ((keyEnable && keyDown) || extKey) {
|
if ((keyEnable && keyDown) || extKey) {
|
||||||
@@ -20,32 +19,34 @@ void UBitxTR::update(bool cw, bool extKey) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
updatePTT();
|
updateMicPTT();
|
||||||
updateVOX();
|
updateMicVOX();
|
||||||
|
updateDataVOX();
|
||||||
|
|
||||||
if (isTX) {
|
if (isTX) {
|
||||||
// If we are currently transmitting, then ANY T/R release (key
|
// If we are currently transmitting, then ANY T/R release (key
|
||||||
// release) will result in exitting transmit... except for VOX
|
// release) will result in exiting transmit... except for VOX
|
||||||
// and CAT which can only function as a release if it was enabled.
|
// and CAT which can only function as a release if it was enabled.
|
||||||
if (pttReleased() || keyReleased() ||
|
if (micPTTReleased() || linePTTReleased() ||
|
||||||
(voxEnable && voxDeactivated()) ||
|
(micVOXEnabled() && micVOXDeactivated()) ||
|
||||||
(catEnable && catDeactivated())) {
|
(catEnabled() && catDeactivated()) ||
|
||||||
|
(dataVOXEnabled() && dataVOXDeactivated())) {
|
||||||
// first, stop transmitting; then, setup RX audio
|
// first, stop transmitting; then, setup RX audio
|
||||||
DBGCMD( setRX() );
|
DBGCMD( setRX() );
|
||||||
DBGCMD( dsp.rx() );
|
DBGCMD( dsp.rx() );
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if ((pttEnable && pttPressed()) || (voxEnable && voxActivated())) {
|
if ((micPTTEnabled() && micPTTPressed()) || (micVOXEnabled() && micVOXActivated())) {
|
||||||
// first, setup TX audio; then, start transmitting (from Mic)
|
// first, setup TX audio; then, start transmitting (from Mic)
|
||||||
DBGCMD( dsp.txMicIn() );
|
DBGCMD( dsp.tx(MIC_IN) );
|
||||||
DBGCMD( setTX() );
|
DBGCMD( setTX() );
|
||||||
} else if (keyEnable && keyPressed()) {
|
} else if ((linePTTEnabled() && linePTTPressed())) {
|
||||||
// first, setup TX audio; then, start transmitting (from Line In)
|
// first, setup TX audio; then, start transmitting (from Line In)
|
||||||
DBGCMD( dsp.txLineIn() );
|
DBGCMD( dsp.tx(LINE_IN) );
|
||||||
DBGCMD( setTX() );
|
DBGCMD( setTX() );
|
||||||
} else if (catEnable && catActivated()) {
|
} else if (catEnable && catActivated()) {
|
||||||
// first, setup TX audio; then, start transmitting (USB)
|
// first, setup TX audio; then, start transmitting (USB)
|
||||||
DBGCMD( dsp.txUSBIn() );
|
DBGCMD( dsp.tx(USB_IN) );
|
||||||
DBGCMD( setTX() );
|
DBGCMD( setTX() );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -19,12 +19,6 @@ const int uBitxTRPttPin = UBITX_TR_PTT_PIN;
|
|||||||
const int uBitxTRVoxPin = UBITX_TR_VOX_PIN;
|
const int uBitxTRVoxPin = UBITX_TR_VOX_PIN;
|
||||||
const int uBitxTRKeyPin = UBITX_TR_KEY_PIN;
|
const int uBitxTRKeyPin = UBITX_TR_KEY_PIN;
|
||||||
|
|
||||||
struct TxSource {
|
|
||||||
MIC_SOURCE = 0,
|
|
||||||
LINE_SOURCE,
|
|
||||||
USB_SOURCE,
|
|
||||||
};
|
|
||||||
|
|
||||||
class UBitxTR {
|
class UBitxTR {
|
||||||
public:
|
public:
|
||||||
UBitxTR(UBitxDSP& d, int out = uBitxTROutPin, int p = uBitxTRPttPin, int v = uBitxTRVoxPin, int k = uBitxTRKeyPin):
|
UBitxTR(UBitxDSP& d, int out = uBitxTROutPin, int p = uBitxTRPttPin, int v = uBitxTRVoxPin, int k = uBitxTRKeyPin):
|
||||||
@@ -38,41 +32,46 @@ class UBitxTR {
|
|||||||
ptt.interval(5);
|
ptt.interval(5);
|
||||||
|
|
||||||
// default configuration: PTT, key, and CAT enabled; VOX disabled
|
// default configuration: PTT, key, and CAT enabled; VOX disabled
|
||||||
DBGCMD( enablePTT() );
|
DBGCMD( enableMicPTT() );
|
||||||
DBGCMD( disableVOX() );
|
DBGCMD( disableMicVOX() );
|
||||||
DBGCMD( enableKey() );
|
DBGCMD( enableLinePTT() );
|
||||||
DBGCMD( enableCAT() );
|
DBGCMD( enableCAT() );
|
||||||
|
|
||||||
DBGCMD( setRX() );
|
DBGCMD( setRX() );
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void enablePTT() { pttEnable = true; }
|
inline void enableMicPTT() { pttEnable = true; }
|
||||||
inline void enableVOX() { voxEnable = true; }
|
inline void enableLinePTT() { keyEnable = true; }
|
||||||
inline void enableKey() { keyEnable = true; }
|
inline void enableMicVOX() { voxEnable = true; }
|
||||||
|
inline void enableDataVOX() { dvoxEnable = true; }
|
||||||
inline void enableCAT() { catEnable = true; }
|
inline void enableCAT() { catEnable = true; }
|
||||||
inline void disablePTT() { pttEnable = false; }
|
|
||||||
inline void disableVOX() { voxEnable = false; }
|
inline void disableMicPTT() { pttEnable = false; }
|
||||||
inline void disableKey() { keyEnable = false; }
|
inline void disableLinePTT() { keyEnable = false; }
|
||||||
|
inline void disableMicVOX() { voxEnable = false; }
|
||||||
|
inline void disableDataVOX() { dvoxEnable = false; }
|
||||||
inline void disableCAT() { catEnable = false; }
|
inline void disableCAT() { catEnable = false; }
|
||||||
|
|
||||||
inline bool pttEnabled() { return pttEnable; }
|
inline bool micPTTEnabled() const { return pttEnable; }
|
||||||
inline bool voxEnabled() { return voxEnable; }
|
inline bool linePTTEnabled() const { return keyEnable; }
|
||||||
inline bool keyEnabled() { return keyEnable; }
|
inline bool micVOXEnabled() const { return voxEnable; }
|
||||||
inline bool catEnabled() { return catEnable; }
|
inline bool dataVOXEnabled() const { return dvoxEnable; }
|
||||||
|
inline bool catEnabled() const { return catEnable; }
|
||||||
|
|
||||||
inline bool pttPressed() { return ptt.fell(); }
|
inline bool micPTTPressed() { return ptt.fell(); }
|
||||||
inline bool pttReleased() { return ptt.rose(); }
|
inline bool micPTTReleased() { return ptt.rose(); }
|
||||||
inline bool voxActivated() { return (L_voxActive != voxActive) && L_voxActive; }
|
inline bool linePTTPressed() { return (L_keyDown != keyDown) && L_keyDown; }
|
||||||
inline bool voxDeactivated() { return (L_voxActive != voxActive) && voxActive; }
|
inline bool linePTTReleased() { return (L_keyDown != keyDown) && keyDown; }
|
||||||
inline bool keyPressed() { return (L_keyDown != keyDown) && L_keyDown; }
|
inline bool micVOXActivated() { return (L_voxActive != voxActive) && L_voxActive; }
|
||||||
inline bool keyReleased() { return (L_keyDown != keyDown) && keyDown; }
|
inline bool micVOXDeactivated() { return (L_voxActive != voxActive) && voxActive; }
|
||||||
|
inline bool dataVOXActivated() { return (L_dvoxActive != dvoxActive) && L_dvoxActive; }
|
||||||
|
inline bool dataVOXDeactivated() { return (L_dvoxActive != dvoxActive) && dvoxActive; }
|
||||||
inline bool catActivated() { return (L_catActive != catActive) && L_catActive; }
|
inline bool catActivated() { return (L_catActive != catActive) && L_catActive; }
|
||||||
inline bool catDeactivated() { return (L_catActive != catActive) && catActive; }
|
inline bool catDeactivated() { return (L_catActive != catActive) && catActive; }
|
||||||
|
|
||||||
inline void catTX(TxSource src) {
|
inline void catTX() {
|
||||||
L_catActive = catActive;
|
L_catActive = catActive;
|
||||||
catActive = true;
|
catActive = true;
|
||||||
txSource = src;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void catRX() {
|
inline void catRX() {
|
||||||
@@ -80,11 +79,10 @@ class UBitxTR {
|
|||||||
catActive = false;
|
catActive = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
//====================================================================
|
//======================================================================
|
||||||
|
|
||||||
inline bool transmitting() { return isTX; }
|
inline bool transmitting() { return isTX; }
|
||||||
inline bool receiving() { return !isTX; }
|
inline bool receiving() { return !isTX; }
|
||||||
inline TxSource source() const { return txSource; }
|
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* @brief Check if any of the PTT's have been pressed or released
|
* @brief Check if any of the PTT's have been pressed or released
|
||||||
@@ -117,43 +115,58 @@ class UBitxTR {
|
|||||||
digitalWrite(outPin, HIGH);
|
digitalWrite(outPin, HIGH);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void updatePTT() {
|
inline void updateMicPTT() {
|
||||||
ptt.update();
|
ptt.update();
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void updateVOX() {
|
inline void updateLinePTT() {
|
||||||
|
L_keyDown = keyDown;
|
||||||
|
keyDown = (digitalRead(keyPin) == LOW);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void updateMicVOX() {
|
||||||
L_voxActive = voxActive;
|
L_voxActive = voxActive;
|
||||||
voxActive = (digitalRead(voxPin) == LOW);
|
voxActive = (digitalRead(voxPin) == LOW);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void updateKey() {
|
inline void updateDataVOX() {
|
||||||
L_keyDown = keyDown;
|
L_dvoxActive = dvoxActive;
|
||||||
keyDown = (digitalRead(keyPin) == LOW);
|
if (dsp.getVoxLevel() > dvoxThreshold) {
|
||||||
|
dvoxActive = true;
|
||||||
|
dvoxElapsed = 0;
|
||||||
|
} else if (dvoxActive && (dvoxElapsed > dvoxDelay)) {
|
||||||
|
dvoxActive = false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
UBitxDSP& dsp;
|
UBitxDSP& dsp;
|
||||||
|
|
||||||
Bounce ptt;
|
Bounce ptt;
|
||||||
|
|
||||||
int outPin;
|
|
||||||
int pttPin;
|
int pttPin;
|
||||||
int voxPin;
|
int voxPin;
|
||||||
int keyPin;
|
int keyPin;
|
||||||
|
int outPin;
|
||||||
|
|
||||||
bool isTX = false;
|
bool isTX = false;
|
||||||
|
|
||||||
bool pttEnable = false;
|
bool pttEnable = false;
|
||||||
bool voxEnable = false;
|
bool voxEnable = false;
|
||||||
|
bool dvoxEnable = false;
|
||||||
bool keyEnable = false;
|
bool keyEnable = false;
|
||||||
bool catEnable = false;
|
bool catEnable = false;
|
||||||
|
|
||||||
bool voxActive = false;
|
bool voxActive = false;
|
||||||
bool L_voxActive = false;
|
bool L_voxActive = false;
|
||||||
|
bool dvoxActive = false;
|
||||||
|
bool L_dvoxActive = false;
|
||||||
bool keyDown = false;
|
bool keyDown = false;
|
||||||
bool L_keyDown = false;
|
bool L_keyDown = false;
|
||||||
bool catActive = false;
|
bool catActive = false;
|
||||||
bool L_catActive = false;
|
bool L_catActive = false;
|
||||||
TxSource txSource = MIC_SOURCE;
|
|
||||||
|
elapsedMillis dvoxElapsed = 0;
|
||||||
|
unsigned dvoxDelay = 250; // TODO: make dynamic
|
||||||
};
|
};
|
||||||
|
|
||||||
extern UBitxTR TR;
|
extern UBitxTR TR;
|
||||||
|
@@ -34,12 +34,11 @@ void ts590SendCommand(const char* format, ...) {
|
|||||||
* than two are supplied, then the command will be
|
* than two are supplied, then the command will be
|
||||||
* initialized with a null prefix.
|
* initialized with a null prefix.
|
||||||
*/
|
*/
|
||||||
TS590Command::TS590Command(const char* pre) {
|
TS590Command::TS590Command(const char* pre)
|
||||||
if (strlen(pre) >= 2) {
|
: myPrefix(pre), prefixLength(strlen(pre))
|
||||||
myPrefix[0] = pre[0];
|
{}
|
||||||
myPrefix[1] = pre[1];
|
|
||||||
}
|
TS590Command::~TS590Command() {}
|
||||||
}
|
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* @brief Determine whether this is a Read command or not. by
|
* @brief Determine whether this is a Read command or not. by
|
||||||
@@ -47,7 +46,7 @@ TS590Command::TS590Command(const char* pre) {
|
|||||||
* @return True if a Read command; false otherwise.
|
* @return True if a Read command; false otherwise.
|
||||||
*/
|
*/
|
||||||
bool TS590Command::isReadCommand(const char* cmd) const {
|
bool TS590Command::isReadCommand(const char* cmd) const {
|
||||||
if (strlen(cmd) == 2) {
|
if (strlen(cmd) == prefixLength) {
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
return false;
|
return false;
|
||||||
@@ -137,22 +136,45 @@ void TS590Command::setDSP(UBitxDSP* d) {
|
|||||||
theDSP = d;
|
theDSP = d;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
|
||||||
* @brief Set the T/R that will be used to process commands.
|
|
||||||
* @param t
|
|
||||||
* Pointer to the UBitxTR object.
|
|
||||||
*/
|
|
||||||
void TS590Command::setDSP(UBitxTR* t) {
|
|
||||||
theTR = t;
|
|
||||||
}
|
|
||||||
|
|
||||||
UBitxRig* TS590Command::theRig = &Rig;
|
UBitxRig* TS590Command::theRig = &Rig;
|
||||||
UBitxDSP* TS590Command::theDSP = &DSP;
|
UBitxDSP* TS590Command::theDSP = &DSP;
|
||||||
UBitxTR* TR590Command::theTR = &TR;
|
|
||||||
TS590Error TS590Command::theError = NoError;
|
TS590Error TS590Command::theError = NoError;
|
||||||
|
|
||||||
/**********************************************************************/
|
/**********************************************************************/
|
||||||
|
|
||||||
|
void TS590Command_Bool::handleCommand(const char* cmd) {
|
||||||
|
setter(cmd[length()] == '0' ? false : true);
|
||||||
|
}
|
||||||
|
|
||||||
|
void TS590Command_Bool::sendResponse(const char* cmd) {
|
||||||
|
ts590SendCommand("%s%s", prefix(), getter() ? "1" : "0");
|
||||||
|
}
|
||||||
|
/**********************************************************************/
|
||||||
|
|
||||||
|
void TS590Command_UL::handleCommand(const char* cmd) {
|
||||||
|
unsigned val = static_cast<unsigned>(strtoul(&cmd[length()], NULL, 10));
|
||||||
|
if (val < myMin) {
|
||||||
|
val = myMin;
|
||||||
|
} else if (val > myMax) {
|
||||||
|
val = myMax;
|
||||||
|
}
|
||||||
|
val = (val * mySlope) + myIntercept;
|
||||||
|
setter(val);
|
||||||
|
}
|
||||||
|
|
||||||
|
void TS590Command_UL::sendResponse(const char* cmd) {
|
||||||
|
unsigned val = getter();
|
||||||
|
val = (val - myIntercept) / mySlope;
|
||||||
|
if (val < myMin) {
|
||||||
|
val = myMin;
|
||||||
|
} else if (val > myMax) {
|
||||||
|
val = myMax;
|
||||||
|
}
|
||||||
|
ts590SendCommand("%s%0*u", prefix(), myWidth, getter());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**********************************************************************/
|
||||||
|
|
||||||
void TS590_FR::handleCommand(const char* cmd) {
|
void TS590_FR::handleCommand(const char* cmd) {
|
||||||
if (strlen(cmd) == 3) {
|
if (strlen(cmd) == 3) {
|
||||||
switch (cmd[2]) {
|
switch (cmd[2]) {
|
||||||
@@ -246,19 +268,19 @@ void TS590_MD::handleCommand(const char* cmd) {
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case '1': // LSB
|
case '1': // LSB
|
||||||
rig()->setModeLSB();
|
rig()->setLSB();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case '2': // USB
|
case '2': // USB
|
||||||
rig()->setModeUSB();
|
rig()->setUSB();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case '3': // CW
|
case '3': // CW
|
||||||
rig()->setModeCW();
|
rig()->setCW();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case '7': // CW-R
|
case '7': // CW-R
|
||||||
rig()->setModeCWR();
|
rig()->setCWR();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
@@ -327,122 +349,78 @@ void TS590_SL::sendResponse(const char* cmd) {
|
|||||||
|
|
||||||
/**********************************************************************/
|
/**********************************************************************/
|
||||||
|
|
||||||
void TS590_TX::handleCommand(const char* cmd) {
|
void TS590_VX::handleCommand(const char* cmd) {
|
||||||
if (strlen(cmd) == 3) {
|
|
||||||
switch (cmd[2]) {
|
|
||||||
case '0':
|
|
||||||
tr.catTX(MIC_SOURCE);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case '1':
|
|
||||||
tr.catTX(rig.isUSBInput() ? USB_INPUT : LINE_INPUT);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case '2':
|
|
||||||
// TODO: Need to implement w/ Teensy Audio Tool.
|
|
||||||
//tr.catTX();
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
setSyntaxError();
|
|
||||||
}
|
|
||||||
} else if (strlen(cmd) == 2) {
|
|
||||||
tr.catTX(MIC_SOURCE);
|
|
||||||
} else {
|
|
||||||
setSyntaxError();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void TS590_TX::sendResponse(const char* cmd) {
|
void TS590_VX::sendResponse(const char* cmd) {
|
||||||
char src;
|
|
||||||
switch (tr.source()) {
|
|
||||||
case MIC_SOURCE:
|
|
||||||
src = '0';
|
|
||||||
break;
|
|
||||||
|
|
||||||
case LINE_SOURCE:
|
|
||||||
case USB_SOURCE:
|
|
||||||
src = '1';
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
ts590SeondCommand("TX%1c", src);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**********************************************************************/
|
/**********************************************************************/
|
||||||
|
|
||||||
/*!
|
void nullSetFunc(unsigned x) { return; }
|
||||||
* @brief Create a new CAT EX command. It should be initialized with
|
unsigned getIDFunc() {
|
||||||
* a 3-character P1 parameter (command number).
|
#ifndef USE_TS590SG_CAT
|
||||||
* @param pre
|
return 021;
|
||||||
* A 3-character command prefix. If more than 3 characters
|
#else
|
||||||
* are supplied, only the first two will be used. If less
|
return 023;
|
||||||
* than three are supplied, then the command will be
|
#endif
|
||||||
* initialized with a null prefix.
|
|
||||||
*/
|
|
||||||
TS590EXCommand::TS590EXCommand(const char* P1):
|
|
||||||
TS590Command("EX") {
|
|
||||||
if (strlen(P1) >= 3) {
|
|
||||||
strncpy(myMenu, P1, 3);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
SetUL setAG = SetUL::create<UBitxDSP, &UBitxDSP::setLineOut255>(DSP);
|
||||||
* @brief Determine whether this is a Read command or not. by
|
GetUL getAG = GetUL::create<UBitxDSP, &UBitxDSP::getLineOut255>(DSP);
|
||||||
* default, if it's a 2-letter command, it's a Read.
|
SetUL setAI = [](unsigned v) -> void { v == 0 ? Rig.aiOff() : Rig.aiOn(); };
|
||||||
* @return True if a Read command; false otherwise.
|
GetUL getAI = []() -> unsigned { return Rig.isAI() ? 4 : 0; };
|
||||||
*/
|
//SetUL setSidetone = SetUL::create<UBitxDSP, ...>(...);
|
||||||
bool TS590EXCommand::isReadCommand(const char* cmd) const {
|
//GetUL getSidetone = GetUL::create<UBitxDSP, ...>(...);
|
||||||
if (strlen(cmd) == 9) {
|
SetUL setUSBin = SetUL::create<UBitxDSP, &UBitxDSP::setUSBIn9>(DSP);
|
||||||
return true;
|
GetUL getUSBin = GetUL::create<UBitxDSP, &UBitxDSP::getUSBIn9>(DSP);
|
||||||
} else {
|
SetUL setUSBout = SetUL::create<UBitxDSP, &UBitxDSP::setUSBOut9>(DSP);
|
||||||
return false;
|
GetUL getUSBout = GetUL::create<UBitxDSP, &UBitxDSP::getUSBOut9>(DSP);
|
||||||
}
|
SetUL setACC2in = SetUL::create<UBitxDSP, &UBitxDSP::setLineIn9>(DSP);
|
||||||
}
|
GetUL getACC2in = GetUL::create<UBitxDSP, &UBitxDSP::getLineIn9>(DSP);
|
||||||
|
SetUL setACC2out = SetUL::create<UBitxDSP, &UBitxDSP::setLineOut9>(DSP);
|
||||||
|
GetUL getACC2out = GetUL::create<UBitxDSP, &UBitxDSP::getLineOut9>(DSP);
|
||||||
|
SetUL setVoxDelay = SetUL::create<UBitxDSP, &UBitxDSP::setDataVoxDelay>(DSP);
|
||||||
|
GetUL getVoxDelay = GetUL::create<UBitxDSP, &UBitxDSP::getDataVoxDelay>(DSP);
|
||||||
|
SetUL setUSBvox = SetUL::create<UBitxDSP, &UBitxDSP::setUSBVOXThresh9>(DSP);
|
||||||
|
GetUL getUSBvox = GetUL::create<UBitxDSP, &UBitxDSP::getUSBVOXThresh9>(DSP);
|
||||||
|
SetUL setACC2vox = SetUL::create<UBitxDSP, &UBitxDSP::setLineVOXThresh9>(DSP);
|
||||||
|
GetUL getACC2vox = GetUL::create<UBitxDSP, &UBitxDSP::getLineVOXThresh9>(DSP);
|
||||||
|
SetUL setID = SetUL::create<nullSetFunc>();
|
||||||
|
GetUL getID = GetUL::create<getIDFunc>();
|
||||||
|
|
||||||
void TS590EXCommand::sendResponse(const char* cmd) {
|
TS590Command_UL TS590_AG("AG0", 3, 0, 255, setAG, getAG);
|
||||||
ts590sendCommand("%2c%3c0000%s", prefix(), menu(), getReturnValue());
|
TS590Command_UL TS590_AI("AI", 1, 0, 4, setAI, getAI);
|
||||||
}
|
// TS590_AS
|
||||||
|
// TS590_BD
|
||||||
/**********************************************************************/
|
// TS590_BU
|
||||||
|
// TS590_CA
|
||||||
void TS590_EX034::handleCommand(const char* cmd) {
|
// TS590_CD0
|
||||||
if (strlen(cmd) == 10 || strlen(cmd) == 11) {
|
// TS590_CD1
|
||||||
index = (uint8_t)atol(&cmd[9]);
|
// TS590_CD2
|
||||||
if (index < 15) {
|
// TS590_CH
|
||||||
rig().setCWSidetone(300.0 + (float)(index * 50));
|
#ifndef USE_TS590SG_CAT
|
||||||
} else {
|
//TS590Command_UL TS590_EX034("EX0340000", 2, 0, 14, 50, 300, setSideTone, getSideTone);
|
||||||
setSyntaxError();
|
TS590Command_UL TS590_EX064("EX0640000", 1, 0, 9, setUSBin, getUSBin);
|
||||||
}
|
TS590Command_UL TS590_EX065("EX0650000", 1, 0, 9, setUSBout, getUSBout);
|
||||||
} else {
|
TS590Command_UL TS590_EX066("EX0660000", 1, 0, 9, setACC2in, getACC2in);
|
||||||
setSyntaxError();
|
TS590Command_UL TS590_EX067("EX0670000", 1, 0, 9, setACC2out, getACC2out);
|
||||||
}
|
TS590Command_UL TS590_EX070("EX0700000", 2, 0, 20, 5, 0, setVoxDelay, getVoxDelay);
|
||||||
}
|
TS590Command_UL TS590_EX071("EX0710000", 1, 0, 9, setUSBvox, getUSBvox);
|
||||||
|
TS590Command_UL TS590_EX072("EX0720000", 1, 0, 9, setACC2vox, getACC2vox);
|
||||||
void TS590_EX034::sendResponse(const char* cmd) {
|
#else
|
||||||
ts590SendCommand("EX0340000%02d", index % 15);
|
//TS590Command_UL TS590_EX040("EX0400000", 2, 0, 14, 50, 300, setSideTone, getSideTone);
|
||||||
}
|
TS590Command_UL TS590_EX071("EX0710000", 1, 0, 9, setUSBin, getUSBin);
|
||||||
|
TS590Command_UL TS590_EX072("EX0720000", 1, 0, 9, setUSBout, getUSBout);
|
||||||
/**********************************************************************/
|
TS590Command_UL TS590_EX073("EX0730000", 1, 0, 9, setACC2in, getACC2in);
|
||||||
|
TS590Command_UL TS590_EX074("EX0740000", 1, 0, 9, setACC2out, getACC2out);
|
||||||
void TS590_EX063::handleCommand(const char* cmd) {
|
TS590Command_UL TS590_EX077("EX0770000", 2, 0, 20, 5, 0, setVoxDelay, getVoxDelay);
|
||||||
if (strlen(cmd) == 10) {
|
TS590Command_UL TS590_EX078("EX0780000", 1, 0, 9, setUSBvox, getUSBvox);
|
||||||
if (cmd[9] == '0') {
|
TS590Command_UL TS590_EX079("EX0790000", 1, 0, 9, setACC2vox, getACC2vox);
|
||||||
rig().setLineInput();
|
#endif
|
||||||
} else if (cmd[9] == '1') {
|
TS590Command_UL TS590_ID("ID", 3, 21, 23, setID, getID);
|
||||||
rig().setUSBInput();
|
|
||||||
} else {
|
|
||||||
setSyntaxError();
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
setSyntaxError();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void TS590_EX063::sendResponse(const char* cmd) {
|
|
||||||
ts590SendCommand("EX0630000%1c", rig().isUSBInput() ? '1' : '0');
|
|
||||||
}
|
|
||||||
|
|
||||||
/**********************************************************************/
|
|
||||||
|
|
||||||
TS590_FA cmdFA;
|
TS590_FA cmdFA;
|
||||||
TS590_FB cmdFB;
|
TS590_FB cmdFB;
|
||||||
@@ -465,7 +443,6 @@ int numCatCommands = sizeof(catCommands) / sizeof(catCommands[0]);
|
|||||||
|
|
||||||
/**********************************************************************/
|
/**********************************************************************/
|
||||||
|
|
||||||
|
|
||||||
void UBitxTS590::begin() {
|
void UBitxTS590::begin() {
|
||||||
Serial.begin(9600); // USB is always 12 Mbit/sec
|
Serial.begin(9600); // USB is always 12 Mbit/sec
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
@@ -506,21 +483,7 @@ typedef class TS590Command* PCmd;
|
|||||||
|
|
||||||
int compareCATCommands(const void* a, const void* b) {
|
int compareCATCommands(const void* a, const void* b) {
|
||||||
TS590Command const *B = *(TS590Command const **)b;
|
TS590Command const *B = *(TS590Command const **)b;
|
||||||
int cmp = strncmp((char*)a, (char*)B->prefix(), 2);
|
int cmp = strncmp((char*)a, (char*)B->prefix(), B->length());
|
||||||
#ifdef DEBUG
|
|
||||||
Serial.print("Comparison: ");
|
|
||||||
Serial.print((char*)a);
|
|
||||||
Serial.print(" ? ");
|
|
||||||
Serial.print((char*)B->prefix());
|
|
||||||
Serial.print(" --> ");
|
|
||||||
Serial.println(cmp);
|
|
||||||
#endif
|
|
||||||
return cmp;
|
|
||||||
}
|
|
||||||
|
|
||||||
int compareCATEXCommands(const void* a, const void* b) {
|
|
||||||
TS590Command const *B = *(TS590Command const **)b;
|
|
||||||
int cmp = strncmp((char*)a, (char*)B->prefix(), 5);
|
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
Serial.print("Comparison: ");
|
Serial.print("Comparison: ");
|
||||||
Serial.print((char*)a);
|
Serial.print((char*)a);
|
||||||
@@ -533,12 +496,7 @@ int compareCATEXCommands(const void* a, const void* b) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void UBitxTS590::processCommand() {
|
void UBitxTS590::processCommand() {
|
||||||
TS590Command** cmd;
|
TS590Command** cmd = (TS590Command**)bsearch(buf, commands, numCommands, sizeof(TS590Command*), compareCATCommands);
|
||||||
if (strncmp(buf, "EX", 2) == 0) {
|
|
||||||
cmd = (TS590Command**)bsearch(buf, commands, numCommands, sizeof(TS590Command*), compareCATEXCommands);
|
|
||||||
} else {
|
|
||||||
cmd = (TS590Command**)bsearch(buf, commands, numCommands, sizeof(TS590Command*), compareCATCommands);
|
|
||||||
}
|
|
||||||
if (cmd == NULL) {
|
if (cmd == NULL) {
|
||||||
ts590SyntaxError();
|
ts590SyntaxError();
|
||||||
} else {
|
} else {
|
||||||
|
@@ -2,15 +2,13 @@
|
|||||||
#define __TS590_h__
|
#define __TS590_h__
|
||||||
|
|
||||||
#include <Arduino.h>
|
#include <Arduino.h>
|
||||||
|
#include <Embedded_Template_Library.h>
|
||||||
|
#include <etl/delegate.h>
|
||||||
#include "DSP.h"
|
#include "DSP.h"
|
||||||
#include "Rig.h"
|
#include "Rig.h"
|
||||||
#include "TR.h"
|
|
||||||
|
|
||||||
/**********************************************************************/
|
/**********************************************************************/
|
||||||
|
|
||||||
// uncomment to use TS-590SG / comment to use TS-590S
|
|
||||||
#define USE_TS590SG
|
|
||||||
|
|
||||||
#define TS590_COMMAND_MAX_LENGTH 50 // including terminator (which will get converted to null)
|
#define TS590_COMMAND_MAX_LENGTH 50 // including terminator (which will get converted to null)
|
||||||
|
|
||||||
const int ts590CommandMaxLength = TS590_COMMAND_MAX_LENGTH;
|
const int ts590CommandMaxLength = TS590_COMMAND_MAX_LENGTH;
|
||||||
@@ -39,6 +37,72 @@ enum TS590Error {
|
|||||||
ProcessError
|
ProcessError
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**********************************************************************
|
||||||
|
**********************************************************************/
|
||||||
|
/*
|
||||||
|
class TS590BaseCommand {
|
||||||
|
public:
|
||||||
|
TS590BaseCommand(const char* prefix)
|
||||||
|
: myPrefix(prefix), prefixLength(strlen(prefix))
|
||||||
|
{}
|
||||||
|
virtual ~TS590BaseCommand() = 0;
|
||||||
|
|
||||||
|
inline const char* prefix() { return &myPrefix[0]; }
|
||||||
|
inline size_t length() { return prefixLength; }
|
||||||
|
|
||||||
|
virtual void handleCommand(const char* cmd) = 0;
|
||||||
|
virtual void sendResponse(const char* cmd) = 0;
|
||||||
|
virtual bool isReadCommand(const char* cmd) const;
|
||||||
|
|
||||||
|
inline void process(const char* cmd) {
|
||||||
|
theError = NoError;
|
||||||
|
|
||||||
|
if (isReadCommand(cmd)) {
|
||||||
|
DBGCMD( sendResponse(cmd) );
|
||||||
|
} else {
|
||||||
|
DBGCMD( handleCommand(cmd) );
|
||||||
|
switch(theError) {
|
||||||
|
case NoError:
|
||||||
|
if (theRig->isAI()) {
|
||||||
|
DBGCMD( sendResponse(cmd) );
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SyntaxError:
|
||||||
|
DBGCMD( ts590SyntaxError() );
|
||||||
|
break;
|
||||||
|
|
||||||
|
case CommError:
|
||||||
|
DBGCMD( ts590CommError() );
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ProcessError:
|
||||||
|
DBGCMD( ts590ProcessError() );
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
const char* myPrefix;
|
||||||
|
size_t prefixLength;
|
||||||
|
};
|
||||||
|
*/
|
||||||
|
typedef etl::delegate<bool(const char*)> ValidateFunc;
|
||||||
|
typedef etl::delegate<bool(const char*)> IsReadFunc;
|
||||||
|
typedef etl::delegate<void(bool)> ToggleFunc;
|
||||||
|
|
||||||
|
/*
|
||||||
|
class TS590ToggleCommand : public TS590BaseCommand {
|
||||||
|
TS590ToggleCommand(const char* prefix, ToggleFunc& setter, ToggleFunc& getter)
|
||||||
|
: TS590BaseCommand(prefix)
|
||||||
|
{}
|
||||||
|
|
||||||
|
private:
|
||||||
|
ToggleFunc& mySetter;
|
||||||
|
ToggleFunc& myGetter;
|
||||||
|
};
|
||||||
|
*/
|
||||||
/**********************************************************************/
|
/**********************************************************************/
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@@ -48,7 +112,7 @@ enum TS590Error {
|
|||||||
class TS590Command {
|
class TS590Command {
|
||||||
public:
|
public:
|
||||||
TS590Command(const char* pre);
|
TS590Command(const char* pre);
|
||||||
virtual ~TS590Command() = 0;
|
virtual ~TS590Command();
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* @brief Return the 2-character prefix for the command.
|
* @brief Return the 2-character prefix for the command.
|
||||||
@@ -56,6 +120,8 @@ class TS590Command {
|
|||||||
*/
|
*/
|
||||||
inline const char* prefix() const { return &myPrefix[0]; }
|
inline const char* prefix() const { return &myPrefix[0]; }
|
||||||
|
|
||||||
|
inline size_t length() const { return prefixLength; }
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* @brief Return the rig that this command will be used to control.
|
* @brief Return the rig that this command will be used to control.
|
||||||
*/
|
*/
|
||||||
@@ -66,11 +132,6 @@ class TS590Command {
|
|||||||
*/
|
*/
|
||||||
inline UBitxDSP* dsp() const { return theDSP; }
|
inline UBitxDSP* dsp() const { return theDSP; }
|
||||||
|
|
||||||
/*!
|
|
||||||
* @brief Return the T/R that this command will be used to control.
|
|
||||||
*/
|
|
||||||
inline UBitxDSP* tr() const { return theTR; }
|
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* @brief Handle the provided Set command. If the Set command
|
* @brief Handle the provided Set command. If the Set command
|
||||||
* results in an error, then set the appropriate flag with
|
* results in an error, then set the appropriate flag with
|
||||||
@@ -97,10 +158,10 @@ class TS590Command {
|
|||||||
static void setProcessError();
|
static void setProcessError();
|
||||||
static void setRig(UBitxRig* r);
|
static void setRig(UBitxRig* r);
|
||||||
static void setDSP(UBitxDSP* d);
|
static void setDSP(UBitxDSP* d);
|
||||||
static void setTR(UBitxTR* t);
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
char myPrefix[3] = "\0\0";
|
const char* myPrefix;
|
||||||
|
size_t prefixLength;
|
||||||
static TS590Error theError;
|
static TS590Error theError;
|
||||||
static UBitxRig* theRig;
|
static UBitxRig* theRig;
|
||||||
static UBitxDSP* theDSP;
|
static UBitxDSP* theDSP;
|
||||||
@@ -108,6 +169,68 @@ class TS590Command {
|
|||||||
|
|
||||||
/**********************************************************************/
|
/**********************************************************************/
|
||||||
|
|
||||||
|
typedef etl::delegate<void(bool)> SetBool;
|
||||||
|
typedef etl::delegate<bool(void)> GetBool;
|
||||||
|
|
||||||
|
class TS590Command_Bool : public TS590Command {
|
||||||
|
public:
|
||||||
|
TS590Command_Bool(const char* prefix, SetBool set, GetBool get)
|
||||||
|
: TS590Command(prefix), setter(set), getter(get) {}
|
||||||
|
|
||||||
|
virtual void handleCommand(const char* cmd);
|
||||||
|
virtual void sendResponse(const char* cmd);
|
||||||
|
|
||||||
|
private:
|
||||||
|
SetBool setter;
|
||||||
|
GetBool getter;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**********************************************************************/
|
||||||
|
|
||||||
|
typedef etl::delegate<void(unsigned)> SetUL;
|
||||||
|
typedef etl::delegate<unsigned(void)> GetUL;
|
||||||
|
|
||||||
|
class TS590Command_UL : public TS590Command {
|
||||||
|
public:
|
||||||
|
TS590Command_UL(const char* prefix, size_t width, unsigned min, unsigned max, SetUL set, GetUL get)
|
||||||
|
: TS590Command(prefix), myWidth(width), myMin(min), myMax(max), mySlope(1), myIntercept(0), setter(set), getter(get) {}
|
||||||
|
|
||||||
|
TS590Command_UL(const char* prefix, size_t width, unsigned min, unsigned max, unsigned slope, unsigned intercept, SetUL set, GetUL get)
|
||||||
|
: TS590Command(prefix), myWidth(width), myMin(min), myMax(max), mySlope(slope), myIntercept(intercept), setter(set), getter(get) {}
|
||||||
|
|
||||||
|
virtual void handleCommand(const char* cmd);
|
||||||
|
virtual void sendResponse(const char* cmd);
|
||||||
|
|
||||||
|
private:
|
||||||
|
size_t myWidth;
|
||||||
|
unsigned myMin;
|
||||||
|
unsigned myMax;
|
||||||
|
unsigned mySlope;
|
||||||
|
unsigned myIntercept;
|
||||||
|
SetUL setter;
|
||||||
|
GetUL getter;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**********************************************************************/
|
||||||
|
/*
|
||||||
|
typedef etl::delegate<void(bool)> SetULArray;
|
||||||
|
typedef etl::delegate<bool(void)> GetULArray;
|
||||||
|
|
||||||
|
class TS590Command_ULArray : public TS590Command {
|
||||||
|
public:
|
||||||
|
TS590Command_ULArray(const char* prefix, SetUL set, GetUL get)
|
||||||
|
: TS590Command(prefix), setter(set), getter(get) {}
|
||||||
|
|
||||||
|
virtual void handleCommand(const char* cmd);
|
||||||
|
virtual void sendResponse(const char* cmd);
|
||||||
|
|
||||||
|
private:
|
||||||
|
SetUL setter;
|
||||||
|
GetUL getter;
|
||||||
|
};
|
||||||
|
*/
|
||||||
|
/**********************************************************************/
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* @brief CAT command for setting or reading the VFO A/B frequency.
|
* @brief CAT command for setting or reading the VFO A/B frequency.
|
||||||
*/
|
*/
|
||||||
@@ -203,134 +326,19 @@ class TS590_SL : public TS590Command {
|
|||||||
};
|
};
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* @brief CAT command to start transmitting.
|
* CAT command for enabling or disabling the mic VOX.
|
||||||
*/
|
*/
|
||||||
class TS590_TX : public TS590Command {
|
class TS590_VX : public TS590Command {
|
||||||
public:
|
public:
|
||||||
TS590_TX(): TS590Command("TX") {}
|
TS590_VX(): TS590Command("VX") {}
|
||||||
virtual void handleCommand(const char* cmd);
|
virtual void handleCommand(const char* cmd);
|
||||||
virtual void sendResponse(const char* cmd);
|
virtual void sendResponse(const char* cmd);
|
||||||
};
|
|
||||||
|
|
||||||
/**********************************************************************/
|
|
||||||
|
|
||||||
class TS590EXCommand : public TS590Command {
|
|
||||||
public:
|
|
||||||
TS590EXCommand(const char *P1);
|
|
||||||
virtual ~TS590EXCommand() = 0;
|
|
||||||
|
|
||||||
inline const char* menu() const { return &myMenu[0]; }
|
|
||||||
|
|
||||||
virtual const char* getReturnValue() const = 0;
|
|
||||||
|
|
||||||
virtual void sendResponse(const char* cmd);
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
char myMenu[4] = "\0\0\0";
|
unsigned index;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**********************************************************************/
|
/**********************************************************************/
|
||||||
|
|
||||||
/*!
|
|
||||||
* @brief CAT command for setting the sidetone pitch/frequency.
|
|
||||||
*/
|
|
||||||
class TS590_EX034 : public TS590EXCommand {
|
|
||||||
public:
|
|
||||||
TS590_EX034(): TS590EXCommand("034") {}
|
|
||||||
virtual void handleCommand(const char* cmd);
|
|
||||||
virtual const char* getReturnValue();
|
|
||||||
private:
|
|
||||||
uint8_t index;
|
|
||||||
};
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* @brief CAT command for selecting the data input line.
|
|
||||||
*/
|
|
||||||
class TS590_EX063 : public TS590EXCommand {
|
|
||||||
public:
|
|
||||||
TS590_EX063(): TS590EXCommand("063") {}
|
|
||||||
virtual void handleCommand(const char* cmd);
|
|
||||||
virtual const char* getReturnValue();
|
|
||||||
};
|
|
||||||
|
|
||||||
/**********************************************************************/
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* @brief CAT command for setting USB/Line audio input levels.
|
|
||||||
*/
|
|
||||||
template<bool USB, bool SG>
|
|
||||||
class TS590_EXDataAudioInLevel : public TS590EXCommand {
|
|
||||||
public:
|
|
||||||
TS590_EXDataAudioInLevel(): TS590EXCommand(USB ? (SG ? "071" : "064") : (SG ? "073" : "066")) {}
|
|
||||||
|
|
||||||
virtual void handleCommand(const char* cmd) {
|
|
||||||
if (strlen(cmd) == 10) {
|
|
||||||
uint8_t val = (cmd[9] - 48) % 10;
|
|
||||||
if (USB) {
|
|
||||||
// set USB input level
|
|
||||||
} else {
|
|
||||||
// set Line input level
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
setSyntaxError();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual const char* getReturnValue() {
|
|
||||||
static char str[2] = "\0";
|
|
||||||
// get input level - decimal 0 to 9 ... str[1] = ...
|
|
||||||
return str;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
#ifdef USE_TS590SG
|
|
||||||
typedef TS590_EXDataAudioInLevel<true, true> TS590_EX071;
|
|
||||||
typedef TS590_EXDataAudioInLevel<false, true> TS590_EX073;
|
|
||||||
#else
|
|
||||||
typedef TS590_EXDataAudioInLevel<true, false> TS590_EX064;
|
|
||||||
typedef TS590_EXDataAudioInLevel<true, false> TS590_EX066;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/**********************************************************************/
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* @brief CAT command for setting USB/Line audio output levels.
|
|
||||||
*/
|
|
||||||
template<bool USB, bool SG>
|
|
||||||
class TS590_EXDataAudioOutLevel : public TS590EXCommand {
|
|
||||||
public:
|
|
||||||
TS590_EXDataAudioOutLevel(): TS590EXCommand(USB ? (SG ? "072" : "065") : (SG ? "074" : "067")) {}
|
|
||||||
|
|
||||||
virtual void handleCommand(const char* cmd) {
|
|
||||||
if (strlen(cmd) == 10) {
|
|
||||||
uint8_t val = (cmd[9] - 48) % 10;
|
|
||||||
if (USB) {
|
|
||||||
// set USB output level
|
|
||||||
} else {
|
|
||||||
// set Line output level
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
setSyntaxError();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual const char* getReturnValue() {
|
|
||||||
static char str[2] = "\0";
|
|
||||||
// get output level - decimal 0 to 9 ... str[1] = ...
|
|
||||||
return str;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
#ifdef USE_TS590SG
|
|
||||||
typedef TS590_EXDataAudioOutLevel<true, true> TS590_EX072;
|
|
||||||
typedef TS590_EXDataAudioOutLevel<false, true> TS590_EX074;
|
|
||||||
#else
|
|
||||||
typedef TS590_EXDataAudioOutLevel<true, false> TS590_EX065;
|
|
||||||
typedef TS590_EXDataAudioOutLevel<true, false> TS590_EX067;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/**********************************************************************/
|
|
||||||
|
|
||||||
class UBitxTS590 {
|
class UBitxTS590 {
|
||||||
public:
|
public:
|
||||||
UBitxTS590(TS590Command** cmds, int len): commands(cmds), numCommands(len) {}
|
UBitxTS590(TS590Command** cmds, int len): commands(cmds), numCommands(len) {}
|
||||||
|
@@ -593,11 +593,11 @@ void loop()
|
|||||||
Serial.println(AudioMemoryUsageMax());
|
Serial.println(AudioMemoryUsageMax());
|
||||||
Serial.println("----------------------------------------------------------------------");
|
Serial.println("----------------------------------------------------------------------");
|
||||||
Serial.print("Enabled/Active: PTT: ");
|
Serial.print("Enabled/Active: PTT: ");
|
||||||
Serial.print(TR.pttEnabled() ? "Y" : "N"); Serial.print("/"); Serial.print(TR.pttPressed() ? "Y" : "N");
|
Serial.print(TR.micPTTEnabled() ? "Y" : "N"); Serial.print("/"); Serial.print(TR.micPTTPressed() ? "Y" : "N");
|
||||||
Serial.print(", VOX: ");
|
Serial.print(", VOX: ");
|
||||||
Serial.print(TR.voxEnabled() ? "Y" : "N"); Serial.print("/"); Serial.print(TR.voxActivated() ? "Y" : "N");
|
Serial.print(TR.micVOXEnabled() ? "Y" : "N"); Serial.print("/"); Serial.print(TR.micVOXActivated() ? "Y" : "N");
|
||||||
Serial.print(", Key: ");
|
Serial.print(", Key: ");
|
||||||
Serial.print(TR.keyEnabled() ? "Y" : "N"); Serial.print("/"); Serial.print(TR.keyPressed() ? "Y" : "N");
|
Serial.print(TR.linePTTEnabled() ? "Y" : "N"); Serial.print("/"); Serial.print(TR.linePTTPressed() ? "Y" : "N");
|
||||||
Serial.print(", CAT: ");
|
Serial.print(", CAT: ");
|
||||||
Serial.print(TR.catEnabled() ? "Y" : "N"); Serial.print("/"); Serial.print(TR.catActivated() ? "Y" : "N");
|
Serial.print(TR.catEnabled() ? "Y" : "N"); Serial.print("/"); Serial.print(TR.catActivated() ? "Y" : "N");
|
||||||
Serial.println();
|
Serial.println();
|
||||||
|
386
TeensyDSP/temp.h
386
TeensyDSP/temp.h
@@ -1,386 +0,0 @@
|
|||||||
const int rxLoCutSSB[] = { 0, 50, 100, 200, 300, 400, 500, 600, 700, 800, 900, 1000};
|
|
||||||
const int rxHiCutSSB[] = {1000, 1200, 1400, 1600, 1800, 2000, 2200, 2400, 2600, 2800, 3000, 3400, 4000, 5000};
|
|
||||||
const int rxDataWidth[] = { 50, 80, 100, 150, 200, 250, 300, 400, 500, 600, 1000, 1500, 2000, 2500};
|
|
||||||
#ifdef USE_TS590SG
|
|
||||||
const int rxDataShift[] = {1000, 1100, 1200, 1300, 1400, 1500, 1600, 1700, 1750, 1800, 1900, 2000, 2100, 2210};
|
|
||||||
#else
|
|
||||||
const int rxDataShift[] = {1000, 1100, 1200, 1300, 1400, 1500, 1600, 1700, 1800, 1900, 2000, 2100, 2210};
|
|
||||||
#endif
|
|
||||||
|
|
||||||
const int txLowCutFilter[] = { 10, 100, 200, 300, 400, 500};
|
|
||||||
const int txHighCutFilter[] = {2500, 2600, 2700, 2800, 2900, 3000};
|
|
||||||
const int timeOutMinutes[] = {3, 5, 10, 20, 30};
|
|
||||||
|
|
||||||
#define MAX_MENU_TITLE_LEN 13
|
|
||||||
#define MAX_MENU_OPTION_LEN 13
|
|
||||||
|
|
||||||
typedef void (*toggleFunc)(UBitxRig&);
|
|
||||||
typedef bool (*boolStatus)(UBitxRig&);
|
|
||||||
|
|
||||||
#define KEYER_MIN_SPEED 4
|
|
||||||
#define KEYER_MAX_SPEED 60
|
|
||||||
|
|
||||||
/**********************************************************************/
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* @brief Abstract base class for a switch/toggle (on/off, A/B, etc.)
|
|
||||||
* option. Derived classes must provide set() and get()
|
|
||||||
* methods for controlling the state of the switch.
|
|
||||||
*/
|
|
||||||
struct ConfigSwitch {
|
|
||||||
virtual ~ConfigSwitch() = 0;
|
|
||||||
virtual void set(bool on) = 0;
|
|
||||||
virtual bool get() const = 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* @brief Abstract base class for an option that supports a linear
|
|
||||||
* sequence of integer values. There can be a minimum and a
|
|
||||||
* maximum value, but otherwise, all integers between those
|
|
||||||
* should be acceptable. The base class takes care of checking
|
|
||||||
* min/max bounds, so the derived class must provide an get()
|
|
||||||
* and onSet() methods. In addition, derived classes can
|
|
||||||
* optionally override the onTooHigh() and onTooLow(), which
|
|
||||||
* by default clamp any out-of-band inputs to the min/max.
|
|
||||||
*/
|
|
||||||
struct ConfigInteger {
|
|
||||||
ConfigInteger(int min, int max)
|
|
||||||
: myMin(min), myMax(max) {}
|
|
||||||
|
|
||||||
virtual ~ConfigInteger() = 0;
|
|
||||||
|
|
||||||
inline void set(int val) {
|
|
||||||
if (val > myMax) val = onTooHigh(val);
|
|
||||||
if (val < myMin) val = onTooLow(val);
|
|
||||||
onSet(val);
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual int get() const = 0;
|
|
||||||
virtual void onSet() = 0;
|
|
||||||
virtual int onTooHigh(int val) const { return myMax; }
|
|
||||||
virtual int onTooLow(int val) const { return myMin; }
|
|
||||||
|
|
||||||
int myMin, myMax;
|
|
||||||
};
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* @brief Abstract base class for an option that supports a set
|
|
||||||
* of integer values stored in an array. The derived
|
|
||||||
* class must provide get() and onSet() methods. It can
|
|
||||||
* optionally provide an onTooHigh() method, which by
|
|
||||||
* default will clamp indices to the highest allowable.
|
|
||||||
*/
|
|
||||||
struct ConfigArray {
|
|
||||||
ConfigArray(int len, int* data)
|
|
||||||
: myLen(len), myData(data) {}
|
|
||||||
|
|
||||||
virtual ~ConfigArray() = 0;
|
|
||||||
|
|
||||||
inline void set(int i) {
|
|
||||||
if (i < 0) i = 0;
|
|
||||||
if (i > myLen - 1) i = onTooHigh(i);
|
|
||||||
onSet(myData[i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual int get() const = 0;
|
|
||||||
virtual void onSet(int val) = 0;
|
|
||||||
virtual int onTooHigh(int i) const { return myLen - 1; }
|
|
||||||
inline int getData(int i) { return myData[i]; }
|
|
||||||
|
|
||||||
int myLen;
|
|
||||||
int *myData;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**********************************************************************/
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* @brief Option class to set the configuration of the RX DSP filter.
|
|
||||||
*/
|
|
||||||
template<bool isHIGH>
|
|
||||||
struct ConfigRXFilter : public ConfigArray {
|
|
||||||
ConfigFilter(UBitxDSP& d, int default)
|
|
||||||
: ConfigArray(0, NULL), dsp(d), useData(false) {
|
|
||||||
if (isHIGH) {
|
|
||||||
current[0] = 10; // SSB - hi cut
|
|
||||||
current[1] = 05; // Data - center (shift)
|
|
||||||
data[0] = rxHiCutSSB;
|
|
||||||
data[1] = rxDataShift;
|
|
||||||
length[0] = sizeof(rxHiCutSSB)/sizeof(rxHiCutSSB[0]);
|
|
||||||
length[1] = sizeof(rxDataShift)/sizeof(rxDataShift[0]);
|
|
||||||
} else {
|
|
||||||
current[0] = 04; // SSB - lo cut
|
|
||||||
current[1] = 12; // Data - width
|
|
||||||
data[0] = rxLoCutSSB;
|
|
||||||
data[1] = rxDataWidth;
|
|
||||||
length[0] = sizeof(rxLoCutSSB)/sizeof(rxLoCutSSB[0]);
|
|
||||||
length[1] = sizeof(rxDataWidth)/sizeof(rxDataWidth[0]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// TODO - A TON MORE TO DO HERE TO MAKE IT CONSISTENT WITH CONSTRUCTION
|
|
||||||
inline void setSSB() {
|
|
||||||
useData = false;
|
|
||||||
}
|
|
||||||
inline void setData() { useData = true; }
|
|
||||||
|
|
||||||
virtual void get() { return current; }
|
|
||||||
virtual void onSet(int i) {
|
|
||||||
current = i;
|
|
||||||
float value = static_cast<float>(getData(i));
|
|
||||||
if (isHIGH) {
|
|
||||||
if (useCENTER) {
|
|
||||||
dsp.setRxFilterCenter(value);
|
|
||||||
} else {
|
|
||||||
dsp.setRxFilterHi(value);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (useCENTER) {
|
|
||||||
dsp.setRxFilterWidth(value);
|
|
||||||
} else {
|
|
||||||
dsp.setRxFilterLo(static_cast<float>(getData(i)));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
UBitxDSP& dsp;
|
|
||||||
int* data[2];
|
|
||||||
int length[2];
|
|
||||||
int current[2];
|
|
||||||
int mode; // 0 = SSB, 1 = Data
|
|
||||||
};
|
|
||||||
typedef ConfigRXFilter<false, false> ConfigRxLoCutSSB;
|
|
||||||
typedef ConfigRXFilter<true, false> ConfigRxHiCutSSB;
|
|
||||||
typedef ConfigRXFilter<false, true > ConfigRxLoCutData;
|
|
||||||
typedef ConfigRXFilter<true, true > ConfigRxHiCutData;
|
|
||||||
|
|
||||||
struct DSPConfigurator {
|
|
||||||
DSPConfigurator(UBitxDSP& d)
|
|
||||||
: dsp(d) {}
|
|
||||||
|
|
||||||
ConfigRxLoCutSSB ssbRxLoCut;
|
|
||||||
ConfigRxHiCutSSB ssbRxHiCut;
|
|
||||||
ConfigRxLoCutData dataRxLoCut;
|
|
||||||
ConfigRxHiCutData dataRxHiCut;
|
|
||||||
|
|
||||||
private:
|
|
||||||
UBitxDSP& dsp;
|
|
||||||
} dspConfigurator(DSP);
|
|
||||||
|
|
||||||
|
|
||||||
/**********************************************************************/
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**********************************************************************/
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* @brief A configuration class for the Keyer. Since the Keyer has
|
|
||||||
* its own state that is not 100% compatible with the way way
|
|
||||||
* the Rig will interact with it (primarily in terms of CAT
|
|
||||||
* commands), this class provides the glue. (This is mostly
|
|
||||||
* used because, while the configuration objects are generally
|
|
||||||
* all separate, there is some state that needs to be
|
|
||||||
* communicated between e.g. the iambic mode configuration and
|
|
||||||
* the bug mode configuration.)
|
|
||||||
*/
|
|
||||||
struct KeyerConfigurator {
|
|
||||||
KeyerConfigurator(UBitxKeyer& k): keyer(k) { iambicAB = keyer.getMode(); }
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* @brief An inner class that supports switching between Iambic A & B.
|
|
||||||
*/
|
|
||||||
struct IambicMode : public ConfigSwitch {
|
|
||||||
IambicMode(KeyerConfigurator& c): ConfigSwitch(), config(c) {}
|
|
||||||
virtual void set(bool on) {
|
|
||||||
config.iambicAB = on;
|
|
||||||
if (config.keyer.getMode() != STRAIGHT) {
|
|
||||||
config.keyer.setMode(config.iambicAB ? IAMBICB : IAMBICA);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
virtual bool get() const { return config.iambicAB; }
|
|
||||||
private: KeyerConfigurator& config;
|
|
||||||
} iambicMode;
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* @brief An inner class that supports switching bug mode on/off.
|
|
||||||
*/
|
|
||||||
struct BugMode : public ConfigSwitch {
|
|
||||||
BugMode(KeyerConfigurator& c): ConfigSwitch(), config(c) {}
|
|
||||||
virtual void set(bool on) {
|
|
||||||
config.isBug = on;
|
|
||||||
if (config.isBug && (config.keyer.getMode() != STRAIGHT)) {
|
|
||||||
config.keyer.setMode(STRAIGHT);
|
|
||||||
} else if (!config.isBug && (config.keyer.getMode() == STRAIGHT)) {
|
|
||||||
config.keyer.setMode(config.iambicAB ? IAMBICB : IAMBICA);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
virtual bool get() const { return config.isBug; }
|
|
||||||
private: KeyerConfigurator& config;
|
|
||||||
} bugMode;
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* @brief An inner class that supports switching the left and right
|
|
||||||
* paddles. TODO: This currently does nothing.
|
|
||||||
*/
|
|
||||||
struct PaddleSwap : public ConfigSwitch {
|
|
||||||
PaddleSwap(KeyerConfigurator& c): ConfigSwitch(), config(c) {}
|
|
||||||
virtual void set(bool on) { ; }
|
|
||||||
virtual bool get() const { return false(); }
|
|
||||||
private: KeyerConfigurator& config;
|
|
||||||
} paddleSwap;
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* @brief An inner class that supports changing the keyer speed.
|
|
||||||
*/
|
|
||||||
struct KeyerSpeed : public ConfigInteger {
|
|
||||||
KeyerSpeed(KeyerConfigurator& c): ConfigInteger(KEYER_MIN_SPEED, KEYER_MAX_SPEED), config(c) {}
|
|
||||||
virtual void onSet(int val) { config.keyer.setWPM(val); }
|
|
||||||
virtual int get { return config.keyer.getWPM(); }
|
|
||||||
private: KeyerConfigurator& config;
|
|
||||||
} keyerSpeed;
|
|
||||||
|
|
||||||
private:
|
|
||||||
Keyer& keyer;
|
|
||||||
bool iambicAB;
|
|
||||||
bool isBug;
|
|
||||||
} keyerConfigurator(Keyer);
|
|
||||||
|
|
||||||
/**********************************************************************/
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**********************************************************************/
|
|
||||||
|
|
||||||
class MenuItem {
|
|
||||||
public:
|
|
||||||
MenuItem(int idno, const char* title, int numOpt, int defOpt, ): myID(idno), myTitle(title), numOptions(numOpt), selected(defOpt) {}
|
|
||||||
virtual ~MenuItem() = 0;
|
|
||||||
|
|
||||||
inline void id() { return myID; }
|
|
||||||
|
|
||||||
inline void writeTitle(char* outbuf, int maxlen) { strncpy(outbuf, myTitle, maxlen); }
|
|
||||||
inline char* writeOption(char* outbuf, int o = -1, int maxlen = MAX_MENU_OPTION_LEN) {
|
|
||||||
if (o == -1) {
|
|
||||||
setOptionText(selected);
|
|
||||||
} else if ((o >= 0) && (o < numOptions)) {
|
|
||||||
setOptionTitle(o);
|
|
||||||
} else {
|
|
||||||
memset(myOption, '\0', MAX_MENU_OPTION_LEN);
|
|
||||||
}
|
|
||||||
return strncpy(outbuf, myOption, maxlen);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline int getNumOptions() { return numOptions; }
|
|
||||||
inline int getSelected() { return selected; }
|
|
||||||
inline int nextOption(bool doUpdate = true) {
|
|
||||||
selected = (selected + 1) % numOptions;
|
|
||||||
if (doUpdate) update();
|
|
||||||
return selected;
|
|
||||||
}
|
|
||||||
inline int prevOption(bool doUpdate = true) {
|
|
||||||
selected = (selected - 1) % numOptions;
|
|
||||||
if (doUpdate) update();
|
|
||||||
return selected;
|
|
||||||
}
|
|
||||||
inline int gotoOption(int o, bool doUpdate = true) {
|
|
||||||
selected = o >= numOptions ? numOptions : (o < 0 ? 0 : o);
|
|
||||||
if (doUpdate) update();
|
|
||||||
return selected;
|
|
||||||
}
|
|
||||||
virtual void update() = 0;
|
|
||||||
|
|
||||||
private:
|
|
||||||
int myID;
|
|
||||||
char myTitle[MAX_MENU_TITLE_LEN] = {'\0'};
|
|
||||||
char myOption[MAX_MENU_OPTION_LEN] = {'\0'};
|
|
||||||
|
|
||||||
int numOptions;
|
|
||||||
int selected;
|
|
||||||
};
|
|
||||||
|
|
||||||
class StepItem : public MenuItem {
|
|
||||||
public:
|
|
||||||
StepItem(int idno, const char* title, int numOpt, int defOpt): MenuItem(idno, title, numOpt, defOpt) {}
|
|
||||||
};
|
|
||||||
|
|
||||||
static const char off_str[] = "OFF";
|
|
||||||
static const char on_str[] = "ON";
|
|
||||||
static const char line_str[] = "LINE";
|
|
||||||
static const char usb_str[] = "USB";
|
|
||||||
static const char key_a_str[] = "A";
|
|
||||||
static const char key_b_str[] = "B";
|
|
||||||
|
|
||||||
class ToggleItem : public MenuItem {
|
|
||||||
public:
|
|
||||||
ToggleItem(int idno, const char* title, const char* off, const char* on, int defOpt): MenuItem(idno, title, 2, defOpt) {}
|
|
||||||
};
|
|
||||||
|
|
||||||
/**********************************************************************/
|
|
||||||
|
|
||||||
struct MenuConfig {
|
|
||||||
byte sidetoneVolume = 9;
|
|
||||||
byte ssbLoCut = 0;
|
|
||||||
byte ssbHiCut = 5;
|
|
||||||
byte dataLoCut = 0;
|
|
||||||
byte dataHiCut = 0;
|
|
||||||
byte keyerAB = 0;
|
|
||||||
byte sidetonePitch = 6;
|
|
||||||
};
|
|
||||||
|
|
||||||
// CAT COMMANDS - BASIC
|
|
||||||
|
|
||||||
// KS - Sets and reads the Keying speed.
|
|
||||||
IntegerItem ("KS", "KEYER SPEED", 0, 2, keyerConfigurator.keyerSpeed),
|
|
||||||
ArrayItem ("SH", "RX HI CUT ", 0, 2, dspConfigurator.ssbRxHiCut),
|
|
||||||
ArrayItem ("SL", "RX LO CUT ", 0, 2, dspConfigurator.ssbRxLoCut),
|
|
||||||
|
|
||||||
// CAT COMMANDS - EX MENU
|
|
||||||
|
|
||||||
// Sidetone volume
|
|
||||||
Steps {004, "ST VOL ", 10, [](auto x) { return static_cast<double>(x-48)/9.0; }},
|
|
||||||
// SSB/AM Low Cut transmit filter (Hz)
|
|
||||||
Steps {025, "SSB TX LO ", 6, [](auto x) { return txLowCutFilter[x]; }},
|
|
||||||
// SSB/AM High Cut transmit filter (Hz)
|
|
||||||
Steps {026, "SSB TX HI ", 6, [](auto x) { return txHighCutFilter[x]; }},
|
|
||||||
// SSB-DATA Low Cut transmit filter (Hz)
|
|
||||||
Steps {027, "DATA TX LO ", 6, [](auto x) { return txLowCutFilter[x]; }},
|
|
||||||
// SSB-DATA High Cut transmit filter (Hz)
|
|
||||||
Steps {028, "DATA TX HI ", 6, [](auto x) { return txHighCutFilter[x]; }},
|
|
||||||
// Electronic keyer operation mode
|
|
||||||
ToggleItem (032, "KEYER A/B ", "A ", "B ", keyerConfigurator.iambicMode),
|
|
||||||
// Sidetone/ pitch frequency setting (Hz)
|
|
||||||
Steps {034, "ST PITCH ", 15, [](auto x) { return 300+(x*50); }},
|
|
||||||
// Keying weight ratio
|
|
||||||
StepsSpec {036, "KEYER WEIGHT", 17, ...},
|
|
||||||
// Bug key function
|
|
||||||
ToggleItem (038, "KEYER BUG ", "OFF ", "ON ", keyerConfigurator.bugMode),
|
|
||||||
// Paddle dot/dash replacement setting
|
|
||||||
ToggleItem (039, "KEYER SWAP ", "OFF ", "ON ", keyerConfigurator.paddleSwap),
|
|
||||||
// Auto CW TX in SSB mode
|
|
||||||
//ToggleItem (041, "AUTO CW TX ", "OFF ", "ON ", [&Rig](bool on) { Rig.setKeyerAutoTransmitCW(on); } ),
|
|
||||||
// Time-out Timer
|
|
||||||
//StepsSpec {049, "TIMEOUT ", 6, ... },
|
|
||||||
// Transmit inhibit
|
|
||||||
ToggleItem (060, "TX INHIBIT ", "OFF ", "ON ", [&Rig](bool on) { Rig.setTransmitInhibit(on); } ),
|
|
||||||
// DATA moduleation line
|
|
||||||
ToggleItem (063, "DATA LINE ", "LINE", "USB ", [&Rig](bool usb) { Rig.setDataInputLine(usb); } ),
|
|
||||||
// USB audio input level
|
|
||||||
Steps {064, "USB IN LVL ", [](auto x) { return static_cast<double>(x-48)/9.0; }},
|
|
||||||
// USB audio output level
|
|
||||||
Steps {065, "USB OUT LVL ", [](auto x) { return static_cast<double>(x-48)/9.0; }},
|
|
||||||
// ACC2 terminal AF input level
|
|
||||||
Steps {066, "LINE IN LVL ", [](auto x) { return static_cast<double>(x-48)/9.0; }},
|
|
||||||
// ACC2 terminal AF output level
|
|
||||||
Steps {067, "LINE OUT LVL", [](auto x) { return static_cast<double>(x-48)/9.0; }},
|
|
||||||
// DATA VOX
|
|
||||||
ToggleItem (069, "DATA VOX ", "OFF ", "ON ", [&Rig](bool on) { Rig.setDataVoxOn(on); } ),
|
|
||||||
// DATA VOX delay
|
|
||||||
Steps {070, "DATA VOX DEL", 20, ...},
|
|
||||||
// DATA VOX gain for USB audio input
|
|
||||||
Steps {071, "USB VOX LVL ", 10, [](auto x) { return static_cast<double>(x-48)/9.0; }},
|
|
||||||
// DATA VOX gain for ACC2 terminal input
|
|
||||||
Steps {072, "LINE VOX LVL", 10, [](auto x) { return static_cast<double>(x-48)/9.0; }},
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
Reference in New Issue
Block a user