/*************************************************************************
  KD8CEC's uBITX Display Routine for Nextion LCD
  
  Uses the default protocol of Nextion LCD.
  Do not assign a 2 byte address to Nextion LCD.
-----------------------------------------------------------------------------
   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 <http://www.gnu.org/licenses/>.

**************************************************************************/
#include "ubitx.h"
#include "ubitx_lcd.h"

//======================================================================== 
//Begin of Nextion LCD Library by KD8CEC
//========================================================================
#ifdef UBITX_DISPLAY_NEXTION
/*************************************************************************
  Nextion Library for uBItX
  KD8CEC
**************************************************************************/
extern void SWSerial_Begin(long speedBaud);
extern void SWSerial_Write(uint8_t b);
extern int SWSerial_Available(void);
extern int SWSerial_Read(void);
extern void SWSerial_Print(uint8_t *b);

#define TEXT_LINE_LENGTH 20
char softBuffLines[2][TEXT_LINE_LENGTH + 1];
char softBuffSended[2][TEXT_LINE_LENGTH + 1];
char softBuffTemp[TEXT_LINE_LENGTH + 1];    //for STR Command

char c[30], b[30];
char softBuff[20];
char softTemp[20];

void LCDNextion_Init()
{
  SWSerial_Begin(9600);
  memset(softBuffLines[0], ' ', TEXT_LINE_LENGTH); 
  softBuffLines[0][TEXT_LINE_LENGTH + 1] = 0x00;
  memset(softBuffLines[1], ' ', TEXT_LINE_LENGTH);
  softBuffLines[1][TEXT_LINE_LENGTH + 1] = 0x00;
}

void LCD_Init(void)
{
  LCDNextion_Init();  
}

//===================================================================
//Begin of Nextion LCD Protocol
//
// v0~v9, va~vz : Numeric (Transceiver -> Nextion LCD)
// s0~s9  : String (Text) (Transceiver -> Nextion LCD)
// vlSendxxx, vloxxx: Reserve for Nextion (Nextion LCD -> Transceiver)
//
//===================================================================
#define CMD_NOW_DISP      '0' //c0
char L_nowdisp = -1;          //Sended nowdisp

#define CMD_VFO_TYPE      'v' //cv
char L_vfoActive;             //vfoActive

#define CMD_CURR_FREQ     'c' //vc
unsigned long L_vfoCurr;      //vfoA
#define CMD_CURR_MODE     'c' //cc
byte L_vfoCurr_mode;          //vfoA_mode

#define CMD_VFOA_FREQ     'a' //va
unsigned long L_vfoA;         //vfoA
#define CMD_VFOA_MODE     'a' //ca
byte L_vfoA_mode;             //vfoA_mode

#define CMD_VFOB_FREQ     'b' //vb
unsigned long L_vfoB;         //vfoB
#define CMD_VFOB_MODE     'b' //cb
byte L_vfoB_mode;             //vfoB_mode

#define CMD_IS_RIT        'r' //cr
char L_ritOn;
#define CMD_RIT_FREQ      'r' //vr
unsigned long L_ritTxFrequency; //ritTxFrequency

#define CMD_IS_TX         't' //ct
char L_inTx;

#define CMD_IS_DIALLOCK   'l' //cl
byte L_isDialLock;            //byte isDialLock

#define CMD_IS_SPLIT      's' //cs
byte  L_Split;            //isTxType
#define CMD_IS_TXSTOP     'x' //cx
byte  L_TXStop;           //isTxType

#define CMD_TUNEINDEX     'n' //cn
byte L_tuneStepIndex;     //byte tuneStepIndex

#define CMD_SMETER        'p' //cs
byte L_scaledSMeter;      //scaledSMeter

#define CMD_SIDE_TONE     't' //vt
unsigned long L_sideTone; //sideTone
#define CMD_KEY_TYPE      'k' //ck
byte L_cwKeyType = -1;          //L_cwKeyType 0: straight, 1 : iambica, 2: iambicb

#define CMD_CW_SPEED      's' //vs
unsigned int L_cwSpeed;   //cwSpeed

#define CMD_CW_DELAY      'y' //vy
byte L_cwDelayTime=-1;       //cwDelayTime

#define CMD_CW_STARTDELAY 'e' //ve
byte L_delayBeforeCWStartTime=-1;  //byte delayBeforeCWStartTime

#define CMD_ATT_LEVEL     'f' //vf
byte L_attLevel;

byte L_isIFShift;             //1 = ifShift, 2 extend
#define CMD_IS_IFSHIFT    'i' //ci

int L_ifShiftValue;
#define CMD_IFSHIFT_VALUE 'i' //vi

byte L_sdrModeOn;
#define CMD_SDR_MODE      'j' //cj

#define CMD_UBITX_INFO     'm' //cm  Complete Send uBITX Information

//Once Send Data, When boot
//arTuneStep, When boot, once send
//long arTuneStep[5];
#define CMD_AR_TUNE1      '1' //v1
#define CMD_AR_TUNE2      '2' //v2
#define CMD_AR_TUNE3      '3' //v3
#define CMD_AR_TUNE4      '4' //v4
#define CMD_AR_TUNE5      '5' //v5


