IC746CAT/IC746.cpp

806 wiersze
27 KiB
C++

/*************************************************************************
IC746 CAT Library, by KK4DAS, Dean Souleles
V1.3 1/21/2023
- Included all defined modes in Get/Set Mode (thanks to Mike, KA4CDN)
- Fix to allow frequencies greater than 100MHz -(thanks to Bob, KA1GT)
V1.2 10/22/2021
- Fixes bug that caused "WSJTX Rig Control Error" for versions after 2.2.2
- The problem was caused by an unsupported CIV command being sent by WSJTX
- This fix responds to unimplemented commands with a NACK instead of an ACK
- Bug was reported on the WSJTX groups board.
V1.1 2/3/2021
- various fixes, now works properly with OmniRig and flrig
- smeter now returns proper BCD code - calibrated to emulate ICOM responses
V1.0 1/24/2021
- Initial build
Inspired by: ft857d CAT Library, by Pavel Milanes, CO7WT, pavelmc@gmail.com
Emulates an ICOM 746 CAT functionality to work with all ham radio software that include CAT control
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
***************************************************************************/
#include "Arduino.h"
#include "IC746.h"
//#define DEBUG_CAT
#ifdef DEBUG_CAT
#define DEBUG_CAT_DETAIL
//#define DEBUG_CAT_SMETER
#include <SoftwareSerial.h>
SoftwareSerial catDebug(11,12); // RX, TX
String dbg;
#endif
//extern void displayBanner(String s);
// User supplied calback function work variables, must be static
static FuncPtrBoolean catSplit;
static FuncPtrBoolean catSetPtt;
static FuncPtrVoidBoolean catGetPtt;
static FuncPtrVoidLong catGetFreq;
static FuncPtrLong catSetFreq;
static FuncPtrVoidByte catGetMode;
static FuncPtrByte catSetMode;
static FuncPtrVoidByte catGetSmeter;
static FuncPtrByte catSetVFO;
static FuncPtrVoid catAtoB;
static FuncPtrVoid catSwapVfo;
// Command indices
//
// Command structure after preamble and EOM have been discarded
// |56|E0|cmd|sub-cmd|data
// 56 - fixed transceiver address for IC746
// E0 - fixed cat xontroller address
// The sub-command field varies by command. For somme commands the sub-cmd field is not supplied and the data
// begins immediatedly follwing the command.
//
// The following are the array indedes within the command buffer for command elements that are sent with the command
// or are where we put data to return to the conroller
//
#define CAT_IX_TO_ADDR 0
#define CAT_IX_FROM_ADDR 1
#define CAT_IX_CMD 2
#define CAT_IX_SUB_CMD 3
#define CAT_IX_FREQ 3 // Set Freq has no sub-command
#define CAT_IX_MODE 3 // Get mode has no sub-command
#define CAT_IX_TUNE_STEP 3 // Get step has no sub-command
#define CAT_IX_ANT_SEL 3 // Get amt has no sub-command
#define CAT_IX_PTT 4 // PTT RX/TX indicator
#define CAT_IX_IF_FILTER 4 // IF Filter value
#define CAT_IX_SMETER 4 // S Meter 0-255
#define CAT_IX_SQUELCH 4 // Squelch 0=close, 1= open
#define CAT_IX_ID 5
#define CAT_IX_DATA 4 // Data following sub-comand
// Lentgth of commands that request data
#define CAT_RD_LEN_NOSUB 3 // 3 bytes - 56 E0 cc
#define CAT_RD_LEN_SUB 4 // 4 bytes - 56 E0 cc ss (cmd, sub command)
// Length of data responses
#define CAT_SZ_SMETER 6 // 6 bytes - E0 56 15 02 nn nn
#define CAT_SZ_SQUELCH 5 // 5 bytes - E0 56 15 01 nn
#define CAT_SZ_PTT 5 // 5 bytes - E0 56 1C 00 nn
#define CAT_SZ_FREQ 8 // 8 bytes - E0 56 03 ff ff ff ff ff (frequency in little endian BCD)
#define CAT_SZ_MODE 5 // 5 bytes - E0 56 04 mm ff (mode, then filter)
#define CAT_SZ_IF_FILTER 5 // 5 bytes - E0 56 1A 03 nn
#define CAT_SZ_TUNE_STEP 4 // 4 bytes - E0 56 10 nn
#define CAT_SZ_ANT_SEL 4 // 4 bytes - E0 56 12 nn
#define CAT_SZ_ID 5 // 5 bytes - E0 56 19 00 56 (returns RIG ID)
#define CAT_SZ_UNIMP_1B 5 // 5 bytes - E0 56 NN SS 00 (unimplemented commands that require 1 data byte
#define CAT_SZ_UNIMP_2B 6 // 6 bytes - EO 56 NN SS 00 00 (unimplemented commandds that required 2 data bytes
/*
Contructor, simple constructor, it initiates the serial port in the
default mode for the radio: 9600 @ 8N2
*/
void IC746::begin() {
Serial.begin(9600, SERIAL_8N2);
// while (!Serial);;
// Serial.flush();
#ifdef DEBUG_CAT
catDebug.begin(9600);
dbg = "CAT Debug Ready:";
catDebug.println(dbg.c_str());
#endif
}
// Alternative initializer with a custom baudrate and mode
void IC746::begin(long br, int mode) {
/*
Allowed Arduino modes for the serial:
SERIAL_5N1; SERIAL_6N1; SERIAL_7N1; SERIAL_8N1; SERIAL_5N2; SERIAL_6N2;
SERIAL_7N2; SERIAL_8N2; SERIAL_5E1; SERIAL_6E1; SERIAL_7E1; SERIAL_8E1;
SERIAL_5E2; SERIAL_6E2; SERIAL_7E2; SERIAL_8E2; SERIAL_5O1; SERIAL_6O1;
SERIAL_7O1; SERIAL_8O1; SERIAL_5O2; SERIAL_6O2; SERIAL_7O2; SERIAL_8O2
*/
Serial.begin(br, mode);
// Serial.flush();
#ifdef DEBUG_CAT
catDebug.begin(9600);
dbg = "CAT Debug Ready";
catDebug.println(dbg.c_str());
delay(1000);
catDebug.println(dbg.c_str());
catDebug.println(dbg.c_str());
catDebug.println(dbg.c_str());
#endif
}
/*
Linking user supplied callback functions
*/
// PTT
void IC746::addCATPtt(void (*userFunc)(boolean)) {
catSetPtt = userFunc;
}
// Split
void IC746::addCATsplit(void (*userFunc)(boolean)) {
catSplit = userFunc;
}
// VFO A=B - set both VFOs to be the same as the active VFO
void IC746::addCATAtoB(void (*userFunc)(void)) {
catAtoB = userFunc;
}
// Swap Active VFO
void IC746::addCATSwapVfo(void (*userFunc)(void)) {
catSwapVfo = userFunc;
}
// Get the freq of operation, the function must return the freq
void IC746::addCATGetFreq(long (*userFunc)(void)) {
catGetFreq = userFunc;
}
// Get the mode of operation, the function must return the mode
void IC746::addCATGetMode(byte (*userFunc)(void)) {
catGetMode = userFunc;
}
// GetPTT - function must return true for Tx and false for Rx
void IC746::addCATGetPtt(boolean (*userFunc)(void)) {
catGetPtt = userFunc;
}
// S meter (user function must return 0-15)
void IC746::addCATSMeter(byte (*userFunc)(void)) {
catGetSmeter = userFunc;
}
// Set Frequency - user function must accept a long as the freq in hz
void IC746::addCATFSet(void (*userFunc)(long)) {
catSetFreq = userFunc;
}
// Set Mode - user function must interpret MODE per the constants in IC746.h
void IC746::addCATMSet(void (*userFunc)(byte)) {
catSetMode = userFunc;
}
// SEt VFOA or B - user function must interpret VFO per the constants in IC746.h
void IC746::addCATVSet(void (*userFunc)(byte)) {
catSetVFO = userFunc;
}
////////////////////////////////////////////////////////////////////////////////
// Protocol Message Handling
////////////////////////////////////////////////////////////////////////////////
//
// Send a message back to CAT controller
// Format PREAMBLE, PREAMBLE, MSG, EOM
//
void IC746::send(byte *buf, int len) {
int i;
Serial.write(CAT_PREAMBLE);
Serial.write(CAT_PREAMBLE);
for (i = 0; i < len; i++) {
Serial.write(buf[i]);
}
Serial.write(CAT_EOM);
#ifdef DEBUG_CAT_DETAIL
dbg = "sent: ";
dbg += String(len);
dbg += ": ";
for (int i = 0; i < len; i++) {
dbg += String(buf[i], HEX);
dbg += " ";
}
catDebug.println(dbg.c_str());
#endif
}
//
// sendResponse
//
void IC746::sendResponse(byte *buf, int len) {
buf[CAT_IX_FROM_ADDR] = CAT_RIG_ADDR;
buf[CAT_IX_TO_ADDR] = CAT_CTRL_ADDR;
send(buf, len);
}
//
// sendAck() - send back hard-code acknowledge message
//
void IC746::sendAck() {
byte ack[] = {CAT_RIG_ADDR, CAT_CTRL_ADDR, CAT_ACK};
send(ack, 3);
}
//
// sendNack() - send back hard-code negative-acknowledge message
//
void IC746::sendNack() {
byte nack[] = {CAT_RIG_ADDR, CAT_CTRL_ADDR, CAT_NACK};
// displayBanner(String("Nack"));
send(nack, 3);
}
/*
readCMD - state machine to receive a command from the controller
States:
CAT_RCV_WAITING - scan incoming serial data for first preamble byte
CAT_RCV_INIT - second premable byte confirms start of message
CAT_RCV_RECEIVING - fill command buffer until EOM received
Command format
|FE|FE|56|E0|cmd|sub-cmd|data|FD|
FE FE = preamble, FD = end of command
56 = transceiver default address for IC746 (unused)
E0 = CAT controller default address (unused)
Upon successful receipt of EOM, protocol requires echo back of enitre message
On interrupted preamble or buffer overflow (no EOM received), send NAK
On successful receipt of a command the global array cmdBuf
will have the received CAT command (without the preamble and EOM)
*/
boolean IC746::readCmd() {
byte bt;
boolean cmdRcvd = false;
while (Serial.available() && !cmdRcvd) {
bt = byte(Serial.read());
switch (rcvState) {
case CAT_RCV_WAITING: // scan for start of new command
if (bt == CAT_PREAMBLE) {
rcvState = CAT_RCV_INIT;
}
break;
case CAT_RCV_INIT: // check for second preamble byte
if (bt == CAT_PREAMBLE) {
rcvState = CAT_RCV_RECEIVING;
} else { // error - should not happen, reset and report
rcvState = CAT_RCV_WAITING;
bytesRcvd = 0;
sendNack();
}
break;
case CAT_RCV_RECEIVING:
switch (bt) {
case CAT_EOM: // end of message received, return for processing, reset state
#ifdef DEBUG_CAT_DETAIL
dbg = "rcvd: ";
dbg += String(bytesRcvd);
dbg += ": ";
for (int i = 0; i < bytesRcvd; i++) {
dbg += String(cmdBuf[i], HEX);
dbg += " ";
}
catDebug.println(dbg.c_str());
#endif
send(cmdBuf, bytesRcvd); // echo received packet for protocol
cmdRcvd = true;
rcvState = CAT_RCV_WAITING;
cmdLength = bytesRcvd;
bytesRcvd = 0;
break;
default: // fill command buffer
if (bytesRcvd <= CAT_CMD_BUF_LENGTH) {
cmdBuf[bytesRcvd] = bt;
bytesRcvd++;
} else { // overflow - should not happen reset for new comand
rcvState = CAT_RCV_WAITING;
bytesRcvd = 0;
sendNack(); // report error
}
break;
}
break;
}
}
return cmdRcvd;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////
//
// COMMAND PROCESSORS
//
///////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////
// doSmeter() - process the CAT_READ_SMETER Command
// This command has two sub-commands, SMETER and SQUELCH, only SMETER is fully implemented
//
// The SMETER sub command requests the current Return S-meter readingscaled for IC 746 appropriate values
// It calls a user function returns 0-15 S0-9, +10, +20, +30, +40, +50 +60
// The mapping of s-units to IC746 equivalents done imperically using the CatBkt cat test program
//
// The second sub-command, SQUELCH request wheterh Squelch is open or closed. Return a fixed value
// of "Open" to keep the protocol happly
///////////////////////////////////////////////////////////////////////////////////////////////////////
void IC746::doSmeter() {
switch (cmdBuf[CAT_IX_SUB_CMD]) {
case CAT_READ_SUB_SMETER:
if (catGetSmeter) {
//S0 S1 S2 S3 S4 S5 S6 S7 S8 S9 +10 +20 +30 +40 +50 +60
const byte smap[] = {0, 15, 25, 40, 55, 65, 75, 90, 100, 120, 135, 150, 170, 190, 210, 241};
byte s = catGetSmeter();
SmetertoBCD(smap[s]);
#ifdef DEBUG_CAT_DETAIL
dbg = "doSmeter- s:";
dbg += String(s);
dbg += " map: ";
dbg += String(smap[s]);
dbg += " BCD: ";
for (int i = CAT_IX_SMETER; i < CAT_IX_SMETER+2; i++) {
dbg += String(cmdBuf[i], HEX);
dbg += " ";
}
catDebug.println(dbg.c_str());
#endif
} else {
cmdBuf[CAT_IX_SMETER] = 0; // user has not supplied S Meter function - keep the protocol happy
cmdBuf[CAT_IX_SMETER + 1] = 0;
}
sendResponse(cmdBuf, CAT_SZ_SMETER);
break;
case CAT_READ_SUB_SQL: // Squelch condition 0=closed, 1=open
cmdBuf[CAT_IX_SQUELCH] = 1;
send(cmdBuf, CAT_SZ_SQUELCH);
break;
}
}
///////////////////////////////////////////////////////////////////////////////////////////////////////
// doPtt() - process the CAT_PTT Command
// CAT_PTT calls the user supplied functions to either put the rig in to Tx or Rx or to request the rigs
// current Tx/Rx state
//
// A "read ptt" request does not have a data byte and is therefore one byte shorter
// than a "set ptt" request.
// 56 | E0 | 1C | 00 - Read request 1C is PTT command, sub-command 0 is uused, no data byte
// 56 | E0 | 1C | 00 | 01 - Set Tx, trailing data bit 1 for Tx, 0 for Rx
////////////////////////////////////////////////////////////////////////////////////////////////////////
void IC746::doPtt() {
if (cmdLength == CAT_RD_LEN_SUB) { // Read request
if (catGetPtt) {
cmdBuf[CAT_IX_PTT] = catGetPtt();
sendResponse(cmdBuf, CAT_SZ_PTT);
}
} else { // Set request
if (catSetPtt) {
if (cmdBuf[CAT_IX_PTT] == CAT_PTT_TX) {
catSetPtt(true);
} else {
catSetPtt(false);
}
}
sendAck(); // always acknowledge "set" commands
}
}
///////////////////////////////////////////////////////////////////////////////////////////////////////
// doSplit() - process the CAT_SPLIT Command
// Call user supplied function to turn split on or off
///////////////////////////////////////////////////////////////////////////////////////////////////////
void IC746::doSplit() {
switch (cmdBuf[CAT_IX_SUB_CMD]) {
case CAT_SPLIT_OFF:
if (catSplit) {
catSplit(false);
}
break;
case CAT_SPLIT_ON:
case CAT_SIMPLE_DUP:
if (catSplit) {
catSplit(true);
}
default:
break;
}
sendAck();
}
///////////////////////////////////////////////////////////////////////////////////////////////////////
// doSetVfo() - process the CAT_SET_VFO Command, calls user supplied functions
// SET_VFO with no sub-command selects VFO Tuning vice Memory Tuning (memory tuning is not implemented)
// SET_VFO has four sub-commands:
// VFOA or VFOB - directs the rig to make the selected VFO the active VFO
// VFO_A_TO_B - directs the rig to copy the make both VFO frequencies the same as the Active VFO
// VFO_SWAP - directs the rig to exchange VFOA and VFOB
///////////////////////////////////////////////////////////////////////////////////////////////////////
void IC746::doSetVfo() {
if (cmdLength == CAT_RD_LEN_NOSUB) { // No sub-command - sets VFO Tuning vice memory tuning
sendAck(); // Memory tuning is not implemented so send ack to keep protocol happy
return;
}
switch (cmdBuf[CAT_IX_SUB_CMD]) {
case CAT_VFO_A:
case CAT_VFO_B:
if (catSetVFO) {
catSetVFO(cmdBuf[CAT_IX_SUB_CMD]);
}
break;
case CAT_VFO_A_TO_B:
if (catAtoB) {
catAtoB();
}
break;
case CAT_VFO_SWAP:
if (catSwapVfo) {
catSwapVfo();
}
break;
}
sendAck();
}
///////////////////////////////////////////////////////////////////////////////////////////////////////
// doSetFreq() - proces CAT_SET_FREQ command
// Call the user supplied function to set the righ frequency
///////////////////////////////////////////////////////////////////////////////////////////////////////
void IC746::doSetFreq() {
if (catSetFreq) {
catSetFreq(BCDtoFreq()); // Convert the frequency BCD to Long and call the user function
}
sendAck();
}
///////////////////////////////////////////////////////////////////////////////////////////////////////
// doReadFreq() - process the CAT_READ_FREQ command
// Call the user supplied function to read set the rig frequency
// Frequecies are sent and received in BCD - call the support functions to do the conversion
///////////////////////////////////////////////////////////////////////////////////////////////////////
void IC746::doReadFreq() {
if (catGetFreq) {
// displayBanner(String("Read Freq"));
FreqtoBCD(catGetFreq()); // get the frequency, convert to BCD and stuff it in the response buffer
sendResponse(cmdBuf, CAT_SZ_FREQ);
}
}
///////////////////////////////////////////////////////////////////////////////////////////////////////
// doSetMode() - process the CAT_SET_MODE command
// Call the user function to put the rig into the requested mode.
// The rig must handle all of the possible modes
// CAT_MODE_LSB
// CAT_MODE_USB
// CAT_MODE_AM:
// CAT_MODE_CW - (LSB)
// CAT_MODE_RTTY - (LSB)
// CAT_MODE_FM
// CAT_MODE_CW_R - (Reverse - USB)
// CAT_MODE_RTTY_R - (Reverse - LSB)
///////////////////////////////////////////////////////////////////////////////////////////////////////
void IC746::doSetMode() {
if (catSetMode) {
catSetMode(cmdBuf[CAT_IX_SUB_CMD]);
}
sendAck();
}
///////////////////////////////////////////////////////////////////////////////////////////////////////
// doReadMode() - process the CAT_READ_MODE command
// Call the user function to query the rig's current mode
///////////////////////////////////////////////////////////////////////////////////////////////////////
void IC746::doReadMode() {
if (catGetMode) {
cmdBuf[CAT_IX_MODE] = catGetMode();
cmdBuf[CAT_IX_MODE+1] = CAT_MODE_FILTER1; // protocol filter - return reasonable value
sendResponse(cmdBuf, CAT_SZ_MODE);
}
}
///////////////////////////////////////////////////////////////////////////////////////////////////////
// doMisc() - process the CAT_MISC command
//
// The MISC command has several unrelated sub-commands
// The only one implemented here is the sub-command to read the IF Filter Setting
// The code sends a hard-coded response since most homebrew rigs won't have such a setting
// but programs like WSJTX and FLDIGI request it
//
// Commands that "set" values are replied to with an ACK message
///////////////////////////////////////////////////////////////////////////////////////////////////////
void IC746::doMisc() {
switch (cmdBuf[CAT_IX_SUB_CMD]) {
case CAT_READ_IF_FILTER:
cmdBuf[CAT_IX_IF_FILTER] = 0;
sendResponse(cmdBuf, CAT_SZ_IF_FILTER);
break;
// Not implemented
// Reply with ACK to keep the protocol happy
case CAT_SET_MEM_CHAN:
case CAT_SET_BANDSTACK:
case CAT_SET_MEM_KEYER:
sendAck();
break;
}
}
///////////////////////////////////////////////////////////////////////////////////////////////////////
// UNIMPLEMENTED COMMAND STUBS
///////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////
// doUnimplemented() - reasonable processing for features that are not fully implemented
//
// Unimplimented command handling
//
// These following commands are used to both set and read various parameters in the IC-746 that are not
// typically implemented in a homebrew transceiver.
// Commands requesting the state of various parameters require one or two data bytes returned.
// We return zero in all cases which typically means the requsted feature is OFF - eg AGC, NB, VOX, etc.
// Command that "set" various parameters only require an ACK reply
// A "read" request has no data byte and is one byte shorter than a set request (length =4)
///////////////////////////////////////////////////////////////////////////////////////////////////////
void IC746::doUnimplemented_1b() {
if (cmdLength == CAT_RD_LEN_SUB) { // Read request
cmdBuf[CAT_IX_DATA] = 0; // return 0 for all read requests
sendResponse(cmdBuf, CAT_SZ_UNIMP_1B);
} else { // Set parameter request
sendAck(); // Send an acknowledgement to keep the protocol happy
}
}
void IC746::doUnimplemented_2b() {
if (cmdLength == CAT_RD_LEN_SUB) { // Read request
cmdBuf[CAT_IX_DATA] = 0; // return 0 for all read requests
cmdBuf[CAT_IX_DATA+1] = 0;
sendResponse(cmdBuf, CAT_SZ_UNIMP_2B);
} else { // Set parameter request
sendAck(); // Send an acknowledgement to keep the protocol happy
}
}
void IC746::doTuneStep() {
if (cmdLength == CAT_RD_LEN_NOSUB) { // Read request
cmdBuf[CAT_IX_TUNE_STEP] = 0; // return 0 for all read requests
sendResponse(cmdBuf, CAT_SZ_TUNE_STEP);
} else { // Set parameter request
sendAck(); // Send an acknowledgement to keep the protocol happy
}
}
void IC746::doAntSel() {
if (cmdLength == CAT_RD_LEN_NOSUB) { // Read request
cmdBuf[CAT_IX_ANT_SEL] = 0; // return 0 for all read requests
sendResponse(cmdBuf, CAT_SZ_ANT_SEL);
} else { // Set parameter request
sendAck(); // Send an acknowledgement to keep the protocol happy
}
}
///////////////////////////////////////////////////////////////////////////////////////////////////////
// check() - process commands from CAT controller, should be called from the sketch main loop
///////////////////////////////////////////////////////////////////////////////////////////////////////
void IC746::check() {
// do nothing if it was disabled by software
if (!enabled) return;
// Receive a CAT Command
if (!readCmd()) return;
/*
#ifdef DEBUG_CAT_DETAIL
dbg = "rcvd: ";
dbg += String(cmdLength);
dbg += ": ";
for (int i = 0; i < cmdLength; i++) {
dbg += String(cmdBuf[i], HEX);
dbg += " ";
}
catDebug.println(dbg.c_str());
#endif
*/
// Process the command - command opcode is at CAT_IX_CMD location in command buffer
switch (cmdBuf[CAT_IX_CMD]) {
case CAT_PTT:
doPtt();
break;
case CAT_SPLIT:
doSplit();
break;
case CAT_SET_VFO:
doSetVfo();
break;
case CAT_SET_FREQ:
doSetFreq();
break;
case CAT_SET_MODE:
doSetMode();
break;
case CAT_READ_MODE:
doReadMode();
break;
case CAT_READ_FREQ:
doReadFreq();
break;
case CAT_READ_SMETER:
doSmeter();
break;
case CAT_MISC:
doMisc();
break;
case CAT_READ_ID:
cmdBuf[CAT_IX_ID] = CAT_RIG_ADDR; // Send back the transmitter ID
send(cmdBuf, CAT_SZ_ID);
break;
// Unimplemented commands that request one or two bytes of data from the rig - keep the protocol happy
case CAT_SET_RD_STEP:
doTuneStep();
break;
case CAT_SET_RD_ANT:
doAntSel();
break;
case CAT_SET_RD_ATT:
case CAT_SET_RD_PARAMS2:
doUnimplemented_1b();
break;
case CAT_SET_RD_PARAMS1:
case CAT_READ_OFFSET:
doUnimplemented_2b();
break;
default: // For all other commands respond with an NACK
#ifdef DEBUG_CAT
String dbg;
dbg = "unimp cmd: ";
dbg += String(cmdBuf[CAT_IX_CMD], HEX);
dbg += " ";
dbg += String(cmdBuf[CAT_IX_SUB_CMD], HEX);
// displayBanner(dbg);
catDebug.println(dbg.c_str());
#endif
sendNack();
break;
}
}
///////////////////////////////////////////////////////////////////////////////////////////////////////
//
// UTILITY FUNCTIONS
//
///////////////////////////////////////////////////////////////////////////////////////////////////////
//
// BCD FrequencyConversion Routines
// Convert BCD frequency to/from command buffer to/from long
// Format (beginning at first data byte in buffer is
// Byte 0 10Hz | 1Hz
// Byte 1 1KHz | 100Hz
// Byte 2 100KHz | 10KHz
// Byte 3 10MHz | 1MHz
// Example: 7,123,456 is encoded 56 | 34 | 12 | 07
//
long IC746::BCDtoFreq() {
long freq;
freq = cmdBuf[CAT_IX_FREQ] & 0xf; // lower 4 bits
freq += 10L * (cmdBuf[CAT_IX_FREQ] >> 4); // upper 4 bits
freq += 100L * (cmdBuf[CAT_IX_FREQ + 1] & 0xf);
freq += 1000L * (cmdBuf[CAT_IX_FREQ + 1] >> 4);
freq += 10000L * (cmdBuf[CAT_IX_FREQ + 2] & 0xf);
freq += 100000L * (cmdBuf[CAT_IX_FREQ + 2] >> 4);
freq += 1000000L * (cmdBuf[CAT_IX_FREQ + 3] & 0xf);
freq += 10000000L * (cmdBuf[CAT_IX_FREQ + 3] >> 4);
freq += 100000000L * (cmdBuf[CAT_IX_FREQ + 4] & 0xf);
freq += 1000000000L * (cmdBuf[CAT_IX_FREQ + 4] >> 4);
return freq;
}
void IC746::FreqtoBCD(long freq) {
byte ones, tens, hund, thou, ten_thou, hund_thou, mil, ten_mil, hund_mil, thou_mil;
ones = byte(freq % 10);
tens = byte((freq / 10L) % 10);
cmdBuf[CAT_IX_FREQ] = byte((tens << 4)) | ones;
hund = byte((freq / 100L) % 10);
thou = byte((freq / 1000L) % 10);
cmdBuf[CAT_IX_FREQ + 1] = byte((thou << 4)) | hund;
ten_thou = byte((freq / 10000L) % 10);
hund_thou = byte((freq / 100000L) % 10);
cmdBuf[CAT_IX_FREQ + 2] = byte((hund_thou << 4)) | ten_thou;
mil = byte((freq / 1000000L) % 10);
ten_mil = byte(freq / 10000000L) % 10;
cmdBuf[CAT_IX_FREQ + 3] = byte((ten_mil << 4)) | mil;
hund_mil = byte((freq / 100000000L) % 10);
thou_mil = byte(freq / 1000000000L % 10); // Allow frequencies up to 9999.999999 MHz to be enterd
cmdBuf[CAT_IX_FREQ + 4] = byte((thou_mil << 4)) | hund_mil;
}
void IC746::SmetertoBCD(byte s) {
byte ones, tens, hund;
ones = byte(s % 10);
tens = byte((s / byte(10)) % 10);
cmdBuf[CAT_IX_SMETER+1] = byte((tens << 4)) | ones;
hund = byte((s / byte(100)) % 10);
cmdBuf[CAT_IX_SMETER] = hund;
}