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/Keyer.cpp b/TeensyDSP/Keyer.cpp index 10fe9c6..954f648 100644 --- a/TeensyDSP/Keyer.cpp +++ b/TeensyDSP/Keyer.cpp @@ -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,59 +124,57 @@ 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 - keyDown = true; - 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; + case KEYED_PREP: // Assert key down, start timing + // state shared for dit or dah + keyDown = true; + ktimer += millis(); // set ktimer to interval end time + keyerControl &= ~(DIT_L + DAH_L); // clear both paddle latch bits + keyerState = KEYED; // next state + 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; - } else if (keyMode == IAMBICB) { // Iambic B Mode ? - updatePaddleLatch(); // yes, early paddle latch in Iambic B mode - } else { - 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 + return true; + } else if (keyMode == IAMBICB) { // Iambic B Mode ? + updatePaddleLatch(); // yes, early paddle latch in Iambic B mode + } + return true; + // break; case INTER_ELEMENT: // Insert time between dits/dahs - updatePaddleLatch(); // latch paddle state - if (millis() > ktimer) { // are we at end of inter-space ? - if (keyerControl & DIT_PROC) { // was it a dit or dah ? - keyerControl &= ~(DIT_L + DIT_PROC); // clear two bits - keyerState = CHK_DAH; // dit done, check for dah - return true; - } else { - keyerControl &= ~(DAH_L); // clear dah latch - keyerState = IDLE; // go idle - return false; - } - } else { + updatePaddleLatch(); // latch paddle state + if (millis() > ktimer) { // are we at end of inter-space ? + if (keyerControl & DIT_PROC) { // was it a dit or dah ? + keyerControl &= ~(DIT_L + DIT_PROC); // clear two bits + keyerState = CHK_DAH; // dit done, check for dah return true; + } else { + keyerControl &= ~(DAH_L); // clear dah latch + keyerState = IDLE; // go idle + return false; } -// break; + } + return true; + //break; } return false; // resolve compiler warning; do we ever get here? diff --git a/TeensyDSP/Keyer.h b/TeensyDSP/Keyer.h index 49b5d8c..c0613bf 100644 --- a/TeensyDSP/Keyer.h +++ b/TeensyDSP/Keyer.h @@ -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(); 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.cpp b/TeensyDSP/TR.cpp index 826df64..5cf9b66 100644 --- a/TeensyDSP/TR.cpp +++ b/TeensyDSP/TR.cpp @@ -5,7 +5,8 @@ #include #include "TR.h" -UBitxTR TR(DSP); +UBitxTR _tr(DSP); +UBitxTR& TR = _tr; void UBitxTR::update(bool cw, bool extKey) { updateKey(); 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 {