#define CMD_IS_CW_SHIFT_DISPLAY 'h' //ch
byte L_isShiftDisplayCWFreq;  //byte isShiftDisplayCWFreq

#define CMD_CW_SHIFT_ADJUST     'h' //vh
int L_shiftDisplayAdjustVal;        //int shiftDisplayAdjustVal

//0:CW Display Shift Confirm, 1 : IFshift save
#define CMD_COMM_OPTION     'o'     //vo
byte L_commonOption0;         //byte commonOption0

//0:Line Toggle, 1 : Always display Callsign, 2 : scroll display, 3 : s.meter
#define CMD_DISP_OPTION1    'p'   //vp
byte L_displayOption1;            //byte displayOption1
#define CMD_DISP_OPTION2    'q'   //vq
byte L_displayOption2;            //byte displayOption2 (Reserve)

#define CMD_TEXT_LINE0      '0'   //s0
#define CMD_TEXT_LINE1      '1'   //s1

#define CMD_CW_TEXT         'a'   //sa
#define CMD_CALLSIGN        'c'   //sc
#define CMD_VERSION         'v'   //sv

#define TS_CMD_MODE           1
#define TS_CMD_FREQ           2
#define TS_CMD_BAND           3
#define TS_CMD_VFO            4
#define TS_CMD_SPLIT          5
#define TS_CMD_RIT            6
#define TS_CMD_TXSTOP         7
#define TS_CMD_SDR            8
#define TS_CMD_LOCK           9 //Dial Lock
#define TS_CMD_ATT           10 //ATT
#define TS_CMD_IFS           11 //IFS Enabled
#define TS_CMD_IFSVALUE      12 //IFS VALUE
#define TS_CMD_STARTADC      13
#define TS_CMD_STOPADC       14
#define TS_CMD_SPECTRUMOPT   15 //Option for Spectrum
#define TS_CMD_SPECTRUM      16 //Get Spectrum Value
#define TS_CMD_TUNESTEP      17 //Get Spectrum Value
#define TS_CMD_WPM           18 //Set WPM
#define TS_CMD_KEYTYPE       19 //Set KeyType

#define TS_CMD_SWTRIG        21 //SW Action Trigger for WSPR and more
#define TS_CMD_READMEM       31 //Read EEProm
#define TS_CMD_WRITEMEM      32 //Write EEProm
#define TS_CMD_LOOPBACK0     74 //Loopback1 (Response to Loopback Channgel)
#define TS_CMD_LOOPBACK1     75 //Loopback2 (Response to Loopback Channgel)
#define TS_CMD_LOOPBACK2     76 //Loopback3 (Response to Loopback Channgel)
#define TS_CMD_LOOPBACK3     77 //Loopback4 (Response to Loopback Channgel)
#define TS_CMD_LOOPBACK4     78 //Loopback5 (Response to Loopback Channgel)
#define TS_CMD_LOOPBACK5     79 //Loopback6 (Response to Loopback Channgel)
#define TS_CMD_FACTORYRESET  85 //Factory Reset
#define TS_CMD_UBITX_REBOOT  95 //Reboot

char nowdisp = 0;

#define SWS_HEADER_CHAR_TYPE 'c'  //1Byte Protocol Prefix
#define SWS_HEADER_INT_TYPE  'v'  //Numeric Protocol Prefex
#define SWS_HEADER_STR_TYPE  's'  //for TEXT Line compatiable Character LCD Control

//Control must have prefix 'v' or 's'
char softSTRHeader[11] = {'p', 'm', '.', 's', '0', '.', 't', 'x', 't', '=', '\"'};
char softINTHeader[10] = {'p', 'm', '.', 'v', '0', '.', 'v', 'a', 'l', '='};
const byte ADCIndex[6] = {A0, A1, A2, A3, A6, A7};

//send data for Nextion LCD
void SendHeader(char varType, char varIndex)
{
  if (varType == SWS_HEADER_STR_TYPE)
  {
    softSTRHeader[4] = varIndex;
    for (int i = 0; i < 11; i++)
      SWSerial_Write(softSTRHeader[i]);
  }
  else
  {
    softINTHeader[4] = varIndex;
    for (int i = 0; i < 10; i++)
      SWSerial_Write(softINTHeader[i]);
  }
}

#define INT_ETX 0
#define STR_ETX 1
#define TMP_ETX 2
//Send 0xFF, 0xFF, 0xFF
//etxType : INT_ETX = 0xFF, 0xFF, 0xFF
//          STR_ETX = ", 0xFF, 0xFF, 0xFF
//          TEMP_ETX = softTemp, 0xFF, 0xFF, 0xff

void SendCommandETX(char etxType)
{
  if (etxType == 2)
  {
    SWSerial_Print(softTemp);
  }
  else if (etxType == 1)
  {
    SWSerial_Print("\"");
  }
  
  SWSerial_Write(0xff);
  SWSerial_Write(0xff);
  SWSerial_Write(0xff);
}

