Heavily modified the TS590 class.
This commit is contained in:
parent
b9be616361
commit
702f370d1b
3
TeensyDSP/Rig.cpp
Normal file
3
TeensyDSP/Rig.cpp
Normal file
@ -0,0 +1,3 @@
|
||||
#include "Rig.h"
|
||||
|
||||
UBitxRig Rig;
|
132
TeensyDSP/Rig.h
Normal file
132
TeensyDSP/Rig.h
Normal file
@ -0,0 +1,132 @@
|
||||
#ifndef __Rig_h__
|
||||
#define __Rig_h__
|
||||
|
||||
#include "RigState.h"
|
||||
|
||||
enum UpdateSource {
|
||||
NoSource,
|
||||
RaduinoSource,
|
||||
CATSource
|
||||
};
|
||||
|
||||
class UBitxRig {
|
||||
public:
|
||||
inline unsigned long getFreqA() const { return state.vfo[0]; }
|
||||
inline unsigned long getFreqB() const { return state.vfo[1]; }
|
||||
inline short getRIT() const { return state.rit; }
|
||||
inline short getXIT() const { return state.xit; }
|
||||
inline bool isVFOA() const { return (state.flags & UBITX_VFOB_FLAG) != UBITX_VFOB_FLAG; }
|
||||
inline bool isVFOB() const { return (state.flags & UBITX_VFOB_FLAG) == UBITX_VFOB_FLAG; }
|
||||
inline bool isSplit() const { return (state.flags & UBITX_SPLIT_FLAG) == UBITX_SPLIT_FLAG; }
|
||||
inline bool isRITOn() const { return (state.flags & UBITX_RIT_FLAG) == UBITX_RIT_FLAG; }
|
||||
inline bool isXITOn() const { return (state.flags & UBITX_XIT_FLAG) == UBITX_XIT_FLAG; }
|
||||
inline bool isCW() const { return (state.flags & UBITX_CW_FLAG) == UBITX_CW_FLAG; }
|
||||
inline bool isLSB() const { return (state.flags & UBITX_USB_FLAG) != UBITX_USB_FLAG; }
|
||||
inline bool isUSB() const { return (state.flags & UBITX_USB_FLAG) == UBITX_USB_FLAG; }
|
||||
inline bool getAI() const { return autoInfo; }
|
||||
inline bool updatedByCAT() const { return lastUpdatedBy == CATSource; }
|
||||
inline bool updatedByRaduino() const { return lastUpdatedBy == RaduinoSource; }
|
||||
|
||||
inline void clearUpdate() { lastUpdatedBy = NoSource; }
|
||||
inline void setRaduinoUpdate() { lastUpdatedBy = RaduinoSource; }
|
||||
inline void setCATUpdate() { lastUpdatedBy = CATSource; }
|
||||
|
||||
inline void setFreqA(unsigned long freq, bool isCAT = false) {
|
||||
lastUpdatedBy = isCAT ? CATSource : RaduinoSource;
|
||||
state.vfo[0] = freq;
|
||||
}
|
||||
|
||||
inline void setFreqB(unsigned long freq, bool isCAT = false) {
|
||||
lastUpdatedBy = isCAT ? CATSource : RaduinoSource;
|
||||
state.vfo[1] = freq;
|
||||
}
|
||||
|
||||
inline void setRIT(short offset, bool isCAT = false) {
|
||||
lastUpdatedBy = isCAT ? CATSource : RaduinoSource;
|
||||
state.rit = offset;
|
||||
}
|
||||
|
||||
inline void setXIT(short offset, bool isCAT = false) {
|
||||
lastUpdatedBy = isCAT ? CATSource : RaduinoSource;
|
||||
state.xit = offset;
|
||||
}
|
||||
|
||||
inline void selectVFOA(bool isCAT = false) {
|
||||
lastUpdatedBy = isCAT ? CATSource : RaduinoSource;
|
||||
state.flags &= ~UBITX_VFOB_FLAG;
|
||||
}
|
||||
|
||||
inline void selectVFOB(bool isCAT = false) {
|
||||
lastUpdatedBy = isCAT ? CATSource : RaduinoSource;
|
||||
state.flags |= UBITX_VFOB_FLAG;
|
||||
}
|
||||
|
||||
inline void toggleVFO(bool isCAT = false) {
|
||||
lastUpdatedBy = isCAT ? CATSource : RaduinoSource;
|
||||
state.flags ^= UBITX_VFOB_FLAG;
|
||||
}
|
||||
|
||||
inline void splitOn(bool isCAT = false) {
|
||||
lastUpdatedBy = isCAT ? CATSource : RaduinoSource;
|
||||
state.flags |= UBITX_SPLIT_FLAG;
|
||||
}
|
||||
|
||||
inline void splitOff(bool isCAT = false) {
|
||||
lastUpdatedBy = isCAT ? CATSource : RaduinoSource;
|
||||
state.flags &= ~UBITX_SPLIT_FLAG;
|
||||
}
|
||||
|
||||
inline void ritOn(bool isCAT = false) {
|
||||
lastUpdatedBy = isCAT ? CATSource : RaduinoSource;
|
||||
state.flags |= UBITX_RIT_FLAG;
|
||||
}
|
||||
|
||||
inline void ritOff(bool isCAT = false) {
|
||||
lastUpdatedBy = isCAT ? CATSource : RaduinoSource;
|
||||
state.flags &= ~UBITX_RIT_FLAG;
|
||||
}
|
||||
|
||||
inline void xitOn(bool isCAT = false) {
|
||||
lastUpdatedBy = isCAT ? CATSource : RaduinoSource;
|
||||
state.flags |= UBITX_XIT_FLAG;
|
||||
}
|
||||
|
||||
inline void xitOff(bool isCAT = false) {
|
||||
lastUpdatedBy = isCAT ? CATSource : RaduinoSource;
|
||||
state.flags &= ~UBITX_XIT_FLAG;
|
||||
}
|
||||
|
||||
inline void cwOn(bool isCAT = false) {
|
||||
lastUpdatedBy = isCAT ? CATSource : RaduinoSource;
|
||||
state.flags |= UBITX_CW_FLAG;
|
||||
}
|
||||
|
||||
inline void cwOff(bool isCAT = false) {
|
||||
lastUpdatedBy = isCAT ? CATSource : RaduinoSource;
|
||||
state.flags &= ~UBITX_CW_FLAG;
|
||||
}
|
||||
|
||||
inline void selectLSB(bool isCAT = false) {
|
||||
lastUpdatedBy = isCAT ? CATSource : RaduinoSource;
|
||||
state.flags &= ~UBITX_USB_FLAG;
|
||||
}
|
||||
|
||||
inline void selectUSB(bool isCAT = false) {
|
||||
lastUpdatedBy = isCAT ? CATSource : RaduinoSource;
|
||||
state.flags |= UBITX_USB_FLAG;
|
||||
}
|
||||
|
||||
inline void aiOn() { autoInfo = true; }
|
||||
inline void aiOff() { autoInfo = false; }
|
||||
|
||||
uint8_t* const stateAsBytes() const { return (uint8_t* const)&state; }
|
||||
|
||||
private:
|
||||
bool autoInfo = false;
|
||||
UpdateSource lastUpdatedBy = NoSource;
|
||||
UBitxRigState state;
|
||||
};
|
||||
|
||||
extern UBitxRig Rig;
|
||||
|
||||
#endif
|
266
TeensyDSP/TS590.cpp
Normal file
266
TeensyDSP/TS590.cpp
Normal file
@ -0,0 +1,266 @@
|
||||
#include <Arduino.h>
|
||||
#include "TS590.h"
|
||||
|
||||
/**********************************************************************/
|
||||
|
||||
/*!
|
||||
* @brief Send a command to the PC via CAT. Note that the command
|
||||
* should not include the trailing terminator (;). That will
|
||||
* be automatically added.
|
||||
* @param format
|
||||
* A printf-style format string.
|
||||
* @param args
|
||||
* Zero or more arguments to include in the command.
|
||||
*/
|
||||
void ts590SendCommand(const char* format, ...) {
|
||||
static char outBuf[ts590CommandMaxLength];
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
vsprintf(outBuf, format, args);
|
||||
va_end(args);
|
||||
Serial.print(outBuf);
|
||||
Serial.print(";");
|
||||
}
|
||||
|
||||
/**********************************************************************/
|
||||
|
||||
/*!
|
||||
* @brief Create a new CAT command. It should be initialized with
|
||||
* a 2-character command prefix.
|
||||
* @param pre
|
||||
* A 2-character command prefix. If more than 2 characters
|
||||
* are supplied, only the first two will be used. If less
|
||||
* than two are supplied, then the command will be
|
||||
* initialized with a null prefix.
|
||||
*/
|
||||
TS590Command::TS590Command(const char* pre) {
|
||||
if (strlen(pre) >= 2) {
|
||||
myPrefix[0] = pre[0];
|
||||
myPrefix[1] = pre[1];
|
||||
}
|
||||
}
|
||||
|
||||
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.
|
||||
* @return True if a Read command; false otherwise.
|
||||
*/
|
||||
bool TS590Command::isReadCommand(const char* cmd) const {
|
||||
if (strlen(cmd) == 2) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
* @brief Process the provided command. If the command is a Set
|
||||
* command, it calls handleCommand(). If Auto Information
|
||||
* is eet (by the rig), sendResponse() is called at the end.
|
||||
* If the command is a Read command, it also calls
|
||||
* sendResponse(). Finally, if necessary, it will return
|
||||
* any error codes to the PC.
|
||||
* @param cmd
|
||||
* The current command string received from the PC via CAT.
|
||||
* It should be null-terminated, and should no longer have
|
||||
* the terminator (;).
|
||||
*/
|
||||
void TS590Command::process(const char* cmd) {
|
||||
theError = NoError;
|
||||
|
||||
if (isReadCommand(cmd)) {
|
||||
sendResponse(cmd);
|
||||
} else {
|
||||
handleCommand(cmd);
|
||||
switch(theError) {
|
||||
case NoError:
|
||||
if (theRig->getAI()) {
|
||||
sendResponse(cmd);
|
||||
}
|
||||
break;
|
||||
|
||||
case SyntaxError:
|
||||
ts590SyntaxError();
|
||||
break;
|
||||
|
||||
case CommError:
|
||||
ts590CommError();
|
||||
break;
|
||||
|
||||
case ProcessError:
|
||||
ts590ProcessError();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
* @brief Set the syntax error flag. This is cleared at the
|
||||
* beginning of each call to process().
|
||||
*/
|
||||
void TS590Command::setSyntaxError() {
|
||||
theError = SyntaxError;
|
||||
}
|
||||
|
||||
/*!
|
||||
* @brief Set the comms error flag. This is cleared at the
|
||||
* beginning of each call to process().
|
||||
*/
|
||||
void TS590Command::setCommError() {
|
||||
theError = CommError;
|
||||
}
|
||||
|
||||
/*!
|
||||
* @brief Set the process error flag. This is cleared at the
|
||||
* beginning of each call to process().
|
||||
*/
|
||||
void TS590Command::setProcessError() {
|
||||
theError = ProcessError;
|
||||
}
|
||||
|
||||
/*!
|
||||
* @brief Set the rig that will be used to process commands.
|
||||
* @param r
|
||||
* Pointer to the UBitxRig object.
|
||||
*/
|
||||
void TS590Command::setRig(UBitxRig* r) {
|
||||
theRig = r;
|
||||
}
|
||||
|
||||
UBitxRig* TS590Command::theRig = &Rig;
|
||||
TS590Error TS590Command::theError = NoError;
|
||||
|
||||
/**********************************************************************/
|
||||
|
||||
void TS590_FR::handleCommand(const char* cmd) {
|
||||
if (strlen(cmd) == 3) {
|
||||
switch (cmd[2]) {
|
||||
case 0:
|
||||
rig()->selectVFOA(true);
|
||||
rig()->splitOff(true);
|
||||
break;
|
||||
|
||||
case 1:
|
||||
rig()->selectVFOB(true);
|
||||
rig()->splitOff(true);
|
||||
break;
|
||||
|
||||
case 2:
|
||||
// TODO: Need to add something for channel mode.
|
||||
break;
|
||||
|
||||
default:
|
||||
setSyntaxError();
|
||||
}
|
||||
} else {
|
||||
setSyntaxError();
|
||||
}
|
||||
}
|
||||
|
||||
void TS590_FR::sendResponse(const char* cmd) {
|
||||
if (rig()->isVFOA()) {
|
||||
ts590SendCommand("FR0");
|
||||
} else if (rig()->isVFOB()) {
|
||||
ts590SendCommand("FR1");
|
||||
} else {
|
||||
ts590SendCommand("FR2");
|
||||
}
|
||||
}
|
||||
|
||||
/**********************************************************************/
|
||||
|
||||
void TS590_FT::handleCommand(const char* cmd) {
|
||||
if (strlen(cmd) == 3) {
|
||||
switch (cmd[2]) {
|
||||
case 0:
|
||||
if (rig()->isVFOA()) {
|
||||
rig()->splitOff();
|
||||
} else if (rig()->isVFOB()) {
|
||||
rig()->splitOn();
|
||||
} else {
|
||||
setSyntaxError();
|
||||
}
|
||||
break;
|
||||
|
||||
case 1:
|
||||
if (rig()->isVFOA()) {
|
||||
rig()->splitOn();
|
||||
} else if (rig()->isVFOB()) {
|
||||
rig()->splitOff();
|
||||
} else {
|
||||
setSyntaxError();
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
setSyntaxError();
|
||||
}
|
||||
} else {
|
||||
setSyntaxError();
|
||||
}
|
||||
}
|
||||
|
||||
void TS590_FT::sendResponse(const char* cmd) {
|
||||
if (rig()->isVFOA()) {
|
||||
ts590SendCommand(rig()->isSplit() ? "FT1" : "FT0");
|
||||
} else if (rig()->isVFOB()) {
|
||||
ts590SendCommand(rig()->isSplit() ? "FT0" : "FT1");
|
||||
} else {
|
||||
ts590SendCommand("FT2");
|
||||
}
|
||||
}
|
||||
|
||||
/**********************************************************************/
|
||||
|
||||
TS590_FA cmdFA;
|
||||
TS590_FB cmdFB;
|
||||
TS590_FR cmdFR;
|
||||
TS590_FT cmdFT;
|
||||
|
||||
TS590Command* catCommands[] = {
|
||||
&cmdFA,
|
||||
&cmdFB,
|
||||
&cmdFR,
|
||||
&cmdFT
|
||||
};
|
||||
|
||||
/**********************************************************************/
|
||||
|
||||
void UBitxTS590::update() {
|
||||
char incomingChar;
|
||||
|
||||
while (Serial.available()) {
|
||||
if (bufLen < ts590CommandMaxLength) {
|
||||
incomingChar = Serial.read();
|
||||
if (incomingChar == ';') {
|
||||
buf[bufLen++] = '\0';
|
||||
processCommand();
|
||||
} else {
|
||||
buf[bufLen++] = incomingChar;
|
||||
}
|
||||
} else {
|
||||
// too long... we're going to bail on this.
|
||||
ts590SyntaxError();
|
||||
bufLen = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int compareCATCommands(const void* a, const void* b) {
|
||||
return strcmp(((TS590Command*)a)->prefix(), ((TS590Command*)b)->prefix());
|
||||
}
|
||||
|
||||
void UBitxTS590::processCommand() {
|
||||
TS590Command* cmd = (TS590Command*)bsearch((void*)buf, (void*)commands, sizeof(commands) / sizeof(commands[0]), sizeof(commands[0]), compareCATCommands);
|
||||
if (cmd == NULL) {
|
||||
ts590SyntaxError();
|
||||
} else {
|
||||
cmd->process(buf);
|
||||
}
|
||||
}
|
||||
|
||||
UBitxTS590 TS590(catCommands);
|
||||
|
||||
/**********************************************************************/
|
173
TeensyDSP/TS590.h
Normal file
173
TeensyDSP/TS590.h
Normal file
@ -0,0 +1,173 @@
|
||||
#ifndef __TS590_h__
|
||||
#define __TS590_h__
|
||||
|
||||
#include <Arduino.h>
|
||||
#include "Rig.h"
|
||||
|
||||
/**********************************************************************/
|
||||
|
||||
#define TS590_COMMAND_MAX_LENGTH 50 // including terminator (which will get converted to null)
|
||||
|
||||
const int ts590CommandMaxLength = TS590_COMMAND_MAX_LENGTH;
|
||||
|
||||
void ts590SendCommand(const char*, ...);
|
||||
|
||||
/*!
|
||||
* @brief Send a syntax error response to the PC via CAT.
|
||||
*/
|
||||
inline void ts590SyntaxError() { ts590SendCommand("?"); }
|
||||
|
||||
/*!
|
||||
* @brief Send a communications error response to the PC via CAT.
|
||||
*/
|
||||
inline void ts590CommError() { ts590SendCommand("E"); }
|
||||
|
||||
/*!
|
||||
* @brief Send a processing error response to the PC via CAT.
|
||||
*/
|
||||
inline void ts590ProcessError() { ts590SendCommand("O"); }
|
||||
|
||||
enum TS590Error {
|
||||
NoError,
|
||||
SyntaxError,
|
||||
CommError,
|
||||
ProcessError
|
||||
};
|
||||
|
||||
/**********************************************************************/
|
||||
|
||||
/*!
|
||||
* @brief A TS590S/SG "CAT" command. This is the base class for all
|
||||
* CAT commands.
|
||||
*/
|
||||
class TS590Command {
|
||||
public:
|
||||
TS590Command(const char* pre);
|
||||
virtual ~TS590Command() = 0;
|
||||
|
||||
/*!
|
||||
* @brief Return the 2-character prefix for the command.
|
||||
* @return The 2-character prefix for the command.
|
||||
*/
|
||||
inline const char* prefix() const { return &myPrefix[0]; }
|
||||
|
||||
/*!
|
||||
* @brief Return the rig that this command will be used to control.
|
||||
*/
|
||||
inline UBitxRig* rig() const { return theRig; }
|
||||
|
||||
/*!
|
||||
* @brief Handle the provided Set command. If the Set command
|
||||
* results in an error, then set the appropriate flag with
|
||||
* setSyntaxError(), setCommError(), or setProcessError().
|
||||
* @param cmd
|
||||
* The current command string received from the PC via CAT.
|
||||
* It should be null-terminated, and should no longer have
|
||||
* the terminator (;).
|
||||
*/
|
||||
virtual void handleCommand(const char* cmd) = 0;
|
||||
|
||||
/*!
|
||||
* @brief Send a response back to the PC. This assumes a
|
||||
* successful command (no errors).
|
||||
*/
|
||||
virtual void sendResponse(const char* cmd) = 0;
|
||||
|
||||
virtual bool isReadCommand(const char* cmd) const;
|
||||
|
||||
void process(const char* cmd);
|
||||
|
||||
static void setSyntaxError();
|
||||
static void setCommError();
|
||||
static void setProcessError();
|
||||
static void setRig(UBitxRig* r);
|
||||
|
||||
private:
|
||||
char myPrefix[3] = "\0\0";
|
||||
static TS590Error theError;
|
||||
static UBitxRig* theRig;
|
||||
};
|
||||
|
||||
/**********************************************************************/
|
||||
|
||||
/*!
|
||||
* @brief CAT command for setting or reading the VFO A/B frequency.
|
||||
*/
|
||||
template<bool VFOA>
|
||||
class TS590_FAB : public TS590Command {
|
||||
public:
|
||||
TS590_FAB(): TS590Command(VFOA ? "FA" : "FB") {}
|
||||
|
||||
virtual void handleCommand(const char* cmd) {
|
||||
if (strlen(cmd) == 13) {
|
||||
unsigned long freq = strtoul(&cmd[2], NULL, 10);
|
||||
if (VFOA) {
|
||||
rig()->setFreqA(freq, true);
|
||||
} else {
|
||||
rig()->setFreqB(freq, true);
|
||||
}
|
||||
} else {
|
||||
setSyntaxError();
|
||||
}
|
||||
}
|
||||
|
||||
virtual void sendResponse(const char* cmd) {
|
||||
ts590SendCommand(VFOA ? "FA%011u" : "FB%011u", VFOA ? rig()->getFreqA() : rig()->getFreqB());
|
||||
}
|
||||
};
|
||||
|
||||
typedef TS590_FAB<true> TS590_FA;
|
||||
typedef TS590_FAB<false> TS590_FB;
|
||||
|
||||
/**********************************************************************/
|
||||
|
||||
/*!
|
||||
* @brief CAT command for setting the receiver VFO. This will always
|
||||
* disable split mode, if it was previously enabled.
|
||||
*/
|
||||
class TS590_FR : public TS590Command {
|
||||
public:
|
||||
TS590_FR(): TS590Command("FR") {}
|
||||
virtual void handleCommand(const char* cmd);
|
||||
virtual void sendResponse(const char* cmd);
|
||||
};
|
||||
|
||||
/**********************************************************************/
|
||||
|
||||
/*!
|
||||
* @brief CAT command for setting the transmitter VFO. If it is
|
||||
* different than the receiver VFO, then split mode will be
|
||||
* automatically enabled.
|
||||
*/
|
||||
class TS590_FT : public TS590Command {
|
||||
public:
|
||||
TS590_FT(): TS590Command("FT") {}
|
||||
virtual void handleCommand(const char* cmd);
|
||||
virtual void sendResponse(const char* cmd);
|
||||
};
|
||||
|
||||
/**********************************************************************/
|
||||
|
||||
class UBitxTS590 {
|
||||
public:
|
||||
UBitxTS590(TS590Command** cmds): commands(cmds) {}
|
||||
|
||||
inline void begin() {
|
||||
Serial.begin(9600); // USB is always 12 Mbit/sec
|
||||
}
|
||||
|
||||
void update();
|
||||
|
||||
private:
|
||||
void processCommand();
|
||||
|
||||
char buf[ts590CommandMaxLength] = {0};
|
||||
int bufLen = 0;
|
||||
TS590Command** commands;
|
||||
};
|
||||
|
||||
extern UBitxTS590 TS590;
|
||||
|
||||
#endif
|
||||
|
||||
/**********************************************************************/
|
@ -313,9 +313,6 @@ void sendMeterData(uint8_t isSend)
|
||||
|
||||
void setup()
|
||||
{
|
||||
#ifdef DEBUG
|
||||
Serial.begin(38400);
|
||||
#endif
|
||||
|
||||
DBGCMD( DSP.begin() );
|
||||
DBGCMD( TR.begin() );
|
||||
|
Loading…
Reference in New Issue
Block a user