From 5f906a4497233c9f963eb5ceb3f4526e2185a4be Mon Sep 17 00:00:00 2001 From: phdlee Date: Thu, 5 Apr 2018 22:16:54 +0900 Subject: [PATCH] To Support various LCD Type --- ubitx_20/cw_autokey.ino | 15 +- ubitx_20/ubitx_20.ino | 33 +- ubitx_20/ubitx_lcd_1602i.ino | 561 ++++++++++++++++++ .../{ubitx_idle.ino => ubitx_lcd_1602p.ino} | 42 +- ubitx_20/ubitx_lcd_2404i.ino | 22 + ubitx_20/ubitx_lcd_2404p.ino | 22 + 6 files changed, 663 insertions(+), 32 deletions(-) create mode 100644 ubitx_20/ubitx_lcd_1602i.ino rename ubitx_20/{ubitx_idle.ino => ubitx_lcd_1602p.ino} (92%) create mode 100644 ubitx_20/ubitx_lcd_2404i.ino create mode 100644 ubitx_20/ubitx_lcd_2404p.ino diff --git a/ubitx_20/cw_autokey.ino b/ubitx_20/cw_autokey.ino index 4d2d93f..f5fcbde 100644 --- a/ubitx_20/cw_autokey.ino +++ b/ubitx_20/cw_autokey.ino @@ -299,13 +299,14 @@ void controlAutoCW(){ printLineFromEEPRom(0, 2, cwStartIndex + displayScrolStep + CW_DATA_OFSTADJ, cwEndIndex + CW_DATA_OFSTADJ, 0); - byte diplayAutoCWLine = 0; - if ((displayOption1 & 0x01) == 0x01) - diplayAutoCWLine = 1; - - lcd.setCursor(0, diplayAutoCWLine); - lcd.write(byteToChar(selectedCWTextIndex)); - lcd.write(':'); + //byte diplayAutoCWLine = 0; + //if ((displayOption1 & 0x01) == 0x01) + // diplayAutoCWLine = 1; + + Display_AutoKeyTextIndex(selectedCWTextIndex); + //lcd.setCursor(0, diplayAutoCWLine); + //lcd.write(byteToChar(selectedCWTextIndex)); + //lcd.write(':'); isNeedScroll = (cwEndIndex - cwStartIndex) > 14 ? 1 : 0; scrollDispayTime = millis() + scrollSpeed; beforeCWTextIndex = selectedCWTextIndex; diff --git a/ubitx_20/ubitx_20.ino b/ubitx_20/ubitx_20.ino index 08b24d2..fc2c584 100644 --- a/ubitx_20/ubitx_20.ino +++ b/ubitx_20/ubitx_20.ino @@ -2,6 +2,16 @@ #define FIRMWARE_VERSION_INFO F("CE v1.070") #define FIRMWARE_VERSION_NUM 0x02 //1st Complete Project : 1 (Version 1.061), 2st Project : 2 +//Depending on the type of LCD mounted on the uBITX, uncomment one of the options below. +//You must select only one. + +//#define UBITX_DISPLAY_LCD1602P //LCD mounted on unmodified uBITX +#define UBITX_DISPLAY_LCD1602I //I2C type 16 x 02 LCD +//#define UBITX_DISPLAY_LCD2404P //24 x 04 LCD +//#define UBITX_DISPLAY_LCD2404I //I2C type 24 x 04 LCD + + + /** Cat Suppoort uBITX CEC Version Most features(TX, Frequency Range, Ham Band, TX Control, CW delay, start Delay... more) have been added by KD8CEC. @@ -91,24 +101,6 @@ #define ANALOG_SPARE (A7) #define ANALOG_SMETER (A7) //by KD8CEC -/** - * The Raduino board is the size of a standard 16x2 LCD panel. It has three connectors: - * - * First, is an 8 pin connector that provides +5v, GND and six analog input pins that can also be - * configured to be used as digital input or output pins. These are referred to as A0,A1,A2, - * A3,A6 and A7 pins. The A4 and A5 pins are missing from this connector as they are used to - * talk to the Si5351 over I2C protocol. - * - * Second is a 16 pin LCD connector. This connector is meant specifically for the standard 16x2 - * LCD display in 4 bit mode. The 4 bit mode requires 4 data lines and two control lines to work: - * Lines used are : RESET, ENABLE, D4, D5, D6, D7 - * We include the library and declare the configuration of the LCD panel too - */ - -#include -LiquidCrystal lcd(8,9,10,11,12,13); - - /** * The Arduino, unlike C/C++ on a regular computer with gigabytes of RAM, has very little memory. * We have to be very careful with variables that are declared inside the functions as they are @@ -120,8 +112,6 @@ LiquidCrystal lcd(8,9,10,11,12,13); * the input and output from the USB port. We must keep a count of the bytes used while reading * the serial port as we can easily run out of buffer space. This is done in the serial_in_count variable. */ -char c[30], b[30]; -char printBuff[2][17]; //mirrors what is showing on the two lines of the display int count = 0; //to generally count ticks, loops, etc /** @@ -1133,11 +1123,10 @@ void setup() */ //Serial.begin(9600); - lcd.begin(16, 2); + LCD_Init(); printLineF(1, FIRMWARE_VERSION_INFO); Init_Cat(38400, SERIAL_8N1); - initMeter(); //not used in this build initSettings(); if (userCallsignLength > 0 && ((userCallsignLength & 0x80) == 0x80)) { diff --git a/ubitx_20/ubitx_lcd_1602i.ino b/ubitx_20/ubitx_lcd_1602i.ino new file mode 100644 index 0000000..7b56eaf --- /dev/null +++ b/ubitx_20/ubitx_lcd_1602i.ino @@ -0,0 +1,561 @@ +/************************************************************************* + KD8CEC, _______ + uBITX Display Routine for LCD1602 I2C + + 1.Code for 16 x 2 LCD for I2C. + 2.Display related functions of uBITX. Some functions moved from uBITX_Ui. + 3.uBITX Idle time Processing + Functions that run at times that do not affect TX, CW, and CAT + It is called in 1/10 time unit. +----------------------------------------------------------------------------- + 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 . + +**************************************************************************/ +#ifdef UBITX_DISPLAY_LCD1602I + + + +/** + * The Raduino board is the size of a standard 16x2 LCD panel. It has three connectors: + * + * First, is an 8 pin connector that provides +5v, GND and six analog input pins that can also be + * configured to be used as digital input or output pins. These are referred to as A0,A1,A2, + * A3,A6 and A7 pins. The A4 and A5 pins are missing from this connector as they are used to + * talk to the Si5351 over I2C protocol. + * + * Second is a 16 pin LCD connector. This connector is meant specifically for the standard 16x2 + * LCD display in 4 bit mode. The 4 bit mode requires 4 data lines and two control lines to work: + * Lines used are : RESET, ENABLE, D4, D5, D6, D7 + * We include the library and declare the configuration of the LCD panel too + */ + +#include +LiquidCrystal lcd(8,9,10,11,12,13); + +char c[30], b[30]; +char printBuff[2][17]; //mirrors what is showing on the two lines of the display + +void LCD_Init(void) +{ + lcd.begin(16, 2); + initMeter(); //for Meter Display +} + +void Display_AutoKeyTextIndex(char textIndex) +{ + byte diplayAutoCWLine = 0; + + if ((displayOption1 & 0x01) == 0x01) + diplayAutoCWLine = 1; + lcd.setCursor(0, diplayAutoCWLine); + lcd.write(byteToChar(selectedCWTextIndex)); + lcd.write(':'); +} + + +//======================================================================== +//Display Routine +//======================================================================== +const PROGMEM uint8_t meters_bitmap[] = { + B10000, B10000, B10000, B10000, B10000, B10000, B10000, B10000 , //custom 1 + B11000, B11000, B11000, B11000, B11000, B11000, B11000, B11000 , //custom 2 + B11100, B11100, B11100, B11100, B11100, B11100, B11100, B11100 , //custom 3 + B11110, B11110, B11110, B11110, B11110, B11110, B11110, B11110 , //custom 4 + B11111, B11111, B11111, B11111, B11111, B11111, B11111, B11111 , //custom 5 + B01000, B11100, B01000, B00000, B10111, B10101, B10101, B10111 //custom 6 +}; + +PGM_P p_metes_bitmap = reinterpret_cast(meters_bitmap); + +const PROGMEM uint8_t lock_bitmap[8] = { + 0b01110, + 0b10001, + 0b10001, + 0b11111, + 0b11011, + 0b11011, + 0b11111, + 0b00000}; +PGM_P plock_bitmap = reinterpret_cast(lock_bitmap); + + +// initializes the custom characters +// we start from char 1 as char 0 terminates the string! +void initMeter(){ + uint8_t tmpbytes[8]; + byte i; + + for (i = 0; i < 8; i++) + tmpbytes[i] = pgm_read_byte(plock_bitmap + i); + lcd.createChar(0, tmpbytes); + + for (i = 0; i < 8; i++) + tmpbytes[i] = pgm_read_byte(p_metes_bitmap + i); + lcd.createChar(1, tmpbytes); + + for (i = 0; i < 8; i++) + tmpbytes[i] = pgm_read_byte(p_metes_bitmap + i + 8); + lcd.createChar(2, tmpbytes); + + for (i = 0; i < 8; i++) + tmpbytes[i] = pgm_read_byte(p_metes_bitmap + i + 16); + lcd.createChar(3, tmpbytes); + + for (i = 0; i < 8; i++) + tmpbytes[i] = pgm_read_byte(p_metes_bitmap + i + 24); + lcd.createChar(4, tmpbytes); + + for (i = 0; i < 8; i++) + tmpbytes[i] = pgm_read_byte(p_metes_bitmap + i + 32); + lcd.createChar(5, tmpbytes); + + for (i = 0; i < 8; i++) + tmpbytes[i] = pgm_read_byte(p_metes_bitmap + i + 40); + lcd.createChar(6, tmpbytes); +} + +//by KD8CEC +//0 ~ 25 : 30 over : + 10 +void drawMeter(int needle) { + //5Char + O over + int i; + + for (i = 0; i < 5; i++) { + if (needle >= 5) + lcdMeter[i] = 5; //full + else if (needle > 0) + lcdMeter[i] = needle; //full + else //0 + lcdMeter[i] = 0x20; + + needle -= 5; + } + + if (needle > 0) + lcdMeter[5] = 6; + else + lcdMeter[5] = 0x20; +} + + + +// The generic routine to display one line on the LCD +void printLine(unsigned char linenmbr, const char *c) { + if ((displayOption1 & 0x01) == 0x01) + linenmbr = (linenmbr == 0 ? 1 : 0); //Line Toggle + + if (strcmp(c, printBuff[linenmbr])) { // only refresh the display when there was a change + lcd.setCursor(0, linenmbr); // place the cursor at the beginning of the selected line + lcd.print(c); + strcpy(printBuff[linenmbr], c); + + for (byte i = strlen(c); i < 16; i++) { // add white spaces until the end of the 16 characters line is reached + lcd.print(' '); + } + } +} + +void printLineF(char linenmbr, const __FlashStringHelper *c) +{ + int i; + char tmpBuff[17]; + PGM_P p = reinterpret_cast(c); + + for (i = 0; i < 17; i++){ + unsigned char fChar = pgm_read_byte(p++); + tmpBuff[i] = fChar; + if (fChar == 0) + break; + } + + printLine(linenmbr, tmpBuff); +} + +#define LCD_MAX_COLUMN 16 +void printLineFromEEPRom(char linenmbr, char lcdColumn, byte eepromStartIndex, byte eepromEndIndex, char offsetTtype) { + if ((displayOption1 & 0x01) == 0x01) + linenmbr = (linenmbr == 0 ? 1 : 0); //Line Toggle + + lcd.setCursor(lcdColumn, linenmbr); + + for (byte i = eepromStartIndex; i <= eepromEndIndex; i++) + { + if (++lcdColumn <= LCD_MAX_COLUMN) + lcd.write(EEPROM.read((offsetTtype == 0 ? USER_CALLSIGN_DAT : WSPR_MESSAGE1) + i)); + else + break; + } + + for (byte i = lcdColumn; i < 16; i++) //Right Padding by Space + lcd.write(' '); +} + +// short cut to print to the first line +void printLine1(const char *c){ + printLine(1,c); +} +// short cut to print to the first line +void printLine2(const char *c){ + printLine(0,c); +} + +void clearLine2() +{ + printLine2(""); + line2DisplayStatus = 0; +} + +// short cut to print to the first line +void printLine1Clear(){ + printLine(1,""); +} +// short cut to print to the first line +void printLine2Clear(){ + printLine(0, ""); +} + +void printLine2ClearAndUpdate(){ + printLine(0, ""); + line2DisplayStatus = 0; + updateDisplay(); +} + +//012...89ABC...Z +char byteToChar(byte srcByte){ + if (srcByte < 10) + return 0x30 + srcByte; + else + return 'A' + srcByte - 10; +} + +// this builds up the top line of the display with frequency and mode +void updateDisplay() { + // tks Jack Purdum W8TEE + // replaced fsprint commmands by str commands for code size reduction + // replace code for Frequency numbering error (alignment, point...) by KD8CEC + int i; + unsigned long tmpFreq = frequency; // + + memset(c, 0, sizeof(c)); + + if (inTx){ + if (isCWAutoMode == 2) { + for (i = 0; i < 4; i++) + c[3-i] = (i < autoCWSendReservCount ? byteToChar(autoCWSendReserv[i]) : ' '); + + //display Sending Index + c[4] = byteToChar(sendingCWTextIndex); + c[5] = '='; + } + else { + if (cwTimeout > 0) + strcpy(c, " CW:"); + else + strcpy(c, " TX:"); + } + } + else { + if (ritOn) + strcpy(c, "RIT "); + else { + if (cwMode == 0) + { + if (isUSB) + strcpy(c, "USB "); + else + strcpy(c, "LSB "); + } + else if (cwMode == 1) + { + strcpy(c, "CWL "); + } + else + { + strcpy(c, "CWU "); + } + } + if (vfoActive == VFO_A) // VFO A is active + strcat(c, "A:"); + else + strcat(c, "B:"); + } + + //Fixed by Mitani Massaru (JE4SMQ) + if (isShiftDisplayCWFreq == 1) + { + if (cwMode == 1) //CWL + tmpFreq = tmpFreq - sideTone + shiftDisplayAdjustVal; + else if (cwMode == 2) //CWU + tmpFreq = tmpFreq + sideTone + shiftDisplayAdjustVal; + } + + //display frequency + for (int i = 15; i >= 6; i--) { + if (tmpFreq > 0) { + if (i == 12 || i == 8) c[i] = '.'; + else { + c[i] = tmpFreq % 10 + 0x30; + tmpFreq /= 10; + } + } + else + c[i] = ' '; + } + + //remarked by KD8CEC + //already RX/TX status display, and over index (16 x 2 LCD) + //if (inTx) + // strcat(c, " TX"); + printLine(1, c); + + byte diplayVFOLine = 1; + if ((displayOption1 & 0x01) == 0x01) + diplayVFOLine = 0; + + if ((vfoActive == VFO_A && ((isDialLock & 0x01) == 0x01)) || + (vfoActive == VFO_B && ((isDialLock & 0x02) == 0x02))) { + lcd.setCursor(5,diplayVFOLine); + lcd.write((uint8_t)0); + } + else if (isCWAutoMode == 2){ + lcd.setCursor(5,diplayVFOLine); + lcd.write(0x7E); + } + else + { + lcd.setCursor(5,diplayVFOLine); + lcd.write(":"); + } +} + + + +char line2Buffer[16]; +//KD8CEC 200Hz ST +//L14.150 200Hz ST +//U14.150 +150khz +int freqScrollPosition = 0; +//Example Line2 Optinal Display +//immediate execution, not call by scheulder +void updateLine2Buffer(char displayType) +{ + unsigned long tmpFreq = 0; + if (ritOn) + { + strcpy(line2Buffer, "RitTX:"); + + //display frequency + tmpFreq = ritTxFrequency; + for (int i = 15; i >= 6; i--) { + if (tmpFreq > 0) { + if (i == 12 || i == 8) line2Buffer[i] = '.'; + else { + line2Buffer[i] = tmpFreq % 10 + 0x30; + tmpFreq /= 10; + } + } + else + line2Buffer[i] = ' '; + } + + return; + } //end of ritOn display + + //====================================================== + //other VFO display + //====================================================== + if (vfoActive == VFO_B) + { + tmpFreq = vfoA; + } + else + { + tmpFreq = vfoB; + } + + // EXAMPLE 1 & 2 + //U14.150.100 + //display frequency + for (int i = 9; i >= 0; i--) { + if (tmpFreq > 0) { + if (i == 2 || i == 6) line2Buffer[i] = '.'; + else { + line2Buffer[i] = tmpFreq % 10 + 0x30; + tmpFreq /= 10; + } + } + else + line2Buffer[i] = ' '; + } + + //EXAMPLE #1 + if ((displayOption1 & 0x04) == 0x00) //none scroll display + line2Buffer[6] = 'k'; + else + { + //example #2 + if (freqScrollPosition++ > 18) //none scroll display time + { + line2Buffer[6] = 'k'; + if (freqScrollPosition > 25) + freqScrollPosition = -1; + } + else //scroll frequency + { + line2Buffer[10] = 'H'; + line2Buffer[11] = 'z'; + + if (freqScrollPosition < 7) + { + for (int i = 11; i >= 0; i--) + if (i - (7 - freqScrollPosition) >= 0) + line2Buffer[i] = line2Buffer[i - (7 - freqScrollPosition)]; + else + line2Buffer[i] = ' '; + } + else + { + for (int i = 0; i < 11; i++) + if (i + (freqScrollPosition - 7) <= 11) + line2Buffer[i] = line2Buffer[i + (freqScrollPosition - 7)]; + else + line2Buffer[i] = ' '; + } + } + } //scroll + + line2Buffer[7] = ' '; + + if (isIFShift) + { +// if (isDirectCall == 1) +// for (int i = 0; i < 16; i++) +// line2Buffer[i] = ' '; + + //IFShift Offset Value + line2Buffer[8] = 'I'; + line2Buffer[9] = 'F'; + + line2Buffer[10] = ifShiftValue >= 0 ? '+' : 0; + line2Buffer[11] = 0; + line2Buffer[12] = ' '; + + //11, 12, 13, 14, 15 + memset(b, 0, sizeof(b)); + ltoa(ifShiftValue, b, DEC); + strncat(line2Buffer, b, 5); + + //if (isDirectCall == 1) //if call by encoder (not scheduler), immediate print value + printLine2(line2Buffer); + } // end of display IF + else // step & Key Type display + { + //if (isDirectCall != 0) + // return; + + memset(&line2Buffer[8], ' ', 8); + //Step + long tmpStep = arTuneStep[tuneStepIndex -1]; + + byte isStepKhz = 0; + if (tmpStep >= 1000) + { + isStepKhz = 2; + } + + for (int i = 10; i >= 8 - isStepKhz; i--) { + if (tmpStep > 0) { + line2Buffer[i + isStepKhz] = tmpStep % 10 + 0x30; + tmpStep /= 10; + } + else + line2Buffer[i +isStepKhz] = ' '; + } + + if (isStepKhz == 0) + { + line2Buffer[11] = 'H'; + line2Buffer[12] = 'z'; + } + + line2Buffer[13] = ' '; + + //Check CW Key cwKeyType = 0; //0: straight, 1 : iambica, 2: iambicb + if (cwKeyType == 0) + { + line2Buffer[14] = 'S'; + line2Buffer[15] = 'T'; + } + else if (cwKeyType == 1) + { + line2Buffer[14] = 'I'; + line2Buffer[15] = 'A'; + } + else + { + line2Buffer[14] = 'I'; + line2Buffer[15] = 'B'; + } + } +} + +//meterType : 0 = S.Meter, 1 : P.Meter +void DisplayMeter(byte meterType, byte meterValue, char drawPosition) +{ + if (meterType == 0 || meterType == 1 || meterType == 2) + { + drawMeter(meterValue); //call original source code + int lineNumber = 0; + if ((displayOption1 & 0x01) == 0x01) + lineNumber = 1; + + lcd.setCursor(drawPosition, lineNumber); + + for (int i = 0; i < 6; i++) //meter 5 + +db 1 = 6 + lcd.write(lcdMeter[i]); + } +} + +byte testValue = 0; +char checkCount = 0; +void idle_process() +{ + //space for user graphic display + if (menuOn == 0) + { + if ((displayOption1 & 0x10) == 0x10) //always empty topline + return; + + //if line2DisplayStatus == 0 <-- this condition is clear Line, you can display any message + if (line2DisplayStatus == 0 || (((displayOption1 & 0x04) == 0x04) && line2DisplayStatus == 2)) { + if (checkCount++ > 1) + { + updateLine2Buffer(0); //call by scheduler + printLine2(line2Buffer); + line2DisplayStatus = 2; + checkCount = 0; + } + + //EX for Meters + /* + DisplayMeter(0, testValue++, 7); + if (testValue > 30) + testValue = 0; + */ + } + } +} + + +#endif diff --git a/ubitx_20/ubitx_idle.ino b/ubitx_20/ubitx_lcd_1602p.ino similarity index 92% rename from ubitx_20/ubitx_idle.ino rename to ubitx_20/ubitx_lcd_1602p.ino index bee7c2f..b37bb45 100644 --- a/ubitx_20/ubitx_idle.ino +++ b/ubitx_20/ubitx_lcd_1602p.ino @@ -1,7 +1,10 @@ /************************************************************************* - KD8CEC's uBITX Idle time Processing - Functions that run at times that do not affect TX, CW, and CAT - It is called in 1/10 time unit. + KD8CEC's uBITX Display Routine for LCD1602 Parrel + 1.This is the display code for the default LCD mounted in uBITX. + 2.Display related functions of uBITX. Some functions moved from uBITX_Ui. + 3.uBITX Idle time Processing + Functions that run at times that do not affect TX, CW, and CAT + It is called in 1/10 time unit. ----------------------------------------------------------------------------- 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 @@ -17,6 +20,37 @@ along with this program. If not, see . **************************************************************************/ +#ifdef UBITX_DISPLAY_LCD1602P + + +//========================================================================= +//Hardware Control routines +//========================================================================= + + +#include +LiquidCrystal lcd(8,9,10,11,12,13); + +char c[30], b[30]; +char printBuff[2][17]; //mirrors what is showing on the two lines of the display + +void LCD_Init(void) +{ + lcd.begin(16, 2); + initMeter(); //for Meter Display +} + +void Display_AutoKeyTextIndex(char textIndex) +{ + byte diplayAutoCWLine = 0; + + if ((displayOption1 & 0x01) == 0x01) + diplayAutoCWLine = 1; + lcd.setCursor(0, diplayAutoCWLine); + lcd.write(byteToChar(selectedCWTextIndex)); + lcd.write(':'); +} + //======================================================================== //Display Routine @@ -511,3 +545,5 @@ void idle_process() } } + +#endif diff --git a/ubitx_20/ubitx_lcd_2404i.ino b/ubitx_20/ubitx_lcd_2404i.ino new file mode 100644 index 0000000..bee57ab --- /dev/null +++ b/ubitx_20/ubitx_lcd_2404i.ino @@ -0,0 +1,22 @@ +/************************************************************************* + KD8CEC's uBITX Display Routine for LCD2404 I2C + uBITX Idle time Processing + Functions that run at times that do not affect TX, CW, and CAT + It is called in 1/10 time unit. +----------------------------------------------------------------------------- + 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 . + +**************************************************************************/ + + diff --git a/ubitx_20/ubitx_lcd_2404p.ino b/ubitx_20/ubitx_lcd_2404p.ino new file mode 100644 index 0000000..66c9868 --- /dev/null +++ b/ubitx_20/ubitx_lcd_2404p.ino @@ -0,0 +1,22 @@ +/************************************************************************* + KD8CEC's uBITX Display Routine for LCD2404 Parrel + uBITX Idle time Processing + Functions that run at times that do not affect TX, CW, and CAT + It is called in 1/10 time unit. +----------------------------------------------------------------------------- + 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 . + +**************************************************************************/ + +