void SendCommandUL(char varIndex, unsigned long sendValue)
{
  SendHeader(SWS_HEADER_INT_TYPE, varIndex);

  memset(softTemp, 0, 20);
  ultoa(sendValue, softTemp, DEC);
  SendCommandETX(TMP_ETX);
}

void SendCommandL(char varIndex, long sendValue)
{
  SendHeader(SWS_HEADER_INT_TYPE, varIndex);

  memset(softTemp, 0, 20);
  ltoa(sendValue, softTemp, DEC);
  SendCommandETX(TMP_ETX);
}

void SendCommandStr(char varIndex, char* sendValue)
{
  SendHeader(SWS_HEADER_STR_TYPE, varIndex);
  
  SWSerial_Print(sendValue);
  SendCommandETX(STR_ETX);
}

//Send String data with duplicate check
void SendTextLineBuff(char lineNumber)
{
  //Check Duplicated data
  if (strcmp(softBuffLines[lineNumber], softBuffSended[lineNumber]))
  {
    SendHeader(SWS_HEADER_STR_TYPE, lineNumber + 0x30);  //s0.txt, s1.txt
  
    SWSerial_Print(softBuffLines[lineNumber]);
    SendCommandETX(STR_ETX);
    
    strcpy(softBuffSended[lineNumber], softBuffLines[lineNumber]);
  }
}

void SendTextLineStr(char lineNumber, char* sendValue)
{
  int i = 0;
  for (i = 0; i < 16; i++)
  {
    if (sendValue[i] == 0x00)
      break;
    else
      softBuffLines[lineNumber][i] = sendValue[i];
  }
  
  for (;i < 20; i++)
  {
    softBuffLines[lineNumber][i] = ' ';
  }

  softBuffLines[lineNumber][TEXT_LINE_LENGTH + 1] = 0x00;
  SendTextLineBuff(lineNumber);
}

void SendEEPromData(char varIndex, int eepromStartIndex, int eepromEndIndex, char offsetTtype) 
{
  SendHeader(SWS_HEADER_STR_TYPE, varIndex);
  
  for (int i = eepromStartIndex; i <= eepromEndIndex; i++)
  {
      SWSerial_Write(EEPROM.read((offsetTtype == 0 ? USER_CALLSIGN_DAT : WSPR_MESSAGE1) + i));
  }

  SendCommandETX(STR_ETX);
}

uint8_t softBuff1Num[14] = {'p', 'm', '.', 'c', '0', '.', 'v', 'a', 'l', '=', 0, 0xFF, 0xFF, 0xFF};
void SendCommand1Num(char varType, char sendValue) //0~9 : Mode, nowDisp, ActiveVFO, IsDialLock, IsTxtType, IsSplitType
{
  softBuff1Num[4] = varType;
  softBuff1Num[10] = sendValue + 0x30;

  for (int i = 0; i < 14; i++)
    SWSerial_Write(softBuff1Num[i]);
}

void SetSWActivePage(char newPageIndex)
{
    if (L_nowdisp != newPageIndex)
    {
      L_nowdisp = newPageIndex;
      SendCommand1Num(CMD_NOW_DISP, L_nowdisp);
    }
}
//===================================================================
//End of Nextion LCD Protocol
//===================================================================

// The generic routine to display one line on the LCD 
void printLine(unsigned char linenmbr, const char *c) {
  SendTextLineStr(linenmbr, c);
}

void printLineF(char linenmbr, const __FlashStringHelper *c)
{
  int i;
  char tmpBuff[21];
  PGM_P p = reinterpret_cast<PGM_P>(c);  

  for (i = 0; i < 21; i++){
    unsigned char fChar = pgm_read_byte(p++);
    tmpBuff[i] = fChar;
    if (fChar == 0)
      break;
  }

  printLine(linenmbr, tmpBuff);
}

#define LCD_MAX_COLUMN 20
void printLineFromEEPRom(char linenmbr, char lcdColumn, byte eepromStartIndex, byte eepromEndIndex, char offsetTtype) 
{
  int colIndex = lcdColumn;
  for (byte i = eepromStartIndex; i <= eepromEndIndex; i++)
  {
    if (++lcdColumn <= LCD_MAX_COLUMN)
      softBuffLines[linenmbr][colIndex++] = EEPROM.read((offsetTtype == 0 ? USER_CALLSIGN_DAT : WSPR_MESSAGE1) + i);
    else
      break;
  }

  SendTextLineBuff(linenmbr);
}

//  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();
}

//==================================================================================
//End of Display Base Routines
//==================================================================================

//==================================================================================
//Begin of User Interface Routines
//==================================================================================
//Main Display for Nextion LCD
//unsigned long 
byte nowPageIndex = 0;

