/************************************************************************* KD8CEC's CAT Library for uBITX and HAM This source code is written for uBITX, but it can also be used on other radios. The CAT protocol is used by many radios to provide remote control to comptuers through the serial port. it is based on FT-817, uBITX's only protocol has been added and will be added in the future. In addition, simple things such as FT-857 frequency control and PTT control can also be transmitted to the FT-857 protocol. This code refers to the following code. - FT857D CAT Library, by Pavel Milanes, CO7WT, pavelmc@gmail.com https://github.com/pavelmc/FT857d/ - Ham Radio Control Libraries, https://sourceforge.net/projects/hamlib/ - Not found protocols decription were analyzed using an RS-232 analyzer. using FT-817 and - http://www.ka7oei.com/ft817_meow.html <-- It was a great help here. ----------------------------------------------------------------------------- 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 . **************************************************************************/ #include #include "ubitx.h" //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 /* * KC4UPR - IOP update, 2020-05-03 * * Send the current mode to the I/O Processor. */ void iopSendMode(char cw_mode, char is_usb, char digi_mode, char is_test) { byte mode; if (cw_mode > 0) { mode = (cw_mode == 1 ? RIG_MODE_CWL : RIG_MODE_CWU); } else if (digi_mode > 0) { mode = (is_usb ? RIG_MODE_DGU : RIG_MODE_DGL); } else if (is_test) { mode = (is_usb ? RIG_MODE_TTU : RIG_MODE_TTL); } else { mode = (is_usb ? RIG_MODE_USB : RIG_MODE_LSB); } sendIOPModeCommand(mode); } unsigned int skipTimeCount = 0; byte CAT_BUFF[34]; byte CAT_SNDBUFF[34]; void SendCatData(byte sendCount) { // KC4UPR--uBITX IOP: Adding an additional byte at the beginning that // indicates that this is a "CAT mode" transmission. Extra byte includes // a prefix, as well as the number of bytes being sent. // // NOTE: Need to do some error checking at some point to ensure we don't // try to send more than 15 bytes!!! Serial.write(prefixAndLengthToByte(CAT_PREFIX, sendCount)); for (byte i = 0; i < sendCount; i++) Serial.write(CAT_BUFF[i]); //Serial.flush(); } //PROTOCOL : 0x01 //Computer ->(frequency)-> TRCV CAT_BUFF void CatSetFreq(byte fromType) { //CAT_BUFF byte i; unsigned long tempFreq = 0; if (fromType == 2 || fromType == 3) { Serial.write(ACK); return; } //2 digit in 1 byte (4 bit + 4bit) * 4.5 byte for (i = 0; i < 4; i++) { tempFreq *= 10; tempFreq += CAT_BUFF[i] >> 4; tempFreq *= 10; tempFreq += CAT_BUFF[i] & 0x0f; } tempFreq *= 10; tempFreq += CAT_BUFF[4] >> 4; if (!inTx && (frequency != tempFreq)) { //Check Frequency Range if (tempFreq >= LOWEST_FREQ_DIAL && tempFreq <= HIGHEST_FREQ_DIAL) { setFrequency(tempFreq); updateDisplay(); } else { //KD8CEC //Remark for rduce program size, if you need, you can remove remark, //however alomost rig control software available 1.0 ~ 50Mhz //printLine(0, "OUT OF RANGE!!!"); //delay_background(300, 0); } } Serial.write(ACK); } //#define BCD_LEN 9 //PROTOCOL : 0x03 //Computer <-(frequency)-> TRCV CAT_BUFF //void CatGetFreqMode(unsigned long freq, byte fromType) void CatGetFreqMode(unsigned long freq) //for remove warning messages { int i; byte tmpValue; unsigned BCD_LEN = 9; if (BCD_LEN & 1) { CAT_BUFF[BCD_LEN / 2] &= 0x0f; CAT_BUFF[BCD_LEN / 2] |= (freq % 10) << 4; freq /= 10; } for (i = (BCD_LEN / 2) - 1; i >= 0; i--) { tmpValue = freq % 10; freq /= 10; tmpValue |= (freq % 10) << 4; freq /= 10; CAT_BUFF[i] = tmpValue; } //Mode Check if (cwMode == 0) { if (isUSB) CAT_BUFF[4] = CAT_MODE_USB; else CAT_BUFF[4] = CAT_MODE_LSB; } else if (cwMode == 1) { CAT_BUFF[4] = CAT_MODE_CW; } else { CAT_BUFF[4] = CAT_MODE_CW; } SendCatData(5); } //void CatSetSplit(boolean isSplit, byte fromType) void CatSetSplit(boolean isSplit) //for remove warning messages { if (isSplit) splitOn = 1; else splitOn = 0; Serial.write(ACK); } void CatSetPTT(boolean isPTTOn, byte fromType) { // KC4UPR - so I think this means, that if we're currently processing a CW keyer (auto/manual), // not to accept a CAT command in the middle of it. if ((!inTx) && (fromType == 2 || fromType == 3)) { Serial.write(ACK); return; } // Set PTT Mode if (isPTTOn) { if (!inTx) { txCAT = true; // KC4UPR - added the next line to tell the IOP we're transmitting sendIOPStartTxCommand(); startTx(TX_SSB, 1); //Exit menu, Memory Keyer... ETC if (isCWAutoMode > 0) { isCWAutoMode = 0; printLineF2(F("AutoKey Exit/CAT")); //delay_background(1000, 0); } } } else { if (inTx) { // KC4UPR - added the next line to tell the IOP we're not transmitting sendIOPStopTxCommand(); stopTx(); txCAT = false; } } Serial.write(ACK); } void CatVFOToggle(boolean isSendACK, byte fromType) { if (fromType != 2 && fromType != 3) { menuVfoToggle(1); } if (isSendACK) Serial.write(ACK); //Time } void CatSetMode(byte tmpMode, byte fromType) { if (fromType == 2 || fromType == 3) { Serial.write(ACK); return; } if (!inTx) { switch(tmpMode) { case CAT_MODE_CW: cwMode = 2; // should be CWU break; case CAT_MODE_CWR: cwMode = 1; // should be CWL break; case CAT_MODE_USB: cwMode = 0; digiMode = 0; isUSB = true; break; case CAT_MODE_LSB: cwMode = 0; digiMode = 0; isUSB = false; break; case CAT_MODE_DIG: cwMode = 0; digiMode = 1; isUSB = true; // DGU - but need to eventually use the FT-817 customization } iopSendMode(cwMode, isUSB, digiMode, isTest); setFrequency(frequency); updateDisplay(); } Serial.write(ACK); } //Read EEProm by uBITX Manager Software //void ReadEEPRom(byte fromType) void ReadEEPRom() //for remove warnings. { //5BYTES //CAT_BUFF[0] [1] [2] [3] [4] //4 COMMAND //0, 1 START ADDRESS uint16_t eepromStartIndex = CAT_BUFF[0] + CAT_BUFF[1] * 256; uint16_t eepromReadLength = CAT_BUFF[2] + CAT_BUFF[3] * 256;; byte checkSum = 0; byte read1Byte = 0; // KC4UPR--uBITX IOP: Adding an additional byte at the beginning that // indicates that this is a "Memory Manager mode" transmission. // Then we repeat some of the CAT_BUFF data. Serial.write(prefixAndLengthToByte(RAD_EEPROM_READ_PREFIX, 5)); Serial.write(CAT_BUFF[0]); Serial.write(CAT_BUFF[1]); Serial.write(CAT_BUFF[2]); Serial.write(CAT_BUFF[3]); Serial.write(0x02); //STX checkSum = 0x02; //I2C Scanner //Magic Key Start 59414, Length : 48583 //if (eepromStartIndex == 59414 && eepromReadLength == 48583) if (CAT_BUFF[0] == 0x16 && CAT_BUFF[1] == 0xe8) { for (uint8_t i = 1; i < 127; i++) { Wire.beginTransmission(i); read1Byte = Wire.endTransmission(); if (read1Byte == 0) { Serial.write(i); } else { Serial.write(0); } } } else { for (uint16_t i = 0; i < eepromReadLength; i++) { read1Byte = EEPROM.read(eepromStartIndex + i); checkSum += read1Byte; Serial.write(read1Byte); } } Serial.write(checkSum); Serial.write(ACK); } //Write just proecess 1byes //void WriteEEPRom(byte fromType) void WriteEEPRom(void) //for remove warning { //5BYTES uint16_t eepromStartIndex = CAT_BUFF[0] + CAT_BUFF[1] * 256; byte write1Byte = CAT_BUFF[2]; // KC4UPR--uBITX IOP: Adding an additional byte at the beginning that // indicates that this is a "Memory Manager mode" transmission. // // Also indicates that we are going to be sending two bytes of data. Serial.write(prefixAndLengthToByte(RAD_EEPROM_WRITE_PREFIX, 2)); //Check Checksum if (CAT_BUFF[3] != ((CAT_BUFF[0] + CAT_BUFF[1] + CAT_BUFF[2]) % 256)) { Serial.write(0x56); //CHECK SUM ERROR Serial.write(ACK); } else { //Special Command if (eepromStartIndex == 13131) //Magic Key { if (write1Byte == 0x51) //Restart { asm volatile (" jmp 0"); } } else { EEPROM.write(eepromStartIndex, write1Byte); } Serial.write(0x77); //OK Serial.write(ACK); } } //void ReadEEPRom_FT817(byte fromType) void ReadEEPRom_FT817(void) //for remove warnings { byte temp0 = CAT_BUFF[0]; byte temp1 = CAT_BUFF[1]; CAT_BUFF[0] = 0; CAT_BUFF[1] = 0; switch (temp1) { case 0x45 : // if (temp0 == 0x03) { CAT_BUFF[0] = 0x00; CAT_BUFF[1] = 0xD0; } break; case 0x47 : // if (temp0 == 0x03) { CAT_BUFF[0] = 0xDC; CAT_BUFF[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) CAT_BUFF[0] = 0x80 + (vfoActive == VFO_B ? 1 : 0); CAT_BUFF[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_BUFF[0] = 0xC0; CAT_BUFF[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_BUFF[0] = 0xB2; CAT_BUFF[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; CAT_BUFF[0] = sideTonePitch; CAT_BUFF[1] = 0x25; break; case 0x61 : //Sidetone (Volume) (#44) CAT_BUFF[0] = sideToneSub; CAT_BUFF[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_BUFF[0] = 0x32; CAT_BUFF[1] = 0x08; break; case 0x60 : //CW Delay (10-2500 ms) (#17) From 1 to 250 (decimal) with each step representing 10 ms CAT_BUFF[0] = cwDelayTime; CAT_BUFF[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; CAT_BUFF[0] = 1200 / cwSpeed - 4; CAT_BUFF[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_BUFF[0] = 0xB2; CAT_BUFF[1] = 0xA5; break; case 0x64 : // break; case 0x67 : //6-0 SSB Mic (#46) Contains 0-100 (decimal) as displayed CAT_BUFF[0] = 0xB2; CAT_BUFF[1] = 0xB2; break; case 0x69 : //FM Mic (#29) Contains 0-100 (decimal) as displayed case 0x78 : if (cwMode == 0) { if (isUSB) CAT_BUFF[0] = CAT_MODE_USB; else CAT_BUFF[0] = CAT_MODE_LSB; } else if (cwMode == 1) { CAT_BUFF[0] = CAT_MODE_CW; } else if (cwMode == 2) { CAT_BUFF[0] = CAT_MODE_CW; } if (CAT_BUFF[0] != 0) CAT_BUFF[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_BUFF[0] = 0x00; CAT_BUFF[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 CAT_BUFF[0] = (splitOn ? 0xFF : 0x7F); break; case 0xB3 : // CAT_BUFF[0] = 0x00; CAT_BUFF[1] = 0x4D; break; } // sent the data SendCatData(2); } void WriteEEPRom_FT817(byte fromType) { //byte temp0 = CAT_BUFF[0]; byte temp1 = CAT_BUFF[1]; CAT_BUFF[0] = 0; CAT_BUFF[1] = 0; if (fromType == 2 || fromType == 3) { SendCatData(2); Serial.write(ACK); return; } switch (temp1) { 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) if (CAT_BUFF[2] & 0x01) //vfoB { //nowVFO Check if (vfoActive != VFO_B) { CatVFOToggle(false, fromType); } } else { //vfoA if (vfoActive != VFO_A) { CatVFOToggle(false, fromType); } } 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_BUFF[0] = 0xC0; CAT_BUFF[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_BUFF[0] = 0xB2; CAT_BUFF[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 sideTonePitch = (CAT_BUFF[2] & 0x0F); if (sideTonePitch != 0 || sideToneSub != 0) { sideTone = (sideTonePitch * 50 + 300) + sideToneSub; printLineF2(F("Sidetone set! CAT")); EEPROM.put(CW_SIDETONE, sideTone); delay(300); //If timeout errors occur in the calling software, remove them clearLine2(); } break; case 0x61 : //Sidetone (Volume) (#44) sideToneSub = (CAT_BUFF[2] & 0x7F); if (sideTonePitch != 0 || sideToneSub != 0) { sideTone = (sideTonePitch * 50 + 300) + sideToneSub; printLineF2(F("Sidetone set! CAT")); EEPROM.put(CW_SIDETONE, sideTone); delay(300); //If timeout errors occur in the calling software, remove them clearLine2(); line2DisplayStatus = 0; } 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_BUFF[0] = 0x32; CAT_BUFF[1] = 0x08; break; */ case 0x60 : //CW Delay (10-2500 ms) (#17) From 1 to 250 (decimal) with each step representing 10 ms //CAT_BUFF[0] = 0x19; cwDelayTime = CAT_BUFF[2]; printLineF2(F("CW Speed set!")); EEPROM.put(CW_DELAY, cwDelayTime); delay(300); clearLine2(); 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 cwSpeed = 1200 / ((CAT_BUFF[2] & 0x3F) + 4); printLineF2(F("CW Speed set!")); EEPROM.put(CW_SPEED, cwSpeed); delay(300); clearLine2(); 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_BUFF[0] = 0xB2; CAT_BUFF[1] = 0xA5; break; case 0x64 : // //CAT_BUFF[0] = 0xA5; //CAT_BUFF[1] = 0x00; break; case 0x67 : //6-0 SSB Mic (#46) Contains 0-100 (decimal) as displayed CAT_BUFF[0] = 0xB2; CAT_BUFF[1] = 0xB2; //break; case 0x69 : //FM Mic (#29) Contains 0-100 (decimal) as displayed //CAT_BUFF[0] = 0x32; //CAT_BUFF[1] = 0x32; //break; case 0x78 : CAT_BUFF[0] = catGetMode(); // check, it must be a bit argument if (CAT_BUFF[0] != 0) CAT_BUFF[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_BUFF[0] = 0x00; CAT_BUFF[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 CAT_BUFF[0] = (isSplitOn ? 0xFF : 0x7F); break; case 0xB3 : // CAT_BUFF[0] = 0x00; CAT_BUFF[1] = 0x4D; break; */ } // sent the data SendCatData(2); Serial.write(ACK); } const byte anlogPinIndex[6] = {A0, A1, A2, A3, A6, A7}; //Read ADC Value by uBITX Manager Software void ReadADCValue(void) { //ADC MAP for uBITX int readedADCValue; //5BYTES //CAT_BUFF[0] [1] [2] [3] [4] //4 COMMAND //0 READ ADDRESS readedADCValue = analogRead(anlogPinIndex[CAT_BUFF[0]]); CAT_BUFF[0] = readedADCValue >> 8; CAT_BUFF[1] = readedADCValue; SendCatData(2); Serial.write(ACK); } void SetIFSValue(void) { //Set IFShift Value isIFShift = CAT_BUFF[0]; ifShiftValue = CAT_BUFF[1] + CAT_BUFF[2] * 256; setFrequency(frequency); SetCarrierFreq(); updateLine2Buffer(1); //option, perhap not need Serial.write(ACK); } //void CatRxStatus(byte fromType) void CatRxStatus(void) //for remove warning { byte sMeterValue = 0; /* http://www.ka7oei.com/ft817_meow.html Command E7 - Read Receiver Status: This command returns one byte. Its contents are valid only when the '817 is in receive mode and it should be ignored when transmitting. The lower 4 bits (0-3) of this byte indicate the current S-meter reading. 00 refers to an S-Zero reading, 04 = S4, 09 = S9, 0A = "10 over," 0B = "20 over" and so on up to 0F. Bit 4 contains no useful information. Bit 5 is 0 in non-FM modes, and it is 0 if the discriminator is centered (within 3.5 kHz for standard FM) when in the FM, FMN, or PKT modes, and 1 if the receiver is off-frequency. Bit 6 is 0 if the CTCSS or DCS is turned off (or in a mode where it is not available.) It is also 0 if there is a signal being receive and the correct CTCSS tone or DCS code is being decoded. It is 1 if there is a signal and the CTCSS/DCS decoding is enable, but the wrong CTCSS tone, DCS code, or no CTCSS/DCS is present. Bit 7 is 0 if there is a signal present, or 1 if the receiver is squelched. */ // The lower 4 bits (0-3) of this byte indicate the current S-meter reading. 00 refers to an S-Zero reading, 04 = S4, 09 = S9, 0A = "10 over," 0B = "20 over" and so on up to 0F. //0~8 switch (scaledSMeter) { case 8 : sMeterValue = 0x0B; break; case 7 : sMeterValue = 0x0A; break; case 6 : sMeterValue = 0x09; break; case 5 : sMeterValue = 0x07; break; case 4 : sMeterValue = 0x05; break; case 3 : sMeterValue = 0x04; break; case 2 : sMeterValue = 0x02; break; case 1 : sMeterValue = 0x01; break; } /* sMeterValue = (scaledSMeter * 2) -1; if (sMeterValue > 0) sMeterValue--; */ CAT_BUFF[0] = sMeterValue & 0b00001111; SendCatData(1); } //void CatTxStatus(byte fromType) void CatTxStatus(void) //for remove warning { boolean isHighSWR = false; boolean isSplitOn = false; /* Inverted -> *ptt = ((p->tx_status & 0x80) == 0); <-- souce code in ft817.c (hamlib) */ CAT_BUFF[0] = ((inTx ? 0 : 1) << 7) + ((isHighSWR ? 1 : 0) << 6) + //hi swr off / on ((isSplitOn ? 1 : 0) << 5) + //Split on / off (0 << 4) + //dummy data 0x08; //P0 meter data SendCatData(1); } unsigned long rxBufferArriveTime = 0; byte rxBufferCheckCount = 0; //Prevent Stack Overflow byte isProcessCheck_Cat = 0; char iopStatusWindow[4] = " "; // may need to move this if it's not visible to ubitx_lcd_1602 char iopMenuDisplay[17] = " "; // KC4UPR - these are used to delay the display of the Smeter, if the // IOP status has recently been displayed, to give time to see it. // Put these here because of how Arduino IDE puts .ino files together. //#define SMETER_DELAY_TIME 5000 //bool displaySmeter = true; //int delaySmeter; int delayTopLine = 0; int stateTopLine = 0; //fromType normal : 0, TX : 1, CW_STRAIGHT : 2, CW_PADDLE : 3, CW_AUTOMODE : 4 //if cw mode, no delay void Check_Cat(byte fromType) { byte i; static PrefixID readPrefix; static uint8_t readLength; static IOPMessage msg; //Check Serial Port Buffer if (Serial.available() == 0) { //Set Buffer Clear status rxBufferCheckCount = 0; return; } // KC4UPR - IOP update: changed this to 6 characters, because we're going to have a // first character which defines if this is CAT or IOP. else if (Serial.available() < 6) //5) { //First Arrived if (rxBufferCheckCount == 0) { rxBufferCheckCount = Serial.available(); rxBufferArriveTime = millis() + CAT_RECEIVE_TIMEOUT; //Set time for timeout } else if (rxBufferArriveTime < millis()) //timeout { //Clear Buffer for (i = 0; i < Serial.available(); i++) rxBufferCheckCount = Serial.read(); rxBufferCheckCount = 0; } else if (rxBufferCheckCount < Serial.available()) //increase buffer count, slow arrived { rxBufferCheckCount = Serial.available(); rxBufferArriveTime = millis() + CAT_RECEIVE_TIMEOUT; //Set time for timeout } return; } //Arived CAT DATA // KC4UPR - IOP update - 6 characters; first character determines mode (CAT or IOP) // Will adjust based on readlength byte first = Serial.read(); readPrefix = byteToPrefix(first); readLength = byteToLength(first); for (int i = 0; i < readLength; i++) { CAT_BUFF[i] = Serial.read(); } // KC4UPR: I don't understand why this is here or how/when it will ever get called, but I will leave // it alone for now. if (isProcessCheck_Cat == 1) return; isProcessCheck_Cat = 1; if (readPrefix == IOP_PREFIX) { recvIOPMessage(msg, CAT_BUFF, readLength); // not super robust... if IOP ever sends more (or less) than a 5 (6) byte message // following assumes it's a status message, 4 chars (including trailing null, which I'm ignoring... switch(msg.id) { /*case IOP_SSB_STATUS_MSG: case IOP_DGT_STATUS_MSG: case IOP_CW_STATUS_MSG: case IOP_TEST_STATUS_MSG: iopStatusWindow[0] = msg.data[0]; iopStatusWindow[1] = msg.data[1]; iopStatusWindow[2] = msg.data[2]; displaySmeter = false; delaySmeter = millis() + SMETER_DELAY_TIME; break;*/ case IOP_MODE_REQUEST: iopSendMode(cwMode, isUSB, digiMode, isTest); break; case IOP_MENU_DISPLAY_MSG: for (int i = 0; i < 16; i++) { iopMenuDisplay[i] = msg.data[i+1]; } if (int8_t(msg.data[0]) == 0) { stateTopLine = 4; } else if (int8_t(msg.data[0]) < 0) { stateTopLine = 0; } else { // > 0 delayTopLine = millis() + (int8_t(msg.data[0]) * 1000); stateTopLine = 2; } break; } } else if (readPrefix == CAT_PREFIX) { //reference : http://www.ka7oei.com/ft817_meow.html switch(CAT_BUFF[4]) { //The stability has not been verified and there seems to be no need. so i remarked codes, //if you need, unmark lines /* case 0x00 : //Lock On if (isDialLock == 1) //This command returns 00 if it was unlocked, and F0 if already locked. CAT_BUFF[0] = 0xF0; else { CAT_BUFF[0] = 0x00; setDialLock(1, fromType); } Serial.write(CAT_BUFF[0]); //Time break; case 0x80 : //Lock Off if (isDialLock == 0) //This command returns 00 if the '817 was already locked, and F0 (HEX) if already unlocked. CAT_BUFF[0] = 0xF0; else { CAT_BUFF[0] = 0x00; setDialLock(0, fromType); } Serial.write(CAT_BUFF[0]); //Time break; */ case 0x01 : //Set Frequency CatSetFreq(fromType); break; case 0x02 : //Split On case 0x82: //Split Off CatSetSplit(CAT_BUFF[4] == 0x02); break; case 0x03 : //Read Frequency and mode CatGetFreqMode(frequency); break; case 0x07 : //Set Operating Mode CatSetMode(CAT_BUFF[0], fromType); break; case 0x08 : //Set PTT_ON case 0x88: //Set PTT Off CatSetPTT(CAT_BUFF[4] == 0x08, fromType); break; case 0x81: //Toggle VFO CatVFOToggle(true, fromType); break; case 0xDB: //Read uBITX EEPROM Data ReadEEPRom(); //Call by uBITX Manager Program break; case 0xBB: //Read FT-817 EEPROM Data (for comfirtable) ReadEEPRom_FT817(); break; case 0xDC: //Write uBITX EEPROM Data WriteEEPRom(); //Call by uBITX Manager Program break; case 0xBC: //Write FT-817 EEPROM Data (for comfirtable) WriteEEPRom_FT817(fromType); break; case 0xDD: //Read uBITX ADC Data ReadADCValue(); //Call by uBITX Manager Program break; case 0xDE: //IF-Shift Control by CAT SetIFSValue(); // break; case 0xE7 : //Read RX Status CatRxStatus(); break; case 0xF7: //Read TX Status CatTxStatus(); break; default: /* char buff[16]; sprintf(buff, "DEFAULT : %x", CAT_BUFF[4]); printLine2(buff); */ Serial.write(ACK); break; } //end of switch } isProcessCheck_Cat = 0; } void Init_Cat(long baud, int portConfig) { Serial.begin(baud, portConfig); Serial.flush(); // At start, immediately send mode to IOP. Currently, IOP has no way to // request the mode. iopSendMode(cwMode, isUSB, digiMode, isTest); }