ubitx-v5x/TeensyDSP/temp.h

387 lines
13 KiB
C++

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; }},