2019-12-18 01:32:44 -05:00
# include <Arduino.h>
2020-01-04 02:11:55 -05:00
# include "settings.h"
2019-12-18 01:32:44 -05:00
# include "ubitx.h"
# include "nano_gui.h"
/**
* 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
*/
static unsigned long rxBufferArriveTime = 0 ;
static byte rxBufferCheckCount = 0 ;
# define CAT_RECEIVE_TIMEOUT 500
static byte cat [ 5 ] ;
static byte insideCat = 0 ;
static byte useOpenRadioControl = 0 ;
//for broken protocol
# define CAT_RECEIVE_TIMEOUT 500
# define CAT_MODE_LSB 0x00
# define CAT_MODE_USB 0x01
# define CAT_MODE_CW 0x02
# define CAT_MODE_CWR 0x03
# define CAT_MODE_AM 0x04
# define CAT_MODE_FM 0x08
# define CAT_MODE_DIG 0x0A
# define CAT_MODE_PKT 0x0C
# define CAT_MODE_FMN 0x88
# define ACK 0
unsigned int skipTimeCount = 0 ;
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 ;
}
//void ReadEEPRom_FT817(byte fromType)
void catReadEEPRom ( void )
{
//for remove warnings
byte temp0 = cat [ 0 ] ;
byte temp1 = cat [ 1 ] ;
/*
itoa ( ( int ) cat [ 0 ] , b , 16 ) ;
strcat ( b , " : " ) ;
itoa ( ( int ) cat [ 1 ] , c , 16 ) ;
strcat ( b , c ) ;
printLine2 ( b ) ;
*/
cat [ 0 ] = 0 ;
cat [ 1 ] = 0 ;
//for remove warnings[1] = 0;
switch ( temp1 )
{
case 0x45 : //
if ( temp0 = = 0x03 )
{
cat [ 0 ] = 0x00 ;
cat [ 1 ] = 0xD0 ;
}
break ;
case 0x47 : //
if ( temp0 = = 0x03 )
{
cat [ 0 ] = 0xDC ;
cat [ 1 ] = 0xE0 ;
}
break ;
case 0x55 :
//0 : VFO A/B 0 = VFO-A, 1 = VFO-B
//1 : MTQMB Select 0 = (Not MTQMB), 1 = MTQMB ("Memory Tune Quick Memory Bank")
//2 : QMB Select 0 = (Not QMB), 1 = QMB ("Quick Memory Bank")
//3 :
//4 : Home Select 0 = (Not HOME), 1 = HOME memory
//5 : Memory/MTUNE select 0 = Memory, 1 = MTUNE
//6 :
//7 : MEM/VFO Select 0 = Memory, 1 = VFO (A or B - see bit 0)
2020-01-04 02:11:55 -05:00
cat [ 0 ] = 0x80 + ( ( VFO_B = = globalSettings . activeVfo ) ? 1 : 0 ) ;
2019-12-18 01:32:44 -05:00
cat [ 1 ] = 0x00 ;
break ;
case 0x57 : //
//0 : 1-0 AGC Mode 00 = Auto, 01 = Fast, 10 = Slow, 11 = Off
//2 DSP On/Off 0 = Off, 1 = On (Display format)
//4 PBT On/Off 0 = Off, 1 = On (Passband Tuning)
//5 NB On/Off 0 = Off, 1 = On (Noise Blanker)
//6 Lock On/Off 0 = Off, 1 = On (Dial Lock)
//7 FST (Fast Tuning) On/Off 0 = Off, 1 = On (Fast tuning)
cat [ 0 ] = 0xC0 ;
cat [ 1 ] = 0x40 ;
break ;
case 0x59 : // band select VFO A Band Select 0000 = 160 M, 0001 = 75 M, 0010 = 40 M, 0011 = 30 M, 0100 = 20 M, 0101 = 17 M, 0110 = 15 M, 0111 = 12 M, 1000 = 10 M, 1001 = 6 M, 1010 = FM BCB, 1011 = Air, 1100 = 2 M, 1101 = UHF, 1110 = (Phantom)
//http://www.ka7oei.com/ft817_memmap.html
//CAT_BUFF[0] = 0xC2;
//CAT_BUFF[1] = 0x82;
break ;
case 0x5C : //Beep Volume (0-100) (#13)
cat [ 0 ] = 0xB2 ;
cat [ 1 ] = 0x42 ;
break ;
case 0x5E :
//3-0 : CW Pitch (300-1000 Hz) (#20) From 0 to E (HEX) with 0 = 300 Hz and each step representing 50 Hz
//5-4 : Lock Mode (#32) 00 = Dial, 01 = Freq, 10 = Panel
//7-6 : Op Filter (#38) 00 = Off, 01 = SSB, 10 = CW
//CAT_BUFF[0] = 0x08;
2020-01-04 02:11:55 -05:00
cat [ 0 ] = ( globalSettings . cwSideToneFreq - 300 ) / 50 ;
2019-12-18 01:32:44 -05:00
cat [ 1 ] = 0x25 ;
break ;
2020-01-04 02:11:55 -05:00
case 0x61 : //globalSettings.cwSideToneFreq (Volume) (#44)
cat [ 0 ] = globalSettings . cwSideToneFreq % 50 ;
2019-12-18 01:32:44 -05:00
cat [ 1 ] = 0x08 ;
break ;
case 0x5F : //
//4-0 CW Weight (1.:2.5-1:4.5) (#22) From 0 to 14 (HEX) with 0 = 1:2.5, incrementing in 0.1 weight steps
//5 420 ARS (#2) 0 = Off, 1 = On
//6 144 ARS (#1) 0 = Off, 1 = On
//7 Sql/RF-G (#45) 0 = Off, 1 = On
cat [ 0 ] = 0x32 ;
cat [ 1 ] = 0x08 ;
break ;
case 0x60 : //CW Delay (10-2500 ms) (#17) From 1 to 250 (decimal) with each step representing 10 ms
2020-01-04 02:11:55 -05:00
cat [ 0 ] = globalSettings . cwActiveTimeoutMs / 10 ;
2019-12-18 01:32:44 -05:00
cat [ 1 ] = 0x32 ;
break ;
case 0x62 : //
//5-0 CW Speed (4-60 WPM) (#21) From 0 to 38 (HEX) with 0 = 4 WPM and 38 = 60 WPM (1 WPM steps)
//7-6 Batt-Chg (6/8/10 Hours (#11) 00 = 6 Hours, 01 = 8 Hours, 10 = 10 Hours
//CAT_BUFF[0] = 0x08;
2020-01-04 02:43:33 -05:00
cat [ 0 ] = 1200 / globalSettings . cwDitDurationMs - 4 ;
2019-12-18 01:32:44 -05:00
cat [ 1 ] = 0xB2 ;
break ;
case 0x63 : //
//6-0 VOX Gain (#51) Contains 1-100 (decimal) as displayed
//7 Disable AM/FM Dial (#4) 0 = Enable, 1 = Disable
cat [ 0 ] = 0xB2 ;
cat [ 1 ] = 0xA5 ;
break ;
case 0x64 : //
break ;
case 0x67 : //6-0 SSB Mic (#46) Contains 0-100 (decimal) as displayed
cat [ 0 ] = 0xB2 ;
cat [ 1 ] = 0xB2 ;
break ; case 0x69 : //FM Mic (#29) Contains 0-100 (decimal) as displayed
case 0x78 :
2020-01-04 02:11:55 -05:00
if ( VfoMode_e : : VFO_MODE_USB = = GetActiveVfoMode ( ) )
2019-12-18 01:32:44 -05:00
cat [ 0 ] = CAT_MODE_USB ;
else
cat [ 0 ] = CAT_MODE_LSB ;
if ( cat [ 0 ] ! = 0 ) cat [ 0 ] = 1 < < 5 ;
break ;
case 0x79 : //
//1-0 TX Power (All bands) 00 = High, 01 = L3, 10 = L2, 11 = L1
//3 PRI On/Off 0 = Off, 1 = On
//DW On/Off 0 = Off, 1 = On
//SCN (Scan) Mode 00 = No scan, 10 = Scan up, 11 = Scan down
//ART On/Off 0 = Off, 1 = On
cat [ 0 ] = 0x00 ;
cat [ 1 ] = 0x00 ;
break ;
case 0x7A : //SPLIT
//7A 0 HF Antenna Select 0 = Front, 1 = Rear
//7A 1 6 M Antenna Select 0 = Front, 1 = Rear
//7A 2 FM BCB Antenna Select 0 = Front, 1 = Rear
//7A 3 Air Antenna Select 0 = Front, 1 = Rear
//7A 4 2 M Antenna Select 0 = Front, 1 = Rear
//7A 5 UHF Antenna Select 0 = Front, 1 = Rear
//7A 6 ? ?
//7A 7 SPL On/Off 0 = Off, 1 = On
2020-01-04 02:11:55 -05:00
cat [ 0 ] = ( globalSettings . splitOn ? 0xFF : 0x7F ) ;
2019-12-18 01:32:44 -05:00
break ;
case 0xB3 : //
cat [ 0 ] = 0x00 ;
cat [ 1 ] = 0x4D ;
break ;
}
// sent the data
Serial . write ( cat , 2 ) ;
}
void processCATCommand2 ( byte * cmd ) {
byte response [ 5 ] ;
unsigned long f ;
switch ( cmd [ 4 ] ) {
/* case 0x00:
response [ 0 ] = 0 ;
Serial . write ( response , 1 ) ;
break ;
*/
case 0x01 :
//set frequency
f = readFreq ( cmd ) ;
setFrequency ( f ) ;
updateDisplay ( ) ;
response [ 0 ] = 0 ;
Serial . write ( response , 1 ) ;
//sprintf(b, "set:%ld", f);
//printLine2(b);
break ;
case 0x02 :
//split on
2020-01-04 02:11:55 -05:00
globalSettings . splitOn = 1 ;
2019-12-18 01:32:44 -05:00
break ;
case 0x82 :
//split off
2020-01-04 02:11:55 -05:00
globalSettings . splitOn = 0 ;
2019-12-18 01:32:44 -05:00
break ;
case 0x03 :
2020-01-04 02:11:55 -05:00
writeFreq ( GetActiveVfoFreq ( ) , response ) ; // Put the frequency into the buffer
if ( VfoMode_e : : VFO_MODE_USB = = GetActiveVfoMode ( ) )
2019-12-18 01:32:44 -05:00
response [ 4 ] = 0x01 ; //USB
else
response [ 4 ] = 0x00 ; //LSB
Serial . write ( response , 5 ) ;
//printLine2("cat:getfreq");
break ;
case 0x07 : // set mode
if ( cmd [ 0 ] = = 0x00 | | cmd [ 0 ] = = 0x03 )
2020-01-04 02:11:55 -05:00
SetActiveVfoMode ( VfoMode_e : : VFO_MODE_LSB ) ;
2019-12-18 01:32:44 -05:00
else
2020-01-04 02:11:55 -05:00
SetActiveVfoMode ( VfoMode_e : : VFO_MODE_USB ) ;
2019-12-18 01:32:44 -05:00
response [ 0 ] = 0x00 ;
Serial . write ( response , 1 ) ;
2020-01-04 02:11:55 -05:00
setFrequency ( GetActiveVfoFreq ( ) ) ;
2019-12-18 01:32:44 -05:00
//printLine2("cat: mode changed");
//updateDisplay();
break ;
case 0x08 : // PTT On
2020-01-04 02:11:55 -05:00
if ( ! globalSettings . txActive ) {
2019-12-18 01:32:44 -05:00
response [ 0 ] = 0 ;
2020-01-04 02:11:55 -05:00
globalSettings . txCatActive = true ;
startTx ( TuningMode_e : : TUNE_SSB ) ;
2019-12-18 01:32:44 -05:00
updateDisplay ( ) ;
} else {
response [ 0 ] = 0xf0 ;
}
Serial . write ( response , 1 ) ;
updateDisplay ( ) ;
break ;
case 0x88 : //PTT OFF
2020-01-04 02:11:55 -05:00
if ( globalSettings . txActive ) {
2019-12-18 01:32:44 -05:00
stopTx ( ) ;
2020-01-04 02:11:55 -05:00
globalSettings . txCatActive = false ;
2019-12-18 01:32:44 -05:00
}
response [ 0 ] = 0 ;
Serial . write ( response , 1 ) ;
updateDisplay ( ) ;
break ;
case 0x81 :
//toggle the VFOs
response [ 0 ] = 0 ;
2020-01-04 02:11:55 -05:00
if ( VFO_A = = globalSettings . activeVfo )
2019-12-18 01:32:44 -05:00
switchVFO ( VFO_B ) ;
else
switchVFO ( VFO_A ) ;
//menuVfoToggle(1); // '1' forces it to change the VFO
Serial . write ( response , 1 ) ;
updateDisplay ( ) ;
break ;
case 0xBB : //Read FT-817 EEPROM Data (for comfirtable)
catReadEEPRom ( ) ;
break ;
case 0xe7 :
// get receiver status, we have hardcoded this as
//as we dont' support ctcss, etc.
response [ 0 ] = 0x09 ;
Serial . write ( response , 1 ) ;
break ;
case 0xf7 :
{
boolean isHighSWR = false ;
2020-01-04 02:11:55 -05:00
boolean issplitOn = false ;
2019-12-18 01:32:44 -05:00
/*
Inverted - > * ptt = ( ( p - > tx_status & 0x80 ) = = 0 ) ; < - - souce code in ft817 . c ( hamlib )
*/
2020-01-04 02:11:55 -05:00
response [ 0 ] = ( ( globalSettings . txActive ? 0 : 1 ) < < 7 ) +
2019-12-18 01:32:44 -05:00
( ( isHighSWR ? 1 : 0 ) < < 6 ) + //hi swr off / on
2020-01-04 02:11:55 -05:00
( ( issplitOn ? 1 : 0 ) < < 5 ) + //Split on / off
2019-12-18 01:32:44 -05:00
( 0 < < 4 ) + //dummy data
0x08 ; //P0 meter data
Serial . write ( response , 1 ) ;
}
break ;
default :
//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 ] ) ;
}
insideCat = false ;
}
int catCount = 0 ;
void checkCAT ( ) {
byte i ;
//Check Serial Port Buffer
if ( Serial . available ( ) = = 0 ) { //Set Buffer Clear status
rxBufferCheckCount = 0 ;
return ;
}
else if ( Serial . available ( ) < 5 ) { //First Arrived
if ( rxBufferCheckCount = = 0 ) {
rxBufferCheckCount = Serial . available ( ) ;
rxBufferArriveTime = millis ( ) + CAT_RECEIVE_TIMEOUT ; //Set time for timeout
}
else if ( rxBufferArriveTime < millis ( ) ) { //Clear Buffer
for ( i = 0 ; i < Serial . available ( ) ; i + + )
rxBufferCheckCount = Serial . read ( ) ;
rxBufferCheckCount = 0 ;
}
else if ( rxBufferCheckCount < Serial . available ( ) ) { // Increase buffer count, slow arrive
rxBufferCheckCount = Serial . available ( ) ;
rxBufferArriveTime = millis ( ) + CAT_RECEIVE_TIMEOUT ; //Set time for timeout
}
return ;
}
//Arived CAT DATA
for ( i = 0 ; i < 5 ; i + + )
cat [ i ] = Serial . read ( ) ;
//this code is not re-entrant.
if ( insideCat = = 1 )
return ;
insideCat = 1 ;
/**
* This routine is enabled to debug the cat protocol
* */
catCount + + ;
/*
if ( cat [ 4 ] ! = 0xf7 & & cat [ 4 ] ! = 0xbb & & cat [ 4 ] ! = 0x03 ) {
sprintf ( b , " %d %02x %02x%02x%02x%02x " , catCount , cat [ 4 ] , cat [ 0 ] , cat [ 1 ] , cat [ 2 ] , cat [ 3 ] ) ;
printLine2 ( b ) ;
}
*/
/*
if ( ! doingCAT ) {
doingCAT = 1 ;
displayText ( " CAT on " , 100 , 120 , 100 , 40 , ILI9341_ORANGE , ILI9341_BLACK , ILI9341_WHITE ) ;
}
*/
processCATCommand2 ( cat ) ;
insideCat = 0 ;
}