//sendType == 1 not check different 
void sendUIData(int sendType)
{
  char nowActiveVFO = vfoActive == VFO_A ? 0 : 1;

  //#define CMD_VFO_TYPE      'v' //cv
  if (L_vfoActive != nowActiveVFO)
  {
    L_vfoActive = nowActiveVFO;
    SendCommand1Num(CMD_VFO_TYPE, L_vfoActive);
  }

  //#define CMD_CURR_FREQ     'c' //vc
  if (L_vfoCurr != frequency)
  {
    L_vfoCurr = frequency;
    SendCommandUL(CMD_CURR_FREQ, frequency);
  }

  //#define CMD_CURR_MODE     'c' //cc
  byte vfoCurr_mode = modeToByte();
  if (L_vfoCurr_mode != vfoCurr_mode)
  {
    L_vfoCurr_mode = vfoCurr_mode;
    SendCommand1Num(CMD_CURR_MODE, L_vfoCurr_mode);
  }

  //if auto cw key mode, exit
  //if (isCWAutoMode != 0 || menuOn != 0)
  if (isCWAutoMode != 0)
    return;

  //nowPageIndex = 0;
  if (menuOn==0)
  {
    if (sendType == 0)
    {
      SetSWActivePage(0);
    }
    else
    {
      SetSWActivePage(0);
    }
  }
  else
  {
    //Text Line Mode
      SetSWActivePage(1);
  }

  //#define CMD_VFOA_FREQ     'a' //va
  //VFOA
  if (L_vfoA != vfoA)
  {
    L_vfoA = vfoA;
    SendCommandUL(CMD_VFOA_FREQ, L_vfoA);
  }

  //#define CMD_VFOA_MODE     'a' //ca
  if (L_vfoA_mode != vfoA_mode)
  {
    L_vfoA_mode = vfoA_mode;
    SendCommand1Num(CMD_VFOA_MODE, L_vfoA_mode);
  }

  //#define CMD_VFOB_FREQ     'b' //vb
  //VFOB
  if (L_vfoB != vfoB)
  {
    L_vfoB = vfoB;
    SendCommandUL(CMD_VFOB_FREQ, L_vfoB);
  }

  //#define CMD_VFOB_MODE     'b' //cb
  if (L_vfoB_mode != vfoB_mode)
  {
    L_vfoB_mode = vfoB_mode;
    SendCommand1Num(CMD_VFOB_MODE, L_vfoB_mode);  
  }

  //byte isDialLock = ((isTxType & 0x01) == 0x01) ? 1 : 0;
  if (L_isDialLock != isDialLock)
  {
    L_isDialLock = isDialLock;
    SendCommand1Num(CMD_IS_DIALLOCK, L_isDialLock);  
  }

  //#define CMD_IS_RIT        'r' //cr
  if (L_ritOn != ritOn)
  {
    L_ritOn = ritOn;
    SendCommand1Num(CMD_IS_RIT, L_ritOn);  
  }
  
  //#define CMD_RIT_FREQ      'r' //vr
  //unsigned long L_ritTxFrequency; //ritTxFrequency
  if (L_ritTxFrequency != ritTxFrequency)
  {
    L_ritTxFrequency = ritTxFrequency;
    SendCommandUL(CMD_RIT_FREQ, L_ritTxFrequency);  
  }

  //#define CMD_IS_TX         't' //ct
  //char L_inTx;
  if (L_inTx != inTx)
  {
    L_inTx = inTx;
    SendCommand1Num(CMD_IS_TX, L_inTx);  
  }

  //#define CMD_IS_DIALLOCK   'l' //cl
  //byte L_isDialLock;            //byte isDialLock
  if (L_isDialLock != isDialLock)
  {
    L_isDialLock = isDialLock;
    SendCommand1Num(CMD_IS_DIALLOCK, L_isDialLock);  
  }

  //#define CMD_IS_SPLIT      's' //cs
  //byte  L_Split;            //isTxType
  if (L_Split != splitOn)
  {
    L_Split = splitOn;
    SendCommand1Num(CMD_IS_SPLIT, L_Split);  
  }
  

  //#define CMD_IS_TXSTOP     'x' //cx
  byte isTXStop = ((isTxType & 0x01) == 0x01);
  if (L_TXStop != isTXStop)
  {
    L_TXStop = isTXStop;
    SendCommand1Num(CMD_IS_TXSTOP, L_TXStop);
  }

  //#define CMD_TUNEINDEX     'n' //cn
  if (L_tuneStepIndex != tuneStepIndex)
  {
    L_tuneStepIndex = tuneStepIndex;
    SendCommand1Num(CMD_TUNEINDEX, L_tuneStepIndex);
  }

  //#define CMD_SMETER        'p' //cp
  if (L_scaledSMeter != scaledSMeter)
  {
    L_scaledSMeter = scaledSMeter;
    SendCommand1Num(CMD_SMETER, L_scaledSMeter);  
  }

  //#define CMD_SIDE_TONE     't' //vt
  if (L_sideTone != sideTone)
  {
    L_sideTone = sideTone;
    SendCommandL(CMD_SIDE_TONE, L_sideTone);
  }

  //#define CMD_KEY_TYPE      'k' //ck
  if (L_cwKeyType != cwKeyType)
  {
    L_cwKeyType = cwKeyType;
    SendCommand1Num(CMD_KEY_TYPE, L_cwKeyType);  
  }

  //#define CMD_CW_SPEED      's' //vs
  if (L_cwSpeed != cwSpeed)
  {
    L_cwSpeed = cwSpeed;
    SendCommandL(CMD_CW_SPEED, L_cwSpeed);  
  }

  //#define CMD_CW_DELAY      'y' //vy
  if (L_cwDelayTime != cwDelayTime)
  {
    L_cwDelayTime = cwDelayTime;
    SendCommandL(CMD_CW_DELAY, L_cwDelayTime);  
  }

  //#define CMD_CW_STARTDELAY 'e' //ve
  if (L_delayBeforeCWStartTime != delayBeforeCWStartTime)
  {
    L_delayBeforeCWStartTime = delayBeforeCWStartTime;
    SendCommandL(CMD_CW_STARTDELAY, L_delayBeforeCWStartTime);
  }

  //#define CMD_ATT_LEVEL     'f' //vf
  if (L_attLevel != attLevel)
  {
    L_attLevel = attLevel;
    SendCommandL(CMD_ATT_LEVEL, L_attLevel);
  }

  //#define CMD_IS_IFSHIFT    'i'
  if (L_isIFShift != isIFShift)
  {
    L_isIFShift = isIFShift;
    SendCommand1Num(CMD_IS_IFSHIFT, L_isIFShift);
  }

  //#define CMD_IFSHIFT_VALUE 'i'
  if (L_ifShiftValue != ifShiftValue)
  {
    L_ifShiftValue = ifShiftValue;
    SendCommandL(CMD_IFSHIFT_VALUE, L_ifShiftValue);
  }

  //#define CMD_SDR_MODE      'j' //cj
  if (L_sdrModeOn != sdrModeOn)
  {
    L_sdrModeOn = sdrModeOn;
    SendCommand1Num(CMD_SDR_MODE, L_sdrModeOn);
  }
}

