diff --git a/TeensyDSP/DSP.cpp b/TeensyDSP/DSP.cpp index f1689c9..3f90fce 100644 --- a/TeensyDSP/DSP.cpp +++ b/TeensyDSP/DSP.cpp @@ -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); } diff --git a/TeensyDSP/DSP.h b/TeensyDSP/DSP.h index fe293a8..54a7069 100644 --- a/TeensyDSP/DSP.h +++ b/TeensyDSP/DSP.h @@ -9,12 +9,12 @@ #include #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. diff --git a/TeensyDSP/Rig.h b/TeensyDSP/Rig.h index 65cf04c..9137863 100644 --- a/TeensyDSP/Rig.h +++ b/TeensyDSP/Rig.h @@ -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(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(f)); } + + inline void setUSBInput() { conf.useUSBInput = true; } + inline void setLineInput() { conf.useUSBInput = false; } inline void aiOn() { autoInfo = true; } inline void aiOff() { autoInfo = false; } @@ -58,10 +112,13 @@ class UBitxRig { //void setBand(); //void getBand(); - private: + private: + RigConfig conf; UBitxRigState catState; UBitxRigState radState; bool autoInfo = false; + + BandConfig band[NUM_BANDS]; }; extern UBitxRig Rig; diff --git a/TeensyDSP/RigState.cpp b/TeensyDSP/RigState.cpp index da25d38..28bc836 100644 --- a/TeensyDSP/RigState.cpp +++ b/TeensyDSP/RigState.cpp @@ -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(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(sideTone)) { + setSidetone(static_cast(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 diff --git a/TeensyDSP/RigState.h b/TeensyDSP/RigState.h index a50d5e5..05f26be 100644 --- a/TeensyDSP/RigState.h +++ b/TeensyDSP/RigState.h @@ -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 }; diff --git a/TeensyDSP/TR.h b/TeensyDSP/TR.h index 9700e51..61e0ab8 100644 --- a/TeensyDSP/TR.h +++ b/TeensyDSP/TR.h @@ -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; diff --git a/TeensyDSP/TS590.cpp b/TeensyDSP/TS590.cpp index 3f51806..9fea333 100644 --- a/TeensyDSP/TS590.cpp +++ b/TeensyDSP/TS590.cpp @@ -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 { diff --git a/TeensyDSP/TS590.h b/TeensyDSP/TS590.h index 2f1b6a4..39d6061 100644 --- a/TeensyDSP/TS590.h +++ b/TeensyDSP/TS590.h @@ -4,9 +4,13 @@ #include #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 +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 TS590_EX071; +typedef TS590_EXDataAudioInLevel TS590_EX073; +#else +typedef TS590_EXDataAudioInLevel TS590_EX064; +typedef TS590_EXDataAudioInLevel TS590_EX066; +#endif + +/**********************************************************************/ + +/*! + * @brief CAT command for setting USB/Line audio output levels. + */ +template +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 TS590_EX072; +typedef TS590_EXDataAudioOutLevel TS590_EX074; +#else +typedef TS590_EXDataAudioOutLevel TS590_EX065; +typedef TS590_EXDataAudioOutLevel TS590_EX067; +#endif + /**********************************************************************/ class UBitxTS590 {