#include #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); /**********************************************************************/