void updateDisplay() {
  sendUIData(0);  //UI 
}

//****************************************************************
// Spectrum for Range scan and Band Scan
//****************************************************************
#define RESPONSE_SPECTRUM     0
#define RESPONSE_EEPROM       1
#define RESPONSE_EEPROM_HEX_F 89  //C Language order
#define RESPONSE_EEPROM_HEX_R 72  //Nextion order (Reverse)
#define RESPONSE_EEPROM_STR   87  //String

const uint8_t ResponseHeader[11]={'p', 'm', '.', 's', 'h', '.', 't', 'x', 't', '=', '"'};
const char HexCodes[16] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f', };

//void sendSpectrumData(unsigned long startFreq, unsigned long incStep, int scanCount, int delayTime, int sendCount)
//sendResponseData(RESPONSE_EEPROM, 0, eepromIndex, eepromReadLength, eepromDataType, 1);
//protocol Type : 0 - Spectrum, 1 : EEProm
//startFreq   : Spectrum - Frequency, EEProm - 0
//sendOption1 : Spectrum - 1 Step Frequency, EEProm - EEProm Start Address
//scanCount   : Spectrum - 1 Set Length, EEProm - Read Length
//sendOption2 : Spectrum - Value offset (because support various S-Meter), EEProm - EEProm Response DataType (0:HEX, 1:String)
//sendCount : Spectrum - All scan set count, EEProm - always 1
void sendResponseData(int protocolType, unsigned long startFreq, unsigned int sendOption1, int readCount, int sendOption2, int sendCount)  //Spectrum and EEProm Data
{
  unsigned long beforFreq = frequency;
  unsigned long k;
  uint8_t adcBytes[200];    //Maximum 200 Step
  
  //Voltage drop
  //scanResult[0] = analogRead(ANALOG_SMETER);
  //adcBytes[0] = analogRead(ANALOG_SMETER);
  //delay(10);
  int readedValue = 0;

  for (int si = 0; si < sendCount; si++)
  {
    for (int i = 0; i < 11; i++)
      SWSerial_Write(ResponseHeader[i]);
      
    for (k = 0; k < readCount; k ++)
    {
      if (protocolType == RESPONSE_SPECTRUM)
      {
        //Spectrum Data
        //Sampling Range
        setFrequency(startFreq + (k * sendOption1));
        //Wait time for charging
        //delay(10);

#ifdef USE_I2CSMETER 
        readedValue = GetI2CSmeterValue(I2CMETER_UNCALCS);
#else
  
        //ADC
        readedValue = analogRead(ANALOG_SMETER);
        readedValue -= (sendOption2 * 3); //0 ~ 765
        //Down Scale
        readedValue /= 2;
        if (readedValue < 0)
        {
          readedValue = 0;
        }
        else if (readedValue>255)
        {
          readedValue=255;
        }
#endif        
      }
      else
      {
        readedValue = EEPROM.read(((sendOption2 == RESPONSE_EEPROM_HEX_R) ? (readCount - k - 1) : k) + sendOption1);
      }

      if (protocolType == RESPONSE_EEPROM && sendOption2 == RESPONSE_EEPROM_STR) //None HEX
      {
        SWSerial_Write(readedValue);
      }
      else
      {
        SWSerial_Write(HexCodes[readedValue >> 4]);
        SWSerial_Write(HexCodes[readedValue & 0xf]);
      }
    }
    
    SendCommandETX(STR_ETX);
  } //end of for
}

