Compare commits
2 Commits
new-main-d
...
mode-based
Author | SHA1 | Date | |
---|---|---|---|
|
5e280b33dd | ||
|
cc94f89cfe |
@@ -214,12 +214,12 @@ void UBitxDSP::txUSBIn() {
|
||||
/**********************************************************************/
|
||||
// RX filter settings
|
||||
|
||||
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;
|
||||
const float minRxFilterLo = MIN_RX_FILTER_LO;
|
||||
const float maxRxFilterHi = MAX_RX_FILTER_HI;
|
||||
const float minRxFilterWidth = MIN_RX_FILTER_WIDTH;
|
||||
const float maxRxFilterWidth = MAX_RX_FILTER_WIDTH;
|
||||
const float minRxFilterCenter = MIN_RX_FILTER_CENTER;
|
||||
const float maxRxFilterCenter = MAX_RX_FILTER_CENTER;
|
||||
|
||||
/*!
|
||||
* @brief Bypass the RX audio filter.
|
||||
@@ -238,7 +238,7 @@ void UBitxDSP::updateRxFilter() {
|
||||
rxFilter.begin(coefficients, NUM_COEFFICIENTS);
|
||||
}
|
||||
|
||||
void UBitxDSP::setRxFilter(int lo, int hi) {
|
||||
void UBitxDSP::setRxFilter(float lo, float hi) {
|
||||
if (hi < lo + minRxFilterWidth) {
|
||||
hi = lo + minRxFilterWidth;
|
||||
}
|
||||
@@ -256,7 +256,7 @@ void UBitxDSP::setRxFilter(int lo, int hi) {
|
||||
updateRxFilter();
|
||||
}
|
||||
|
||||
void UBitxDSP::setRxFilterLo(int lo) {
|
||||
void UBitxDSP::setRxFilterLo(float lo) {
|
||||
if (lo > state.rxFilterHi - minRxFilterWidth) {
|
||||
lo = state.rxFilterHi - minRxFilterWidth;
|
||||
}
|
||||
@@ -267,7 +267,7 @@ void UBitxDSP::setRxFilterLo(int lo) {
|
||||
updateRxFilter();
|
||||
}
|
||||
|
||||
void UBitxDSP::setRxFilterHi(int hi) {
|
||||
void UBitxDSP::setRxFilterHi(float hi) {
|
||||
if (hi < state.rxFilterLo + minRxFilterWidth) {
|
||||
hi = state.rxFilterLo + minRxFilterWidth;
|
||||
}
|
||||
@@ -278,27 +278,27 @@ void UBitxDSP::setRxFilterHi(int hi) {
|
||||
updateRxFilter();
|
||||
}
|
||||
|
||||
void UBitxDSP::setRxFilterWidth(int width) {
|
||||
void UBitxDSP::setRxFilterWidth(float width) {
|
||||
if (width < minRxFilterWidth) {
|
||||
width = minRxFilterWidth;
|
||||
} else if (width > maxRxFilterWidth) {
|
||||
width = maxRxFilterWidth;
|
||||
}
|
||||
int center = (state.rxFilterHi + state.rxFilterLo) / 2;
|
||||
int lo = center - (width / 2);
|
||||
int hi = center + (width / 2);
|
||||
float center = (state.rxFilterHi + state.rxFilterLo) / 2;
|
||||
float lo = center - (width / 2);
|
||||
float hi = center + (width / 2);
|
||||
setRxFilter(lo, hi);
|
||||
}
|
||||
|
||||
void UBitxDSP::setRxFilterCenter(int center) {
|
||||
void UBitxDSP::setRxFilterCenter(float center) {
|
||||
if (center < minRxFilterCenter) {
|
||||
center = minRxFilterCenter;
|
||||
} else if (center > maxRxFilterCenter) {
|
||||
center = maxRxFilterCenter;
|
||||
}
|
||||
int width = state.rxFilterHi - state.rxFilterLo;
|
||||
int lo = center - (width / 2);
|
||||
int hi = center + (width / 2);
|
||||
float width = state.rxFilterHi - state.rxFilterLo;
|
||||
float lo = center - (width / 2);
|
||||
float hi = center + (width / 2);
|
||||
setRxFilter(lo, hi);
|
||||
}
|
||||
|
||||
|
@@ -9,12 +9,12 @@
|
||||
#include <dynamicFilters.h>
|
||||
#include "Debug.h"
|
||||
|
||||
#define MIN_RX_FILTER_LO 0
|
||||
#define MAX_RX_FILTER_HI 5000
|
||||
#define MIN_RX_FILTER_WIDTH 0
|
||||
#define MAX_RX_FILTER_WIDTH 5000
|
||||
#define MIN_RX_FILTER_CENTER 0
|
||||
#define MAX_RX_FILTER_CENTER 5000
|
||||
#define MIN_RX_FILTER_LO 0.0
|
||||
#define MAX_RX_FILTER_HI 5000.0
|
||||
#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
|
||||
|
||||
@@ -41,8 +41,8 @@ struct DSPState {
|
||||
// RX audio output settings
|
||||
|
||||
// RX filter settings
|
||||
int rxFilterLo = 300;
|
||||
int rxFilterHi = 3000;
|
||||
float rxFilterLo = 300.0;
|
||||
float rxFilterHi = 3000.0;
|
||||
|
||||
// TX audio input settings
|
||||
float txInLvl[4] = {0.5, 0.5, 0.0, 0.0};
|
||||
@@ -86,11 +86,11 @@ class UBitxDSP {
|
||||
|
||||
// RX filter settings
|
||||
void bypassRxFilter();
|
||||
void setRxFilter(int lo, int hi);
|
||||
void setRxFilterLo(int lo);
|
||||
void setRxFilterHi(int hi);
|
||||
void setRxFilterWidth(int width);
|
||||
void setRxFilterCenter(int center);
|
||||
void setRxFilter(float lo, float hi);
|
||||
void setRxFilterLo(float lo);
|
||||
void setRxFilterHi(float hi);
|
||||
void setRxFilterWidth(float width);
|
||||
void setRxFilterCenter(float center);
|
||||
|
||||
/*!
|
||||
* @brief Get the current low frequency bound of the RX band pass filter.
|
||||
|
@@ -61,7 +61,7 @@ speed(wpm), symWeight(weight)
|
||||
// Calculate the length of dot, dash and silence
|
||||
void UBitxKeyer::calcRatio()
|
||||
{
|
||||
float w = (1 + symWeight) / (symWeight -1);
|
||||
float w = (1.0 + symWeight) / (symWeight - 1.0);
|
||||
spaceLen = (1200 / speed);
|
||||
dotLen = spaceLen * (w - 1);
|
||||
dashLen = (1 + w) * spaceLen;
|
||||
@@ -73,6 +73,12 @@ void UBitxKeyer::setWPM(int wpm)
|
||||
calcRatio();
|
||||
}
|
||||
|
||||
void UBitxKeyer::setWeight(float weight)
|
||||
{
|
||||
symWeight = weight;
|
||||
calcRatio();
|
||||
}
|
||||
|
||||
//======================================================================
|
||||
// Latch paddle press
|
||||
//======================================================================
|
||||
@@ -107,11 +113,10 @@ bool UBitxKeyer::doPaddles()
|
||||
if ((digitalRead(LP_in) == LOW) || (digitalRead(RP_in) == LOW) || (keyerControl & 0x03)) {
|
||||
updatePaddleLatch();
|
||||
keyerState = CHK_DIT;
|
||||
// letting this fall through // return true;
|
||||
} else {
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
// break;
|
||||
return false;
|
||||
//break;
|
||||
|
||||
case CHK_DIT: // See if the dit paddle was pressed
|
||||
if (keyerControl & DIT_L) {
|
||||
@@ -119,20 +124,20 @@ bool UBitxKeyer::doPaddles()
|
||||
ktimer = dotLen;
|
||||
keyerState = KEYED_PREP;
|
||||
return true;
|
||||
} else { // fall through
|
||||
keyerState = CHK_DAH;
|
||||
}
|
||||
// fall through
|
||||
keyerState = CHK_DAH;
|
||||
|
||||
case CHK_DAH: // See if dah paddle was pressed
|
||||
if (keyerControl & DAH_L) {
|
||||
ktimer = dashLen;
|
||||
keyerState = KEYED_PREP;
|
||||
// letting this fall through // return true;
|
||||
return true;
|
||||
} else {
|
||||
keyerState = IDLE;
|
||||
return false;
|
||||
}
|
||||
// break;
|
||||
//break;
|
||||
|
||||
case KEYED_PREP: // Assert key down, start timing
|
||||
// state shared for dit or dah
|
||||
@@ -140,21 +145,20 @@ bool UBitxKeyer::doPaddles()
|
||||
ktimer += millis(); // set ktimer to interval end time
|
||||
keyerControl &= ~(DIT_L + DAH_L); // clear both paddle latch bits
|
||||
keyerState = KEYED; // next state
|
||||
// letting this fall through // return true;
|
||||
// break;
|
||||
return true;
|
||||
//break;
|
||||
|
||||
case KEYED: // Wait for timer to expire
|
||||
if (millis() > ktimer) { // are we at end of key down ?
|
||||
keyDown = false;
|
||||
ktimer = millis() + spaceLen; // inter-element time
|
||||
keyerState = INTER_ELEMENT; // next state
|
||||
// letting this fall through // return true;
|
||||
return true;
|
||||
} else if (keyMode == IAMBICB) { // Iambic B Mode ?
|
||||
updatePaddleLatch(); // yes, early paddle latch in Iambic B mode
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
// break;
|
||||
return true;
|
||||
// break;
|
||||
|
||||
case INTER_ELEMENT: // Insert time between dits/dahs
|
||||
updatePaddleLatch(); // latch paddle state
|
||||
@@ -168,10 +172,9 @@ bool UBitxKeyer::doPaddles()
|
||||
keyerState = IDLE; // go idle
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
// break;
|
||||
return true;
|
||||
//break;
|
||||
}
|
||||
|
||||
return false; // resolve compiler warning; do we ever get here?
|
||||
|
@@ -44,10 +44,12 @@ public:
|
||||
//void cw_pin(int pin);
|
||||
//void ptt_pin(int pin);
|
||||
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 int getMode() { return keyMode; }
|
||||
inline bool isDown() { return keyDown; }
|
||||
// void setWeight();
|
||||
|
||||
bool doPaddles();
|
||||
|
||||
|
@@ -3,15 +3,56 @@
|
||||
|
||||
#include "RigState.h"
|
||||
|
||||
#define DEFAULT_SSB_LO_CUT 300.0
|
||||
#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 {
|
||||
public:
|
||||
UBitxRig();
|
||||
|
||||
inline void begin() {}
|
||||
inline void update() {}
|
||||
|
||||
inline unsigned getFreqA() const { return radState.getFreqA(); }
|
||||
inline unsigned getFreqB() const { return radState.getFreqB(); }
|
||||
|
||||
inline int getRIT() const { return radState.getRIT(); }
|
||||
inline int getXIT() const { return radState.getXIT(); }
|
||||
|
||||
inline bool isVFOA() const { return radState.isVFOA(); }
|
||||
inline bool isVFOB() const { return radState.isVFOB(); }
|
||||
inline bool isSplit() const { return radState.isSplit(); }
|
||||
@@ -22,12 +63,20 @@ class UBitxRig {
|
||||
inline bool isModeCWR() const { return radState.isModeCWR(); }
|
||||
inline bool isModeUSB() const { return radState.isModeUSB(); }
|
||||
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 void setFreqA(unsigned freq) { catState.setFreqA(freq); }
|
||||
inline void setFreqB(unsigned freq) { catState.setFreqB(freq); }
|
||||
|
||||
inline void setRIT(int freq) { catState.setRIT(freq); }
|
||||
inline void setXIT(int freq) { catState.setXIT(freq); }
|
||||
|
||||
inline void setVFOA() { catState.setVFOA(); }
|
||||
inline void setVFOB() { catState.setVFOB(); }
|
||||
inline void setSplitOn() { catState.setSplitOn(); }
|
||||
@@ -36,10 +85,15 @@ class UBitxRig {
|
||||
inline void setRITOff() { catState.setRITOff(); }
|
||||
inline void setXITOn() { catState.setXITOn(); }
|
||||
inline void setXITOff() { catState.setXITOff(); }
|
||||
inline void setCW() { catState.setCW(); }
|
||||
inline void setCWR() { catState.setCWR(); }
|
||||
inline void setUSB() { catState.setUSB(); }
|
||||
inline void setLSB() { catState.setLSB(); }
|
||||
inline void setModeCW() { catState.setModeCW(); }
|
||||
inline void setModeCWR() { catState.setModeCWR(); }
|
||||
inline void setModeUSB() { catState.setModeUSB(); }
|
||||
inline void setModeLSB() { catState.setModeLSB(); }
|
||||
|
||||
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 aiOn() { autoInfo = true; }
|
||||
inline void aiOff() { autoInfo = false; }
|
||||
@@ -59,9 +113,12 @@ class UBitxRig {
|
||||
//void getBand();
|
||||
|
||||
private:
|
||||
RigConfig conf;
|
||||
UBitxRigState catState;
|
||||
UBitxRigState radState;
|
||||
bool autoInfo = false;
|
||||
|
||||
BandConfig band[NUM_BANDS];
|
||||
};
|
||||
|
||||
extern UBitxRig Rig;
|
||||
|
@@ -56,7 +56,7 @@ void UBitxRigState::begin() {
|
||||
#include "ubitx.h"
|
||||
#include "ubitx_eemap.h"
|
||||
|
||||
extern unsigned long frequency, ritRxFrequency, ritTxFrequency;
|
||||
extern unsigned long frequency, ritRxFrequency, ritTxFrequency, sideTone;
|
||||
extern unsigned long vfoA;
|
||||
extern unsigned long vfoB;
|
||||
extern char cwMode;
|
||||
@@ -169,8 +169,10 @@ void UBitxRigState::writeDirty() {
|
||||
// XIT - TODO
|
||||
}
|
||||
|
||||
// VFO A/B selection
|
||||
// Various flags
|
||||
if (isDirty(FLAGS_WORD)) {
|
||||
|
||||
// VFO A/B selection
|
||||
char prev = vfoActive;
|
||||
vfoActive = isVFOA() ? VFO_A : VFO_B;
|
||||
if (vfoActive != prev) {
|
||||
@@ -214,6 +216,13 @@ void UBitxRigState::writeDirty() {
|
||||
setFrequency(frequency);
|
||||
}
|
||||
}
|
||||
|
||||
// Keyer information
|
||||
if (isDirty(KEYER_WORD)) {
|
||||
|
||||
// Sidetone frequency
|
||||
sideTone = static_cast<unsigned long>(getSidetone());
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -284,17 +293,22 @@ void UBitxRigState::readDirty() {
|
||||
char curr = (cwMode << 1) | isUSB;
|
||||
if (curr != prev) {
|
||||
if (cwMode == 2) {
|
||||
setCW();
|
||||
setModeCW();
|
||||
} else if (cwMode == 1) {
|
||||
setCWR();
|
||||
setModeCWR();
|
||||
} else {
|
||||
if (isUSB) {
|
||||
setUSB();
|
||||
setModeUSB();
|
||||
} else {
|
||||
setLSB();
|
||||
setModeLSB();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Sidetone
|
||||
if (getSidetone() != static_cast<uint16_t>(sideTone)) {
|
||||
setSidetone(static_cast<uint16_t>(sideTone));
|
||||
}
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
@@ -332,6 +346,16 @@ 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( serialPrettyState("Rcvd") );
|
||||
}
|
||||
@@ -372,6 +396,13 @@ void UBitxRigState::send_RIGINF() {
|
||||
//--------------------------------------------------------------------
|
||||
}
|
||||
|
||||
/*!
|
||||
* @brief Perform required actions based on any dirty bits set.
|
||||
*/
|
||||
void UBitxRigState::processDirty() {
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef DEBUG
|
||||
|
@@ -15,6 +15,9 @@
|
||||
#define UBITX_USB_FLAG 0x00000020
|
||||
#define UBITX_TX_FLAG 0x00000040
|
||||
|
||||
#define UBITX_SIDETONE_MASK 0x000007FF
|
||||
#define UBITX_KEYER_MODE_MASK 0x00003800
|
||||
|
||||
#ifdef TEENSYDUINO
|
||||
#define DISABLEINTS(CMD) do { noInterrupts(); CMD; interrupts(); } while (0)
|
||||
#else
|
||||
@@ -27,6 +30,7 @@ enum RigStateWord {
|
||||
VFOB_WORD,
|
||||
OFFSETS_WORD,
|
||||
FLAGS_WORD,
|
||||
KEYER_WORD,
|
||||
NUM_WORDS
|
||||
};
|
||||
|
||||
@@ -255,25 +259,25 @@ struct UBitxRigState {
|
||||
return result;
|
||||
}
|
||||
|
||||
inline void setUSB(bool mark = true) {
|
||||
inline void setModeUSB(bool mark = true) {
|
||||
DISABLEINTS( data[FLAGS_WORD] |= UBITX_USB_FLAG;
|
||||
data[FLAGS_WORD] &= ~UBITX_CW_FLAG;
|
||||
if (mark) setDirty(FLAGS_WORD) );
|
||||
}
|
||||
|
||||
inline void setLSB(bool mark = true) {
|
||||
inline void setModeLSB(bool mark = true) {
|
||||
DISABLEINTS( data[FLAGS_WORD] &= ~UBITX_USB_FLAG;
|
||||
data[FLAGS_WORD] &= ~UBITX_CW_FLAG;
|
||||
if (mark) setDirty(FLAGS_WORD) );
|
||||
}
|
||||
|
||||
inline void setCW(bool mark = true) {
|
||||
inline void setModeCW(bool mark = true) {
|
||||
DISABLEINTS( data[FLAGS_WORD] |= UBITX_USB_FLAG;
|
||||
data[FLAGS_WORD] |= UBITX_CW_FLAG;
|
||||
if (mark) setDirty(FLAGS_WORD) );
|
||||
}
|
||||
|
||||
inline void setCWR(bool mark = true) {
|
||||
inline void setModeCWR(bool mark = true) {
|
||||
DISABLEINTS( data[FLAGS_WORD] &= ~UBITX_USB_FLAG;
|
||||
data[FLAGS_WORD] |= UBITX_CW_FLAG;
|
||||
if (mark) setDirty(FLAGS_WORD) );
|
||||
@@ -309,6 +313,18 @@ struct UBitxRigState {
|
||||
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
|
||||
void serialHexState(const char* label);
|
||||
void serialPrettyState(const char* label);
|
||||
@@ -319,6 +335,9 @@ struct UBitxRigState {
|
||||
// RigState, not in the TeensyDSP (Teensy) case.
|
||||
void writeDirty(); // write fields FROM RigState TO Raduino
|
||||
void readDirty(); // read variables FROM Raduino TO RigState
|
||||
#else
|
||||
// These methods are only defined (currently) in the TeensyDSP case.
|
||||
void processDirty();
|
||||
#endif
|
||||
};
|
||||
|
||||
|
@@ -5,7 +5,8 @@
|
||||
#include <Arduino.h>
|
||||
#include "TR.h"
|
||||
|
||||
UBitxTR TR(DSP);
|
||||
UBitxTR _tr(DSP);
|
||||
UBitxTR& TR = _tr;
|
||||
|
||||
void UBitxTR::update(bool cw, bool extKey) {
|
||||
updateKey();
|
||||
|
@@ -19,6 +19,12 @@ const int uBitxTRPttPin = UBITX_TR_PTT_PIN;
|
||||
const int uBitxTRVoxPin = UBITX_TR_VOX_PIN;
|
||||
const int uBitxTRKeyPin = UBITX_TR_KEY_PIN;
|
||||
|
||||
struct TxSource {
|
||||
MIC_SOURCE = 0,
|
||||
LINE_SOURCE,
|
||||
USB_SOURCE,
|
||||
};
|
||||
|
||||
class UBitxTR {
|
||||
public:
|
||||
UBitxTR(UBitxDSP& d, int out = uBitxTROutPin, int p = uBitxTRPttPin, int v = uBitxTRVoxPin, int k = uBitxTRKeyPin):
|
||||
@@ -63,9 +69,10 @@ class UBitxTR {
|
||||
inline bool catActivated() { return (L_catActive != catActive) && L_catActive; }
|
||||
inline bool catDeactivated() { return (L_catActive != catActive) && catActive; }
|
||||
|
||||
inline void catTX() {
|
||||
inline void catTX(TxSource src) {
|
||||
L_catActive = catActive;
|
||||
catActive = true;
|
||||
txSource = src;
|
||||
}
|
||||
|
||||
inline void catRX() {
|
||||
@@ -73,10 +80,11 @@ class UBitxTR {
|
||||
catActive = false;
|
||||
}
|
||||
|
||||
//======================================================================
|
||||
//====================================================================
|
||||
|
||||
inline bool transmitting() { 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
|
||||
@@ -145,6 +153,7 @@ class UBitxTR {
|
||||
bool L_keyDown = false;
|
||||
bool catActive = false;
|
||||
bool L_catActive = false;
|
||||
TxSource txSource = MIC_SOURCE;
|
||||
};
|
||||
|
||||
extern UBitxTR TR;
|
||||
|
@@ -41,8 +41,6 @@ TS590Command::TS590Command(const char* pre) {
|
||||
}
|
||||
}
|
||||
|
||||
TS590Command::~TS590Command() {}
|
||||
|
||||
/*!
|
||||
* @brief Determine whether this is a Read command or not. by
|
||||
* default, if it's a 2-letter command, it's a Read.
|
||||
@@ -139,8 +137,18 @@ void TS590Command::setDSP(UBitxDSP* 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;
|
||||
UBitxDSP* TS590Command::theDSP = &DSP;
|
||||
UBitxTR* TR590Command::theTR = &TR;
|
||||
TS590Error TS590Command::theError = NoError;
|
||||
|
||||
/**********************************************************************/
|
||||
@@ -238,19 +246,19 @@ void TS590_MD::handleCommand(const char* cmd) {
|
||||
break;
|
||||
|
||||
case '1': // LSB
|
||||
rig()->setLSB();
|
||||
rig()->setModeLSB();
|
||||
break;
|
||||
|
||||
case '2': // USB
|
||||
rig()->setUSB();
|
||||
rig()->setModeUSB();
|
||||
break;
|
||||
|
||||
case '3': // CW
|
||||
rig()->setCW();
|
||||
rig()->setModeCW();
|
||||
break;
|
||||
|
||||
case '7': // CW-R
|
||||
rig()->setCWR();
|
||||
rig()->setModeCWR();
|
||||
break;
|
||||
|
||||
default:
|
||||
@@ -319,6 +327,123 @@ void TS590_SL::sendResponse(const char* cmd) {
|
||||
|
||||
/**********************************************************************/
|
||||
|
||||
void TS590_TX::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) {
|
||||
char src;
|
||||
switch (tr.source()) {
|
||||
case MIC_SOURCE:
|
||||
src = '0';
|
||||
break;
|
||||
|
||||
case LINE_SOURCE:
|
||||
case USB_SOURCE:
|
||||
src = '1';
|
||||
break;
|
||||
}
|
||||
ts590SeondCommand("TX%1c", src);
|
||||
}
|
||||
|
||||
/**********************************************************************/
|
||||
|
||||
/*!
|
||||
* @brief Create a new CAT EX command. It should be initialized with
|
||||
* a 3-character P1 parameter (command number).
|
||||
* @param pre
|
||||
* A 3-character command prefix. If more than 3 characters
|
||||
* are supplied, only the first two will be used. If less
|
||||
* than three are supplied, then the command will be
|
||||
* initialized with a null prefix.
|
||||
*/
|
||||
TS590EXCommand::TS590EXCommand(const char* P1):
|
||||
TS590Command("EX") {
|
||||
if (strlen(P1) >= 3) {
|
||||
strncpy(myMenu, P1, 3);
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
* @brief Determine whether this is a Read command or not. by
|
||||
* default, if it's a 2-letter command, it's a Read.
|
||||
* @return True if a Read command; false otherwise.
|
||||
*/
|
||||
bool TS590EXCommand::isReadCommand(const char* cmd) const {
|
||||
if (strlen(cmd) == 9) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void TS590EXCommand::sendResponse(const char* cmd) {
|
||||
ts590sendCommand("%2c%3c0000%s", prefix(), menu(), getReturnValue());
|
||||
}
|
||||
|
||||
/**********************************************************************/
|
||||
|
||||
void TS590_EX034::handleCommand(const char* cmd) {
|
||||
if (strlen(cmd) == 10 || strlen(cmd) == 11) {
|
||||
index = (uint8_t)atol(&cmd[9]);
|
||||
if (index < 15) {
|
||||
rig().setCWSidetone(300.0 + (float)(index * 50));
|
||||
} else {
|
||||
setSyntaxError();
|
||||
}
|
||||
} else {
|
||||
setSyntaxError();
|
||||
}
|
||||
}
|
||||
|
||||
void TS590_EX034::sendResponse(const char* cmd) {
|
||||
ts590SendCommand("EX0340000%02d", index % 15);
|
||||
}
|
||||
|
||||
/**********************************************************************/
|
||||
|
||||
void TS590_EX063::handleCommand(const char* cmd) {
|
||||
if (strlen(cmd) == 10) {
|
||||
if (cmd[9] == '0') {
|
||||
rig().setLineInput();
|
||||
} else if (cmd[9] == '1') {
|
||||
rig().setUSBInput();
|
||||
} else {
|
||||
setSyntaxError();
|
||||
}
|
||||
} else {
|
||||
setSyntaxError();
|
||||
}
|
||||
}
|
||||
|
||||
void TS590_EX063::sendResponse(const char* cmd) {
|
||||
ts590SendCommand("EX0630000%1c", rig().isUSBInput() ? '1' : '0');
|
||||
}
|
||||
|
||||
/**********************************************************************/
|
||||
|
||||
TS590_FA cmdFA;
|
||||
TS590_FB cmdFB;
|
||||
TS590_FR cmdFR;
|
||||
@@ -393,8 +518,27 @@ int compareCATCommands(const void* a, const void* b) {
|
||||
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
|
||||
Serial.print("Comparison: ");
|
||||
Serial.print((char*)a);
|
||||
Serial.print(" ? ");
|
||||
Serial.print((char*)B->prefix());
|
||||
Serial.print(" --> ");
|
||||
Serial.println(cmp);
|
||||
#endif
|
||||
return cmp;
|
||||
}
|
||||
|
||||
void UBitxTS590::processCommand() {
|
||||
TS590Command** cmd = (TS590Command**)bsearch(buf, commands, numCommands, sizeof(TS590Command*), compareCATCommands);
|
||||
TS590Command** cmd;
|
||||
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) {
|
||||
ts590SyntaxError();
|
||||
} else {
|
||||
|
@@ -4,9 +4,13 @@
|
||||
#include <Arduino.h>
|
||||
#include "DSP.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)
|
||||
|
||||
const int ts590CommandMaxLength = TS590_COMMAND_MAX_LENGTH;
|
||||
@@ -62,6 +66,11 @@ class TS590Command {
|
||||
*/
|
||||
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
|
||||
* results in an error, then set the appropriate flag with
|
||||
@@ -88,6 +97,7 @@ class TS590Command {
|
||||
static void setProcessError();
|
||||
static void setRig(UBitxRig* r);
|
||||
static void setDSP(UBitxDSP* d);
|
||||
static void setTR(UBitxTR* t);
|
||||
|
||||
private:
|
||||
char myPrefix[3] = "\0\0";
|
||||
@@ -192,6 +202,133 @@ class TS590_SL : public TS590Command {
|
||||
unsigned index;
|
||||
};
|
||||
|
||||
/*!
|
||||
* @brief CAT command to start transmitting.
|
||||
*/
|
||||
class TS590_TX : public TS590Command {
|
||||
public:
|
||||
TS590_TX(): TS590Command("TX") {}
|
||||
virtual void handleCommand(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:
|
||||
char myMenu[4] = "\0\0\0";
|
||||
};
|
||||
|
||||
/**********************************************************************/
|
||||
|
||||
/*!
|
||||
* @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 {
|
||||
|
386
TeensyDSP/temp.h
Normal file
386
TeensyDSP/temp.h
Normal file
@@ -0,0 +1,386 @@
|
||||
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