ubitx-upr/ubitx_20/ubitx_cat.ino

232 lines
5.5 KiB
C++

/**
* The CAT protocol is used by many radios to provide remote control to comptuers through
* the serial port.
*
* This is very much a work in progress. Parts of this code have been liberally
* borrowed from other GPLicensed works like hamlib.
*
* WARNING : This is an unstable version and it has worked with fldigi,
* it gives time out error with WSJTX 1.8.0
*/
// The next 4 functions are needed to implement the CAT protocol, which
// uses 4-bit BCD formatting.
//
byte setHighNibble(byte b,byte v) {
// Clear the high nibble
b &= 0x0f;
// Set the high nibble
return b | ((v & 0x0f) << 4);
}
byte setLowNibble(byte b,byte v) {
// Clear the low nibble
b &= 0xf0;
// Set the low nibble
return b | (v & 0x0f);
}
byte getHighNibble(byte b) {
return (b >> 4) & 0x0f;
}
byte getLowNibble(byte b) {
return b & 0x0f;
}
// Takes a number and produces the requested number of decimal digits, staring
// from the least significant digit.
//
void getDecimalDigits(unsigned long number,byte* result,int digits) {
for (int i = 0; i < digits; i++) {
// "Mask off" (in a decimal sense) the LSD and return it
result[i] = number % 10;
// "Shift right" (in a decimal sense)
number /= 10;
}
}
// Takes a frequency and writes it into the CAT command buffer in BCD form.
//
void writeFreq(unsigned long freq,byte* cmd) {
// Convert the frequency to a set of decimal digits. We are taking 9 digits
// so that we can get up to 999 MHz. But the protocol doesn't care about the
// LSD (1's place), so we ignore that digit.
byte digits[9];
getDecimalDigits(freq,digits,9);
// Start from the LSB and get each nibble
cmd[3] = setLowNibble(cmd[3],digits[1]);
cmd[3] = setHighNibble(cmd[3],digits[2]);
cmd[2] = setLowNibble(cmd[2],digits[3]);
cmd[2] = setHighNibble(cmd[2],digits[4]);
cmd[1] = setLowNibble(cmd[1],digits[5]);
cmd[1] = setHighNibble(cmd[1],digits[6]);
cmd[0] = setLowNibble(cmd[0],digits[7]);
cmd[0] = setHighNibble(cmd[0],digits[8]);
}
// This function takes a frquency that is encoded using 4 bytes of BCD
// representation and turns it into an long measured in Hz.
//
// [12][34][56][78] = 123.45678? Mhz
//
unsigned long readFreq(byte* cmd) {
// Pull off each of the digits
byte d7 = getHighNibble(cmd[0]);
byte d6 = getLowNibble(cmd[0]);
byte d5 = getHighNibble(cmd[1]);
byte d4 = getLowNibble(cmd[1]);
byte d3 = getHighNibble(cmd[2]);
byte d2 = getLowNibble(cmd[2]);
byte d1 = getHighNibble(cmd[3]);
byte d0 = getLowNibble(cmd[3]);
return
(unsigned long)d7 * 100000000L +
(unsigned long)d6 * 10000000L +
(unsigned long)d5 * 1000000L +
(unsigned long)d4 * 100000L +
(unsigned long)d3 * 10000L +
(unsigned long)d2 * 1000L +
(unsigned long)d1 * 100L +
(unsigned long)d0 * 10L;
}
/**
* Responds to all the cat commands, emulates FT-817
*/
void processCATCommand(byte* cmd) {
byte response[5];
// Debugging code, enable it to fix the cat implementation
count++;
if (cmd[4] == 0x00){
response[0]=0;
Serial.write(response, 1);
}
else if (cmd[4] == 0x01) {
unsigned long f = readFreq(cmd);
setFrequency(f);
updateDisplay();
//sprintf(b, "set:%ld", f);
//printLine2(b);
}
// Get frequency
else if (cmd[4] == 0x03){
writeFreq(frequency,response); // Put the frequency into the buffer
if (isUSB)
response[4] = 0x01; //USB
else
response[4] = 0x00; //LSB
Serial.write(response,5);
printLine2("cat:getfreq");
}
else if (cmd[4] == 0x07){ // set mode
if (cmd[0] == 0x00 || cmd[0] == 0x03)
isUSB = 0;
else
isUSB = 1;
response[0] = 0x00;
Serial.write(response, 1);
setFrequency(frequency);
//printLine2("cat: mode changed");
//updateDisplay();
}
else if (cmd[4] == 0x88){
if (inTx){
stopTx();
txCAT = false;
}
else
response[0] = 0xf0;
printLine2("tx > rx");
Serial.write(response,1);
}
else if (cmd[4] == 0x08) { // PTT On
if (!inTx) {
response[0] = 0;
txCAT = true;
startTx(TX_SSB);
updateDisplay();
} else {
response[0] = 0xf0;
}
Serial.write(response,1);
printLine2("rx > tx");
}
// Read TX keyed state
else if (cmd[4] == 0x10) {
if (!inTx) {
response[0] = 0;
} else {
response[0] = 0xf0;
}
Serial.write(response,1);
printLine2("cat;0x10");
}
// PTT Off
else if (cmd[4] == 0x88) {
byte resBuf[0];
if (inTx) {
response[0] = 0;
} else {
response[0] = 0xf0;
}
Serial.write(response,1);
printLine2("cat;0x88");
//keyed = false;
//digitalWrite(13,LOW);
}
// Read receiver status
else if (cmd[4] == 0xe7) {
response[0] = 0x09;
Serial.write(response,1);
printLine2("cat;0xe7");
}
else if (cmd[4] == 0xf5){
}
// Read receiver status
else if (cmd[4] == 0xf7) {
response[0] = 0x00;
if (inTx) {
response[0] = response[0] | 0xf0;
}
Serial.write(response,1);
printLine2("cat;0xf7");
}
else {
//somehow, get this to print the four bytes
ultoa(*((unsigned long *)cmd), c, 16);
itoa(cmd[4], b, 16);
strcat(b, ":");
strcat(b, c);
printLine2(b);
response[0] = 0x00;
Serial.write(response[0]);
}
}
void checkCAT(){
static byte cat[5];
byte i;
if (Serial.available() < 5)
return;
cat[4] = cat[3];
cat[3] = cat[2];
cat[2] = cat[0];
for (i = 0; i < 5; i++)
cat[i] = Serial.read();
processCATCommand(cat);
}