//****************************************************************
//Receive command and processing from External device (LCD or MCU)
//****************************************************************
int spectrumSendCount = 10;   //count of full scan and Send
int spectrumOffset = 0;    //offset position
int spectrumScanCount = 100;  //Maximum 200
unsigned int spectrumIncStep = 1000;   //Increaase Step
extern uint8_t receivedCommandLength;
extern void SWSerial_Read(uint8_t * receive_cmdBuffer);
uint8_t swr_buffer[20];

//SoftwareSerial_Process
void SWS_Process(void)
{
  //Received Command from touch screen
  if (receivedCommandLength > 0)
  {
    SWSerial_Read(swr_buffer);

    int8_t comandLength = receivedCommandLength;
    int8_t commandStartIndex = -1;
    receivedCommandLength = 0;

    //Data Process
    //comandLength //Find start Length
    for (int i = 0; i < comandLength - 3; i++)
    {
      if (swr_buffer[i] == 0x59 && swr_buffer[i+ 1] == 0x58 && swr_buffer[i + 2] == 0x68)
      {
        commandStartIndex = i;
        break;
      }
    } //end of for

    if (commandStartIndex != -1)
    {
      //Complete received command from touch screen
      uint8_t commandType = swr_buffer[commandStartIndex + 3];

      if (commandType == TS_CMD_MODE)
      {
        byteToMode(swr_buffer[commandStartIndex + 4], 1);
      }
      else if (commandType == TS_CMD_FREQ)
      {
        unsigned long *tempFreq;
        tempFreq = (unsigned long *)(&swr_buffer[commandStartIndex + 4]);
        //if (*tempFreq > 3000)  //for loss protcol
        //{
          frequency = *tempFreq;
        //}
      }
      else if (commandType == TS_CMD_BAND)
      {
        char currentBandIndex = -1;
        if (tuneTXType == 2 || tuneTXType == 3 || tuneTXType == 102 || tuneTXType == 103) 
        {  //only ham band move
          currentBandIndex = getIndexHambanBbyFreq(frequency);
          
          if (currentBandIndex >= 0) 
          {
            saveBandFreqByIndex(frequency, modeToByte(), currentBandIndex);
          }
        }
        setNextHamBandFreq(frequency, swr_buffer[commandStartIndex + 4] == 1 ? -1 : 1);  //Prior Band      
      }
      else if (commandType == TS_CMD_VFO)
      {
        menuVfoToggle(1); //Vfo Toggle        
      }
      else if (commandType == TS_CMD_SPLIT)
      {
        menuSplitOnOff(10);
      }
      else if (commandType == TS_CMD_RIT)
      {
        menuRitToggle(1);
      }
      else if (commandType == TS_CMD_TXSTOP)
      {
        menuTxOnOff(1, 0x01);
      }
      else if (commandType == TS_CMD_SDR)
      {
        menuSDROnOff(1);
      }
      else if (commandType == TS_CMD_LOCK)
      {
        if (vfoActive == VFO_A)
          setDialLock((isDialLock & 0x01) == 0x01 ? 0 : 1, 0); //Reverse Dial lock
        else
          setDialLock((isDialLock & 0x02) == 0x02 ? 0 : 1, 0); //Reverse Dial lock
      }
      else if (commandType == TS_CMD_ATT)
      {
        attLevel = swr_buffer[commandStartIndex + 4];
      }
      else if (commandType == TS_CMD_IFS)
      {
        isIFShift = isIFShift ? 0 : 1;  //Toggle
      }
      else if (commandType == TS_CMD_IFSVALUE)
      {
        ifShiftValue = *(long *)(&swr_buffer[commandStartIndex + 4]);
      }
      else if (commandType == TS_CMD_STARTADC)
      {
        int startIndex = swr_buffer[commandStartIndex + 4];
        int endIndex = swr_buffer[commandStartIndex + 5];
        int adcCheckInterval = swr_buffer[commandStartIndex + 6] * 10;
        int nowCheckIndex = startIndex;
        
        while(1 == 1)
        {
          if (receivedCommandLength > 0)
          {
            break;
          }
          
          SendCommandL('n', nowCheckIndex);    //Index Input
          SendCommandL('x', analogRead(ADCIndex[nowCheckIndex++]));
          
          if (nowCheckIndex > endIndex)
            nowCheckIndex = startIndex;
            
          delay(adcCheckInterval);
        } //end of while
      }
      else if (commandType == TS_CMD_STOPADC)
      {
          //None Action
          return;
      }
      else if (commandType == TS_CMD_SPECTRUM)
      {
        //sendSpectrumData(unsigned long startFreq, unsigned int incStep, int scanCount, int delayTime, int sendCount)
        //sendSpectrumData(frequency - (1000L * 50), 1000, 100, 0, 10);
        //sendSpectrumData(*(long *)(&swr_buffer[commandStartIndex + 4]), spectrumIncStep, spectrumScanCount, spectrumDelayTime, spectrumSendCount);
        unsigned long beforeFreq = frequency;
        sendResponseData(RESPONSE_SPECTRUM, *(long *)(&swr_buffer[commandStartIndex + 4]), spectrumIncStep, spectrumScanCount, spectrumOffset, spectrumSendCount);
        frequency = beforeFreq;
      }
      else if (commandType == TS_CMD_SPECTRUMOPT)
      {
        //sendSpectrumData(unsigned long startFreq, unsigned int incStep, int scanCount, int delayTime, int sendCount)
        //sendSpectrumData(frequency - (1000L * 50), 1000, 100, 0, 10);
        spectrumSendCount = swr_buffer[commandStartIndex + 4];          //count of full scan and Send
        spectrumOffset = swr_buffer[commandStartIndex + 5];             //Scan interval time
        spectrumScanCount = swr_buffer[commandStartIndex + 6];          //Maximum 120
        spectrumIncStep = swr_buffer[commandStartIndex + 7] * 20;       //Increaase Step
      }
      else if (commandType == TS_CMD_TUNESTEP)      //Set Tune Step
      {
        tuneStepIndex = swr_buffer[commandStartIndex + 4];    //Tune Step Index
      }
      else if (commandType == TS_CMD_WPM)      //Set WPM
      {
        cwSpeed = swr_buffer[commandStartIndex + 4];    //
      }
      else if (commandType == TS_CMD_KEYTYPE)                 //Set Key Type
      {
        cwKeyType = swr_buffer[commandStartIndex + 4];

        //for reduce program memory
        Iambic_Key = cwKeyType != 0;
        //if (cwKeyType == 0)
        //  Iambic_Key = false;
        //else
          //Iambic_Key = true;
          if (cwKeyType == 1)
            keyerControl &= ~IAMBICB;
          else
            keyerControl |= IAMBICB;
        //}
      }
      else if (commandType == TS_CMD_SWTRIG)
      {
        TriggerBySW = 1;    //Action Trigger by Software
      }
      else if (commandType == TS_CMD_READMEM ) //Read Mem
      {
       uint16_t eepromIndex    = *(uint16_t *)(&swr_buffer[commandStartIndex + 4]);
        byte eepromReadLength   = swr_buffer[commandStartIndex + 6];
        byte eepromDataType     = swr_buffer[commandStartIndex + 7];  //0 : Hex, 1 : String
        
        sendResponseData(RESPONSE_EEPROM, 0, eepromIndex, eepromReadLength, eepromDataType, 1);
      }
      else if (commandType == TS_CMD_WRITEMEM)    //Write Mem
      {
        /*
          Address : 2 byte int
          Length   : Data Length
          Checksum : (Addr0+Addr1+Len) %256
          Data      : Variable (Max 23)
         */
        uint16_t eepromIndex = *(uint16_t *)(&swr_buffer[commandStartIndex + 4]);
        byte writeLength     = swr_buffer[commandStartIndex + 6];
        byte writeCheckSum   = swr_buffer[commandStartIndex + 7];

        //Check Checksum
        if (writeCheckSum == (swr_buffer[commandStartIndex + 4] + swr_buffer[commandStartIndex + 5] + swr_buffer[commandStartIndex + 6]))
        //if (writeCheckSum == (swr_buffer[commandStartIndex + 4] + swr_buffer[commandStartIndex + 5] + writeLength))
        {
            //if (eepromIndex > 64) //Safe #1
#ifdef UBITX_DISPLAY_NEXTION_SAFE
            //Safe #2
            if (eepromIndex < 770 || eepromIndex > 775 )
            {
              eepromIndex = -2;              
            }
            else
#else
            if (1 == 1)            
#endif
            {
              for (int i = 0; i < writeLength; i++)
                EEPROM.write(eepromIndex + i , swr_buffer[commandStartIndex + 8 + i]);
            }
        }
        else
        {
          eepromIndex = -2;
        }
        SendCommandL('n', eepromIndex);             //Index Input
      }
      //else if (TS_CMD_LOOPBACK0 <= commandType && commandType <= TS_CMD_LOOPBACK5)  //Loop back Channel 0 ~ 5 Loop back Channel 1~5 : Reserve
      else if (TS_CMD_LOOPBACK0 == commandType)    //Loop back Channel 0 ~ 5
      {
        SendCommandUL('v', *(unsigned long *)&swr_buffer[commandStartIndex + 4]);     //Return data
        SendCommandUL('g', commandType);                                               //Index Input
        //return;
      }
      else if (commandType == TS_CMD_FACTORYRESET || commandType == TS_CMD_UBITX_REBOOT)
      {
        if (*(unsigned long *)&swr_buffer[commandStartIndex + 4] == 1497712748)
        {
          if (commandType == TS_CMD_UBITX_REBOOT)
          {
            FrequencyToVFO(1);  //Save current Frequency and Mode to eeprom
            asm volatile ("  jmp 0");
          }
          else
          {
            for (unsigned int i = 0; i < 32; i++) //factory setting range
              EEPROM.write(i, EEPROM.read(FACTORY_VALUES + i)); //65~96 => 0~31
          }
        }
      }

      setFrequency(frequency);
      SetCarrierFreq();
      updateDisplay(); 
    }
  }
}

