267 lines
6.3 KiB
C++
267 lines
6.3 KiB
C++
|
#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);
|
||
|
|
||
|
/**********************************************************************/
|