ubitx-v5x/TeensyDSP/TS590.cpp

359 lines
8.3 KiB
C++

#include <Arduino.h>
#include "TS590.h"
#include "Debug.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)) {
DBGCMD( sendResponse(cmd) );
} else {
DBGCMD( handleCommand(cmd) );
switch(theError) {
case NoError:
if (theRig->getAI()) {
DBGCMD( sendResponse(cmd) );
}
break;
case SyntaxError:
DBGCMD( ts590SyntaxError() );
break;
case CommError:
DBGCMD( ts590CommError() );
break;
case ProcessError:
DBGCMD( 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(true);
} else if (rig()->isVFOB()) {
rig()->splitOn(true);
} else {
setSyntaxError();
}
break;
case '1':
if (rig()->isVFOA()) {
rig()->splitOn(true);
} else if (rig()->isVFOB()) {
rig()->splitOff(true);
} 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");
}
}
/**********************************************************************/
void TS590_MD::handleCommand(const char* cmd) {
if (strlen(cmd) == 3) {
switch (cmd[2]) {
case '0': // None (setting failure)
case '4': // FM - not supported
case '5': // AM - not supported
case '6': // FSK - not supported
case '8': // None (setting failure)
case '9': // FSK-R - not supported
setProcessError();
break;
case '1': // LSB
rig()->selectLSB(true);
rig()->cwOff(true);
break;
case '2': // USB
rig()->selectUSB(true);
rig()->cwOff(true);
break;
case '3': // CW
rig()->selectUSB(true);
rig()->cwOn(true);
break;
case '7': // CW-R
rig()->selectLSB(true);
rig()->cwOn(true);
break;
default:
setSyntaxError();
}
} else {
setSyntaxError();
}
}
void TS590_MD::sendResponse(const char* cmd) {
if (rig()->isCW()) {
if (rig()->isUSB()) {
ts590SendCommand("MD3");
} else {
ts590SendCommand("MD7");
}
} else {
if (rig()->isUSB()) {
ts590SendCommand("MD2");
} else {
ts590SendCommand("MD1");
}
}
}
/**********************************************************************/
TS590_FA cmdFA;
TS590_FB cmdFB;
TS590_FR cmdFR;
TS590_FT cmdFT;
TS590_MD cmdMD;
TS590Command* catCommands[] = {
&cmdFA,
&cmdFB,
&cmdFR,
&cmdFT,
&cmdMD
};
int numCatCommands = sizeof(catCommands) / sizeof(catCommands[0]);
/**********************************************************************/
void UBitxTS590::begin() {
Serial.begin(9600); // USB is always 12 Mbit/sec
#ifdef DEBUG
delay(500);
Serial.print("DBG: Number of CAT commands: ");
Serial.println(numCommands);
for (int i = 0; i < numCommands; i++) {
Serial.print(" ");
Serial.println(commands[i]->prefix());
}
#endif
}
void UBitxTS590::update() {
char incomingChar;
while (Serial.available()) {
if (bufLen < ts590CommandMaxLength) {
incomingChar = Serial.read();
if (incomingChar == ';') {
buf[bufLen++] = '\0';
strupr(buf);
processCommand();
} else if (incomingChar == '\n' && bufLen == 0) {
;
} else {
buf[bufLen++] = incomingChar;
}
} else {
// too long... we're going to bail on this.
ts590SyntaxError();
bufLen = 0;
}
}
}
typedef class TS590Command* PCmd;
int compareCATCommands(const void* a, const void* b) {
TS590Command const *B = *(TS590Command const **)b;
int cmp = strncmp((char*)a, (char*)B->prefix(), 2);
#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);
if (cmd == NULL) {
ts590SyntaxError();
} else {
(*cmd)->process(buf);
}
bufLen = 0;
}
UBitxTS590 TS590(catCommands, numCatCommands);
/**********************************************************************/