char checkCount = 0;
char checkCountSMeter = 0;

UBitxRigState rigState;
UBitxRigState catState;

//execute interval : 0.25sec
void idle_process()
{
  // KC4UPR 2021-02-05 added update process for Raduino-TeensyDSP coordination
  // Note, need to not have to copy this every time...
  rigState.vfo[0] = vfoA;
  rigState.vfo[1] = vfoB;
  doRaduinoToTeensy(&rigState);
  
  //S-Meter Display
  if (((displayOption1 & 0x08) == 0x08 && (sdrModeOn == 0)) && (++checkCountSMeter > SMeterLatency))
  {
#ifdef USE_I2CSMETER 
    scaledSMeter = GetI2CSmeterValue(I2CMETER_CALCS);
#else
    int newSMeter;
    
    newSMeter = analogRead(ANALOG_SMETER) / 4;
    currentSMeter = newSMeter;
  
    scaledSMeter = 0;
    for (byte s = 8; s >= 1; s--) {
      if (currentSMeter > sMeterLevels[s]) {
        scaledSMeter = s;
        break;
      }
    }

#endif  
    checkCountSMeter = 0; //Reset Latency time
  } //end of S-Meter

  sendUIData(1);
}

//When boot time, send data
void SendUbitxData(void)
{
  //Wait for ready other device (LCD, DSP and more)
  //delay(500);
  delay_background(500, 2);
  
  SendCommandL(CMD_AR_TUNE1, arTuneStep[0]);
  SendCommandL(CMD_AR_TUNE2, arTuneStep[1]);
  SendCommandL(CMD_AR_TUNE3, arTuneStep[2]);
  SendCommandL(CMD_AR_TUNE4, arTuneStep[3]);
  SendCommandL(CMD_AR_TUNE5, arTuneStep[4]);
  
  SendCommand1Num(CMD_IS_CW_SHIFT_DISPLAY, isShiftDisplayCWFreq);
  SendCommandL(CMD_CW_SHIFT_ADJUST, shiftDisplayAdjustVal);
  SendCommandL(CMD_COMM_OPTION, commonOption0);
  SendCommandL(CMD_DISP_OPTION1, displayOption1);  

  unsigned long nextionDisplayOption;
  EEPROM.get(EXTERNAL_DEVICE_OPT1, nextionDisplayOption); 
  SendCommandUL(CMD_DISP_OPTION2, nextionDisplayOption);

  SendCommandStr(CMD_VERSION, (char *)("+v1.200")); //Version
  SendEEPromData(CMD_CALLSIGN, 0, userCallsignLength -1, 0);

  /*
  //Frequency of Bands
  for (int i = 0; i < 11; i++)
    SWSerial_Write(SpectrumHeader[i]);

  byte *tmpByte;
  tmpByte = (byte *)hamBandRange;
  for (byte i = 0; i < (useHamBandCount -1) * 4; i++) 
  {
    SWSerial_Write(HexCodes[*tmpByte >> 4]);
    SWSerial_Write(HexCodes[*tmpByte & 0xf]);
    tmpByte++;
  }
      
  for (int i = 0; i < 4; i++)
    SWSerial_Write(SpectrumFooter[i]);
  */    
    
  //Complte Send Info
  SendCommand1Num(CMD_UBITX_INFO, 1);

  //Page Init
  L_nowdisp = 0;
  SendCommand1Num(CMD_NOW_DISP, L_nowdisp);
}


//AutoKey LCD Display Routine
void Display_AutoKeyTextIndex(byte textIndex)
{
  byte diplayAutoCWLine = 0;
  
  if ((displayOption1 & 0x01) == 0x01)
    diplayAutoCWLine = 1;
  //LCD_SetCursor(0, diplayAutoCWLine);

  softBuffLines[diplayAutoCWLine][0] = byteToChar(textIndex);
  softBuffLines[diplayAutoCWLine][1] = ':';

  SendTextLineBuff(diplayAutoCWLine);
}

void LCD_CreateChar(uint8_t location, uint8_t charmap[]) 
{
}

void updateLine2Buffer(char displayType)
{
}

//not use with Nextion LCD
void DisplayCallsign(byte callSignLength)
{
}

//Not use with Nextion LCD
void DisplayVersionInfo(const __FlashStringHelper * fwVersionInfo)
{
}

#endif
