diff --git a/ubitx_20/cat_libs.ino b/ubitx_20/cat_libs.ino new file mode 100644 index 0000000..b3f4f32 --- /dev/null +++ b/ubitx_20/cat_libs.ino @@ -0,0 +1,698 @@ +/************************************************************************* + 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 . + +**************************************************************************/ + +//for broken protocol +#define MAX_PROTOCOL_SKIP_COUNT 200 + +#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 CAT_BUFF[5]; +byte CAT_SNDBUFF[5]; + +void SendCatData(byte 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) +{ + 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 (isUSB) + CAT_BUFF[4] = CAT_MODE_USB; + else + CAT_BUFF[4] = CAT_MODE_LSB; + + SendCatData(5); +} + +void CatSetSplit(boolean isSplit, byte fromType) +{ + + Serial.write(ACK); +} + +void CatSetPTT(boolean isPTTOn, byte fromType) +{ + if (fromType == 2 || fromType == 3) { + Serial.write(ACK); + return; + } + + // Set PTT Mode + if (isPTTOn) + { + if (!inTx) + { + txCAT = true; + startTx(TX_SSB, 1); + } + } + else + { + if (inTx) + { + 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) + { + if (tmpMode == CAT_MODE_USB) + { + isUSB = true; + } + else + { + isUSB = false; + } + + setFrequency(frequency); + updateDisplay(); + } + + Serial.write(ACK); +} + + +void ReadEEPRom(byte fromType) +{ + // This is to make hamlib happy, PC requested reading two bytes + // we must answer with two bytes, we forge it as empty ones or... + // if the second byte in the request is 0x78 we have to send the first + // with the 5th bit set if the USB or zero if LSB. + + // mem zone to "read" + byte temp0 = CAT_BUFF[0]; + byte temp1 = CAT_BUFF[1]; + + // clear the CAT_BUFF + //npadClear(); + 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 (isUSB) + CAT_BUFF[0] = CAT_MODE_USB; + else + CAT_BUFF[0] = CAT_MODE_LSB; + + 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); +} + +void WriteEEPRom(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; + //debugBytePrint(CAT_BUFF[2], sideToneSub, 0); + printLine2("Sidetone set! CAT"); + EEPROM.put(CW_SIDETONE, sideTone); + delay(500); + printLine2(""); + } + break; + + case 0x61 : //Sidetone (Volume) (#44) + sideToneSub = (CAT_BUFF[2] & 0x7F); + if (sideTonePitch != 0 || sideToneSub != 0) + { + sideTone = (sideTonePitch * 50 + 300) + sideToneSub; + //debugBytePrint(CAT_BUFF[2], sideToneSub, 0); + printLine2("Sidetone set! CAT"); + EEPROM.put(CW_SIDETONE, sideTone); + delay(500); + printLine2(""); + } + 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]; + printLine2("CW Speed set!"); + EEPROM.put(CW_DELAY, cwDelayTime); + delay(500); + printLine2(""); + 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); + printLine2("CW Speed set!"); + EEPROM.put(CW_SPEED, cwSpeed); + delay(500); + printLine2(""); + + 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); +} + +void CatRxStatus(byte fromType) +{ + byte sMeterValue = 1; + + /* + 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. + CAT_BUFF[0] = sMeterValue & 0b00001111; + SendCatData(1); +} + + +void CatTxStatus(byte fromType) +{ + 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 int skiptimeCount = 0; + +//Prevent Stack Overflow +byte isProcessCheck_Cat = 0; + +//fromType normal : 0, TX : 1, CW_STRAIGHT : 2, CW_PADDLE : 3 +//if cw mode, no delay +void Check_Cat(byte fromType) +{ + byte i; + + //Check Serial Port Buffer + if (Serial.available() == 0) + { + skipTimeCount = 0; //Init skipTimeCount for broken protocol + return; + } + else if (Serial.available() < 5) + { + /* + //if Broken Protocol, Reset Buffer + //when TX mode very fast count because stkip dial check, button check functions + if ((fromType == 0 && ++skiptimeCount > MAX_PROTOCOL_SKIP_COUNT) || + ((fromType == 1 || 2) && ++skiptimeCount > MAX_PROTOCOL_SKIP_COUNT * 70) ) + { + //Clear Buffer + for (i = 0; i < Serial.available(); i++) + CAT_BUFF[0] = Serial.read(); + skipTimeCount = 0; //Init skipTimeCount for broken protocol + } + */ + + return; + } + + //Arived CAT DATA + for (i = 0; i < 5; i++) + CAT_BUFF[i] = Serial.read(); + + if (isProcessCheck_Cat == 1) + return; + + isProcessCheck_Cat = 1; + + //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, fromType); + break; + + case 0x03 : //Read Frequency and mode + CatGetFreqMode(frequency, fromType); + 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 + case 0xBB: //Read FT-817 EEPROM Data (for comfirtable) + ReadEEPRom(fromType); + break; + + case 0xDC: //Write uBITX EEPROM Data + case 0xBC: //Write FT-817 EEPROM Data (for comfirtable) + WriteEEPRom(fromType); + break; + + case 0xE7 : //Read RX Status + CatRxStatus(fromType); + break; + case 0xF7: //Read TX Status + CatTxStatus(fromType); + 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(); +} + diff --git a/ubitx_20/ubitx_20.ino b/ubitx_20/ubitx_20.ino index fdb1b0f..23e178e 100644 --- a/ubitx_20/ubitx_20.ino +++ b/ubitx_20/ubitx_20.ino @@ -141,6 +141,12 @@ int count = 0; //to generally count ticks, loops, etc #define CW_SIDETONE 24 #define CW_SPEED 28 +//AT328 has 1KBytes EEPROM +#define VFO_A_MODE 256 +#define VFO_B_MODE 257 +#define CW_DELAY 258 +#define CW_START 259 + /** * The uBITX is an upconnversion transceiver. The first IF is at 45 MHz. * The first IF frequency is not exactly at 45 Mhz but about 5 khz lower, @@ -186,6 +192,20 @@ unsigned long frequency, ritRxFrequency, ritTxFrequency; //frequency is the cur int cwSpeed = 100; //this is actuall the dot period in milliseconds extern int32_t calibration; +//for store the mode in eeprom +byte vfoA_mode=0, vfoB_mode = 0; //0: default, 1:not use, 2:LSB, 3:USB, 4:CW, 5:AM, 6:FM +bool isSplitOn = false; +byte cwDelayTime = 60; +byte delayBeforeCWStartTime = 50; + +//sideTonePitch + sideToneSub = sideTone +byte sideTonePitch=0; +byte sideToneSub = 0; + +//DialLock +byte isDialLock = 0; + + /** * Raduino needs to keep track of current state of the transceiver. These are a few variables that do it */ @@ -206,6 +226,24 @@ boolean modeCalibrate = false;//this mode of menus shows extended menus to calib * you start hacking around */ +/* + KD8CEC + When using the basic delay of the Arduino, the program freezes. + When the delay is used, the program will generate an error because it is not communicating, + so Create a new delay function that can do background processing. + */ + +unsigned long delayBeforeTime = 0; +void delay_background(unsigned delayTime, byte fromType){ + delayBeforeTime = millis(); + + while (millis() <= delayBeforeTime + delayTime) { + //Background Work + Check_Cat(fromType); + } +} + + /** * Select the properly tx harmonic filters * The four harmonic filters use only three relays @@ -261,7 +299,10 @@ void setTXFilters(unsigned long freq){ void setFrequency(unsigned long f){ uint64_t osc_f; - + + //1 digits discarded + f = (f / 10) * 10; + setTXFilters(f); if (isUSB){ @@ -282,7 +323,7 @@ void setFrequency(unsigned long f){ * Note: In cw mode, doesnt key the radio, only puts it in tx mode */ -void startTx(byte txMode){ +void startTx(byte txMode, byte isDisplayUpdate){ unsigned long tx_freq = 0; digitalWrite(TX_RX, 1); inTx = 1; @@ -306,7 +347,10 @@ void startTx(byte txMode){ else si5351bx_setfreq(2, frequency - sideTone); } - updateDisplay(); + + //reduce latency time when begin of CW mode + if (isDisplayUpdate == 1) + updateDisplay(); } void stopTx(){ @@ -359,7 +403,7 @@ void checkPTT(){ return; if (digitalRead(PTT) == 0 && inTx == 0){ - startTx(TX_SSB); + startTx(TX_SSB, 1); delay(50); //debounce the PTT } @@ -378,9 +422,12 @@ void checkButton(){ return; doMenu(); + //wait for the button to go up again - while(btnDown()) + while(btnDown()) { delay(10); + Check_Cat(0); + } delay(50);//debounce } @@ -397,6 +444,9 @@ void doTuning(){ unsigned long prev_freq; int incdecValue = 0; + if (isDialLock == 1) + return; + s = enc_read(); if (s){ prev_freq = frequency; @@ -474,17 +524,53 @@ void initSettings(){ EEPROM.get(VFO_B, vfoB); EEPROM.get(CW_SIDETONE, sideTone); EEPROM.get(CW_SPEED, cwSpeed); + + //for Save VFO_A_MODE to eeprom + //0: default, 1:not use, 2:LSB, 3:USB, 4:CW, 5:AM, 6:FM + EEPROM.get(VFO_A_MODE, vfoA_mode); + EEPROM.get(VFO_B_MODE, vfoB_mode); + + //CW DelayTime + EEPROM.get(CW_DELAY, cwDelayTime); + + //CW interval between TX and CW Start + EEPROM.get(CW_START, delayBeforeCWStartTime); + + if (cwDelayTime < 1 || cwDelayTime > 250) + cwDelayTime = 60; + + if (vfoA_mode < 2) + vfoA_mode = 2; + + if (vfoB_mode < 2) + vfoB_mode = 3; + if (usbCarrier > 12010000l || usbCarrier < 11990000l) usbCarrier = 11997000l; - if (vfoA > 35000000l || 3500000l > vfoA) + + if (vfoA > 35000000l || 3500000l > vfoA) { vfoA = 7150000l; - if (vfoB > 35000000l || 3500000l > vfoB) + vfoA_mode = 2; + } + + if (vfoB > 35000000l || 3500000l > vfoB) { vfoB = 14150000l; + vfoB_mode = 3; + } + if (sideTone < 100 || 2000 < sideTone) sideTone = 800; if (cwSpeed < 10 || 1000 < cwSpeed) cwSpeed = 100; - + + if (sideTone < 300 || sideTone > 1000) { + sideTonePitch = 0; + sideToneSub = 0;; + } + else{ + sideTonePitch = (sideTone - 300) / 50; + sideToneSub = sideTone % 50; + } } void initPorts(){ @@ -522,21 +608,29 @@ void initPorts(){ void setup() { - Serial.begin(9600); - + //Init EEProm for factory reset test + /* + for (int i = 0; i < 512; i++) + EEPROM.write(i, 0); + */ + //Serial.begin(9600); lcd.begin(16, 2); //we print this line so this shows up even if the raduino //crashes later in the code + printLine2("CEC Ver 0.22"); printLine1("uBITX v0.20"); - delay(500); + delay_background(500, 0); + printLine2(""); + Init_Cat(38400, SERIAL_8N1); initMeter(); //not used in this build initSettings(); initPorts(); initOscillators(); frequency = vfoA; + byteToMode(vfoA_mode); setFrequency(vfoA); updateDisplay(); @@ -548,7 +642,8 @@ void setup() /** * The loop checks for keydown, ptt, function button and tuning. */ - +//for debug +int dbgCnt = 0; byte flasher = 0; void loop(){ @@ -566,5 +661,11 @@ void loop(){ } //we check CAT after the encoder as it might put the radio into TX - checkCAT(); + //checkCAT(); + Check_Cat(inTx? 1 : 0); + + /* + lcd.setCursor(0, 0); // place the cursor at the beginning of the selected line + lcd.print(dbgCnt++); + */ } diff --git a/ubitx_20/ubitx_cat.ino b/ubitx_20/ubitx_cat.ino index 687595c..4649e3b 100644 --- a/ubitx_20/ubitx_cat.ino +++ b/ubitx_20/ubitx_cat.ino @@ -148,9 +148,9 @@ void processCATCommand(byte* cmd) { if (!inTx) { response[0] = 0; txCAT = true; - startTx(TX_SSB); - updateDisplay(); - } else { + startTx(TX_SSB, 1); + } + else { response[0] = 0xf0; } Serial.write(response,1); diff --git a/ubitx_20/ubitx_keyer.ino b/ubitx_20/ubitx_keyer.ino index 3a9c86f..e955659 100644 --- a/ubitx_20/ubitx_keyer.ino +++ b/ubitx_20/ubitx_keyer.ino @@ -23,7 +23,7 @@ // in milliseconds, this is the parameter that determines how long the tx will hold between cw key downs -#define CW_TIMEOUT (600l) +//#define CW_TIMEOUT (600l) //Change to CW Delaytime for value save to eeprom #define PADDLE_DOT 1 #define PADDLE_DASH 2 #define PADDLE_BOTH 3 @@ -61,7 +61,10 @@ void cwKeydown(){ keyDown = 1; //tracks the CW_KEY tone(CW_TONE, (int)sideTone); digitalWrite(CW_KEY, 1); - cwTimeout = millis() + CW_TIMEOUT; + + //Modified by KD8CEC, for CW Delay Time save to eeprom + //cwTimeout = millis() + CW_TIMEOUT; + cwTimeout = millis() + cwDelayTime * 10; } /** @@ -72,7 +75,10 @@ void cwKeyUp(){ keyDown = 0; //tracks the CW_KEY noTone(CW_TONE); digitalWrite(CW_KEY, 0); - cwTimeout = millis() + CW_TIMEOUT; + + //Modified by KD8CEC, for CW Delay Time save to eeprom + //cwTimeout = millis() + CW_TIMEOUT; + cwTimeout = millis() + cwDelayTime * 10; } /** @@ -103,48 +109,64 @@ void cwKeyer(){ //if a paddle was used (not a straight key) we should extend the space to be a full dash //by adding two more dots long space (one has already been added at the end of the dot or dash) + /* if (cwTimeout > 0 && lastPaddle != PADDLE_STRAIGHT) - delay(cwSpeed * 2); + delay_background(cwSpeed * 2, 3); + //delay(cwSpeed * 2); // got back to the begining of the loop, if no further activity happens on the paddle or the straight key // we will time out, and return out of this routine delay(5); + */ continue; } - Serial.print("paddle:");Serial.println(paddle); + //Remoark Debug code / Serial Use by CAT Protocol + //Serial.print("paddle:");Serial.println(paddle); // if we are here, it is only because the key or the paddle is pressed if (!inTx){ keyDown = 0; - cwTimeout = millis() + CW_TIMEOUT; - startTx(TX_CW); + //Modified by KD8CEC, for CW Delay Time save to eeprom + //cwTimeout = millis() + CW_TIMEOUT; + cwTimeout = millis() + cwDelayTime * 10; + + startTx(TX_CW, 0); //disable updateDisplay Command for reduce latency time updateDisplay(); + + //DelayTime Option + delay_background(delayBeforeCWStartTime * 2, 2); } // star the transmission) // we store the transmitted character in the lastPaddle cwKeydown(); if (paddle == PADDLE_DOT){ - delay(cwSpeed); + //delay(cwSpeed); + delay_background(cwSpeed, 3); lastPaddle = PADDLE_DOT; } else if (paddle == PADDLE_DASH){ - delay(cwSpeed * 3); + //delay(cwSpeed * 3); + delay_background(cwSpeed * 3, 3); lastPaddle = PADDLE_DASH; } else if (paddle == PADDLE_BOTH){ //both paddles down //depending upon what was sent last, send the other if (lastPaddle == PADDLE_DOT) { - delay(cwSpeed * 3); + //delay(cwSpeed * 3); + delay_background(cwSpeed * 3, 3); lastPaddle = PADDLE_DASH; }else{ - delay(cwSpeed); + //delay(cwSpeed); + delay_background(cwSpeed, 3); lastPaddle = PADDLE_DOT; } } else if (paddle == PADDLE_STRAIGHT){ - while (getPaddle() == PADDLE_STRAIGHT) + while (getPaddle() == PADDLE_STRAIGHT) { delay(1); + Check_Cat(2); + } lastPaddle = PADDLE_STRAIGHT; } cwKeyUp(); diff --git a/ubitx_20/ubitx_menu.ino b/ubitx_20/ubitx_menu.ino index 003266a..3d8f9e3 100644 --- a/ubitx_20/ubitx_menu.ino +++ b/ubitx_20/ubitx_menu.ino @@ -28,8 +28,11 @@ int menuBand(int btn){ printLine2("Press to confirm"); //wait for the button menu select button to be lifted) - while (btnDown()) + while (btnDown()) { delay(50); + Check_Cat(0); //To prevent disconnections + } + delay(50); ritDisable(); @@ -58,10 +61,14 @@ int menuBand(int btn){ updateDisplay(); } delay(20); + Check_Cat(0); //To prevent disconnections } - while(btnDown()) + while(btnDown()) { delay(50); + Check_Cat(0); //To prevent disconnections + } + delay(50); printLine2(""); @@ -69,8 +76,23 @@ int menuBand(int btn){ menuOn = 0; } -void menuVfoToggle(int btn){ - +//0: default, 1:not use, 2:LSB, 3:USB, 4:CW, 5:AM, 6:FM +byte modeToByte(){ + if (isUSB) + return 3; + else + return 2; +} + +void byteToMode(byte modeValue){ + if (modeValue == 3) + isUSB = 1; + else + isUSB = 0; +} + +void menuVfoToggle(int btn) +{ if (!btn){ if (vfoActive == VFO_A) printLine2("Select VFO B? "); @@ -80,28 +102,36 @@ void menuVfoToggle(int btn){ else { if (vfoActive == VFO_B){ vfoB = frequency; - EEPROM.put(VFO_B, frequency); + EEPROM.put(VFO_B, vfoB); + + //For save MODE to eeprom + vfoB_mode = modeToByte(); + EEPROM.put(VFO_B_MODE, vfoB_mode); + vfoActive = VFO_A; printLine2("Selected VFO A "); frequency = vfoA; + byteToMode(vfoA_mode); } else { vfoA = frequency; EEPROM.put(VFO_A, frequency); + + //For save MODE to eeprom + vfoA_mode = modeToByte(); + EEPROM.put(VFO_A_MODE, vfoA_mode); + vfoActive = VFO_B; printLine2("Selected VFO B "); frequency = vfoB; + byteToMode(vfoB_mode); } - + ritDisable(); - setFrequency(frequency); - if (frequency >= 10000000l) - isUSB = true; - else - isUSB = false; + updateDisplay(); printLine2(""); - delay(1000); + delay_background(500, 0); //exit the menu menuOn = 0; } @@ -125,7 +155,7 @@ void menuRitToggle(int btn){ ritDisable(); } menuOn = 0; - delay(500); + delay_background(500, 0); printLine2(""); updateDisplay(); } @@ -142,15 +172,13 @@ void menuSidebandToggle(int btn){ if (isUSB == true){ isUSB = false; printLine2("LSB Selected"); - delay(500); - printLine2(""); } else { isUSB = true; printLine2("USB Selected"); - delay(500); - printLine2(""); } + delay_background(500, 0); + printLine2(""); updateDisplay(); menuOn = 0; @@ -176,7 +204,7 @@ void menuSetup(int btn){ modeCalibrate = false; printLine2("Setup:Off "); } - delay(2000); + delay_background(2000, 0); printLine2(""); menuOn = 0; } @@ -189,7 +217,7 @@ void menuExit(int btn){ } else{ printLine2("Exiting menu"); - delay(300); + delay_background(300, 0); printLine2(""); updateDisplay(); menuOn = 0; @@ -216,7 +244,7 @@ int menuCWSpeed(int btn){ itoa(wpm,c, 10); strcat(b, c); printLine2(b); - delay(300); + delay_background(300, 0); while(!btnDown() && digitalRead(PTT) == HIGH){ @@ -236,6 +264,8 @@ int menuCWSpeed(int btn){ if (btnDown()) //re-enable the clock1 and clock 2 break; + + Check_Cat(0); //To prevent disconnections } //save the setting @@ -243,13 +273,110 @@ int menuCWSpeed(int btn){ printLine2("CW Speed set!"); cwSpeed = 1200/wpm; EEPROM.put(CW_SPEED, cwSpeed); - delay(2000); + delay_background(2000, 0); } printLine2(""); updateDisplay(); menuOn = 0; } +int menuSetupCwDelay(int btn){ + int knob = 0; + int tmpCWDelay = cwDelayTime * 10; + + if (!btn){ + strcpy(b, "CW TX->RX Delay"); + printLine2(b); + return; + } + + printLine1("Press PTT to set"); + strcpy(b, "DELAY:"); + itoa(tmpCWDelay,c, 10); + strcat(b, c); + printLine2(b); + delay_background(300, 0); + + while(!btnDown() && digitalRead(PTT) == HIGH){ + knob = enc_read(); + if (knob != 0){ + if (tmpCWDelay > 3 && knob < 0) + tmpCWDelay -= 10; + if (tmpCWDelay < 2500 && knob > 0) + tmpCWDelay += 10; + + strcpy(b, "DELAY:"); + itoa(tmpCWDelay,c, 10); + strcat(b, c); + printLine2(b); + } + //abort if this button is down + if (btnDown()) + break; + + Check_Cat(0); //To prevent disconnections + } + + //save the setting + if (digitalRead(PTT) == LOW){ + printLine2("CW Delay set!"); + cwDelayTime = tmpCWDelay / 10; + EEPROM.put(CW_DELAY, cwDelayTime); + delay_background(2000, 0); + } + printLine2(""); + updateDisplay(); + menuOn = 0; +} + +int menuSetupTXCWInterval(int btn){ + int knob = 0; + int tmpTXCWInterval = delayBeforeCWStartTime * 2; + + if (!btn){ + strcpy(b, "CW Start Delay"); + printLine2(b); + return; + } + + printLine1("Press PTT to set"); + strcpy(b, "Start Delay:"); + itoa(tmpTXCWInterval,c, 10); + strcat(b, c); + printLine2(b); + delay_background(300, 0); + + while(!btnDown() && digitalRead(PTT) == HIGH){ + knob = enc_read(); + if (knob != 0){ + if (tmpTXCWInterval > 0 && knob < 0) + tmpTXCWInterval -= 2; + if (tmpTXCWInterval < 500 && knob > 0) + tmpTXCWInterval += 2; + + strcpy(b, "Start Delay:"); + itoa(tmpTXCWInterval,c, 10); + strcat(b, c); + printLine2(b); + } + //abort if this button is down + if (btnDown()) + break; + + Check_Cat(0); //To prevent disconnections + } + + //save the setting + if (digitalRead(PTT) == LOW){ + printLine2("CW Start set!"); + delayBeforeCWStartTime = tmpTXCWInterval / 2; + EEPROM.put(CW_START, delayBeforeCWStartTime); + delay_background(2000, 0); + } + printLine2(""); + updateDisplay(); + menuOn = 0; +} /** @@ -288,7 +415,7 @@ int factoryCalibration(int btn){ //turn off the second local oscillator and the bfo si5351_set_calibration(calibration); - startTx(TX_CW); + startTx(TX_CW, 1); si5351bx_setfreq(2, 10000000l); strcpy(b, "#1 10 MHz cal:"); @@ -347,7 +474,7 @@ int menuSetupCalibration(int btn){ printLine1("Set to Zero-beat,"); printLine2("press PTT to save"); - delay(1000); + delay_background(1000, 0); prev_calibration = calibration; calibration = 0; @@ -389,7 +516,7 @@ int menuSetupCalibration(int btn){ printLine1("Calibration set!"); printLine2("Set Carrier now"); EEPROM.put(MASTER_CAL, calibration); - delay(2000); + delay_background(2000, 0); } else calibration = prev_calibration; @@ -430,7 +557,7 @@ void menuSetupCarrier(int btn){ prevCarrier = usbCarrier; printLine1("Tune to best Signal"); printLine2("PTT to confirm. "); - delay(1000); + delay_background(1000, 0); usbCarrier = 11995000l; si5351bx_setfreq(0, usbCarrier); @@ -450,7 +577,8 @@ void menuSetupCarrier(int btn){ si5351bx_setfreq(0, usbCarrier); printCarrierFreq(usbCarrier); - + + Check_Cat(0); //To prevent disconnections delay(100); } @@ -458,7 +586,7 @@ void menuSetupCarrier(int btn){ if (digitalRead(PTT) == LOW){ printLine2("Carrier set! "); EEPROM.put(USB_CAL, usbCarrier); - delay(1000); + delay_background(1000, 0); } else usbCarrier = prevCarrier; @@ -475,18 +603,18 @@ void menuSetupCwTone(int btn){ int prev_sideTone; if (!btn){ - printLine2("Change CW Tone"); + printLine2("Change CW Tone"); return; } prev_sideTone = sideTone; printLine1("Tune CW tone"); printLine2("PTT to confirm. "); - delay(1000); + delay_background(1000, 0); tone(CW_TONE, sideTone); //disable all clock 1 and clock 2 - while (digitalRead(PTT) == LOW || !btnDown()) + while (digitalRead(PTT) == HIGH && !btnDown()) { knob = enc_read(); @@ -502,13 +630,14 @@ void menuSetupCwTone(int btn){ printLine2(b); delay(100); + Check_Cat(0); //To prevent disconnections } noTone(CW_TONE); //save the setting if (digitalRead(PTT) == LOW){ printLine2("Sidetone set! "); EEPROM.put(CW_SIDETONE, usbCarrier); - delay(2000); + delay_background(2000, 0); } else sideTone = prev_sideTone; @@ -518,13 +647,57 @@ void menuSetupCwTone(int btn){ menuOn = 0; } +void setDialLock(byte tmpLock, byte fromMode) { + isDialLock = tmpLock; + + if (fromMode == 2 || fromMode == 3) return; + + if (isDialLock == 1) + printLine2("Dial Lock ON"); + else + printLine2("Dial Lock OFF"); + + updateDisplay(); + delay_background(1000, 0); + printLine2(""); +} + +int btnDownTimeCount; + void doMenu(){ int select=0, i,btnState; - + + //for DialLock On/Off function + btnDownTimeCount = 0; + //wait for the button to be raised up - while(btnDown()) + while(btnDown()){ delay(50); + Check_Cat(0); //To prevent disconnections + + //btnDownTimeCount++; + //check long time Down Button -> 3 Second + if (btnDownTimeCount++ > (3000 / 50)) { + setDialLock(isDialLock == 1 ? 0 : 1, 0); //Reverse Dialo lock + return; + } + } delay(50); //debounce + +/* + //check long time Down Button -> 3 Second + if (btnDownTimeCount > (3000 / 50)) { + isDialLock = isDialLock == 1 ? 0 : 1; //Reverse Dialo lock + if (isDialLock == 1) + printLine2("Dial Lock ON"); + else + printLine2("Dial Lock OFF"); + + delay_background(1000); + printLine2(""); + return; + } +*/ menuOn = 2; @@ -533,7 +706,7 @@ void doMenu(){ btnState = btnDown(); if (i > 0){ - if (modeCalibrate && select + i < 110) + if (modeCalibrate && select + i < 130) select += i; if (!modeCalibrate && select + i < 70) select += i; @@ -562,12 +735,20 @@ void doMenu(){ else if (select < 100 && modeCalibrate) menuSetupCwTone(btnState); else if (select < 110 && modeCalibrate) - menuExit(btnState); + menuSetupCwDelay(btnState); + else if (select < 120 && modeCalibrate) + menuSetupTXCWInterval(btnState); + else if (select < 130 && modeCalibrate) + menuExit(btnState); + + Check_Cat(0); //To prevent disconnections } //debounce the button - while(btnDown()) + while(btnDown()){ delay(50); + Check_Cat(0); //To prevent disconnections + } delay(50); } diff --git a/ubitx_20/ubitx_ui.ino b/ubitx_20/ubitx_ui.ino index 590fcbd..d7b0388 100644 --- a/ubitx_20/ubitx_ui.ino +++ b/ubitx_20/ubitx_ui.ino @@ -34,11 +34,22 @@ byte s_meter_bitmap[] = { B00001,B00001,B00001,B00001,B00101,B00101,B00101,B11011 }; +byte lock_bitmap[8] = { + 0b01110, + 0b10001, + 0b10001, + 0b11111, + 0b11011, + 0b11011, + 0b11111, + 0b00000}; // initializes the custom characters // we start from char 1 as char 0 terminates the string! void initMeter(){ + lcd.createChar(0, lock_bitmap); + lcd.createChar(1, s_meter_bitmap); lcd.createChar(2, s_meter_bitmap + 8); lcd.createChar(3, s_meter_bitmap + 16); @@ -145,6 +156,12 @@ void updateDisplay() { strcat(c, " TX"); printLine(1, c); + if (isDialLock == 1) + { + lcd.setCursor(3,1); + lcd.write((uint8_t)0); + } + /* //now, the second line memset(c, 0, sizeof(c));