#include "soc/soc.h"
#include "soc/rtc_cntl_reg.h"
#include <WiFiClient.h>
#include <EEPROM.h>
#include <Wire.h>
#include <math.h>
#include <ESP32Time.h>              // https://github.com/fbiego/ESP32Time
#include <TFT_eSPI.h>               // https://github.com/ohmytime/TFT_eSPI_DynamicSpeed (Modified version)
#include <Hash.h>                   // https://github.com/bbx10/Hash_tng
#include "src/WiFiConnect.h"
#include "src/WiFiConnectParam.h"
#include "src/FONT16.h"
#include "src/FONT16_CHS.h"
#include "src/FONT28.h"
#include "src/FONT28_CHS.h"
#include "src/FONT48DEC.h"
#include "src/FREQFONT.h"
#include "src/TEF6686.h"
#include "src/constants.h"
#include "src/config.h"
#include "src/language.h"
#include "src/gui.h"
#include "src/comms.h"
#include "src/rds.h"

#define ROTARY_PIN_A    34
#define ROTARY_PIN_B    36
#define ROTARY_BUTTON   39
#define PIN_POT         35
#define BATTERY_PIN     13
#define BANDBUTTON       4
#define BWBUTTON        25
#define MODEBUTTON      26
#define CONTRASTPIN     2
#define STANDBYLED      19
#define SMETERPIN       27

#define DYNAMIC_SPI_SPEED   // uncomment to enable dynamic SPI Speed https://github.com/ohmytime/TFT_eSPI_DynamicSpeed

#ifdef ARS
TFT_eSPI tft = TFT_eSPI(320, 240);
#else
TFT_eSPI tft = TFT_eSPI(240, 320);
#endif

#ifdef DYNAMIC_SPI_SPEED
bool dynamicspi = true;
#else
bool dynamicspi = false;
#endif

bool advancedRDS;
bool afmethodBold;
bool afpage;
bool afscreen;
bool aftest;
bool artheadold;
bool autosquelch = true;
bool batterydetect = true;
bool beepresetstart;
bool beepresetstop;
bool BWreset;
bool BWtune;
bool change;
bool compressedold;
bool direction;
bool dropout;
bool dynamicPTYold;
bool edgebeep;
bool externaltune;
bool flashing;
bool fmsi;
bool fullsearchrds;
bool hasafold;
bool hasCTold;
bool haseonold;
bool hasrtplusold;
bool hastmcold;
bool LowLevelInit;
bool memorystore;
bool memreset;
bool memtune;
bool menu;
bool menuopen;
bool mwstepsize;
#ifdef HAS_AIR_BAND
bool airstepsize;
#endif
bool nobattery;
bool optenc;
bool rdsflagreset;
bool rdsreset;
bool RDSSPYTCP;
bool RDSSPYUSB;
bool RDSstatus;
bool RDSstatusold;
bool rdsstereoold;
bool rtcset;
bool scandxmode;
bool scanmem;
bool scanmute;
bool screenmute;
bool screensavertriggered = false;
bool seek;
bool setupmode;
byte showrdserrors;
bool usesquelch;
bool softmuteam;
bool softmutefm;
bool SQ;
bool Stereostatusold;
bool StereoToggle;
bool store;
bool TAold;
bool TPold;
bool tuned;
bool USBmode = 1;
bool XDRGTKMuteScreen;
bool wifi;
bool wificonnected;
bool XDRGTKdata;
bool XDRGTKTCP;
bool XDRGTKUSB;
bool XDRMute;
byte af_counterold;
byte aid_counterold;
byte af;
byte afpagenr;
byte amagc;
byte amnb;
byte amscansens;
byte audiomode;
byte band;
byte bandAM;
byte bandFM;
byte bandforbidden;
byte battery;
byte batteryold;
byte batteryoptions;
byte BWset;
byte BWsetAM;
byte BWsetFM;
byte charwidth = 8;
#ifdef CHINA_PORTABLE
byte hardwaremodel = PORTABLE_ILI9341;
#else
byte hardwaremodel = BASE_ILI9341;
#endif
byte ContrastSet;
byte CurrentSkin;
byte CurrentTheme;
byte displayflip;
byte ECCold;
byte eonptyold[20];
byte EQset;
byte fmagc;
byte fmscansens;
byte fmdefaultstepsize;
byte fmnb;
byte fmdeemphasis;
byte freqfont;
byte amcodect;
byte amcodectcount;
byte amgain;
byte freqoldcount;
byte HighCutLevel;
byte HighCutOffset;
byte iMSEQ;
byte iMSset;
byte language;
byte licold;
byte longbandpress;
byte memorypos;
byte memoryposold;
byte memoryposstatus;
byte menupage;
byte MSold;
byte poweroptions;
byte rdsblockold;
byte rdsqualityold;
byte region;
byte rotarymode;
byte touchrotating;
byte scancancel;
byte scanstart;
byte scanstop;
byte scanhold;
byte scanmodeold;
byte screensaverOptions[5] = {0, 3, 10, 30, 60};
byte screensaverset;
byte showmodulation;
byte showSWMIBand;
byte submenu;
byte stationlistid;
byte nowToggleSWMIBand = 1;
byte stepsize;
byte StereoLevel;
byte subnetclient;
byte TEF;
byte tot;
byte tunemode;
byte unit;
byte spispeed;
char buff[16];
char eonpicodeold[20][6];
char programTypePrevious[18];
const uint8_t* currentFont = nullptr;
float vPerold;
int ActiveColor;
int ActiveColorSmooth;
int AGC;
int AMLevelOffset;
int BackgroundColor;
int BackgroundColor1;
int BackgroundColor2;
int BackgroundColor3;
int BackgroundColor4;
int BackgroundColor5;
int BarSignificantColor;
int BarInsignificantColor;
int BatteryValueColor;
int BatteryValueColorSmooth;
int batupdatetimer;
int BWAutoColor;
int BWAutoColorSmooth;
int BWOld;
int bwupdatetimer;
int DeEmphasis;
int ForceMono;
int FrameColor;
int FreqColor;
int FreqColorSmooth;
int freqold;
int GreyoutColor;
int InsignificantColor;
int InsignificantColorSmooth;
int menuoption = ITEM1;
int ModBarInsignificantColor;
int ModBarSignificantColor;
int MStatusold;
int offsetupdatetimer;
int OStatusold;
int peakholdold;
int peakholdtimer;
int PrimaryColor;
int PrimaryColorSmooth;
int RDSColor;
int RDSColorSmooth;
int RDSDropoutColor;
int RDSDropoutColorSmooth;
int SignificantColor;
int SignificantColorSmooth;
int StereoColor;
int StereoColorSmooth;
int SquelchShow;
int rotary;
int rssi;
int rssiold = 200;
int scanner_filter;
int SecondaryColor;
int SecondaryColorSmooth;
int SNRupdatetimer;
int Sqstatusold;
int Squelch;
int Squelchold;
int SStatusold;
int Stereostatus;
int volume;
int XDRBWset;
int XDRBWsetold;
int xPos;
int xPos2;
int xPos3;
int xPos4;
int16_t OStatus;
int16_t SAvg;
int16_t SAvg2;
int16_t SAvg3;
int16_t SStatus;
int8_t LevelOffset;
int8_t LowLevelSet;
int8_t CN;
int8_t CNold;
int8_t VolSet;
float batteryVold;
IPAddress remoteip;
String AIDString;
String cryptedpassword;
String ECColdtxt;
String eonpsold[20];
String LIColdString;
String pinstringold;
String PIold;
String PSold;
String ptynold = " ";
String PTYold;
String rds_clock;
String rds_clockold;
String RDSSPYRDS;
String RDSSPYRDSold;
String RTold;
String salt;
String saltkey = "                ";
String stationIDold;
String stationStateold;
String StereoStatusCommand;
String StereoStatusCommandold;
String SWMIBandstring = String();
String SWMIBandstringold = String();
String XDRGTK_key;
String XDRGTKRDS;
String XDRGTKRDSold;
uint16_t BW;
uint16_t MStatus;
uint16_t SWMIBandPos;
uint16_t SWMIBandPosold;
uint16_t USN;
uint16_t WAM;
uint8_t buff_pos;
unsigned int ConverterSet;
unsigned int freq_scan;
unsigned int frequency;
unsigned int frequency_OIRT;
unsigned int frequency_AM;
unsigned int frequency_LW;
unsigned int frequency_MIBand_11M;
unsigned int frequency_MIBand_120M;
unsigned int frequency_MIBand_13M;
unsigned int frequency_MIBand_15M;
unsigned int frequency_MIBand_160M;
unsigned int frequency_MIBand_16M;
unsigned int frequency_MIBand_19M;
unsigned int frequency_MIBand_22M;
unsigned int frequency_MIBand_25M;
unsigned int frequency_MIBand_31M;
unsigned int frequency_MIBand_41M;
unsigned int frequency_MIBand_49M;
unsigned int frequency_MIBand_60M;
unsigned int frequency_MIBand_75M;
unsigned int frequency_MIBand_90M;
unsigned int frequency_MW;
unsigned int frequency_SW;
#ifdef HAS_AIR_BAND
unsigned int frequency_AIR;
unsigned int AIRHighEdgeSet;
unsigned int AIRLowEdgeSet;
#endif
unsigned int frequencyold;
unsigned int HighEdgeOIRTSet;
unsigned int HighEdgeSet;
unsigned int LowEdgeOIRTSet;
unsigned int LowEdgeSet;
unsigned int LWHighEdgeSet;
unsigned int LWLowEdgeSet;
unsigned int mappedfreqold[20];
unsigned int mappedfreqold2[20];
unsigned int mappedfreqold3[20];
unsigned int MWHighEdgeSet;
unsigned int MWLowEdgeSet;
unsigned int scanner_end;
unsigned int scanner_start;
unsigned int scanner_step;
unsigned int SWHighEdgeSet;
unsigned int SWLowEdgeSet;
unsigned long afticker;
unsigned long aftickerhold;
unsigned long aftimer;
unsigned long autosquelchtimer;
unsigned long eonticker;
unsigned long eontickerhold;
unsigned long flashingtimer;
unsigned long lowsignaltimer;
unsigned long peakholdmillis;
unsigned long rtplusticker;
unsigned long rtplustickerhold;
unsigned long rtticker;
unsigned long rttickerhold;
unsigned long scantimer;
unsigned long signalstatustimer;
unsigned long tottimer;
unsigned long tuningtimer;
unsigned long udptimer;

mem presets[EE_PRESETS_CNT];
TEF6686 radio;
ESP32Time rtc(0);

TFT_eSprite RadiotextSprite = TFT_eSprite(&tft);
TFT_eSprite FrequencySprite = TFT_eSprite(&tft);
TFT_eSprite RDSSprite = TFT_eSprite(&tft);
TFT_eSprite SquelchSprite = TFT_eSprite(&tft);
TFT_eSprite FullLineSprite = TFT_eSprite(&tft);
TFT_eSprite OneBigLineSprite = TFT_eSprite(&tft);
TFT_eSprite SignalSprite = TFT_eSprite(&tft);

WiFiConnect wc;
WiFiServer Server(7373);
WiFiClient RemoteClient;
WiFiUDP Udp;
hw_timer_t *timScreensaver = NULL;
byte screensaver_IRQ = OFF;

void setup() {
  WRITE_PERI_REG(RTC_CNTL_BROWN_OUT_REG, 0);
  gpio_set_drive_capability((gpio_num_t) 5, GPIO_DRIVE_CAP_0);
  gpio_set_drive_capability((gpio_num_t) 16, GPIO_DRIVE_CAP_0);
  gpio_set_drive_capability((gpio_num_t) 17, GPIO_DRIVE_CAP_0);
  gpio_set_drive_capability((gpio_num_t) 18, GPIO_DRIVE_CAP_0);
  gpio_set_drive_capability((gpio_num_t) 19, GPIO_DRIVE_CAP_0);
  gpio_set_drive_capability((gpio_num_t) 21, GPIO_DRIVE_CAP_0);
  gpio_set_drive_capability((gpio_num_t) 22, GPIO_DRIVE_CAP_0);
  gpio_set_drive_capability((gpio_num_t) 23, GPIO_DRIVE_CAP_0);
  setupmode = true;
  EEPROM.begin(EE_TOTAL_CNT);
  if (EEPROM.readByte(EE_BYTE_CHECKBYTE) != EE_CHECKBYTE_VALUE) DefaultSettings(hardwaremodel);

  frequency = EEPROM.readUInt(EE_UINT16_FREQUENCY_FM);
  frequency_OIRT = EEPROM.readUInt(EE_UINT16_FREQUENCY_OIRT);
  VolSet = EEPROM.readByte(EE_BYTE_VOLSET);
  ConverterSet = EEPROM.readUInt(EE_UINT16_CONVERTERSET);
  LowEdgeSet = EEPROM.readUInt(EE_UINT16_FMLOWEDGESET);
  HighEdgeSet = EEPROM.readUInt(EE_UINT16_FMHIGHEDGESET);
  ContrastSet = EEPROM.readByte(EE_BYTE_CONTRASTSET);
  StereoLevel = EEPROM.readByte(EE_BYTE_STEREOLEVEL);
  bandFM = EEPROM.readByte(EE_BYTE_BANDFM);
  bandAM = EEPROM.readByte(EE_BYTE_BANDAM);
  HighCutLevel = EEPROM.readByte(EE_BYTE_HIGHCUTLEVEL);
  HighCutOffset = EEPROM.readByte(EE_BYTE_HIGHCUTOFFSET);
  LevelOffset = EEPROM.readByte(EE_BYTE_LEVELOFFSET);
  radio.rds.rtbuffer = EEPROM.readByte(EE_BYTE_RTBUFFER);
  edgebeep = EEPROM.readByte(EE_BYTE_EDGEBEEP);
  softmuteam = EEPROM.readByte(EE_BYTE_SOFTMUTEAM);
  softmutefm = EEPROM.readByte(EE_BYTE_SOFTMUTEFM);
  frequency_AM = EEPROM.readUInt(EE_UINT16_FREQUENCY_AM);
  language = EEPROM.readByte(EE_BYTE_LANGUAGE);
  showrdserrors = EEPROM.readByte(EE_BYTE_SHOWRDSERRORS);
  TEF = EEPROM.readByte(EE_BYTE_TEF);
  displayflip = EEPROM.readByte(EE_BYTE_DISPLAYFLIP);
  rotarymode = EEPROM.readByte(EE_BYTE_ROTARYMODE);
  tunemode = EEPROM.readByte(EE_BYTE_TUNEMODE);
  if (tunemode == TUNE_MAN) stepsize = EEPROM.readByte(EE_BYTE_STEPSIZE); else stepsize = 0;
  optenc = EEPROM.readByte(EE_BYTE_OPTENC);
  iMSset = EEPROM.readByte(EE_BYTE_IMSSET);
  EQset = EEPROM.readByte(EE_BYTE_EQSET);
  band = EEPROM.readByte(EE_BYTE_BAND);
  LowLevelSet = EEPROM.readByte(EE_BYTE_LOWLEVELSET);
  memorypos = EEPROM.readByte(EE_BYTE_MEMORYPOS);
  region = EEPROM.readByte(EE_BYTE_REGION);
  radio.underscore = EEPROM.readByte(EE_BYTE_RDS_UNDERSCORE);
  USBmode = EEPROM.readByte(EE_BYTE_USBMODE);
  wifi = EEPROM.readByte(EE_BYTE_WIFI);
  subnetclient = EEPROM.readByte(EE_BYTE_SUBNETCLIENT);
  showSWMIBand = EEPROM.readByte(EE_BYTE_SHOWSWMIBAND);
  radio.rds.filter = EEPROM.readByte(EE_BYTE_RDS_FILTER);
  radio.rds.pierrors = EEPROM.readByte(EE_BYTE_RDS_PIERRORS);
  frequency_LW = EEPROM.readUInt(EE_UINT16_FREQUENCY_LW);
  frequency_MW = EEPROM.readUInt(EE_UINT16_FREQUENCY_MW);
  frequency_SW = EEPROM.readUInt(EE_UINT16_FREQUENCY_SW);
#ifdef HAS_AIR_BAND
  frequency_AIR = EEPROM.readUInt(EE_UINT16_FREQUENCY_AIR);
#endif
  XDRGTK_key = EEPROM.readString(EE_STRING_XDRGTK_KEY);
  usesquelch = EEPROM.readByte(EE_BYTE_USESQUELCH);
  showmodulation = EEPROM.readByte(EE_BYTE_SHOWMODULATION);
  amnb = EEPROM.readByte(EE_BYTE_AM_NB);
  fmnb = EEPROM.readByte(EE_BYTE_FM_NB);
  audiomode = EEPROM.readByte(EE_BYTE_AUDIOMODE);
  touchrotating = EEPROM.readByte(EE_BYTE_TOUCH_ROTATING);
  hardwaremodel = EEPROM.readByte(EE_BYTE_HARDWARE_MODEL);
  poweroptions = EEPROM.readByte(EE_BYTE_POWEROPTIONS);
  CurrentTheme = EEPROM.readByte(EE_BYTE_CURRENTTHEME);
  fmdefaultstepsize = EEPROM.readByte(EE_BYTE_FMDEFAULTSTEPSIZE);
  screensaverset = EEPROM.readByte(EE_BYTE_SCREENSAVERSET);
  AMLevelOffset = EEPROM.readInt(EE_INT16_AMLEVELOFFSET);
  unit = EEPROM.readByte(EE_BYTE_UNIT);
  af = EEPROM.readByte(EE_BYTE_AF);
  if (af == 2) radio.rds.afreg = true; else radio.rds.afreg = false;
  StereoToggle = EEPROM.readByte(EE_BYTE_STEREO);
  batteryoptions = EEPROM.readByte(EE_BYTE_BATTERY_OPTIONS);
  amcodect = EEPROM.readByte(EE_BYTE_AM_CO_DECT);
  amcodectcount = EEPROM.readByte(EE_BYTE_AM_CO_DECT_COUNT);
  amgain = EEPROM.readByte(EE_BYTE_AM_RF_GAIN);
  radio.rds.sortaf = EEPROM.readByte(EE_BYTE_SORTAF);
  stationlistid = EEPROM.readByte(EE_BYTE_STATIONLISTID);
  fmdeemphasis = EEPROM.readByte(EE_BYTE_FM_DEEMPHASIS);
  BWsetFM = EEPROM.readByte(EE_BYTE_BWSET_FM);
  BWsetAM = EEPROM.readByte(EE_BYTE_BWSET_AM);
  nowToggleSWMIBand = EEPROM.readByte(EE_BYTE_BANDAUTOSW);
  radio.rds.fastps = EEPROM.readByte(EE_BYTE_FASTPS);
  tot = EEPROM.readByte(EE_BYTE_TOT);
  mwstepsize = EEPROM.readByte(EE_BYTE_MWREGION);
#ifdef HAS_AIR_BAND
  airstepsize = EEPROM.readByte(EE_BYTE_AIRSTEPSIZE);
#endif
  spispeed = EEPROM.readByte(EE_BYTE_SPISPEED);
  amscansens = EEPROM.readByte(EE_BYTE_AMSCANSENS);
  fmscansens = EEPROM.readByte(EE_BYTE_FMSCANSENS);
  freqfont = EEPROM.readByte(EE_BYTE_FREQFONT);
  CurrentSkin = EEPROM.readByte(EE_BYTE_SKIN);
  XDRGTKMuteScreen = EEPROM.readByte(EE_BYTE_XDRGTKMUTE);
  fmagc = EEPROM.readByte(EE_BYTE_FMAGC);
  amagc = EEPROM.readByte(EE_BYTE_AMAGC);
  fmsi = EEPROM.readByte(EE_BYTE_FMSI);
  scanstart = EEPROM.readByte(EE_BYTE_SCANSTART);
  scanstop = EEPROM.readByte(EE_BYTE_SCANSTOP);
  scanhold = EEPROM.readByte(EE_BYTE_SCANHOLD);
  scanmem = EEPROM.readByte(EE_BYTE_SCANMEM);
  scancancel = EEPROM.readByte(EE_BYTE_SCANCANCEL);
  scanmute = EEPROM.readByte(EE_BYTE_SCANMUTE);
  autosquelch = EEPROM.readByte(EE_BYTE_AUTOSQUELCH);
  longbandpress = EEPROM.readByte(EE_BYTE_LONGBANDPRESS);

  if (spispeed == SPI_SPEED_DEFAULT) {
    tft.setSPISpeed(SPI_FREQUENCY / 1000000);
  } else if (spispeed == 7) {
    setAutoSpeedSPI();
  } else {
    tft.setSPISpeed(spispeed * 10);
  }

  LWLowEdgeSet = FREQ_LW_LOW_EDGE_MIN;
  LWHighEdgeSet = FREQ_LW_HIGH_EDGE_MAX;
  MWLowEdgeSet = mwstepsize == false ? FREQ_MW_LOW_EDGE_MIN_9K : FREQ_MW_LOW_EDGE_MIN_10K;
  MWHighEdgeSet = mwstepsize == false ? FREQ_MW_HIGH_EDGE_MAX_9K : FREQ_MW_HIGH_EDGE_MAX_10K;
  SWLowEdgeSet = FREQ_SW_LOW_EDGE_MIN;
  SWHighEdgeSet = FREQ_SW_HIGH_EDGE_MAX;
  if (LowEdgeOIRTSet < FREQ_FM_OIRT_START || LowEdgeOIRTSet > FREQ_FM_OIRT_END) LowEdgeOIRTSet = FREQ_FM_OIRT_START;
  if (HighEdgeOIRTSet < FREQ_FM_OIRT_START || HighEdgeOIRTSet > FREQ_FM_OIRT_END) HighEdgeOIRTSet = FREQ_FM_OIRT_END;

  LowEdgeOIRTSet = LowEdgeOIRTSet;
  HighEdgeOIRTSet = FREQ_FM_OIRT_END;

  for (int i = 0; i < EE_PRESETS_CNT; i++) presets[i].band = EEPROM.readByte(i + EE_PRESETS_BAND_START);
  for (int i = 0; i < EE_PRESETS_CNT; i++) presets[i].frequency = EEPROM.readUInt((i * 4) + EE_PRESETS_FREQUENCY_START);
  for (int i = 0; i < EE_PRESETS_CNT; i++) presets[i].bw = EEPROM.readByte(i + EE_PRESET_BW_START);
  for (int i = 0; i < EE_PRESETS_CNT; i++) presets[i].ms = EEPROM.readByte(i + EE_PRESET_MS_START);

  for (int i = 0; i < EE_PRESETS_CNT; i++) {
    for (int y = 0; y < 9; y++) {
      presets[i].RDSPS[y] = EEPROM.readByte((i * 9) + y + EE_PRESETS_RDSPS_START);
    }
    for (int y = 0; y < 5; y++) {
      presets[i].RDSPI[y] = EEPROM.readByte((i * 5) + y + EE_PRESETS_RDSPI_START);
    }
  }

  btStop();

  if (USBmode) Serial.begin(19200); else Serial.begin(115200);

  if (iMSset == 1 && EQset == 1) iMSEQ = 2;
  if (iMSset == 0 && EQset == 1) iMSEQ = 3;
  if (iMSset == 1 && EQset == 0) iMSEQ = 4;
  if (iMSset == 0 && EQset == 0) iMSEQ = 1;

  switch (band) {
    case BAND_LW:
      frequency_LW = frequency_AM;
      if (stepsize > 3) stepsize = 3;
      break;
    case BAND_MW:
      frequency_MW = frequency_AM;
      if (stepsize > 3) stepsize = 3;
      break;
    case BAND_SW: frequency_SW = frequency_AM; break;
    case BAND_FM:
      if (frequency % 10 != 0) {
        if (fmdefaultstepsize == 1) Round100K(frequency); else Round50K(frequency);
      }
      break;
    case BAND_OIRT:
      if (frequency % FREQ_OIRT_STEP_30K != 2) {
        Round30K(frequency_OIRT);
      }
      break;
  }

  if (IsStationEmpty()) memoryposstatus = MEM_DARK; else memoryposstatus = MEM_NORMAL;

  tft.init();
  tft.initDMA();

  doTheme();

  if (displayflip == 0) {
#ifdef ARS
    tft.setRotation(0);
#else
    tft.setRotation(3);
#endif
  } else {
#ifdef ARS
    tft.setRotation(2);
#else
    tft.setRotation(1);
#endif
  }

  pinMode(MODEBUTTON, INPUT);
  pinMode(BWBUTTON, INPUT);
  pinMode(ROTARY_BUTTON, INPUT);
  pinMode(ROTARY_PIN_A, INPUT);
  pinMode(ROTARY_PIN_B, INPUT);
  pinMode (STANDBYLED, OUTPUT);
  digitalWrite(STANDBYLED, HIGH);

  attachInterrupt(digitalPinToInterrupt(ROTARY_PIN_A), read_encoder, CHANGE);
  attachInterrupt(digitalPinToInterrupt(ROTARY_PIN_B), read_encoder, CHANGE);

  tft.setSwapBytes(true);
  tft.fillScreen(BackgroundColor);

  RadiotextSprite.createSprite(270, 19);
  RadiotextSprite.setTextDatum(TL_DATUM);
  RadiotextSprite.setSwapBytes(true);

  FrequencySprite.createSprite(200, 50);
  FrequencySprite.setTextDatum(TR_DATUM);
  FrequencySprite.setSwapBytes(true);

  RDSSprite.createSprite(165, 19);
  RDSSprite.setTextDatum(TL_DATUM);

  SquelchSprite.createSprite(47, 19);
  SquelchSprite.setTextDatum(TL_DATUM);
  SquelchSprite.setSwapBytes(true);

  FullLineSprite.createSprite(308, 20);
  FullLineSprite.setSwapBytes(true);

  OneBigLineSprite.createSprite(270, 30);
  OneBigLineSprite.setSwapBytes(true);

  SignalSprite.createSprite(80, 48);
  SignalSprite.setTextColor(PrimaryColor, PrimaryColorSmooth, false);
  SignalSprite.setTextDatum(TR_DATUM);
  SignalSprite.setSwapBytes(true);

  UpdateFonts(0);

  if (digitalRead(BWBUTTON) == LOW && digitalRead(ROTARY_BUTTON) == HIGH) {
    if (rotarymode == 0) rotarymode = 1; else rotarymode = 0;
    EEPROM.writeByte(EE_BYTE_ROTARYMODE, rotarymode);
    EEPROM.commit();
    analogWrite(CONTRASTPIN, ContrastSet * 2 + 27);
    tftPrint(0, myLanguage[language][1], 155, 70, ActiveColor, ActiveColorSmooth, 28);
    tftPrint(0, myLanguage[language][2], 155, 130, ActiveColor, ActiveColorSmooth, 28);
    while (digitalRead(BWBUTTON) == LOW) delay(50);
  }

  if (digitalRead(MODEBUTTON) == LOW) {
    if (displayflip == 0) {
      displayflip = 1;
      tft.setRotation(1);
    } else {
      displayflip = 0;
      tft.setRotation(3);
    }
    EEPROM.writeByte(EE_BYTE_DISPLAYFLIP, displayflip);
    EEPROM.commit();
    analogWrite(CONTRASTPIN, ContrastSet * 2 + 27);
    tftPrint(0, myLanguage[language][3], 155, 70, ActiveColor, ActiveColorSmooth, 28);
    tftPrint(0, myLanguage[language][2], 155, 130, ActiveColor, ActiveColorSmooth, 28);
    while (digitalRead(MODEBUTTON) == LOW) delay(50);
  }

  if (digitalRead(BANDBUTTON) == LOW) {
    analogWrite(SMETERPIN, 511);
    analogWrite(CONTRASTPIN, ContrastSet * 2 + 27);
    tftPrint(0, myLanguage[language][4], 155, 70, ActiveColor, ActiveColorSmooth, 28);
    tftPrint(0, myLanguage[language][5], 155, 130, ActiveColor, ActiveColorSmooth, 28);
    while (digitalRead(BANDBUTTON) == LOW) delay(50);
    analogWrite(SMETERPIN, 0);
  }

  if (digitalRead(ROTARY_BUTTON) == LOW && digitalRead(BWBUTTON) == HIGH) {
    analogWrite(CONTRASTPIN, ContrastSet * 2 + 27);
    if (optenc == 0) {
      optenc = 1;
      tftPrint(0, myLanguage[language][6], 155, 70, ActiveColor, ActiveColorSmooth, 28);
    } else {
      optenc = 0;
      tftPrint(0, myLanguage[language][7], 155, 70, ActiveColor, ActiveColorSmooth, 28);
    }
    EEPROM.writeByte(EE_BYTE_OPTENC, optenc);
    EEPROM.commit();
    tftPrint(0, myLanguage[language][2], 155, 130, ActiveColor, ActiveColorSmooth, 28);
    while (digitalRead(ROTARY_BUTTON) == LOW) delay(50);
  }

  if (digitalRead(ROTARY_BUTTON) == LOW && digitalRead(BWBUTTON) == LOW) {
    analogWrite(CONTRASTPIN, ContrastSet * 2 + 27);
    DefaultSettings(hardwaremodel);
    tftPrint(0, myLanguage[language][66], 155, 70, ActiveColor, ActiveColorSmooth, 28);
    tftPrint(0, myLanguage[language][2], 155, 130, ActiveColor, ActiveColorSmooth, 28);
    while (digitalRead(ROTARY_BUTTON) == LOW && digitalRead(BWBUTTON) == LOW) delay(50);
    ESP.restart();
  }

  tft.fillScreen(BackgroundColor);
  tftPrint(0, myLanguage[language][8], 160, 3, PrimaryColor, PrimaryColorSmooth, 28);
  tftPrint(0, "Software " + String(VERSION), 160, 152, PrimaryColor, PrimaryColorSmooth, 16);

  tft.fillRect(120, 230, 16, 6, GreyoutColor);
  tft.fillRect(152, 230, 16, 6, GreyoutColor);
  tft.fillRect(184, 230, 16, 6, GreyoutColor);

  tft.pushImage (78, 34, 163, 84, openradiologo);
  tft.drawBitmap(130, 124, TEFLogo, 59, 23, ActiveColor);

  for (int x = 0; x <= ContrastSet; x++) {
    analogWrite(CONTRASTPIN, x * 2 + 27);
    delay(30);
  }

  TEF = EEPROM.readByte(EE_BYTE_TEF);

  if (TEF != 102 && TEF != 205) SetTunerPatch();

  radio.init(TEF);
  uint16_t device;
  uint16_t hw;
  uint16_t sw;

  radio.getIdentification(device, hw, sw);
  if (TEF != (highByte(hw) * 100 + highByte(sw))) SetTunerPatch();
  tft.fillRect(120, 230, 16, 6, PrimaryColor);

  if (lowByte(device) == 14) {
    fullsearchrds = false;
    fmsi = false;
    tft.fillRect(152, 230, 16, 6, PrimaryColor);
    tftPrint(0, "TEF6686 Lithio", 160, 172, ActiveColor, ActiveColorSmooth, 28);
  } else if (lowByte(device) == 1) {
    fullsearchrds = true;
    tft.fillRect(152, 230, 16, 6, PrimaryColor);
    tftPrint(0, "TEF6687 Lithio FMSI", 160, 172, ActiveColor, ActiveColorSmooth, 28);
  } else if (lowByte(device) == 9) {
    fullsearchrds = false;
    fmsi = false;
    tft.fillRect(152, 230, 16, 6, PrimaryColor);
    tftPrint(0, "TEF6688 Lithio DR", 160, 172, ActiveColor, ActiveColorSmooth, 28);
  } else if (lowByte(device) == 3) {
    fullsearchrds = true;
    tft.fillRect(152, 230, 16, 6, PrimaryColor);
    tftPrint(0, "TEF6689 Lithio FMSI DR", 160, 172, ActiveColor, ActiveColorSmooth, 28);
  } else {
    tftPrint(0, myLanguage[language][9], 160, 172, SignificantColor, SignificantColorSmooth, 28);
    tft.fillRect(152, 230, 16, 6, SignificantColor);
    while (true);
    for (;;);
  }
  tftPrint(0, "Patch: v" + String(TEF), 160, 202, ActiveColor, ActiveColorSmooth, 28);

  if (analogRead(BATTERY_PIN) < 200) batterydetect = false;

  if (wifi) {
    tryWiFi();
    tft.fillRect(184, 230, 16, 6, PrimaryColor);
    delay(2000);
  } else {
    Server.end();
    Udp.stop();
    tft.fillRect(184, 230, 16, 6, SignificantColor);
  }
  delay(1500);

  radio.setVolume(VolSet);
  radio.setOffset(LevelOffset);
  radio.setAMOffset(AMLevelOffset);
  if (band > BAND_GAP && band != BAND_AIR) {
    radio.setAMCoChannel(amcodect, amcodectcount);
    radio.setAMAttenuation(amgain);
  }
  radio.setStereoLevel(StereoLevel);
  radio.setHighCutLevel(HighCutLevel);
  radio.setHighCutOffset(HighCutOffset);
  radio.clearRDS(fullsearchrds);
  radio.setMute();
  if (!StereoToggle) radio.setMono(true);
  radio.setSoftmuteFM(softmutefm);
  radio.setSoftmuteAM(softmuteam);
  radio.setAMNoiseBlanker(amnb);
  radio.setFMNoiseBlanker(fmnb);
  radio.setAudio(audiomode);
  radio.setDeemphasis(fmdeemphasis);
  radio.rds.region = region;
  radio.setAGC(fmagc);
  radio.setAMAGC(amagc);
  if (fmsi) radio.setFMSI(2); else radio.setFMSI(1);
  LowLevelInit = true;

  if (ConverterSet >= 200) {
    Wire.beginTransmission(0x12);
    Wire.write(ConverterSet >> 8);
    Wire.write(ConverterSet & (0xFF));
    Wire.endTransmission();
  }

  SelectBand();
  if (tunemode == TUNE_MEM) DoMemoryPosTune();

  setupmode = false;
  if (edgebeep) radio.tone(50, -5, 2000);
  radio.I2Sin(false);
  if (!usesquelch) radio.setUnMute();
  if (screensaverset) {
    ScreensaverTimerInit();
    ScreensaverTimerSet(screensaverOptions[screensaverset]);
  }
  tottimer = millis();
}

void loop() {
  Communication();

  if (tot != 0) {
    unsigned long totprobe = tot * 60000;
    if (millis() >= tottimer + totprobe) deepSleep();
  }
  if (digitalRead(BANDBUTTON) == LOW ) BANDBUTTONPress();

  if (scandxmode) {
    if (millis() >= scantimer + (scanhold * 1000)) {
      if (scanmem) {
        memorypos++;
        if (memorypos > scanstop) memorypos = scanstart;
        while (IsStationEmpty() || presets[memorypos].band != BAND_FM) {
          memorypos++;
          if (memorypos > scanstop) {
            memorypos = scanstart;
            break;
          }
        }
        DoMemoryPosTune();
        ShowMemoryPos();
      } else {
        TuneUp();
        ShowFreq(0);
        if (XDRGTKUSB || XDRGTKTCP) DataPrint("T" + String((frequency + ConverterSet * 100) * 10) + "\n");
      }
      scantimer = millis();
    }

    if (millis() >= flashingtimer + 500) {
      flashing = !flashing;
      if (flashing) {
        tft.drawRoundRect(1, 79, 42, 20, 5, ActiveColor);
        tftPrint(0, "MEM", 22, 82, ActiveColor, ActiveColorSmooth, 16);
      } else {
        tft.drawRoundRect(1, 79, 42, 20, 5, GreyoutColor);
        tftPrint(0, "MEM", 22, 82, GreyoutColor, BackgroundColor, 16);
      }
      flashingtimer = millis();
    }
    delay(50);
    radio.getStatus(SStatus, USN, WAM, OStatus, BW, MStatus, CN);
    switch (scancancel) {
      case CORRECTPI: if (radio.rds.correctPI != 0) cancelDXScan(); break;
      case SIGNAL: if ((USN < fmscansens * 30) && (WAM < 230) && (OStatus < 80 && OStatus > -80)) cancelDXScan(); break;
    }
  }

  if (millis() >= tuningtimer + 200) {
    if (store) {
      detachInterrupt(digitalPinToInterrupt(ROTARY_PIN_A));
      detachInterrupt(digitalPinToInterrupt(ROTARY_PIN_B));
      StoreFrequency();
      store = false;
      attachInterrupt(digitalPinToInterrupt(ROTARY_PIN_A), read_encoder, CHANGE);
      attachInterrupt(digitalPinToInterrupt(ROTARY_PIN_B), read_encoder, CHANGE);
    }
    rdsflagreset = false;
  }

  if (!menu && !afscreen && !scandxmode) {
    if (af != 0 && dropout && millis() >= aftimer + 1000) {
      aftimer = millis();
      frequency = radio.TestAF();
      if (freqold != frequency) {
        ShowFreq(0);
        dropout = true;
        if (radio.afmethodB) {
          afmethodBold = true;
          radio.clearRDS(fullsearchrds);
        }
        if (XDRGTKUSB || XDRGTKTCP) DataPrint("T" + String((frequency + ConverterSet * 100) * 10) + "\n");
        store = true;
      }
    }

    if (band == BAND_FM && af != 0 && radio.rds.correctPI != 0) {
      if ((aftest && millis() >= aftimer + 3000) || ((USN > 250 || WAM > 250) && millis() >= aftimer + 1000)) {
        aftimer = millis();
        aftest = false;
        frequency = radio.TestAF();
        if (freqold != frequency) {
          ShowFreq(0);
          dropout = true;
          if (radio.afmethodB) {
            afmethodBold = true;
            radio.clearRDS(fullsearchrds);
          }
          if (XDRGTKUSB || XDRGTKTCP) DataPrint("T" + String((frequency + ConverterSet * 100) * 10) + "\n");
          store = true;
        }
      }

      if (band == BAND_FM && millis() >= aftimer + 10000) {
        aftimer = millis();
        if (USN > 150 || WAM > 150) {
          frequency = radio.TestAF();
          if (freqold != frequency) {
            ShowFreq(0);
            dropout = true;
            if (radio.afmethodB) {
              afmethodBold = true;
              radio.clearRDS(fullsearchrds);
            }
            if (XDRGTKUSB || XDRGTKTCP) DataPrint("T" + String((frequency + ConverterSet * 100) * 10) + "\n");
            store = true;
          }
        }
      }
    }
  }

  if (seek) Seek(direction);

  if ((SStatus / 10 > LowLevelSet) && !LowLevelInit && !menu && band < BAND_GAP) {
    if (!screenmute && !advancedRDS && !afscreen) {
      if (showmodulation) {
        tftPrint(-1, "10", 27, 144, ActiveColor, ActiveColorSmooth, 16);
        tftPrint(-1, "30", 57, 144, ActiveColor, ActiveColorSmooth, 16);
        tftPrint(-1, "50", 87, 144, ActiveColor, ActiveColorSmooth, 16);
        tftPrint(-1, "70", 117, 144, ActiveColor, ActiveColorSmooth, 16);
        tftPrint(-1, "100", 164, 144, ActiveColor, ActiveColorSmooth, 16);
        tftPrint(0, "M", 7, 128, ActiveColor, ActiveColorSmooth, 16);
        for (byte segments = 0; segments < 94; segments++) {
          if (segments > 54) {
            if (((segments - 53) % 10) == 0) tft.fillRect(16 + (2 * segments), 141, 2, 2, BarSignificantColor);
          } else {
            if (((segments + 1) % 6) == 0) tft.fillRect(16 + (2 * segments), 141, 2, 2, ModBarInsignificantColor);
          }
        }
      }
      if (region == REGION_EU) tftPrint(-1, "PI:", 212, 193, ActiveColor, ActiveColorSmooth, 16);
      if (region == REGION_US) {
        tftPrint(-1, "PI:", 212, 184, ActiveColor, ActiveColorSmooth, 16);
        tftPrint(-1, "ID:", 212, 201, ActiveColor, ActiveColorSmooth, 16);
      }
      tftPrint(-1, "PS:", 3, 193, ActiveColor, ActiveColorSmooth, 16);
      tftPrint(-1, "RT:", 3, 221, ActiveColor, ActiveColorSmooth, 16);
      tftPrint(-1, "PTY:", 3, 163, ActiveColor, ActiveColorSmooth, 16);
      if (!showmodulation) tft.drawLine(20, 143, 204, 143, GreyoutColor); else tft.drawLine(20, 143, 204, 143, TFT_DARKGREY);
    }
    LowLevelInit = true;
  }

  if ((SStatus / 10 <= LowLevelSet) && band < BAND_GAP) {
    if (LowLevelInit && !menu) {
      if (!screenmute && !afscreen && !advancedRDS) {
        for (byte segments = 0; segments < 94; segments++) {
          if (segments > 54) {
            if (((segments - 53) % 10) == 0) tft.fillRect(16 + (2 * segments), 141, 2, 2, GreyoutColor);
          } else {
            if (((segments + 1) % 6) == 0) tft.fillRect(16 + (2 * segments), 141, 2, 2, GreyoutColor);
          }
        }
        if (showmodulation) {
          tftPrint(-1, "10", 27, 144, GreyoutColor, BackgroundColor, 16);
          tftPrint(-1, "30", 57, 144, GreyoutColor, BackgroundColor, 16);
          tftPrint(-1, "50", 87, 144, GreyoutColor, BackgroundColor, 16);
          tftPrint(-1, "70", 117, 144, GreyoutColor, BackgroundColor, 16);
          tftPrint(-1, "100", 164, 144, GreyoutColor, BackgroundColor, 16);
          tftPrint(0, "M", 7, 128, GreyoutColor, BackgroundColor, 16);
          tft.fillRect(16, 133, 188, 6, GreyoutColor);
        }
        if (region == REGION_EU) tftPrint(-1, "PI:", 212, 193, GreyoutColor, BackgroundColor, 16);
        if (region == REGION_US) {
          tftPrint(-1, "PI:", 212, 184, GreyoutColor, BackgroundColor, 16);
          tftPrint(-1, "ID:", 212, 201, GreyoutColor, BackgroundColor, 16);
        }
        tftPrint(-1, "PS:", 3, 193, GreyoutColor, BackgroundColor, 16);
        tftPrint(-1, "RT:", 3, 221, GreyoutColor, BackgroundColor, 16);
        tftPrint(-1, "PTY:", 3, 163, GreyoutColor, BackgroundColor, 16);
        tft.drawLine(20, 143, 204, 143, GreyoutColor);
        tft.drawBitmap(122, 5, RDSLogo, 35, 22, GreyoutColor);
      }
      LowLevelInit = false;
    }

    if (!menu && (screenmute || radio.rds.correctPI != 0)) readRds();
    if (millis() >= lowsignaltimer + 300) {
      lowsignaltimer = millis();
      if (af || (!screenmute || (screenmute && (XDRGTKTCP || XDRGTKUSB)))) {
        if (band < BAND_GAP) {
          radio.getStatus(SStatus, USN, WAM, OStatus, BW, MStatus, CN);
        } else {
          radio.getStatusAM(SStatus, USN, WAM, OStatus, BW, MStatus, CN);
        }
      }
      if (!menu) {
        doSquelch();
        GetData();
      }
    }

  } else {
    if (af || (!screenmute || (screenmute && (XDRGTKTCP || XDRGTKUSB)))) {
      if (band < BAND_GAP) {
        radio.getStatus(SStatus, USN, WAM, OStatus, BW, MStatus, CN);
      } else {
        radio.getStatusAM(SStatus, USN, WAM, OStatus, BW, MStatus, CN);
      }
    }
    if (!menu) {
      doSquelch();
      if (millis() >= tuningtimer + 200) readRds();
      GetData();
      if (!screenmute && !afscreen && !advancedRDS) ShowModLevel();
    }
  }

  if (menu && menuopen && menupage == FMSETTINGS && menuoption == ITEM4) {
    if (band < BAND_GAP) radio.getStatus(SStatus, USN, WAM, OStatus, BW, MStatus, CN); else radio.getStatusAM(SStatus, USN, WAM, OStatus, BW, MStatus, CN);
    if (millis() >= lowsignaltimer + 500 || change) {
      lowsignaltimer = millis();
      change = false;
      if (SStatus > SStatusold || SStatus < SStatusold) {
        SignalSprite.fillSprite(BackgroundColor);
        SignalSprite.loadFont(FONT48);
        SignalSprite.drawString(String(SStatus / 10), 58, 0);
        SignalSprite.unloadFont();
        SignalSprite.loadFont(FONT28);
        SignalSprite.drawString("." + String(abs(SStatus % 10)), 78, 0);
        SignalSprite.unloadFont();
        SignalSprite.pushSprite(100, 149);
        SStatusold = SStatus;
      }
    }
  }

  if (rotary == -1) {
    tottimer = millis();
    if (screensavertriggered) {
      if (!touchrotating) {
        rotary = 0;
        WakeToSleep(REVERSE);
      } else {
        if (BWtune) doBWtuneUp(); else KeyUp();
      }
    } else {
      if (BWtune) doBWtuneUp(); else KeyUp();
      if (screensaverset && !menu && !screensavertriggered) ScreensaverTimerRestart();
    }
  }

  if (rotary == 1) {
    tottimer = millis();
    if (screensavertriggered) {
      if (!touchrotating) {
        rotary = 0;
        WakeToSleep(REVERSE);
      } else {
        if (BWtune) doBWtuneDown(); else KeyDown();
      }
    } else {
      if (BWtune) doBWtuneDown(); else KeyDown();
      if (screensaverset && !menu && !screensavertriggered) ScreensaverTimerRestart();
    }
  }

  if (digitalRead(ROTARY_BUTTON) == LOW) {
    tottimer = millis();
    if (screensavertriggered && !touchrotating) WakeToSleep(REVERSE);
    if (!afscreen) ButtonPress();
  }

  if (digitalRead(MODEBUTTON) == LOW) {
    tottimer = millis();
    if (screensavertriggered && !touchrotating) WakeToSleep(REVERSE);
    if (!screenmute) ModeButtonPress();
  }

  if (digitalRead(BWBUTTON) == HIGH && BWtune) BWtune = false;

  if (digitalRead(BWBUTTON) == LOW && !BWtune) {
    tottimer = millis();
    if (screensavertriggered && !touchrotating) WakeToSleep(REVERSE);
    if (!screenmute && !afscreen) BWButtonPress();
  }

  if (screensaverset) {
    if (screensaver_IRQ)
    {
      screensaver_IRQ = OFF;
      if (!screensavertriggered && !menu) {
        WakeToSleep(true);
      }
    }
  }
}

void GetData() {
  if (!afscreen) {
    showCT();
    ShowSignalLevel();
  }

  if (!menu && (band < BAND_GAP || tunemode == TUNE_MEM)) showPS();

  if (band < BAND_GAP && !menu) {
    if (advancedRDS && !afscreen && !screenmute) ShowAdvancedRDS();
    if (afscreen && !screenmute) ShowAFEON();
    if (!afscreen) {
      if (!screenmute) ShowErrors();
      showPTY();
      showECC();
      showRadioText();
      if (millis() >= tuningtimer + 200) doAF();
    }
    showPI();
  }

  ShowStereoStatus();

  if (!screenmute) {
    ShowRSSI();
    ShowOffset();
    ShowBW();
    updateCodetect();
    if (millis() >= tuningtimer + 200) ShowBattery();
  }
}

void WakeToSleep(bool yes) {
  if (yes) {
    screensavertriggered = true;
    switch (poweroptions) {
      case LCD_OFF:
        analogWrite(SMETERPIN, 0);
        MuteScreen(1);
        StoreFrequency();
        break;
      case LCD_BRIGHTNESS_1_PERCENT:
        analogWrite(SMETERPIN, 0);
        analogWrite(CONTRASTPIN, 1 * 2 + 27);
        break;
      case LCD_BRIGHTNESS_A_QUARTER:
        analogWrite(SMETERPIN, 0);
        analogWrite(CONTRASTPIN, MIN(ContrastSet, 25) * 2 + 27);
        break;
      case LCD_BRIGHTNESS_HALF:
        analogWrite(SMETERPIN, 0);
        analogWrite(CONTRASTPIN, MIN(ContrastSet, 50) * 2 + 27);
        break;
    }
  } else {
    switch (poweroptions) {
      case LCD_OFF:
        analogWrite(CONTRASTPIN, ContrastSet * 2 + 27);
        MuteScreen(0);
        screensavertriggered = false;
        screensaver_IRQ = OFF;
        ScreensaverTimerReopen();
        break;
      case LCD_BRIGHTNESS_1_PERCENT:
      case LCD_BRIGHTNESS_A_QUARTER:
      case LCD_BRIGHTNESS_HALF:
        analogWrite(CONTRASTPIN, ContrastSet * 2 + 27);
        MuteScreen(0);
        screensavertriggered = false;
        screensaver_IRQ = OFF;
        ScreensaverTimerReopen();
        break;
    }
  }
}

void ScreensaverTimerInit() {
  timScreensaver = timerBegin(0, 80, true);
  timerAttachInterrupt(timScreensaver, ScreensaverInterrupt, true);
}

void ScreensaverTimerSet(byte value) {
  if (timScreensaver == NULL) {
    ScreensaverTimerInit();
    ScreensaverTimerSet(screensaverOptions[screensaverset]);
  }

  if (value == OFF) {
    if (screensaverset) timerStop(timScreensaver);
  } else {
    timerStop(timScreensaver);
    timerAlarmWrite(timScreensaver, value * TIMER_SCREENSAVER_BASE, true);
    timerStart(timScreensaver);
    timerAlarmEnable(timScreensaver);
  }
}

void ScreensaverTimerRestart() {
  if (timScreensaver == NULL) {
    ScreensaverTimerInit();
    ScreensaverTimerSet(screensaverOptions[screensaverset]);
  }
  timerRestart(timScreensaver);
}

void ScreensaverTimerReopen() {
  ScreensaverTimerSet(OFF);
  ScreensaverTimerSet(screensaverOptions[screensaverset]);
  ScreensaverTimerRestart();
}

void ScreensaverInterrupt()
{
  screensaver_IRQ = ON;
}

void CheckBandForbiddenFM () {
  switch (band) {
    case BAND_FM:
      if (bandFM == FM_BAND_OIRT) bandforbidden = 1; else bandforbidden = 0;
      break;
    case BAND_OIRT:
      if (bandFM == FM_BAND_FM) bandforbidden = 1; else bandforbidden = 0;
      break;
  }
}

void doBandSelectionFM() {
  if (band > BAND_GAP) return;

  switch (bandFM) {
    case FM_BAND_ALL:
      break;
    case FM_BAND_OIRT:
      if (band == BAND_FM) {
        band = BAND_OIRT;
        if (frequency_OIRT > FREQ_FM_OIRT_END) {
          frequency_OIRT = FREQ_FM_OIRT_START;
          if (edgebeep) EdgeBeeper();
        } else if (frequency_OIRT < FREQ_FM_OIRT_START) {
          frequency_OIRT = FREQ_FM_OIRT_END;
          if (edgebeep) EdgeBeeper();
        }
        SelectBand();
      }
      break;
    case FM_BAND_FM:
      if (band == BAND_OIRT) {
        band = BAND_FM;
        if (frequency > HighEdgeSet * 10) {
          frequency = LowEdgeSet * 10;
          if (edgebeep) EdgeBeeper();
        } else if (frequency < LowEdgeSet * 10) {
          frequency = HighEdgeSet * 10;
          if (edgebeep) EdgeBeeper();
        }
        SelectBand();
      }
      break;
    case FM_BAND_NONE:
      ToggleBand(band);
      SelectBand();
      break;
  }
}

void CheckBandForbiddenAM() {
#ifdef HAS_AIR_BAND
  switch (band) {
    case BAND_LW:
      if (bandAM == AM_BAND_MW_SW_AIR || bandAM == AM_BAND_MW_SW || bandAM == AM_BAND_MW_AIR || bandAM == AM_BAND_SW_AIR || bandAM == AM_BAND_MW || bandAM == AM_BAND_SW || bandAM == AM_BAND_AIR)
        bandforbidden = 1;
      else
        bandforbidden = 0;
      break;
    case BAND_MW:
      if (bandAM == AM_BAND_LW_SW_AIR || bandAM == AM_BAND_LW_SW || bandAM == AM_BAND_LW_AIR || bandAM == AM_BAND_SW_AIR || bandAM == AM_BAND_LW || bandAM == AM_BAND_SW || bandAM == AM_BAND_AIR)
        bandforbidden = 1;
      else
        bandforbidden = 0;
      break;
    case BAND_SW:
      if (bandAM == AM_BAND_LW_MW_AIR || bandAM == AM_BAND_LW_MW || bandAM == AM_BAND_LW_AIR || bandAM == AM_BAND_MW_AIR || bandAM == AM_BAND_LW || bandAM == AM_BAND_MW || bandAM == AM_BAND_AIR)
        bandforbidden = 1;
      else
        bandforbidden = 0;
      break;
    case BAND_AIR:
      if (bandAM == AM_BAND_LW_MW_SW || bandAM == AM_BAND_LW_MW || bandAM == AM_BAND_LW_SW || bandAM == AM_BAND_MW_SW || bandAM == AM_BAND_LW || bandAM == AM_BAND_MW || bandAM == AM_BAND_SW)
        bandforbidden = 1;
      else
        bandforbidden = 0;
      break;
  }
#else
  switch (band) {
    case BAND_LW:
      if (bandAM == AM_BAND_MW_SW || bandAM == AM_BAND_MW || bandAM == AM_BAND_SW) bandforbidden = 1;
      else bandforbidden = 0;
      break;
    case BAND_MW:
      if (bandAM == AM_BAND_LW_SW || bandAM == AM_BAND_LW || bandAM == AM_BAND_SW) bandforbidden = 1;
      else bandforbidden = 0;
      break;
    case BAND_SW:
      if (bandAM == AM_BAND_LW_MW || bandAM == AM_BAND_LW || bandAM == AM_BAND_MW) bandforbidden = 1;
      else bandforbidden = 0;
      break;
  }
#endif
}

void doBandSelectionAM() {
  if (band < BAND_GAP) return;

#ifdef HAS_AIR_BAND  // has air band
  switch (bandAM) {
    case AM_BAND_ALL:
      break;
    case AM_BAND_LW_MW_SW:
      if (band == BAND_AIR) {
        band = BAND_LW;
        SelectBand();
      }
      break;
    case AM_BAND_LW_MW_AIR:
      if (band == BAND_SW) {
        band = BAND_LW;
        SelectBand();
      }
      break;
    case AM_BAND_LW_SW_AIR:
      if (band == BAND_MW) {
        band = BAND_LW;
        SelectBand();
      }
      break;
    case AM_BAND_MW_SW_AIR:
      if (band == BAND_LW) {
        band = BAND_MW;
        SelectBand();
      }
      break;
    case AM_BAND_LW_MW:
      if (band == BAND_SW || band == BAND_AIR) {
        band = BAND_LW;
        SelectBand();
      }
      break;
    case AM_BAND_LW_SW:
      if (band == BAND_MW || band == BAND_AIR) {
        band = BAND_LW;
        SelectBand();
      }
      break;
    case AM_BAND_LW_AIR:
      if (band == BAND_MW || band == BAND_SW) {
        band = BAND_LW;
        SelectBand();
      }
      break;
    case AM_BAND_MW_SW:
      if (band == BAND_LW || band == BAND_AIR) {
        band = BAND_MW;
        SelectBand();
      }
      break;
    case AM_BAND_MW_AIR:
      if (band == BAND_LW || band == BAND_SW) {
        band = BAND_MW;
        SelectBand();
      }
      break;
    case AM_BAND_SW_AIR:
      if (band == BAND_LW || band == BAND_MW) {
        band = BAND_SW;
        SelectBand();
      }
      break;
    case AM_BAND_LW:
      if (band != BAND_LW) {
        band = BAND_LW;
        SelectBand();
      }
      break;
    case AM_BAND_MW:
      if (band != BAND_MW) {
        band = BAND_MW;
        SelectBand();
      }
      break;
    case AM_BAND_SW:
      if (band != BAND_SW) {
        band = BAND_SW;
        SelectBand();
      }
      break;
    case AM_BAND_AIR:
      if (band != BAND_AIR) {
        band = BAND_AIR;
        SelectBand();
      }
      break;
  }
#else  // has no air band
  switch (bandAM) {
    case AM_BAND_ALL:
      break;
    case AM_BAND_LW_MW:
      if (band == BAND_SW) {
        band = BAND_LW;
        SelectBand();
      }
      break;
    case AM_BAND_LW_SW:
      if (band == BAND_MW) {
        band = BAND_LW;
        SelectBand();
      }
      break;
    case AM_BAND_MW_SW:
      if (band == BAND_LW) {
        band = BAND_MW;
        SelectBand();
      }
      break;
    case AM_BAND_LW:
      if (band != BAND_LW) {
        band = BAND_LW;
        SelectBand();
      }
      break;
    case AM_BAND_MW:
      if (band != BAND_MW) {
        band = BAND_MW;
        SelectBand();
      }
      break;
    case AM_BAND_SW:
      if (band != BAND_SW) {
        band = BAND_SW;
        SelectBand();
      }
      break;
    case AM_BAND_NONE:
      ToggleBand(band);
      SelectBand();
      break;
  }
#endif
}

void AMjumptoFM() {
  if (bandFM != FM_BAND_NONE) {
    if (bandFM == FM_BAND_FM) band = BAND_FM; else band = BAND_OIRT;
  } else {
    FMjumptoAM();
  }
}

void FMjumptoAM() {
#ifdef HAS_AIR_BAND
  if (bandAM == AM_BAND_ALL || bandAM == AM_BAND_LW_MW_AIR || bandAM == AM_BAND_LW_SW_AIR || bandAM == AM_BAND_LW_MW || bandAM == AM_BAND_LW_SW || bandAM == AM_BAND_LW_AIR || bandAM == AM_BAND_LW) {
    band = BAND_LW;
    if (stepsize > 3) stepsize = 3;
  } else if (bandAM == AM_BAND_MW_SW || bandAM == AM_BAND_MW_AIR || bandAM == AM_BAND_MW) {
    band = BAND_MW;
  } else if (bandAM == AM_BAND_SW_AIR || bandAM == AM_BAND_SW) {
    band = BAND_SW;
  } else if (bandAM == AM_BAND_AIR) {
    band = BAND_AIR;
  }
#else
  if (bandAM == AM_BAND_ALL || bandAM == AM_BAND_LW_MW || bandAM == AM_BAND_LW_SW || bandAM == AM_BAND_LW) {
    band = BAND_LW;
    if (stepsize > 3) stepsize = 3;
  } else if (bandAM == AM_BAND_MW_SW || bandAM == AM_BAND_MW) {
    band = BAND_MW;
  } else if (bandAM == AM_BAND_SW) {
    band = BAND_SW;
  }
#endif
}

void ToggleBand(byte nowBand) {
  switch (nowBand) {
#ifdef HAS_AIR_BAND
    case BAND_LW:
      if (bandAM == AM_BAND_LW_MW_SW || bandAM == AM_BAND_LW_MW_AIR || bandAM == AM_BAND_LW_MW || bandAM == AM_BAND_ALL) {
        band = BAND_MW;
      } else if (bandAM == AM_BAND_LW_SW_AIR || bandAM == AM_BAND_LW_SW) {
        band = BAND_SW;
      } else if (bandAM == AM_BAND_LW_MW_AIR || bandAM == AM_BAND_LW_SW_AIR || bandAM == AM_BAND_LW_AIR) {
        band = BAND_AIR;
      } else if (bandAM == AM_BAND_LW || bandAM == AM_BAND_NONE) {
        AMjumptoFM();
      }
      break;
    case BAND_MW:
      if (bandAM == AM_BAND_LW_MW_SW || bandAM == AM_BAND_MW_SW_AIR || bandAM == AM_BAND_MW_SW || bandAM == AM_BAND_ALL) {
        band = BAND_SW;
      } else if (bandAM == AM_BAND_LW_MW_AIR || bandAM == AM_BAND_MW_AIR) {
        band = BAND_AIR;
      } else if (bandAM == AM_BAND_MW || bandAM == AM_BAND_NONE) {
        AMjumptoFM();
      }
      break;
    case BAND_SW:
      if (bandAM == AM_BAND_LW_SW_AIR || bandAM == AM_BAND_MW_SW_AIR || bandAM == AM_BAND_SW_AIR || bandAM == AM_BAND_ALL) {
        band = BAND_AIR;
      } else if (bandAM == AM_BAND_LW_MW_SW || bandAM == AM_BAND_LW_SW || bandAM == AM_BAND_MW_SW || bandAM == AM_BAND_SW || bandAM == AM_BAND_NONE) {
        AMjumptoFM();
      }
      break;
    case BAND_AIR:
      AMjumptoFM();
      break;
#else  // has no air band
    case BAND_LW:
      if (bandAM == AM_BAND_LW_MW || bandAM == AM_BAND_ALL) {
        band = BAND_MW;
      } else if (bandAM == AM_BAND_LW_SW) {
        band = BAND_SW;
      } else if (bandAM == AM_BAND_LW || bandAM == AM_BAND_NONE) {
        AMjumptoFM();
      }
      break;
    case BAND_MW:
      if (bandAM == AM_BAND_MW_SW || bandAM == AM_BAND_ALL) {
        band = BAND_SW;
      } else if (bandAM == AM_BAND_LW_MW) {
        if (bandFM != FM_BAND_NONE) {
          if (bandFM == FM_BAND_FM) band = BAND_FM; else band = BAND_OIRT;
        } else {
          band = BAND_LW;
        }
      } else if (bandAM == AM_BAND_MW || bandAM == AM_BAND_NONE) {
        AMjumptoFM();
      }
      break;
    case BAND_SW:
      if (bandFM != FM_BAND_NONE) {
        if (bandFM == FM_BAND_FM) band = BAND_FM;
        else band = BAND_OIRT;
      } else { // FM be disabled
        if (bandAM == AM_BAND_LW_SW || bandAM == AM_BAND_ALL) {
          band = BAND_LW;
        } else if (bandAM == AM_BAND_MW_SW) {
          band = BAND_MW;
        } else if (bandAM == AM_BAND_SW || bandAM == AM_BAND_NONE) {
          AMjumptoFM();
        }
      }
      break;
#endif
    case BAND_OIRT:
      if (bandFM == FM_BAND_ALL || bandFM == FM_BAND_FM) {
        band = BAND_FM;
      } else if (bandFM == FM_BAND_OIRT) {
        if (bandAM != AM_BAND_NONE) {
          FMjumptoAM();
        } else {
          // do nothing
        }
      }
      break;
    case BAND_FM:
      if (bandAM != AM_BAND_NONE) {
        FMjumptoAM();
      } else {
        if (bandFM == FM_BAND_OIRT || bandFM == FM_BAND_ALL) {
          band = BAND_OIRT;
        } else if (bandFM == FM_BAND_FM) {
          // do nothing
        }
      }
      break;
  }
}

void BANDBUTTONPress() {
  if (scandxmode) {
    cancelDXScan();
  } else {
    if (memorystore) {
      EEPROM.writeUInt((memorypos * 4) + EE_PRESETS_FREQUENCY_START, EE_PRESETS_FREQUENCY);
      EEPROM.commit();
      presets[memorypos].frequency = EE_PRESETS_FREQUENCY;
      memorystore = false;
      ShowTuneMode();
      if (memoryposstatus == MEM_DARK || memoryposstatus == MEM_EXIST) {
        memoryposstatus = MEM_NORMAL;
        ShowMemoryPos();
      }
    } else {
      if (!usesquelch) radio.setUnMute();
      unsigned long counterold = millis();
      unsigned long counter = millis();
      if (!menu) {
        while (digitalRead(BANDBUTTON) == LOW && counter - counterold <= 1000) counter = millis();

        if (counter - counterold < 1000) {
          if (screensavertriggered) {
            WakeToSleep(REVERSE);
            return;
          }
          if (afscreen) {
            BuildAdvancedRDS();
          } else if (advancedRDS) {
            BuildDisplay();
            ScreensaverTimerReopen();
          } else {
            if (tunemode != TUNE_MEM) {
              ToggleBand(band);
              StoreFrequency();
              SelectBand();
              if (XDRGTKUSB || XDRGTKTCP) {
                if (band == BAND_FM) DataPrint("M0\nT" + String(frequency * 10) + "\n");
                else if (band == BAND_OIRT) DataPrint("M0\nT" + String(frequency_OIRT * 10) + "\n");
                else DataPrint("M1\nT" + String(frequency_AM) + "\n");
              }
            } else {
              scanmodeold = tunemode;
              startFMDXScan();
              return;
            }
            ScreensaverTimerRestart();
          }
        } else {
          if (screensavertriggered) {
            WakeToSleep(REVERSE);
            return;
          }

          if (band < BAND_GAP) {
            if (advancedRDS && !seek) BuildAFScreen();
            else BuildAdvancedRDS();
          } else {
            WakeToSleep(true);
          }
          while (digitalRead(BANDBUTTON) == LOW && counter - counterold <= 2500) counter = millis();
          if (counter - counterold > 2499) {
            switch (longbandpress) {
              case STANDBY:
                deepSleep();
                break;

              case SCREENOFF:
                screensavertriggered = true;
                MuteScreen(1);
                break;
            }
          }
        }
      }
    }
  }
  while (digitalRead(BANDBUTTON) == LOW) delay(50);
  delay(100);
}

void StoreFrequency() {
  EEPROM.writeUInt(EE_UINT16_FREQUENCY_FM, frequency);
  EEPROM.writeUInt(EE_UINT16_FREQUENCY_OIRT, frequency_OIRT);
  EEPROM.writeUInt(EE_UINT16_FREQUENCY_AM, frequency_AM);
  EEPROM.writeByte(EE_BYTE_BAND, band);
  EEPROM.writeUInt(EE_UINT16_FREQUENCY_LW, frequency_LW);
  EEPROM.writeUInt(EE_UINT16_FREQUENCY_MW, frequency_MW);
  EEPROM.writeUInt(EE_UINT16_FREQUENCY_SW, frequency_SW);
#ifdef HAS_AIR_BAND
  EEPROM.writeUInt(EE_UINT16_FREQUENCY_AIR, frequency_AIR);
#endif
  EEPROM.commit();
}

void LimitAMFrequency() {//todo air
  switch (band) {
    case BAND_LW:
      frequency_AM = frequency_LW;
      if (frequency_AM > LWHighEdgeSet || frequency_AM < LWLowEdgeSet) {
        frequency_AM = LWLowEdgeSet;
      }
      break;
    case BAND_MW:
      frequency_AM = frequency_MW;
      if (frequency_AM > MWHighEdgeSet || frequency_AM < MWLowEdgeSet) {
        frequency_AM = MWLowEdgeSet;
      }
      break;
    case BAND_SW:
      frequency_AM = frequency_SW;
      if (frequency_AM > SWHighEdgeSet || frequency_AM < SWLowEdgeSet) {
        frequency_AM = SWLowEdgeSet;
      }
      break;
  }
}

void DivdeSWMIBand() {
  if (frequency_AM >= FREQ_SW_160M_START && frequency_AM <= FREQ_SW_160M_END) {
    SWMIBandPos = SW_MI_BAND_160M;
    frequency_MIBand_160M = frequency_AM;
    SWMIBandstring = (String) "" + SWMIBandPos + " m";
  } else if (frequency_AM >= FREQ_SW_120M_START && frequency_AM <= FREQ_SW_120M_END) {
    SWMIBandPos = SW_MI_BAND_120M;
    frequency_MIBand_120M = frequency_AM;
    SWMIBandstring = (String) "" + SWMIBandPos + " m";
  } else if (frequency_AM >= FREQ_SW_90M_START && frequency_AM <= FREQ_SW_90M_END) {
    SWMIBandPos = SW_MI_BAND_90M;
    frequency_MIBand_90M = frequency_AM;
    SWMIBandstring = (String) "" + SWMIBandPos + " m";
  } else if (frequency_AM >= FREQ_SW_75M_START && frequency_AM <= FREQ_SW_75M_END) {
    SWMIBandPos = SW_MI_BAND_75M;
    frequency_MIBand_75M = frequency_AM;
    SWMIBandstring = (String) "" + SWMIBandPos + " m";
  } else if (frequency_AM >= FREQ_SW_60M_START && frequency_AM <= FREQ_SW_60M_END) {
    SWMIBandPos = SW_MI_BAND_60M;
    frequency_MIBand_60M = frequency_AM;
    SWMIBandstring = (String) "" + SWMIBandPos + " m";
  } else if (frequency_AM >= FREQ_SW_49M_START && frequency_AM <= FREQ_SW_49M_END) {
    SWMIBandPos = SW_MI_BAND_49M;
    frequency_MIBand_49M = frequency_AM;
    SWMIBandstring = (String) "" + SWMIBandPos + " m";
  } else if (frequency_AM >= FREQ_SW_41M_START && frequency_AM <= FREQ_SW_41M_END) {
    SWMIBandPos = SW_MI_BAND_41M;
    frequency_MIBand_41M = frequency_AM;
    SWMIBandstring = (String) "" + SWMIBandPos + " m";
  } else if (frequency_AM >= FREQ_SW_31M_START && frequency_AM <= FREQ_SW_31M_END) {
    SWMIBandPos = SW_MI_BAND_31M;
    frequency_MIBand_31M = frequency_AM;
    SWMIBandstring = (String) "" + SWMIBandPos + " m";
  } else if (frequency_AM >= FREQ_SW_25M_START && frequency_AM <= FREQ_SW_25M_END) {
    SWMIBandPos = SW_MI_BAND_25M;
    frequency_MIBand_25M = frequency_AM;
    SWMIBandstring = (String) "" + SWMIBandPos + " m";
  } else if (frequency_AM >= FREQ_SW_22M_START && frequency_AM <= FREQ_SW_22M_END) {
    SWMIBandPos = SW_MI_BAND_22M;
    frequency_MIBand_22M = frequency_AM;
    SWMIBandstring = (String) "" + SWMIBandPos + " m";
  } else if (frequency_AM >= FREQ_SW_19M_START && frequency_AM <= FREQ_SW_19M_END) {
    SWMIBandPos = SW_MI_BAND_19M;
    frequency_MIBand_19M = frequency_AM;
    SWMIBandstring = (String) "" + SWMIBandPos + " m";
  } else if (frequency_AM >= FREQ_SW_16M_START && frequency_AM <= FREQ_SW_16M_END) {
    SWMIBandPos = SW_MI_BAND_16M;
    frequency_MIBand_16M = frequency_AM;
    SWMIBandstring = (String) "" + SWMIBandPos + " m";
  } else if (frequency_AM >= FREQ_SW_15M_START && frequency_AM <= FREQ_SW_15M_END) {
    SWMIBandPos = SW_MI_BAND_15M;
    frequency_MIBand_15M = frequency_AM;
    SWMIBandstring = (String) "" + SWMIBandPos + " m";
  } else if (frequency_AM >= FREQ_SW_13M_START && frequency_AM <= FREQ_SW_13M_END) {
    SWMIBandPos = SW_MI_BAND_13M;
    frequency_MIBand_13M = frequency_AM;
    SWMIBandstring = (String) "" + SWMIBandPos + " m";
  } else if (frequency_AM >= FREQ_SW_11M_START && frequency_AM <= FREQ_SW_11M_END) {
    SWMIBandPos = SW_MI_BAND_11M;
    frequency_MIBand_11M = frequency_AM;
    SWMIBandstring = (String) "" + SWMIBandPos + " m";
  } else {
    if (SWMIBandPos > SW_MI_BAND_GAP) {
      SWMIBandPosold = SWMIBandPos;
      SWMIBandstringold = (String) "" + SWMIBandPosold + " m";
    }
    SWMIBandPos = SW_MI_BAND_GAP;
  }

}

void ToggleSWMIBand(bool frequencyup) {
  switch (SWMIBandPosold) {
    case SW_MI_BAND_GAP:
      if (frequencyup) {
        SWMIBandPos = SW_MI_BAND_160M;
        SWMIBandPosold = SWMIBandPos;
        frequency_AM = FREQ_SW_160M_START;
      } else {
        SWMIBandPos = SW_MI_BAND_11M;
        SWMIBandPosold = SWMIBandPos;
        frequency_AM = FREQ_SW_11M_END;
      }
      radio.SetFreqAM(frequency_AM);
      frequency_SW = frequency_AM;
      break;
    case SW_MI_BAND_11M:
      if (frequencyup) {
        SWMIBandstringold = (String) "" + SWMIBandPosold + " m";
        SWMIBandPos = SW_MI_BAND_160M;
        SWMIBandPosold = SWMIBandPos;
        SWMIBandstring = (String) "" + SWMIBandPos + " m";
        frequency_AM = frequency_MIBand_160M == 0 ? FREQ_SW_160M_START : frequency_MIBand_160M;
      } else {
        SWMIBandstringold = (String) "" + SWMIBandPosold + " m";
        SWMIBandPos = SW_MI_BAND_13M;
        SWMIBandPosold = SWMIBandPos;
        SWMIBandstring = (String) "" + SWMIBandPos + " m";
        frequency_AM = frequency_MIBand_13M == 0 ? FREQ_SW_13M_END : frequency_MIBand_13M;
      }
      radio.SetFreqAM(frequency_AM);
      frequency_SW = frequency_AM;
      break;
    case SW_MI_BAND_13M:
      if (frequencyup) {
        SWMIBandstringold = (String) "" + SWMIBandPosold + " m";
        SWMIBandPos = SW_MI_BAND_11M;
        SWMIBandPosold = SWMIBandPos;
        SWMIBandstring = (String) "" + SWMIBandPos + " m";
        frequency_AM = frequency_MIBand_11M == 0 ? FREQ_SW_11M_START : frequency_MIBand_11M;
      } else {
        SWMIBandstringold = (String) "" + SWMIBandPosold + " m";
        SWMIBandPos = SW_MI_BAND_15M;
        SWMIBandPosold = SWMIBandPos;
        SWMIBandstring = (String) "" + SWMIBandPos + " m";
        frequency_AM = frequency_MIBand_15M == 0 ? FREQ_SW_15M_END : frequency_MIBand_15M;
      }
      radio.SetFreqAM(frequency_AM);
      frequency_SW = frequency_AM;
      break;
    case SW_MI_BAND_15M:
      if (frequencyup) {
        SWMIBandstringold = (String) "" + SWMIBandPosold + " m";
        SWMIBandPos = SW_MI_BAND_13M;
        SWMIBandPosold = SWMIBandPos;
        SWMIBandstring = (String) "" + SWMIBandPos + " m";
        frequency_AM = frequency_MIBand_13M == 0 ? FREQ_SW_13M_START : frequency_MIBand_13M;
      } else {
        SWMIBandstringold = (String) "" + SWMIBandPosold + " m";
        SWMIBandPos = SW_MI_BAND_16M;
        SWMIBandPosold = SWMIBandPos;
        SWMIBandstring = (String) "" + SWMIBandPos + " m";
        frequency_AM = frequency_MIBand_16M == 0 ? FREQ_SW_16M_END : frequency_MIBand_16M;
      }
      radio.SetFreqAM(frequency_AM);
      frequency_SW = frequency_AM;
      break;
    case SW_MI_BAND_16M:
      if (frequencyup) {
        SWMIBandstringold = (String) "" + SWMIBandPosold + " m";
        SWMIBandPos = SW_MI_BAND_15M;
        SWMIBandPosold = SWMIBandPos;
        SWMIBandstring = (String) "" + SWMIBandPos + " m";
        frequency_AM = frequency_MIBand_15M == 0 ? FREQ_SW_15M_START : frequency_MIBand_15M;
      } else {
        SWMIBandstringold = (String) "" + SWMIBandPosold + " m";
        SWMIBandPos = SW_MI_BAND_19M;
        SWMIBandPosold = SWMIBandPos;
        SWMIBandstring = (String) "" + SWMIBandPos + " m";
        frequency_AM = frequency_MIBand_19M == 0 ? FREQ_SW_19M_END : frequency_MIBand_19M;
      }
      radio.SetFreqAM(frequency_AM);
      frequency_SW = frequency_AM;
      break;
    case SW_MI_BAND_19M:
      if (frequencyup) {
        SWMIBandstringold = (String) "" + SWMIBandPosold + " m";
        SWMIBandPos = SW_MI_BAND_16M;
        SWMIBandPosold = SWMIBandPos;
        SWMIBandstring = (String) "" + SWMIBandPos + " m";
        frequency_AM = frequency_MIBand_16M == 0 ? FREQ_SW_16M_START : frequency_MIBand_16M;
      } else {
        SWMIBandstringold = (String) "" + SWMIBandPosold + " m";
        SWMIBandPos = SW_MI_BAND_22M;
        SWMIBandPosold = SWMIBandPos;
        SWMIBandstring = (String) "" + SWMIBandPos + " m";
        frequency_AM = frequency_MIBand_22M == 0 ? FREQ_SW_22M_END : frequency_MIBand_22M;
      }
      radio.SetFreqAM(frequency_AM);
      frequency_SW = frequency_AM;
      break;
    case SW_MI_BAND_22M:
      if (frequencyup) {
        SWMIBandstringold = (String) "" + SWMIBandPosold + " m";
        SWMIBandPos = SW_MI_BAND_19M;
        SWMIBandPosold = SWMIBandPos;
        SWMIBandstring = (String) "" + SWMIBandPos + " m";
        frequency_AM = frequency_MIBand_19M == 0 ? FREQ_SW_19M_START : frequency_MIBand_19M;
      } else {
        SWMIBandstringold = (String) "" + SWMIBandPosold + " m";
        SWMIBandPos = SW_MI_BAND_25M;
        SWMIBandPosold = SWMIBandPos;
        SWMIBandstring = (String) "" + SWMIBandPos + " m";
        frequency_AM = frequency_MIBand_25M == 0 ? FREQ_SW_25M_END : frequency_MIBand_25M;
      }
      radio.SetFreqAM(frequency_AM);
      frequency_SW = frequency_AM;
      break;
    case SW_MI_BAND_25M:
      if (frequencyup) {
        SWMIBandstringold = (String) "" + SWMIBandPosold + " m";
        SWMIBandPos = SW_MI_BAND_22M;
        SWMIBandPosold = SWMIBandPos;
        SWMIBandstring = (String) "" + SWMIBandPos + " m";
        frequency_AM = frequency_MIBand_22M == 0 ? FREQ_SW_22M_START : frequency_MIBand_22M;
      } else {
        SWMIBandstringold = (String) "" + SWMIBandPosold + " m";
        SWMIBandPos = SW_MI_BAND_31M;
        SWMIBandPosold = SWMIBandPos;
        SWMIBandstring = (String) "" + SWMIBandPos + " m";
        frequency_AM = frequency_MIBand_31M == 0 ? FREQ_SW_31M_END : frequency_MIBand_31M;
      }
      radio.SetFreqAM(frequency_AM);
      frequency_SW = frequency_AM;
      break;
    case SW_MI_BAND_31M:
      if (frequencyup) {
        SWMIBandstringold = (String) "" + SWMIBandPosold + " m";
        SWMIBandPos = SW_MI_BAND_25M;
        SWMIBandPosold = SWMIBandPos;
        SWMIBandstring = (String) "" + SWMIBandPos + " m";
        frequency_AM = frequency_MIBand_25M == 0 ? FREQ_SW_25M_START : frequency_MIBand_25M;
      } else {
        SWMIBandstringold = (String) "" + SWMIBandPosold + " m";
        SWMIBandPos = SW_MI_BAND_41M;
        SWMIBandPosold = SWMIBandPos;
        SWMIBandstring = (String) "" + SWMIBandPos + " m";
        frequency_AM = frequency_MIBand_41M == 0 ? FREQ_SW_41M_END : frequency_MIBand_41M;
      }
      radio.SetFreqAM(frequency_AM);
      frequency_SW = frequency_AM;
      break;
    case SW_MI_BAND_41M:
      if (frequencyup) {
        SWMIBandstringold = (String) "" + SWMIBandPosold + " m";
        SWMIBandPos = SW_MI_BAND_31M;
        SWMIBandPosold = SWMIBandPos;
        SWMIBandstring = (String) "" + SWMIBandPos + " m";
        frequency_AM = frequency_MIBand_31M == 0 ? FREQ_SW_31M_START : frequency_MIBand_31M;
      } else {
        SWMIBandstringold = (String) "" + SWMIBandPosold + " m";
        SWMIBandPos = SW_MI_BAND_49M;
        SWMIBandPosold = SWMIBandPos;
        SWMIBandstring = (String) "" + SWMIBandPos + " m";
        frequency_AM = frequency_MIBand_49M == 0 ? FREQ_SW_49M_END : frequency_MIBand_49M;
      }
      radio.SetFreqAM(frequency_AM);
      frequency_SW = frequency_AM;
      break;
    case SW_MI_BAND_49M:
      if (frequencyup) {
        SWMIBandstringold = (String) "" + SWMIBandPosold + " m";
        SWMIBandPos = SW_MI_BAND_41M;
        SWMIBandPosold = SWMIBandPos;
        SWMIBandstring = (String) "" + SWMIBandPos + " m";
        frequency_AM = frequency_MIBand_41M == 0 ? FREQ_SW_41M_START : frequency_MIBand_41M;
      } else {
        SWMIBandstringold = (String) "" + SWMIBandPosold + " m";
        SWMIBandPos = SW_MI_BAND_60M;
        SWMIBandPosold = SWMIBandPos;
        SWMIBandstring = (String) "" + SWMIBandPos + " m";
        frequency_AM = frequency_MIBand_60M == 0 ? FREQ_SW_60M_END : frequency_MIBand_60M;
      }
      radio.SetFreqAM(frequency_AM);
      frequency_SW = frequency_AM;
      break;
    case SW_MI_BAND_60M:
      if (frequencyup) {
        SWMIBandstringold = (String) "" + SWMIBandPosold + " m";
        SWMIBandPos = SW_MI_BAND_49M;
        SWMIBandPosold = SWMIBandPos;
        SWMIBandstring = (String) "" + SWMIBandPos + " m";
        frequency_AM = frequency_MIBand_49M == 0 ? FREQ_SW_49M_START : frequency_MIBand_49M;
      } else {
        SWMIBandstringold = (String) "" + SWMIBandPosold + " m";
        SWMIBandPos = SW_MI_BAND_75M;
        SWMIBandPosold = SWMIBandPos;
        SWMIBandstring = (String) "" + SWMIBandPos + " m";
        frequency_AM = frequency_MIBand_75M == 0 ? FREQ_SW_75M_END : frequency_MIBand_75M;
      }
      radio.SetFreqAM(frequency_AM);
      frequency_SW = frequency_AM;
      break;
    case SW_MI_BAND_75M:
      if (frequencyup) {
        SWMIBandstringold = (String) "" + SWMIBandPosold + " m";
        SWMIBandPos = SW_MI_BAND_60M;
        SWMIBandPosold = SWMIBandPos;
        SWMIBandstring = (String) "" + SWMIBandPos + " m";
        frequency_AM = frequency_MIBand_60M == 0 ? FREQ_SW_60M_START : frequency_MIBand_60M;
      } else {
        SWMIBandstringold = (String) "" + SWMIBandPosold + " m";
        SWMIBandPos = SW_MI_BAND_90M;
        SWMIBandPosold = SWMIBandPos;
        SWMIBandstring = (String) "" + SWMIBandPos + " m";
        frequency_AM = frequency_MIBand_90M == 0 ? FREQ_SW_90M_END : frequency_MIBand_90M;
      }
      radio.SetFreqAM(frequency_AM);
      frequency_SW = frequency_AM;
      break;
    case SW_MI_BAND_90M:
      if (frequencyup) {
        SWMIBandstringold = (String) "" + SWMIBandPosold + " m";
        SWMIBandPos = SW_MI_BAND_75M;
        SWMIBandPosold = SWMIBandPos;
        SWMIBandstring = (String) "" + SWMIBandPos + " m";
        frequency_AM = frequency_MIBand_75M == 0 ? FREQ_SW_75M_START : frequency_MIBand_75M;
      } else {
        SWMIBandstringold = (String) "" + SWMIBandPosold + " m";
        SWMIBandPos = SW_MI_BAND_120M;
        SWMIBandPosold = SWMIBandPos;
        SWMIBandstring = (String) "" + SWMIBandPos + " m";
        frequency_AM = frequency_MIBand_120M == 0 ? FREQ_SW_120M_END : frequency_MIBand_120M;
      }
      radio.SetFreqAM(frequency_AM);
      frequency_SW = frequency_AM;
      break;
    case SW_MI_BAND_120M:
      if (frequencyup) {
        SWMIBandstringold = (String) "" + SWMIBandPosold + " m";
        SWMIBandPos = SW_MI_BAND_90M;
        SWMIBandPosold = SWMIBandPos;
        SWMIBandstring = (String) "" + SWMIBandPos + " m";
        frequency_AM = frequency_MIBand_90M == 0 ? FREQ_SW_90M_START : frequency_MIBand_90M;
      } else {
        SWMIBandstringold = (String) "" + SWMIBandPosold + " m";
        SWMIBandPos = SW_MI_BAND_160M;
        SWMIBandPosold = SWMIBandPos;
        SWMIBandstring = (String) "" + SWMIBandPos + " m";
        frequency_AM = frequency_MIBand_160M == 0 ? FREQ_SW_160M_END : frequency_MIBand_160M;
      }
      radio.SetFreqAM(frequency_AM);
      frequency_SW = frequency_AM;
      break;
    case SW_MI_BAND_160M:
      if (frequencyup) {
        SWMIBandstringold = (String) "" + SWMIBandPosold + " m";
        SWMIBandPos = SW_MI_BAND_120M;
        SWMIBandPosold = SWMIBandPos;
        SWMIBandstring = (String) "" + SWMIBandPos + " m";
        frequency_AM = frequency_MIBand_120M == 0 ? FREQ_SW_120M_START : frequency_MIBand_120M;
      } else {
        SWMIBandstringold = (String) "" + SWMIBandPosold + " m";
        SWMIBandPos = SW_MI_BAND_11M;
        SWMIBandPosold = SWMIBandPos;
        SWMIBandstring = (String) "" + SWMIBandPos + " m";
        frequency_AM = frequency_MIBand_11M == 0 ? FREQ_SW_49M_END : frequency_MIBand_11M;
      }
      radio.SetFreqAM(frequency_AM);
      frequency_SW = frequency_AM;
      break;
  }
}

void SelectBand() {
  if (band > BAND_GAP) {
    seek = false;
    if (!screenmute) tft.drawBitmap(92, 4, Speaker, 26, 22, GreyoutColor);
    if (tunemode == TUNE_MI_BAND && band != BAND_SW) tunemode = TUNE_MAN;
    BWreset = true;
    BWset = BWsetAM;
    switch (band) {
      case BAND_LW: freqold = frequency_LW; frequency_AM = frequency_LW; break;
      case BAND_MW: freqold = frequency_MW; frequency_AM = frequency_MW; break;
      case BAND_SW: freqold = frequency_SW; frequency_AM = frequency_SW; break;
#ifdef HAS_AIR_BAND
      case BAND_AIR: freqold = frequency_AIR; frequency_AM = frequency_AIR; break;
#endif
    }
    LimitAMFrequency();
    if (!externaltune) CheckBandForbiddenAM();
#ifdef HAS_AIR_BAND
    if (band == BAND_AIR) {
      radio.SetFreqAIR(10700);
    } else {
      radio.SetFreqAM(frequency_AM);
    }
#else
    radio.SetFreqAM(frequency_AM);
#endif
    radio.setAMAttenuation(amgain);
    radio.setAMCoChannel(amcodect, amcodectcount);
    doBW();
    if (!screenmute) {
      BuildDisplay();
      if (region == REGION_EU) tftPrint(-1, "PI:", 212, 193, GreyoutColor, BackgroundColor, 16);
      if (region == REGION_US) {
        tftPrint(-1, "PI:", 212, 184, GreyoutColor, BackgroundColor, 16);
        tftPrint(-1, "ID:", 212, 201, GreyoutColor, BackgroundColor, 16);
      }

      tftPrint(-1, "PS:", 3, 193, GreyoutColor, BackgroundColor, 16);
      tftPrint(-1, "RT:", 3, 221, GreyoutColor, BackgroundColor, 16);
      tftPrint(-1, "PTY:", 3, 163, GreyoutColor, BackgroundColor, 16);
      tft.drawBitmap(122, 5, RDSLogo, 35, 22, GreyoutColor);
      tft.drawRoundRect(248, 56, 32, 20, 5, GreyoutColor);
      tftPrint(0, "iMS", 265, 59, GreyoutColor, BackgroundColor, 16);
      tft.drawRoundRect(286, 56, 32, 20, 5, GreyoutColor);
      tftPrint(0, "EQ", 303, 59, GreyoutColor, BackgroundColor, 16);
      // todo
      // if (band == AM_BAND_AIR) tftPrint(-1, "MHz", 258, 76, ActiveColor, ActiveColorSmooth, 28);
      // else tftPrint(-1, "KHz", 258, 76, ActiveColor, ActiveColorSmooth, 28);
    }
  } else {
    if (tunemode == TUNE_MI_BAND) tunemode = TUNE_MAN;
    radio.power(0);
    delay(50);
    if (band == BAND_FM) radio.SetFreq(frequency);
    if (band == BAND_OIRT) radio.SetFreq(frequency_OIRT);
    PIold = "";
    PSold = "";
    PTYold = "";
    RTold = "";
    BWreset = true;
    BWset = BWsetFM;
    radio.clearRDS(fullsearchrds);
    freqold = frequency_AM;
    if (!externaltune) CheckBandForbiddenFM();
    doBW();
    if (!screenmute) BuildDisplay();
  }
}

void BWButtonPress() {
  if (scandxmode) {
    cancelDXScan();
  } else {
    if (!usesquelch) radio.setUnMute();
    if (!menu) {
      seek = false;
      if (!screenmute) tft.drawBitmap(92, 4, Speaker, 26, 22, GreyoutColor);
      unsigned long counterold = millis();
      unsigned long counter = millis();
      while (digitalRead(BWBUTTON) == LOW && counter - counterold <= 1000) counter = millis();

      if (counter - counterold < 1000) {
        if (band == BAND_FM || band == BAND_OIRT) {
          doStereoToggle();
        } else {
          BWset++;
          doBW();
          BWtune = true;
        }
      } else {
        BWset++;
        doBW();
        BWtune = true;
      }
      if (screensaverset) {
        ScreensaverTimerRestart();
      }
      delay(100);
    }
  }
}

void doStereoToggle() {
  if (StereoToggle) {
    if (!screenmute) {
      tft.drawSmoothCircle(66, 15, 10, BackgroundColor, BackgroundColor);
      tft.drawSmoothCircle(66, 15, 9, BackgroundColor, BackgroundColor);
      tft.drawSmoothCircle(76, 15, 10, BackgroundColor, BackgroundColor);
      tft.drawSmoothCircle(76, 15, 9, BackgroundColor, BackgroundColor);
      tft.drawSmoothCircle(71, 15, 10, SecondaryColor, SecondaryColorSmooth);
      tft.drawSmoothCircle(71, 15, 9, SecondaryColor, SecondaryColorSmooth);
    }
    radio.setMono(true);
    StereoToggle = false;
  } else {
    if (!screenmute) {
      tft.drawSmoothCircle(71, 15, 10, BackgroundColor, BackgroundColor);
      tft.drawSmoothCircle(71, 15, 9, BackgroundColor, BackgroundColor);
      tft.drawSmoothCircle(66, 15, 10, GreyoutColor, BackgroundColor);
      tft.drawSmoothCircle(66, 15, 9, GreyoutColor, BackgroundColor);
      tft.drawSmoothCircle(76, 15, 10, GreyoutColor, BackgroundColor);
      tft.drawSmoothCircle(76, 15, 9, GreyoutColor, BackgroundColor);
    }
    radio.setMono(false);
    Stereostatusold = false;
    StereoToggle = true;
  }
  EEPROM.writeByte(EE_BYTE_STEREO, StereoToggle);
  EEPROM.commit();
}

void ModeButtonPress() {
  if (scandxmode) {
    cancelDXScan();
  } else {
    if (!usesquelch) radio.setUnMute();
    if (advancedRDS) {
      BuildDisplay();
      ScreensaverTimerReopen();
    } else if (afscreen) {
      if (afpagenr == 1) afpagenr = 2; else if (afpagenr == 2 && afpage) afpagenr = 3; else afpagenr = 1;
      BuildAFScreen();
    } else {
      if (!menu) {
        seek = false;
        if (!screenmute) {
          tft.drawBitmap(92, 4, Speaker, 26, 22, GreyoutColor);
        }
        memorystore = false;
        unsigned long counterold = millis();
        unsigned long counter = millis();
        while (digitalRead(MODEBUTTON) == LOW && counter - counterold <= 1000) counter = millis();

        if (counter - counterold <= 1000) {
          doTuneMode();
          if (screensaverset) {
            ScreensaverTimerRestart();
          }
        } else {
          if (!menu) {
            menuoption = ITEM1;
            menupage = INDEX;
            menuitem = 0;
            UpdateFonts(1);
            if (spispeed == 7) tft.setSPISpeed(30);
            BuildMenu();
            menu = true;
            ScreensaverTimerSet(OFF);
          }
        }
      } else {
        if (menuopen && !submenu) {
          ButtonPress();
        } else if (!submenu) {
          OStatusold = 1000;
          Stereostatusold = false;
          SStatusold = 2000;
          BWOld = 0;
          radio.clearRDS(fullsearchrds);
          RDSstatus = false;
          if (frequency % 10 != 0) {
            if (fmdefaultstepsize == 1) Round100K(frequency); else Round50K(frequency);
            EEPROM.writeUInt(EE_UINT16_FREQUENCY_FM, frequency);
          }
          CheckBandForbiddenFM();
          CheckBandForbiddenAM();
          if (!usesquelch) radio.setUnMute();
          MWLowEdgeSet = mwstepsize == false ? FREQ_MW_LOW_EDGE_MIN_9K : FREQ_MW_LOW_EDGE_MIN_10K;
          MWHighEdgeSet = mwstepsize == false ? FREQ_MW_HIGH_EDGE_MAX_9K : FREQ_MW_HIGH_EDGE_MAX_10K;
          doBandSelectionFM();
          doBandSelectionAM();
          ScreensaverTimerSet(screensaverOptions[screensaverset]);
          if (screensaverset) ScreensaverTimerRestart();
          endMenu();
        } else {
          if (submenu) {
            if (menuopen) {
              if (menupage == CONNECTIVITY && menuoption == ITEM2 && wifi) {
                tryWiFi();
                delay(2000);
              }
              if (menupage == DISPLAYSETTINGS && menuoption == ITEM5) {
                doTheme();
              }
              menuopen = false;
            }
            submenu = false;
            menuoption = ITEM1;
            menupage = INDEX;
            menuitem = 0;
            if (spispeed == 7) tft.setSPISpeed(30);
            BuildMenu();
          }
        }
      }
    }
  }
  while (digitalRead(MODEBUTTON) == LOW) delay(50);
  delay(100);
}

void ShowStepSize() {
  if (!advancedRDS) {
    tft.fillRect(191, 38, 15, 4, GreyoutColor);
    tft.fillRect(222, 38, 15, 4, GreyoutColor);
    if (band < BAND_GAP) tft.fillRect(113, 38, 15, 4, GreyoutColor); else if (band != BAND_LW && band != BAND_MW) tft.fillRect(129, 38, 15, 4, GreyoutColor);
    if (band < BAND_GAP) tft.fillRect(144, 38, 15, 4, GreyoutColor); else tft.fillRect(159, 38, 15, 4, GreyoutColor);
    if (stepsize == 1) tft.fillRect(222, 38, 15, 4, InsignificantColor);
    if (stepsize == 2) tft.fillRect(191, 38, 15, 4, InsignificantColor);
    if (stepsize == 3) {
      if (band < BAND_GAP) tft.fillRect(144, 38, 15, 4, InsignificantColor); else tft.fillRect(159, 38, 15, 4, InsignificantColor);
    }
    if (stepsize == 4) {
      if (band < BAND_GAP) tft.fillRect(113, 38, 15, 4, InsignificantColor); else tft.fillRect(129, 38, 15, 4, InsignificantColor);
    }
  }
}

void Round30K(unsigned int freq) {
  if (freq % FREQ_OIRT_STEP_30K == 1) {
    frequency_OIRT = (freq + 1);
  } else if (freq % FREQ_OIRT_STEP_30K == 0) {
    frequency_OIRT = (freq - 1);
  }
}

void Round50K(unsigned int freq) {
  if (freq % 10 < 3) {
    frequency = (freq - freq % 10);
  } else if (freq % 10 > 2 && freq % 10 < 8) {
    frequency = (freq - (freq % 10 - 5));
  } else if (freq % 10 > 7) {
    frequency = (freq - (freq % 10) + 10);
  }
}

void Round100K(unsigned int freq) {
  if (freq % 10 < 5) {
    frequency = (freq - freq % 10);
  } else {
    frequency = (freq - (freq % 10) + 10);
  }
}

void Round200K(unsigned int freq) {
  frequency = (freq / 10) * 10;

  if (freq % 10 >= 5) frequency += 10;
  if ((frequency / 100) % 2 == 0) frequency += 10;
  if (frequency > 10800) frequency = 10790;
  if (frequency % 20 == 0 && (frequency / 10) % 2 == 0) frequency -= 10;
}

void Round5K(unsigned int freqAM) {
  if (freqAM % 10 < 3) {
    frequency_AM = (freqAM - freqAM % 10);
  } else if (freqAM % 10 > 2 && freqAM % 10 < 8) {
    frequency_AM = (freqAM - (freqAM % 10 - 5));
  } else if (freqAM % 10 > 7) {
    frequency_AM = (freqAM - (freqAM % 10) + 10);
  }
}

void RoundStep() {//todo air
  if (band == BAND_FM) {
    unsigned int freq = frequency;
    switch (fmdefaultstepsize) {
      case 0: Round50K(freq); break;
      case 1: Round100K(freq); break;
      case 2: Round200K(freq); break;
    }
    radio.SetFreq(frequency);
  } else if (band == BAND_OIRT) {
    Round30K(frequency_OIRT);
    radio.SetFreq(frequency_OIRT);
  } else {
    if (band == BAND_MW) {
      unsigned int freq = frequency_AM / (mwstepsize == false ? FREQ_MW_STEP_9K : FREQ_MW_STEP_10K);
      frequency_AM = freq * (mwstepsize == false ? FREQ_MW_STEP_9K : FREQ_MW_STEP_10K);
      radio.SetFreqAM(frequency_AM);
    } else if (band == BAND_SW) {
      Round5K(frequency_AM);
      radio.SetFreqAM(frequency_AM);
    }
  }

  while (digitalRead(ROTARY_BUTTON) == LOW) delay(50);

  if (band == BAND_FM) {
    EEPROM.writeUInt(EE_UINT16_FREQUENCY_FM, frequency);
  } else if (band == BAND_OIRT) {
    EEPROM.writeUInt(EE_UINT16_FREQUENCY_OIRT, frequency_OIRT);
  } else {
    EEPROM.writeUInt(EE_UINT16_FREQUENCY_AM, frequency_AM);
  }
  EEPROM.commit();
}

void ButtonPress() {
  if (scandxmode) {
    cancelDXScan();
  } else {
    if (!usesquelch) radio.setUnMute();
    if (advancedRDS) BuildDisplay();
    if (!menu) {
      if (tunemode == TUNE_MEM) {
        if (!memorystore) {
          memorystore = true;
          if (!IsStationEmpty()) memoryposstatus = MEM_EXIST;
          else memoryposstatus = MEM_NORMAL;
          ShowMemoryPos();

          ShowTuneMode();
        } else {
          memorystore = false;
          EEPROM.writeByte(memorypos + EE_PRESETS_BAND_START, band);
          EEPROM.writeByte(memorypos + EE_PRESET_BW_START, BWset);
          EEPROM.writeByte(memorypos + EE_PRESET_MS_START, StereoToggle);
          if (band == BAND_FM) {//todo air
            EEPROM.writeUInt((memorypos * 4) + EE_PRESETS_FREQUENCY_START, frequency);
          } else if (band == BAND_OIRT) {
            EEPROM.writeUInt((memorypos * 4) + EE_PRESETS_FREQUENCY_START, frequency_OIRT);
          } else if (band == BAND_LW) {
            EEPROM.writeUInt((memorypos * 4) + EE_PRESETS_FREQUENCY_START, frequency_LW);
          } else if (band == BAND_MW) {
            EEPROM.writeUInt((memorypos * 4) + EE_PRESETS_FREQUENCY_START, frequency_MW);
          } else {
            EEPROM.writeUInt((memorypos * 4) + EE_PRESETS_FREQUENCY_START, frequency_SW);
          }

          presets[memorypos].band = band;
          presets[memorypos].bw = BWset;
          presets[memorypos].ms = StereoToggle;

          String stationName = radio.rds.stationName;
          char stationNameCharArray[10];
          char picodeArray[7];
          stationName.toCharArray(stationNameCharArray, sizeof(stationNameCharArray));
          memcpy(picodeArray, radio.rds.picode, sizeof(picodeArray));

          for (int y = 0; y < 9; y++) {
            presets[memorypos].RDSPS[y] = (y < strlen(stationNameCharArray)) ? stationNameCharArray[y] : '\0';
            EEPROM.writeByte((memorypos * 9) + y + EE_PRESETS_RDSPS_START, presets[memorypos].RDSPS[y]);
          }

          for (int y = 0; y < 5; y++) {
            presets[memorypos].RDSPI[y] = (y < sizeof(picodeArray)) ? picodeArray[y] : '\0';
            EEPROM.writeByte((memorypos * 5) + y + EE_PRESETS_RDSPI_START, presets[memorypos].RDSPI[y]);
          }

          EEPROM.commit();

          if (band == BAND_FM) {//todo air
            presets[memorypos].frequency = frequency;
          } else if (band == BAND_OIRT) {
            presets[memorypos].frequency = frequency_OIRT;
          } else if (band == BAND_LW) {
            presets[memorypos].frequency = frequency_LW;
          } else if (band == BAND_MW) {
            presets[memorypos].frequency = frequency_MW;
          } else {
            presets[memorypos].frequency = frequency_SW;
          }
          ShowTuneMode();
          if (memoryposstatus == MEM_DARK || memoryposstatus == MEM_EXIST) {
            memoryposstatus = MEM_NORMAL;
            ShowMemoryPos();
          }
        }
      } else {
        seek = false;
        if (!screenmute) tft.drawBitmap(92, 4, Speaker, 26, 22, GreyoutColor);
        unsigned long counterold = millis();
        unsigned long counter = millis();
        while (digitalRead(ROTARY_BUTTON) == LOW && counter - counterold <= 1000) counter = millis();

        if (counter - counterold < 1000) {
          if (tunemode == TUNE_MAN) {
            stepsize++;
            if (band == BAND_SW || band < BAND_GAP) {
              if (stepsize > 4) stepsize = 0;
            } else {
              if (stepsize > 3) stepsize = 0;
            }

            if (!screenmute) ShowStepSize();

            EEPROM.writeByte(EE_BYTE_STEPSIZE, stepsize);
            EEPROM.commit();
            if (stepsize == 0) {
              RoundStep();
              ShowFreq(0);
            }
          }
        } else {
          if (band < BAND_GAP) {
            if (iMSEQ == 0) iMSEQ = 1;

            if (iMSEQ == 4) {
              iMSset = 0;
              EQset = 0;
              updateiMS();
              updateEQ();
              iMSEQ = 0;
            }
            if (iMSEQ == 3) {
              iMSset = 1;
              EQset = 0;
              updateiMS();
              updateEQ();
              iMSEQ = 4;
            }
            if (iMSEQ == 2) {
              iMSset = 0;
              EQset = 1;
              updateiMS();
              updateEQ();
              iMSEQ = 3;
            }
            if (iMSEQ == 1) {
              iMSset = 1;
              EQset = 1;
              updateiMS();
              updateEQ();
              iMSEQ = 2;
            }
            EEPROM.writeByte(EE_BYTE_IMSSET, iMSset);
            EEPROM.writeByte(EE_BYTE_EQSET, EQset);
            EEPROM.commit();
            if (XDRGTKUSB || XDRGTKTCP) DataPrint("G" + String(!EQset) + String(!iMSset) + "\n");
          } else {
            if (band == BAND_SW && tunemode != TUNE_MEM) {
              nowToggleSWMIBand = !nowToggleSWMIBand;
              tunemode = TUNE_MAN;
              EEPROM.writeByte(EE_BYTE_BANDAUTOSW, nowToggleSWMIBand);
              EEPROM.commit();
              if (!screenmute) {
                tftPrint(0, "AUTO", 22, 60, BackgroundColor, BackgroundColor, 16);
                tftPrint(0, "BAND", 22, 60, BackgroundColor, BackgroundColor, 16);
              }
              doTuneMode();
              ShowTuneMode();
            }
          }
        }
      }
      if (screensaverset) {
        ScreensaverTimerRestart();
      }
    } else {
      DoMenu();
    }
  }
  while (digitalRead(ROTARY_BUTTON) == LOW) delay(50);
}

void KeyUp() {
  rotary = 0;
  if (scandxmode) {
    cancelDXScan();
  } else {
    if (!afscreen) {
      if (!menu) {
        switch (tunemode) {
          case TUNE_MAN:
            TuneUp();
            break;

          case TUNE_AUTO:
            direction = true;
            seek = true;
            Seek(direction);
            break;

          case TUNE_MEM:
            memorypos++;
            if (memorypos > EE_PRESETS_CNT - 1) memorypos = 0;
            if (!memorystore) {
              while (IsStationEmpty()) {
                memorypos++;
                if (memorypos > EE_PRESETS_CNT - 1) {
                  memorypos = 0;
                  break;
                }
              }
            }
            if (!memorystore) {
              DoMemoryPosTune();
            } else {
              if (!IsStationEmpty()) memoryposstatus = MEM_EXIST;
              else memoryposstatus = MEM_NORMAL;
            }
            ShowMemoryPos();
            EEPROM.writeByte(EE_BYTE_MEMORYPOS, memorypos);
            EEPROM.commit();
            break;

          case TUNE_MI_BAND:
            if (showSWMIBand) {
              if (displayflip) {
                ToggleSWMIBand(true);
              } else {
                ToggleSWMIBand(REVERSE);
              }
            }
            break;
        }
        if (XDRGTKUSB || XDRGTKTCP) {
          if (band == BAND_FM) DataPrint("M0\nT" + String(frequency * 10) + "\n"); else if (band == BAND_OIRT) DataPrint("M0\nT" + String(frequency_OIRT * 10) + "\n"); else DataPrint("M1\nT" + String(frequency_AM) + "\n");
        }
        if (!memorystore) {
          if (!memtune) radio.clearRDS(fullsearchrds);
          memtune = false;
          ShowFreq(0);
          store = true;
        }
      } else {
        MenuUp();
      }
    }
  }
}

void KeyDown() {
  rotary = 0;
  if (scandxmode) {
    cancelDXScan();
  } else {
    if (!afscreen) {
      if (!menu) {
        switch (tunemode) {
          case TUNE_MAN:
            TuneDown();
            break;

          case TUNE_AUTO:
            direction = false;
            seek = true;
            Seek(direction);
            break;

          case TUNE_MEM:
            memorypos--;
            if (memorypos > EE_PRESETS_CNT - 1) memorypos = EE_PRESETS_CNT - 1;
            if (!memorystore) {
              while (IsStationEmpty()) {
                memorypos--;
                if (memorypos > EE_PRESETS_CNT - 1) {
                  memorypos = EE_PRESETS_CNT - 1;
                  break;
                }
              }
            }
            if (!memorystore) {
              DoMemoryPosTune();
            } else {
              if (!IsStationEmpty()) memoryposstatus = MEM_EXIST;
              else memoryposstatus = MEM_NORMAL;
            }
            ShowMemoryPos();
            EEPROM.writeByte(EE_BYTE_MEMORYPOS, memorypos);
            EEPROM.commit();
            break;
          case TUNE_MI_BAND:
            if (showSWMIBand) {
              if (displayflip) {
                ToggleSWMIBand(REVERSE);
              } else {
                ToggleSWMIBand(true);
              }
            }
            break;
        }
        if (XDRGTKUSB || XDRGTKTCP) {
          if (band == BAND_FM) DataPrint("M0\nT" + String(frequency * 10) + "\n"); else if (band == BAND_OIRT) DataPrint("M0\nT" + String(frequency_OIRT * 10) + "\n"); else DataPrint("M1\nT" + String(frequency_AM) + "\n");
        }
        if (!memorystore) {
          if (!memtune) radio.clearRDS(fullsearchrds);
          memtune = false;
          ShowFreq(0);
          store = true;
        }
      } else {
        MenuDown();
      }
    }
  }
}

bool IsStationEmpty() {
  if (presets[memorypos].band == BAND_FM && presets[memorypos].frequency == EE_PRESETS_FREQUENCY) {
    return true;
  }
  return false;
}

bool IsFrequencyUsed(unsigned int freq) {
  bool result = false;
  for (byte x = scanstart; x <= scanstop; x++) {
    if (presets[x].band == BAND_FM && presets[x].frequency == freq) {
      result = true;
      break;
    }
  }
  return result;
}

void ShowMemoryPos() {
  if (tunemode == TUNE_MEM) {
    int memposcolor = 0;
    int memposcolorsmooth = 0;
    switch (memoryposstatus) {
      case MEM_DARK:
        memposcolor = InsignificantColor;
        memposcolorsmooth = InsignificantColorSmooth;
        break;

      case MEM_NORMAL:
        memposcolor = PrimaryColor;
        memposcolorsmooth = PrimaryColorSmooth;
        break;

      case MEM_EXIST:
        memposcolor = SignificantColor;
        memposcolorsmooth = SignificantColorSmooth;
        break;
    }
    if (advancedRDS) {
      tftReplace(-1, String(memoryposold + 1), String(memorypos + 1), 215, 36, SecondaryColor, SecondaryColorSmooth, BackgroundColor, 16);
    } else {
      tftReplace(-1, String(memoryposold + 1), String(memorypos + 1), 50, 32, memposcolor, memposcolorsmooth, BackgroundColor, 16);
    }
    memoryposold = memorypos;
  } else {
    if (advancedRDS) {
      tftPrint(-1, String(memorypos + 1), 215, 36, BackgroundColor, BackgroundColor, 16);
    } else {
      tftPrint(-1, String(memorypos + 1), 50, 32, BackgroundColor, BackgroundColor, 16);
    }
  }
}

void DoMemoryPosTune() {
  // Process empty stations
  if (IsStationEmpty()) {
    memoryposstatus = MEM_DARK;
    return;
  } else {
    memoryposstatus = MEM_NORMAL;
  }

  if (band != presets[memorypos].band) {
    band = presets[memorypos].band;
    SelectBand();
  } else {
    band = presets[memorypos].band;
  }

  switch (band) {
    case BAND_FM:
      frequency = presets[memorypos].frequency;
      radio.SetFreq(frequency);
      break;
    case BAND_OIRT:
      frequency_OIRT = presets[memorypos].frequency;
      radio.SetFreq(frequency_OIRT);
      break;
    case BAND_LW:
      frequency_LW = presets[memorypos].frequency;
      radio.SetFreq(frequency_LW);
      break;
    case BAND_MW:
      frequency_MW = presets[memorypos].frequency;
      radio.SetFreq(frequency_MW);
      break;
    case BAND_SW:
      frequency_SW = presets[memorypos].frequency;
      radio.SetFreq(frequency_SW);
      break;
#ifdef HAS_AIR_BAND
    case BAND_AIR:
      frequency_AIR = presets[memorypos].frequency;
      // radio.SetFreq(frequency_AIR); // todo
      radio.SetFreqAM(10700); // todo
      break;
#endif
  }

  ShowFreq(0);

  if (band == BAND_FM || band == BAND_OIRT) {
    StereoToggle = presets[memorypos].ms;
    if (!StereoToggle) {
      Stereostatusold = false;
      tft.drawSmoothCircle(66, 15, 10, BackgroundColor, BackgroundColor);
      tft.drawSmoothCircle(66, 15, 9, BackgroundColor, BackgroundColor);
      tft.drawSmoothCircle(76, 15, 10, BackgroundColor, BackgroundColor);
      tft.drawSmoothCircle(76, 15, 9, BackgroundColor, BackgroundColor);
      tft.drawSmoothCircle(71, 15, 10, SecondaryColor, SecondaryColorSmooth);
      tft.drawSmoothCircle(71, 15, 9, SecondaryColor, SecondaryColorSmooth);
    } else {
      Stereostatusold = false;
      tft.drawSmoothCircle(71, 15, 10, BackgroundColor, BackgroundColor);
      tft.drawSmoothCircle(71, 15, 9, BackgroundColor, BackgroundColor);
      tft.drawSmoothCircle(66, 15, 10, GreyoutColor, BackgroundColor);
      tft.drawSmoothCircle(66, 15, 9, GreyoutColor, BackgroundColor);
      tft.drawSmoothCircle(76, 15, 10, GreyoutColor, BackgroundColor);
      tft.drawSmoothCircle(76, 15, 9, GreyoutColor, BackgroundColor);
    }
  }

  radio.clearRDS(fullsearchrds);

  if (RDSSPYUSB) Serial.print("G:\r\nRESET-------\r\n\r\n");
  if (RDSSPYTCP) RemoteClient.print("G:\r\nRESET-------\r\n\r\n");
  if (XDRGTKUSB || XDRGTKTCP) DataPrint("T" + String((frequency + ConverterSet * 100) * 10) + "\n");

  String stationText = "";
  if (presets[memorypos].RDSPS[0] != '\0') {
    for (byte i = 0; i < 9; i++) stationText += presets[memorypos].RDSPS[i];
  }

  if (presets[memorypos].RDSPI[0] != '\0') {
    for (byte i = 0; i < 5; i++) {
      radio.rds.picode[i] = presets[memorypos].RDSPI[i];
    }
    radio.rds.picode[6] = '\0';
  } else {
    for (byte i = 0; i < 6; i++) {
      radio.rds.picode[i] = '\0';
    }
  }

  radio.rds.stationName = stationText;

  BWset = presets[memorypos].bw;
  doBW();
  BWtune = true;
  memtune = true;
  memreset = true;
  dropout = true;
}

void ShowFreq(int mode) {
  if (!setupmode) {
    if (band != BAND_FM && band != BAND_OIRT) {
      if (freqold < 2000 && frequency_AM >= 2000 && stepsize == 0) if (frequency_AM != 27000 && freqold != 144) radio.SetFreqAM(2000);
      if (freqold >= 2000 && frequency_AM < 2000 && stepsize == 0) if (frequency_AM != 144 && freqold != 27000) radio.SetFreqAM(1998);
    }
  }

  detachInterrupt(digitalPinToInterrupt(ROTARY_PIN_A));
  detachInterrupt(digitalPinToInterrupt(ROTARY_PIN_B));

  if (band > BAND_GAP) {
    switch (band) {
      case BAND_LW: frequency_AM = frequency_LW; break;
      case BAND_MW: frequency_AM = frequency_MW; break;
      case BAND_SW: frequency_AM = frequency_SW; break;
#ifdef HAS_AIR_BAND
      case BAND_AIR: frequency_AM = frequency_AIR; break; // todo air
#endif
    }

    if (!screenmute) {
      FrequencySprite.fillSprite(BackgroundColor);

      switch (freqfont) {
        case 0: FrequencySprite.loadFont(FREQFONT0); break;
        case 1: FrequencySprite.loadFont(FREQFONT1); break;
        case 2: FrequencySprite.loadFont(FREQFONT2); break;
        case 3: FrequencySprite.loadFont(FREQFONT3); break;
        case 4: FrequencySprite.loadFont(FREQFONT4); break;
        case 5: FrequencySprite.loadFont(FREQFONT5); break;
      }

      FrequencySprite.setTextDatum(TR_DATUM);
      FrequencySprite.setTextColor(FreqColor, FreqColorSmooth, false);
      if (band == BAND_AIR) {
        FrequencySprite.drawString(String(frequency_AM / 1000) + "." + String(frequency_AM % 1000) + " ", 218, -6);
      } else {
        FrequencySprite.drawString(String(frequency_AM) + " ", 218, -6);
      }
      FrequencySprite.unloadFont();
      FrequencySprite.setTextColor(PrimaryColor, PrimaryColorSmooth, false);
      FrequencySprite.setTextDatum(TL_DATUM);
      FrequencySprite.loadFont(FONT16);

      if (band == BAND_SW && showSWMIBand) {
        DivdeSWMIBand();
        updateSWMIBand();
      }

      FrequencySprite.unloadFont();
      FrequencySprite.pushSprite(46, 46);
    }

    freqold = frequency_AM;
  } else {
    unsigned int freq = 0;
    if (band == BAND_FM) freq = frequency + ConverterSet * 100;
    if (band == BAND_OIRT) freq = frequency_OIRT;

    if (!screenmute) {
      if (advancedRDS) {
        for (int i = 0; i < 33; i++) tft.fillCircle((6 * i) + 10, 133, 2, GreyoutColor);
        tftReplace(1, String(freqold / 100) + "." + (freqold % 100 < 10 ? "0" : "") + String(freqold % 100), String(freq / 100) + "." + (freq % 100 < 10 ? "0" : "") + String(freq % 100), 273, 35, PrimaryColor, PrimaryColorSmooth, BackgroundColor, 16);
        freqold = freq;
      } else if (afscreen) {
        tftReplace(1, String(freqold / 100) + "." + (freqold % 100 < 10 ? "0" : "") + String(freqold % 100) + " MHz", String(freq / 100) + "." + (freq % 100 < 10 ? "0" : "") + String(freq % 100), 290, 201, BWAutoColor, BWAutoColorSmooth, BackgroundColor, 16);
        freqold = freq;
      } else {
        switch (freqfont) {
          case 0: FrequencySprite.loadFont(FREQFONT0); break;
          case 1: FrequencySprite.loadFont(FREQFONT1); break;
          case 2: FrequencySprite.loadFont(FREQFONT2); break;
          case 3: FrequencySprite.loadFont(FREQFONT3); break;
          case 4: FrequencySprite.loadFont(FREQFONT4); break;
          case 5: FrequencySprite.loadFont(FREQFONT5); break;
        }

        FrequencySprite.setTextDatum(TR_DATUM);

        if (mode == 0) {
          FrequencySprite.fillSprite(BackgroundColor);
          FrequencySprite.setTextColor(FreqColor, FreqColorSmooth, false);
          FrequencySprite.drawString(String(freq / 100) + "." + (freq % 100 < 10 ? "0" : "") + String(freq % 100) + " ", 218, -6);
          FrequencySprite.pushSprite(46, 46);
          freqold = freq;
        } else if (mode == 1) {
          FrequencySprite.fillSprite(BackgroundColor);
          FrequencySprite.pushSprite(46, 46);
        }
        FrequencySprite.unloadFont();
      }
    }
  }
  attachInterrupt(digitalPinToInterrupt(ROTARY_PIN_A), read_encoder, CHANGE);
  attachInterrupt(digitalPinToInterrupt(ROTARY_PIN_B), read_encoder, CHANGE);

  if (spispeed == 7) setAutoSpeedSPI();
  rdsreset = true;
  licold = 254;
  ECCold = 253;
  afmethodBold = false;
  aid_counterold = 0;
  dropout = false;

  if (wifi) {
    Udp.beginPacket(remoteip, 9030);
    if (band == BAND_FM) {
      Udp.print("from=TEF_tuner " + String(stationlistid, DEC) + ";freq=" + String(frequency) + "0000");
    } else if (band == BAND_OIRT) {
      Udp.print("from=TEF_tuner " + String(stationlistid, DEC) + ";freq=" + String(frequency_OIRT) + "0000");
    } else {
      Udp.print("from=TEF_tuner " + String(stationlistid, DEC) + ";freq=" + String(frequency_AM) + "000");
    }
    Udp.endPacket();
  }
  tuningtimer = millis();

  if (!rdsflagreset && !screenmute && !afscreen) {
    ShowRDSLogo(false);
    if (!advancedRDS) {
      RadiotextSprite.fillSprite(BackgroundColor);
      RadiotextSprite.pushSprite(36, 220);
      tft.fillCircle(314, 223, 2, GreyoutColor);
      tft.fillCircle(314, 234, 2, GreyoutColor);
    } else {
      RDSSprite.fillSprite(BackgroundColor);
      tft.fillCircle(203, 223, 2, GreyoutColor);
      tft.fillCircle(203, 234, 2, GreyoutColor);
      RDSSprite.pushSprite(36, 220);
    }
    rdsflagreset = true;
  }
}

void ShowSignalLevel() {
  if (!screenmute) {
    if (millis() >= SNRupdatetimer + TIMER_SNR_TIMER) {
      SNRupdatetimer = millis();
      if (!advancedRDS) {
        if (CN > (CNold + 1) || CN < (CNold - 1)) {
          if (CNold == 0) tftPrint(1, "--", 295, 163, BackgroundColor, BackgroundColor, 16); else tftPrint(1, String(CNold), 295, 163, BackgroundColor, BackgroundColor, 16);
          if (tuned) {
            if (CN == 0) tftPrint(1, "--", 295, 163, PrimaryColor, PrimaryColorSmooth, 16); else tftPrint(1, String(CN), 295, 163, PrimaryColor, PrimaryColorSmooth, 16);
            CNold = CN;
          } else {
            tftPrint(1, "--", 295, 163, PrimaryColor, PrimaryColorSmooth, 16);
            CNold = 0;
          }
        }
      }
    }
    SAvg = (((SAvg * 9) + 5) / 10) + SStatus;
    SAvg2 = (((SAvg2 * 9) + 5) / 10) + CN;

    float sval = 0;
    int16_t smeter = 0;
    int16_t segments;

    if (SStatus > 0) {
      if (SStatus < 1000) {
        sval = 51 * ((pow(10, (((float)SStatus) / 1000))) - 1);
        smeter = int16_t(sval);
      } else {
        smeter = 511;
      }
    }

    smeter = int16_t(sval);
    SStatus = SAvg / 10;
    CN = SAvg2 / 10;

    if (!menu) analogWrite(SMETERPIN, smeter);

    int SStatusprint = 0;
    if (unit == 0) SStatusprint = SStatus;
    if (unit == 1) SStatusprint = ((SStatus * 100) + 10875) / 100;
    if (unit == 2) SStatusprint = round((float(SStatus) / 10.0 - 10.0 * log10(75) - 90.0) * 10.0);

    if (SStatusprint > (SStatusold + 3) || SStatusprint < (SStatusold - 3)) {
      if (advancedRDS) {
        tftReplace(1, String(SStatusold / 10) + "." + String(abs(SStatusold % 10)), String(SStatusprint / 10) + "." + String(abs(SStatusprint % 10)), 273, 51, PrimaryColor, PrimaryColorSmooth, BackgroundColor, 16);
      } else {
        if (SStatusold / 10 != SStatusprint / 10) tftReplace(1, String(SStatusold / 10), String(SStatusprint / 10), 288, 105, FreqColor, FreqColorSmooth, BackgroundColor, 48);
        tftReplace(1, "." + String(abs(SStatusold % 10)), "." + String(abs(SStatusprint % 10)), 310, 105, FreqColor, FreqColorSmooth, BackgroundColor, 28);

        if (band < BAND_GAP) segments = map(SStatus / 10, 0, 70, 0, 100); else segments = (SStatus + 200) / 10;
        tft.fillRect(16, 105, 2 * constrain(segments, 0, 54), 6, BarInsignificantColor);
        tft.fillRect(16 + 2 * 54, 105, 2 * (constrain(segments, 54, 94) - 54), 6, BarSignificantColor);
        tft.fillRect(16 + 2 * constrain(segments, 0, 94), 105, 2 * (94 - constrain(segments, 0, 94)), 6, GreyoutColor);
      }
      SStatusold = SStatusprint;
    }
  }
  if (wifi && millis() >= udptimer + 2000) {
    udptimer = millis();
    Udp.beginPacket(remoteip, 9030);
    Udp.print("from=TEF_tuner " + String(stationlistid, DEC) + ";RcvLevel=" + String(SStatus / 10));
    Udp.endPacket();
  }
}

void ShowRDSLogo(bool RDSstatus) {
  if (!screenmute) {
    if (RDSstatus != RDSstatusold) {
      if (RDSstatus) {
        tft.drawBitmap(122, 5, RDSLogo, 35, 22, RDSColor);
      } else {
        tft.drawBitmap(122, 5, RDSLogo, 35, 22, GreyoutColor);
      }
    }
    RDSstatusold = RDSstatus;
  }
}

void ShowStereoStatus() {
  if (StereoToggle) {
    if (band < BAND_GAP) Stereostatus = radio.getStereoStatus(); else Stereostatus = false;
    if (Stereostatus != Stereostatusold) {
      if (Stereostatus && !screenmute) {
        tft.drawSmoothCircle(66, 15, 10, StereoColor, StereoColorSmooth);
        tft.drawSmoothCircle(66, 15, 9, StereoColor, StereoColorSmooth);
        tft.drawSmoothCircle(76, 15, 10, StereoColor, StereoColorSmooth);
        tft.drawSmoothCircle(76, 15, 9, StereoColor, StereoColorSmooth);
      } else {
        if (!screenmute) {
          tft.drawSmoothCircle(66, 15, 10, GreyoutColor, BackgroundColor);
          tft.drawSmoothCircle(66, 15, 9, GreyoutColor, BackgroundColor);
          tft.drawSmoothCircle(76, 15, 10, GreyoutColor, BackgroundColor);
          tft.drawSmoothCircle(76, 15, 9, GreyoutColor, BackgroundColor);
        }
      }
      Stereostatusold = Stereostatus;
    }
  }
}

void ShowOffset() {
  if (OStatus != OStatusold) {
    if (millis() >= offsetupdatetimer + TIMER_OFFSET_TIMER) {
      offsetupdatetimer = millis();
    } else {
      return;
    }

    if (band < BAND_GAP) {
      if (OStatus < -500) {
        tft.fillTriangle(3, 8, 3, 22, 11, 14, GreyoutColor);
        tft.fillTriangle(13, 8, 13, 22, 21, 14, GreyoutColor);
        tft.fillCircle(26, 15, 3, GreyoutColor);
        tft.fillTriangle(32, 14, 40, 8, 40, 22, GreyoutColor);
        tft.fillTriangle(42, 14, 50, 8, 50, 22, SignificantColor);
        tuned = false;
      } else if (OStatus < -250 && OStatus > -500) {
        tft.fillTriangle(3, 8, 3, 22, 11, 14, GreyoutColor);
        tft.fillTriangle(13, 8, 13, 22, 21, 14, GreyoutColor);
        tft.fillCircle(26, 15, 3, GreyoutColor);
        tft.fillTriangle(32, 14, 40, 8, 40, 22, SignificantColor);
        tft.fillTriangle(42, 14, 50, 8, 50, 22, GreyoutColor);
        tuned = false;
      } else if (USN < 250 && WAM < 250 && OStatus > -250 && OStatus < 250 && !SQ) {
        tft.fillTriangle(3, 8, 3, 22, 11, 14, GreyoutColor);
        tft.fillTriangle(13, 8, 13, 22, 21, 14, GreyoutColor);
        tft.fillCircle(26, 15, 3, InsignificantColor);
        tft.fillTriangle(32, 14, 40, 8, 40, 22, GreyoutColor);
        tft.fillTriangle(42, 14, 50, 8, 50, 22, GreyoutColor);
        tuned = true;
      } else if (OStatus > 250 && OStatus < 500) {
        tft.fillTriangle(3, 8, 3, 22, 11, 14, GreyoutColor);
        tft.fillTriangle(13, 8, 13, 22, 21, 14, SignificantColor);
        tft.fillCircle(26, 15, 3, GreyoutColor);
        tft.fillTriangle(32, 14, 40, 8, 40, 22, GreyoutColor);
        tft.fillTriangle(42, 14, 50, 8, 50, 22, GreyoutColor);
        tuned = false;
      } else if (OStatus > 500) {
        tft.fillTriangle(3, 8, 3, 22, 11, 14, SignificantColor);
        tft.fillTriangle(13, 8, 13, 22, 21, 14, GreyoutColor);
        tft.fillCircle(26, 15, 3, GreyoutColor);
        tft.fillTriangle(32, 14, 40, 8, 40, 22, GreyoutColor);
        tft.fillTriangle(42, 14, 50, 8, 50, 22, GreyoutColor);
        tuned = false;
      } else {
        tft.fillTriangle(3, 8, 3, 22, 11, 14, GreyoutColor);
        tft.fillTriangle(13, 8, 13, 22, 21, 14, GreyoutColor);
        tft.fillCircle(26, 15, 3, GreyoutColor);
        tft.fillTriangle(32, 14, 40, 8, 40, 22, GreyoutColor);
        tft.fillTriangle(42, 14, 50, 8, 50, 22, GreyoutColor);
        tuned = false;
      }
    } else {
      if (OStatus <= -3) {
        tft.fillTriangle(3, 8, 3, 22, 11, 14, GreyoutColor);
        tft.fillTriangle(13, 8, 13, 22, 21, 14, GreyoutColor);
        tft.fillCircle(26, 15, 3, GreyoutColor);
        tft.fillTriangle(32, 14, 40, 8, 40, 22, GreyoutColor);
        tft.fillTriangle(42, 14, 50, 8, 50, 22, SignificantColor);
        tuned = false;
      } else if (OStatus < -2 && OStatus > -3) {
        tft.fillTriangle(3, 8, 3, 22, 11, 14, GreyoutColor);
        tft.fillTriangle(13, 8, 13, 22, 21, 14, GreyoutColor);
        tft.fillCircle(26, 15, 3, GreyoutColor);
        tft.fillTriangle(32, 14, 40, 8, 40, 22, SignificantColor);
        tft.fillTriangle(42, 14, 50, 8, 50, 22, GreyoutColor);
        tuned = false;
      } else if (OStatus > -2 && OStatus < 2 && !SQ) {
        tft.fillTriangle(3, 8, 3, 22, 11, 14, GreyoutColor);
        tft.fillTriangle(13, 8, 13, 22, 21, 14, GreyoutColor);
        tft.fillCircle(26, 15, 3, InsignificantColor);
        tft.fillTriangle(32, 14, 40, 8, 40, 22, GreyoutColor);
        tft.fillTriangle(42, 14, 50, 8, 50, 22, GreyoutColor);
        tuned = true;
      } else if (OStatus > 2 && OStatus < 3) {
        tft.fillTriangle(3, 8, 3, 22, 11, 14, GreyoutColor);
        tft.fillTriangle(13, 8, 13, 22, 21, 14, SignificantColor);
        tft.fillCircle(26, 15, 3, GreyoutColor);
        tft.fillTriangle(32, 14, 40, 8, 40, 22, GreyoutColor);
        tft.fillTriangle(42, 14, 50, 8, 50, 22, GreyoutColor);
        tuned = false;
      } else if (OStatus >= 3) {
        tft.fillTriangle(3, 8, 3, 22, 11, 14, SignificantColor);
        tft.fillTriangle(13, 8, 13, 22, 21, 14, GreyoutColor);
        tft.fillCircle(26, 15, 3, GreyoutColor);
        tft.fillTriangle(32, 14, 40, 8, 40, 22, GreyoutColor);
        tft.fillTriangle(42, 14, 50, 8, 50, 22, GreyoutColor);
        tuned = false;
      } else {
        tft.fillTriangle(3, 8, 3, 22, 11, 14, GreyoutColor);
        tft.fillTriangle(13, 8, 13, 22, 21, 14, GreyoutColor);
        tft.fillCircle(26, 15, 3, GreyoutColor);
        tft.fillTriangle(32, 14, 40, 8, 40, 22, GreyoutColor);
        tft.fillTriangle(42, 14, 50, 8, 50, 22, GreyoutColor);
        tuned = false;
      }
    }
    OStatusold = OStatus;
  }
}

void ShowBW() {
  if (!BWtune && millis() >= bwupdatetimer + TIMER_BW_TIMER) {
    bwupdatetimer = millis();
  } else {
    if (!BWtune) return;
  }

  if (BW != BWOld || BWreset) {
    if (BWset == 0) tftReplace(1, String (BWOld, DEC), String (BW, DEC), 201, 4, BWAutoColor, BWAutoColorSmooth, BackgroundColor, 28); else tftReplace(1, String (BWOld, DEC), String (BW, DEC), 201, 4, PrimaryColor, PrimaryColorSmooth, BackgroundColor, 28);
    BWOld = BW;
    BWreset = false;
    if (wifi) {
      Udp.beginPacket(remoteip, 9030);
      Udp.print("from=TEF_tuner " + String(stationlistid, DEC) + ";bandwidth=" + String(BW * 1000));
      Udp.endPacket();
    }
  }
}

void ShowModLevel() {
  if (showmodulation) {
    int segments;
    if (MStatus > 120) MStatus = 120;

    if (seek || SQ) {
      MStatus = 0;
      MStatusold = 1;
    }
    segments = map(MStatus, 0, 120, 0, 94);

    if (segments > peakholdold) {
      peakholdold = segments;
      peakholdmillis = millis();
    }

    tft.fillRect(16, 133, 2 * constrain(segments, 0, 54), 6, ModBarInsignificantColor);
    tft.fillRect(16 + 2 * 54, 133, 2 * (constrain(segments, 54, 94) - 54), 6, ModBarSignificantColor);
    tft.fillRect(16 + 2 * constrain(segments, 0, 94), 133, 2 * (94 - constrain(segments, 0, 94)), 6, GreyoutColor);

    int peakHoldPosition = 16 + 2 * constrain(peakholdold, 0, 94);
    tft.fillRect(peakHoldPosition, 133, 2, 6, (MStatus > 80) ? ModBarSignificantColor : PrimaryColor);

    if (millis() - peakholdmillis >= 1000) {
      tft.fillRect(peakHoldPosition, 133, 2, 6, GreyoutColor);
      peakholdold = segments;
      peakholdmillis = millis();
    }
  }
}

void showAutoSquelch(bool mode) {
  if (language == LANGUAGE_CHS) SquelchSprite.loadFont(FONT16_CHS); else SquelchSprite.loadFont(FONT16);
  if (mode) {
    SquelchSprite.setTextColor(PrimaryColor, PrimaryColorSmooth, false);
  } else {
    SquelchSprite.setTextColor(BackgroundColor, BackgroundColor, false);
  }
  SquelchSprite.fillSprite(BackgroundColor);
  SquelchSprite.drawString(String(myLanguage[language][86]), 0, 0);
  SquelchSprite.pushSprite(235, 145);
}

void doSquelch() {
  if (!XDRGTKUSB && !XDRGTKTCP && usesquelch && !autosquelch) Squelch = analogRead(PIN_POT) / 4 - 100;
  if (unit == 0) SquelchShow = Squelch / 10;
  if (unit == 1) SquelchShow = ((Squelch * 100) + 10875) / 1000;
  if (unit == 2) SquelchShow = round((float(Squelch) / 10.0 - 10.0 * log10(75) - 90.0) * 10.0) / 10;
  if (Squelch > 920) Squelch = 920;

  if (autosquelch) {
    if (band < BAND_GAP) {
      if ((USN < fmscansens * 30) && (WAM < 230) && (OStatus < 100 && OStatus > -100) && (!scandxmode || (scandxmode && !scanmute))) {
        if (SQ || BWreset) {
          if (!seek) radio.setUnMute();
          if (!screenmute && !seek) {
            tft.drawBitmap(92, 4, Speaker, 26, 22, GreyoutColor);
          }
          autosquelchtimer = millis();
          SQ = false;
        }
      } else {
        if ((!SQ || BWreset) && (millis() >= autosquelchtimer + 1000)) {
          radio.setMute();
          if (!screenmute && !seek) {
            tft.drawBitmap(92, 4, Speaker, 26, 22, PrimaryColor);
          }
          autosquelchtimer = millis();
          SQ = true;
        }
      }
    } else {
      if ((USN < amscansens * 30) && (OStatus < 2 && OStatus > -2) && (!scandxmode || (scandxmode && !scanmute))) {
        if (!seek) radio.setUnMute();
        if (!screenmute && !seek) {
          tft.drawBitmap(92, 4, Speaker, 26, 22, GreyoutColor);
        }
        SQ = false;
      } else {
        radio.setMute();
        if (!screenmute && !seek) {
          tft.drawBitmap(92, 4, Speaker, 26, 22, PrimaryColor);
        }
        SQ = true;
      }
    }
  } else {
    if (language == LANGUAGE_CHS) SquelchSprite.loadFont(FONT16_CHS); else SquelchSprite.loadFont(FONT16);

    if (!XDRGTKUSB && !XDRGTKTCP && usesquelch && (!scandxmode || (scandxmode && !scanmute))) {
      if (!screenmute && usesquelch && !advancedRDS && !afscreen) {
        if (!menu && (Squelch > Squelchold + 2 || Squelch < Squelchold - 2)) {
          SquelchSprite.setTextColor(PrimaryColor, PrimaryColorSmooth, false);
          SquelchSprite.fillSprite(BackgroundColor);
          if (Squelch == -100) {
            SquelchSprite.drawString(String(myLanguage[language][33]), 0, 0);
          } else if (Squelch == 920) {
            SquelchSprite.drawString("ST", 0, 0);
          } else {
            SquelchSprite.drawString(String(SquelchShow), 0, 0);
          }
          if (Squelch != Squelchold) {
            SquelchSprite.pushSprite(235, 145);
          }
        }
        Squelchold = Squelch;
      }
    }

    if ((XDRGTKUSB || XDRGTKTCP) && (!scandxmode || (scandxmode && !scanmute))) {
      if (!XDRMute) {
        if (Squelch != -1) {
          if (Squelch < SStatus || Squelch == -100 || Squelch == 0) {
            if (!seek) radio.setUnMute();
            if (!screenmute && !seek) {
              tft.drawBitmap(92, 4, Speaker, 26, 22, GreyoutColor);
            }
            SQ = false;
          } else {
            radio.setMute();
            if (!screenmute && !seek) {
              tft.drawBitmap(92, 4, Speaker, 26, 22, PrimaryColor);
            }
            SQ = true;
          }
        } else {
          if (Stereostatus) {
            radio.setUnMute();
            if (!screenmute && !seek) {
              tft.drawBitmap(92, 4, Speaker, 26, 22, GreyoutColor);
            }
            SQ = false;
          } else {
            radio.setMute();
            if (!screenmute && !seek) {
              tft.drawBitmap(92, 4, Speaker, 26, 22, PrimaryColor);
            }
            SQ = true;
          }
        }
        if (!screenmute && usesquelch && !advancedRDS && !afscreen) {
          if (Squelch != Squelchold) {
            SquelchSprite.setTextColor(PrimaryColor, PrimaryColorSmooth, false);
            SquelchSprite.fillSprite(BackgroundColor);

            if (Squelch == -1) {
              SquelchSprite.drawString("ST", 0, 0);
            } else if (Squelch == 0) {
              SquelchSprite.drawString(String(myLanguage[language][33]), 0, 0);
            } else {
              SquelchSprite.drawString(String(SquelchShow), 0, 0);
            }
            if (Squelch != Squelchold) {
              SquelchSprite.pushSprite(235, 145);
            }
            Squelchold = Squelch;
          }
        }
      }
    } else if (usesquelch && (!scandxmode || (scandxmode && !scanmute))) {
      if (Squelch != 920) {
        if (Squelch < SStatus || Squelch == -100 || Squelch == 0) {
          if (!seek) radio.setUnMute();
          if (!screenmute && !seek) {
            tft.drawBitmap(92, 4, Speaker, 26, 22, GreyoutColor);
          }
          SQ = false;
        } else {
          radio.setMute();
          if (!screenmute && !seek) {
            tft.drawBitmap(92, 4, Speaker, 26, 22, PrimaryColor);
          }
          SQ = true;
        }
      } else {
        if (Stereostatus) {
          if (!seek) radio.setUnMute();
          if (!screenmute && !seek) {
            tft.drawBitmap(92, 4, Speaker, 26, 22, GreyoutColor);
          }
          SQ = false;
        } else {
          radio.setMute();
          if (!screenmute && !seek) {
            tft.drawBitmap(92, 4, Speaker, 26, 22, PrimaryColor);
          }
          SQ = true;
        }
      }
    }
  }
  SquelchSprite.unloadFont();
}

void updateBW() {//todo air
  if (BWset == 0) {
    if (!screenmute && !advancedRDS && !afscreen) {
      tft.drawRoundRect(248, 35, 71, 20, 5, ActiveColor);
      tftPrint(0, "AUTO BW", 283, 38, ActiveColor, ActiveColorSmooth, 16);
    }
    radio.setFMABandw();
  } else {
    if (!screenmute && !advancedRDS && !afscreen) {
      tft.drawRoundRect(248, 35, 71, 20, 5, GreyoutColor);
      tftPrint(0, "AUTO BW", 283, 38, GreyoutColor, BackgroundColor, 16);
    }
  }
}

void updateiMS() {
  if (band < BAND_GAP) {
    if (iMSset == 0) {
      if (!screenmute && !advancedRDS && !afscreen) {
        tft.drawRoundRect(248, 56, 32, 20, 5, ActiveColor);
        tftPrint(0, "iMS", 265, 59, ActiveColor, ActiveColorSmooth, 16);
      }
      radio.setiMS(1);
    } else {
      if (!screenmute && !advancedRDS && !afscreen) {
        tft.drawRoundRect(248, 56, 32, 20, 5, GreyoutColor);
        tftPrint(0, "iMS", 265, 59, GreyoutColor, BackgroundColor, 16);
      }
      radio.setiMS(0);
    }
  }
}

void updateEQ() {
  if (band < BAND_GAP) {
    if (EQset == 0) {
      if (!screenmute && !advancedRDS && !afscreen) {
        tft.drawRoundRect(286, 56, 32, 20, 5, ActiveColor);
        tftPrint(0, "EQ", 303, 59, ActiveColor, ActiveColorSmooth, 16);
      }
      radio.setEQ(1);
    } else {
      if (!screenmute && !advancedRDS && !afscreen) {
        tft.drawRoundRect(286, 56, 32, 20, 5, GreyoutColor);
        tftPrint(0, "EQ", 303, 59, GreyoutColor, BackgroundColor, 16);
      }
      radio.setEQ(0);
    }
  }
}

void updateCodetect() {
  if (
    band > BAND_GAP && band != BAND_AIR) {
    if (WAM) {
      tftPrint(-1, "CO", 50, 61, PrimaryColor, PrimaryColorSmooth, 16);
    } else {
      tftPrint(-1, "CO", 50, 61, BackgroundColor, BackgroundColor, 16);
    }
  }
}

void updateSWMIBand() {
  switch (SWMIBandPos) {
    case SW_MI_BAND_11M:
    case SW_MI_BAND_13M:
    case SW_MI_BAND_15M:
    case SW_MI_BAND_16M:
    case SW_MI_BAND_19M:
    case SW_MI_BAND_22M:
    case SW_MI_BAND_25M:
    case SW_MI_BAND_31M:
    case SW_MI_BAND_41M:
    case SW_MI_BAND_49M:
    case SW_MI_BAND_60M:
    case SW_MI_BAND_75M:
    case SW_MI_BAND_90M:
    case SW_MI_BAND_120M:
    case SW_MI_BAND_160M:
      FrequencySprite.drawString(SWMIBandstring + " ", 0, 0);
      beepresetstart = true;
      if (edgebeep && beepresetstop) {
        EdgeBeeper();
        beepresetstop = false;
      }
      break;

    case SW_MI_BAND_GAP:
      beepresetstop = true;
      if (edgebeep && beepresetstart) {
        EdgeBeeper();
        beepresetstart = false;
      }
      break;
  }
}

void doBW() {
  if (band < BAND_GAP) {
    if (BWset > 16) BWset = 0;

    switch (BWset) {
      case 1: radio.setFMBandw(56); break;
      case 2: radio.setFMBandw(64); break;
      case 3: radio.setFMBandw(72); break;
      case 4: radio.setFMBandw(84); break;
      case 5: radio.setFMBandw(97); break;
      case 6: radio.setFMBandw(114); break;
      case 7: radio.setFMBandw(133); break;
      case 8: radio.setFMBandw(151); break;
      case 9: radio.setFMBandw(168); break;
      case 10: radio.setFMBandw(184); break;
      case 11: radio.setFMBandw(200); break;
      case 12: radio.setFMBandw(217); break;
      case 13: radio.setFMBandw(236); break;
      case 14: radio.setFMBandw(254); break;
      case 15: radio.setFMBandw(287); break;
      case 16: radio.setFMBandw(311); break;
    }
    BWsetFM = BWset;
    EEPROM.writeByte(EE_BYTE_BWSET_FM, BWsetFM);
  } else {
    if (BWset > 4) BWset = 1;

    switch (BWset) {
      case 1: radio.setAMBandw(3); break;
      case 2: radio.setAMBandw(4); break;
      case 3: radio.setAMBandw(6); break;
      case 4: radio.setAMBandw(8); break;
    }
    BWsetAM = BWset;
    EEPROM.writeByte(EE_BYTE_BWSET_AM, BWsetAM);
  }
  updateBW();
  BWreset = true;
  EEPROM.commit();
}

void doBWtuneDown() {
  rotary = 0;
  BWset--;
  if (band < BAND_GAP) {
    if (BWset > 16) BWset = 16;
  } else {
    if (BWset == 0) BWset = 4;
  }
  doBW();
  ShowBW();
}

void doBWtuneUp() {
  rotary = 0;
  BWset++;
  if (band < BAND_GAP) {
    if (BWset > 16) BWset = 0;
  } else {
    if (BWset > 4) BWset = 1;
  }
  doBW();
  ShowBW();
}

void doTuneMode() {
  switch (tunemode) {
    case TUNE_MAN:
      if (band == BAND_SW) {
        if (showSWMIBand && nowToggleSWMIBand) {
          tunemode = TUNE_MI_BAND;
        } else {
          tunemode = TUNE_AUTO;
        }
      } else {
        tunemode = TUNE_AUTO;
      }
      if (stepsize != 0) {
        stepsize = 0;
        RoundStep();
        ShowStepSize();
      }
      break;

    case TUNE_MI_BAND:
    case TUNE_AUTO:
      tunemode = TUNE_MEM;
      break;

    case TUNE_MEM:
      if (!bandforbidden) tunemode = TUNE_MAN;
      break;
  }
  ShowTuneMode();
  ShowMemoryPos();
  ShowFreq(0);
  EEPROM.writeByte(EE_BYTE_TUNEMODE, tunemode);
  EEPROM.commit();
}

void ShowTuneMode() {
  if (!screenmute) {
    switch (tunemode) {
      case TUNE_MAN:
        if (band == BAND_SW && nowToggleSWMIBand) {
          tftPrint(0, "AUTO", 22, 60, BackgroundColor, BackgroundColor, 16);
          tft.drawRoundRect(1, 57, 42, 20, 5, GreyoutColor);
          tftPrint(0, "BAND", 22, 60, GreyoutColor, BackgroundColor, 16);
        } else {
          tftPrint(0, "BAND", 22, 60, BackgroundColor, BackgroundColor, 16);
          tft.drawRoundRect(1, 57, 42, 20, 5, GreyoutColor);
          tftPrint(0, "AUTO", 22, 60, GreyoutColor, BackgroundColor, 16);
        }

        tft.drawRoundRect(1, 35, 42, 20, 5, ActiveColor);
        tftPrint(0, "MAN", 22, 38, ActiveColor, ActiveColorSmooth, 16);

        tft.drawRoundRect(1, 79, 42, 20, 5, GreyoutColor);
        tftPrint(0, "MEM", 22, 82, GreyoutColor, BackgroundColor, 16);
        break;

      case TUNE_AUTO:
        tft.drawRoundRect(1, 57, 42, 20, 5, ActiveColor);
        tftPrint(0, "AUTO", 22, 60, ActiveColor, ActiveColorSmooth, 16);

        tft.drawRoundRect(1, 35, 42, 20, 5, GreyoutColor);
        tftPrint(0, "MAN", 22, 38, GreyoutColor, BackgroundColor, 16);

        tft.drawRoundRect(1, 79, 42, 20, 5, GreyoutColor);
        tftPrint(0, "MEM", 22, 82, GreyoutColor, BackgroundColor, 16);
        break;

      case TUNE_MEM:
        if (band == BAND_SW && nowToggleSWMIBand) {
          tftPrint(0, "AUTO", 22, 60, BackgroundColor, BackgroundColor, 16);

          tft.drawRoundRect(1, 57, 42, 20, 5, GreyoutColor);
          tftPrint(0, "BAND", 22, 60, GreyoutColor, BackgroundColor, 16);
        } else {
          tftPrint(0, "BAND", 22, 60, BackgroundColor, BackgroundColor, 16);

          tft.drawRoundRect(1, 57, 42, 20, 5, GreyoutColor);
          tftPrint(0, "AUTO", 22, 60, GreyoutColor, BackgroundColor, 16);
        }

        tft.drawRoundRect(1, 35, 42, 20, 5, GreyoutColor);
        tftPrint(0, "MAN", 22, 39, GreyoutColor, BackgroundColor, 16);

        if (memorystore) {
          tft.drawRoundRect(1, 79, 42, 20, 5, SignificantColor);
          tftPrint(0, "MEM", 22, 82, SignificantColor, SignificantColorSmooth, 16);
        } else {
          tft.drawRoundRect(1, 79, 42, 20, 5, ActiveColor);
          tftPrint(0, "MEM", 22, 82, ActiveColor, ActiveColorSmooth, 16);
        }
        break;

      case TUNE_MI_BAND:
        tft.drawRoundRect(1, 57, 42, 20, 5, ActiveColor);
        tft.setTextColor(ActiveColor);
        tftPrint(0, "BAND", 22, 60, ActiveColor, ActiveColorSmooth, 16);

        tft.drawRoundRect(1, 35, 42, 20, 5, GreyoutColor);
        tftPrint(0, "MAN", 22, 38, GreyoutColor, BackgroundColor, 16);

        tft.drawRoundRect(1, 79, 42, 20, 5, GreyoutColor);
        tftPrint(0, "MEM", 22, 82, GreyoutColor, BackgroundColor, 16);
        break;
    }
  }
}

void ShowRSSI() {
  if (wifi) rssi = WiFi.RSSI(); else rssi = 0;
  if (rssiold != rssi) {
    rssiold = rssi;
    if (rssi == 0) {
      tft.drawBitmap(250, 4, WiFi4, 25, 25, GreyoutColor);
    } else if (rssi > -50 && rssi < 0) {
      tft.drawBitmap(250, 4, WiFi4, 25, 25, PrimaryColor);
    } else if (rssi > -60) {
      tft.drawBitmap(250, 4, WiFi4, 25, 25, GreyoutColor);
      tft.drawBitmap(250, 4, WiFi3, 25, 25, PrimaryColor);
    } else if (rssi > -70) {
      tft.drawBitmap(250, 4, WiFi4, 25, 25, GreyoutColor);
      tft.drawBitmap(250, 4, WiFi2, 25, 25, PrimaryColor);
    } else if (rssi < -70) {
      tft.drawBitmap(250, 4, WiFi4, 25, 25, GreyoutColor);
      tft.drawBitmap(250, 4, WiFi1, 25, 25, PrimaryColor);
    }
  }
}

void ShowBattery() {
  if (millis() >= batupdatetimer + TIMER_BAT_TIMER) {
    batupdatetimer = millis();
  } else {
    return;
  }

  uint16_t v = 0;
  if (!wifi) v = analogRead(BATTERY_PIN);
  battery = map(constrain(v, BAT_LEVEL_EMPTY, BAT_LEVEL_FULL), BAT_LEVEL_EMPTY, BAT_LEVEL_FULL, 0, BAT_LEVEL_STAGE);
  byte batteryprobe = map(constrain(v, BAT_LEVEL_EMPTY, BAT_LEVEL_FULL), BAT_LEVEL_EMPTY, BAT_LEVEL_FULL, 0, 20);

  if (batteryold != batteryprobe) {
    if (!wifi && batterydetect) {
      if (battery == 0) {
        tft.drawRoundRect(277, 6, 37, 20, 2, BarSignificantColor);
        tft.fillRoundRect(313, 13, 4, 6, 2, BarSignificantColor);
      } else {
        tft.drawRoundRect(277, 6, 37, 20, 2, ActiveColor);
        tft.fillRoundRect(313, 13, 4, 6, 2, ActiveColor);
      }
      if (batteryoptions != BATTERY_VALUE && batteryoptions != BATTERY_PERCENT && battery != 0) {
        tft.fillRoundRect(279, 8, (battery * 8) , 16, 2, BarInsignificantColor);
      } else {
        tft.fillRoundRect(279, 8, 33, 16, 2, BackgroundColor);
      }
    } else {
      tft.drawRoundRect(277, 6, 37, 20, 2, GreyoutColor);
      tft.fillRoundRect(313, 13, 4, 6, 2, GreyoutColor);
      tft.fillRoundRect(279, 8, 33, 16, 2, BackgroundColor);
    }
    batteryold = batteryprobe;
    batteryVold = 0;
    vPerold = 0;


    if (!wifi && batterydetect) {
      float batteryV = constrain((((float)v / 4095.0) * 3.3 * (1100 / 1000.0) * 2.0), 0.0, 5.0);
      float vPer = constrain((batteryV - BATTERY_LOW_VALUE) / (BATTERY_FULL_VALUE - BATTERY_LOW_VALUE), 0.0, 0.99) * 100;

      if (abs(batteryV - batteryVold) > 0.05 && batteryoptions == BATTERY_VALUE) {
        tftPrint(-1, String(batteryV, 2) + "V", 279, 9, BatteryValueColor, BatteryValueColorSmooth, 16);
        batteryVold = batteryV;
      } else if (int(vPer) != int(vPerold) && batteryoptions == BATTERY_PERCENT && abs(vPer - vPerold) > 0.5) {
        tftPrint(-1, String(vPer, 0) + "%", 279, 9, BatteryValueColor, BatteryValueColorSmooth, 16);
        vPerold = vPer;
      }
    }
  }
}

void DataPrint(String string) {
  if (XDRGTKUSB) Serial.print(string);
  if (XDRGTKTCP) RemoteClient.print(string);
}

void TuneUp() {
  aftest = true;
  aftimer = millis();
  unsigned int temp = 0;
  if (stepsize == 0) {
    if (band > BAND_GAP) {
      if (frequency_AM <= MWHighEdgeSet && frequency_AM >= MWLowEdgeSet) {
        if (!mwstepsize) {
          temp = FREQ_MW_STEP_9K;
          frequency_AM = (frequency_AM / FREQ_MW_STEP_9K) * FREQ_MW_STEP_9K;
        } else if (mwstepsize) {
          temp = FREQ_MW_STEP_10K;
          frequency_AM = (frequency_AM / FREQ_MW_STEP_10K) * FREQ_MW_STEP_10K;
        }
      } else if (frequency_AM < MWLowEdgeSet) {
        temp = FREQ_MW_STEP_9K;
        frequency_AM = (frequency_AM / FREQ_MW_STEP_9K) * FREQ_MW_STEP_9K;
      } else if (frequency_AM < SWHighEdgeSet && frequency_AM > SWLowEdgeSet) {
        temp = FREQ_SW_STEP_5K;
        frequency_AM = (frequency_AM / FREQ_SW_STEP_5K) * FREQ_SW_STEP_5K;
      }
#ifdef HAS_AIR_BAND
      else if (frequency_AM < AIRHighEdgeSet && frequency_AM > AIRLowEdgeSet) {

        if (airstepsize == 0) temp = FREQ_AIR_STEP_25K;
        else temp = FREQ_AIR_STEP_8K33;
      }
#endif
    } else {
      if (band == BAND_OIRT) {
        temp = FREQ_OIRT_STEP_30K;
      } else {
        switch (fmdefaultstepsize) {
          case 0: temp = FREQ_FM_STEP_50K; break;
          case 1: temp = FREQ_FM_STEP_100K; break;
          case 2: temp = FREQ_FM_STEP_200K; break;
        }
      }
    }
  }
  if (stepsize == 1) temp = 1;
  if (stepsize == 2) temp = 10;
  if (stepsize == 3) temp = 100;
  if (stepsize == 4) temp = 1000;

  if (band == BAND_FM) {
    frequency += temp;
    if (scandxmode) {
      while (IsFrequencyUsed(frequency) || presets[memorypos].band != BAND_FM) {
        frequency += temp;
      }
    }

    if (fmdefaultstepsize == 2 && stepsize == 0 && frequency == 8795) frequency = 8790;
    if (frequency >= (HighEdgeSet * 10) + 1) {
      frequency = LowEdgeSet * 10;
      if (fmdefaultstepsize == 2 && stepsize == 0 && frequency == 8750) frequency = 8775;
      if (edgebeep) EdgeBeeper();
    }
    radio.SetFreq(frequency);
  } else if (band == BAND_OIRT) {
    frequency_OIRT += temp;
    if (frequency_OIRT > HighEdgeOIRTSet) {
      frequency_OIRT = LowEdgeOIRTSet;
      if (edgebeep) EdgeBeeper();
    }
    radio.SetFreq(frequency_OIRT);
  } else if (band == BAND_LW) {
    frequency_AM += temp;
    if (frequency_AM > LWHighEdgeSet) {
      frequency_AM = LWLowEdgeSet;
      if (edgebeep) EdgeBeeper();
    }
    radio.SetFreqAM(frequency_AM);
    frequency_LW = frequency_AM;
  } else if (band == BAND_MW) {
    frequency_AM += temp;
    if (frequency_AM > MWHighEdgeSet) {
      frequency_AM = MWLowEdgeSet;
      if (edgebeep) EdgeBeeper();
    }
    radio.SetFreqAM(frequency_AM);
    frequency_MW = frequency_AM;
  } else if (band == BAND_SW) {
    frequency_AM += temp;
    if (frequency_AM > SWHighEdgeSet) {
      frequency_AM = SWLowEdgeSet;
      if (edgebeep) EdgeBeeper();
    }
    radio.SetFreqAM(frequency_AM);
    frequency_SW = frequency_AM;
  }
#ifdef HAS_AIR_BAND
  else if (band == BAND_AIR) {
    frequency_AM += temp;
    if (frequency_AIR > AIRHighEdgeSet) {
      frequency_AM = AIRLowEdgeSet;
      if (edgebeep) EdgeBeeper();
    }
    radio.SetFreqAM(frequency_AM);
    frequency_AIR = frequency_AM;
  }
#endif
  radio.clearRDS(fullsearchrds);
  if (RDSSPYUSB) Serial.print("G:\r\nRESET-------\r\n\r\n");
  if (RDSSPYTCP) RemoteClient.print("G:\r\nRESET-------\r\n\r\n");
}

void TuneDown() {
  aftest = true;
  aftimer = millis();
  unsigned int temp = 0;
  if (stepsize == 0) {
    if (band > BAND_GAP) {
      if (frequency_AM < MWHighEdgeSet && frequency_AM > MWLowEdgeSet) {
        if (!mwstepsize) {
          temp = FREQ_MW_STEP_9K;
          frequency_AM = (frequency_AM / FREQ_MW_STEP_9K) * FREQ_MW_STEP_9K;
        } else if (mwstepsize) {
          temp = FREQ_MW_STEP_10K;
          frequency_AM = (frequency_AM / FREQ_MW_STEP_10K) * FREQ_MW_STEP_10K;
        }
      } else if (frequency_AM < MWLowEdgeSet) {
        temp = FREQ_MW_STEP_9K;
        frequency_AM = (frequency_AM / FREQ_MW_STEP_9K) * FREQ_MW_STEP_9K;
      } else {
        temp = FREQ_SW_STEP_5K;
        frequency_AM = (frequency_AM / FREQ_SW_STEP_5K) * FREQ_SW_STEP_5K;
      }
    } else {
      if (band == BAND_OIRT) {
        temp = FREQ_OIRT_STEP_30K;
      } else {
        switch (fmdefaultstepsize) {
          case 0: temp = FREQ_FM_STEP_50K; break;
          case 1: temp = FREQ_FM_STEP_100K; break;
          case 2: temp = FREQ_FM_STEP_200K; break;
        }
      }
    }
  }
  if (stepsize == 1) temp = 1;
  if (stepsize == 2) temp = 10;
  if (stepsize == 3) temp = 100;
  if (stepsize == 4) temp = 1000;

  if (band == BAND_FM) {
    frequency -= temp;
    if (fmdefaultstepsize == 2 && stepsize == 0 && frequency == 8770) frequency = 8775;
    if (fmdefaultstepsize == 2 && stepsize == 0 && frequency == 8755) frequency = 10790;

    if (frequency < LowEdgeSet * 10) {
      frequency = HighEdgeSet * 10;
      if (fmdefaultstepsize == 2 && stepsize == 0 && frequency == 10800) frequency = 10790;
      if (edgebeep) EdgeBeeper();
    }
    radio.SetFreq(frequency);
  } else if (band == BAND_OIRT) {
    frequency_OIRT -= temp;
    if (frequency_OIRT < LowEdgeOIRTSet) {
      frequency_OIRT = HighEdgeOIRTSet;
      if (edgebeep) EdgeBeeper();
    }
    radio.SetFreq(frequency_OIRT);
  } else if (band == BAND_LW) {
    frequency_AM -= temp;
    if (frequency_AM < LWLowEdgeSet) {
      frequency_AM = LWHighEdgeSet;
      if (edgebeep) EdgeBeeper();
    }
    radio.SetFreqAM(frequency_AM);
    frequency_LW = frequency_AM;
  } else if (band == BAND_MW) {
    frequency_AM -= temp;
    if (frequency_AM < MWLowEdgeSet) {
      frequency_AM = MWHighEdgeSet;
      if (edgebeep) EdgeBeeper();
    }
    radio.SetFreqAM(frequency_AM);
    frequency_MW = frequency_AM;
  } else if (band == BAND_SW) {
    frequency_AM -= temp;
    if (frequency_AM < SWLowEdgeSet) {
      frequency_AM = SWHighEdgeSet;
      if (edgebeep) EdgeBeeper();
    }
    radio.SetFreqAM(frequency_AM);
    frequency_SW = frequency_AM;
  }
  radio.clearRDS(fullsearchrds);
  if (RDSSPYUSB) Serial.print("G:\r\nRESET-------\r\n\r\n");
  if (RDSSPYTCP) RemoteClient.print("G:\r\nRESET-------\r\n\r\n");
}

void EdgeBeeper() {
  radio.tone(50, -5, 2000);
  if (radio.mute) {
    radio.setMute();
    if (!screenmute) {
      tft.drawBitmap(92, 4, Speaker, 26, 22, PrimaryColor);
    }
  } else {
    radio.setUnMute();
    if (!screenmute) {
      tft.drawBitmap(92, 4, Speaker, 26, 22, GreyoutColor);
    }
  }
}

void Seek(bool mode) {
  radio.setMute();
  if (!screenmute) {
    tft.drawBitmap(92, 4, Speaker, 26, 22, PrimaryColor);
  }
  if (!mode) TuneDown(); else TuneUp();
  delay(50);
  ShowFreq(0);
  if (XDRGTKUSB || XDRGTKTCP) {
    if (band == BAND_FM) DataPrint("M0\nT" + String(frequency * 10) + "\n"); else if (band == BAND_OIRT) DataPrint("M0\nT" + String(frequency_OIRT * 10) + "\n"); else DataPrint("M1\nT" + String(frequency_AM) + "\n");
  }

  if (band < BAND_GAP) {
    radio.getStatus(SStatus, USN, WAM, OStatus, BW, MStatus, CN);
    if ((USN < fmscansens * 30) && (WAM < 230) && (OStatus < 80 && OStatus > -80) && (Squelch < SStatus || Squelch == 920)) {
      seek = false;
      radio.setUnMute();
      if (!screenmute) {
        tft.drawBitmap(92, 4, Speaker, 26, 22, GreyoutColor);
      }
      store = true;
    } else {
      seek = true;
      if (RDSSPYUSB) Serial.print("G:\r\nRESET-------\r\n\r\n");
      if (RDSSPYTCP) RemoteClient.print("G:\r\nRESET-------\r\n\r\n");
    }
  } else {
    radio.getStatusAM(SStatus, USN, WAM, OStatus, BW, MStatus, CN);
    if ((USN < amscansens * 30) && (OStatus < 2 && OStatus > -2) && (Squelch < SStatus || Squelch == 920)) {
      seek = false;
      radio.setUnMute();
      if (!screenmute) {
        tft.drawBitmap(92, 4, Speaker, 26, 22, GreyoutColor);
      }
      store = true;
    } else {
      seek = true;
    }
  }
}

void SetTunerPatch() {
  if (TEF != 102 && TEF != 205) {
    radio.init(102);
    uint16_t device;
    uint16_t hw;
    uint16_t sw;
    radio.getIdentification(device, hw, sw);
    TEF = highByte(hw) * 100 + highByte(sw);
    tft.fillScreen(BackgroundColor);
    analogWrite(CONTRASTPIN, ContrastSet * 2 + 27);

    if (TEF != 102 && TEF != 205) {
      tftPrint(0, myLanguage[language][35], 150, 78, ActiveColor, ActiveColorSmooth, 28);
      for (;;);
    }
    EEPROM.writeByte(EE_BYTE_TEF, TEF);
    EEPROM.commit();
    Tuner_Reset();
    ESP.restart();
  }
}

void read_encoder() {
  static uint8_t old_AB = 3;
  static int8_t encval = 0;
  static const int8_t enc_states[]  = {0, -1, 1, 0, 1, 0, 0, -1, -1, 0, 0, 1, 0, 1, -1, 0};

  old_AB <<= 2;

  if (digitalRead(ROTARY_PIN_A)) old_AB |= 0x02;
  if (digitalRead(ROTARY_PIN_B)) old_AB |= 0x01;
  encval += enc_states[( old_AB & 0x0f )];

  if (optenc) {
    if (encval > 3) {
      if (rotarymode) rotary = -1; else rotary = 1;
      encval = 0;
    } else if (encval < -3) {
      if (rotarymode) rotary = 1; else rotary = -1;
      encval = 0;
    }
  } else {
    if (encval > 3) {
      if (rotarymode) rotary = -1; else rotary = 1;
      encval = 0;
    } else if (encval < -3) {
      if (rotarymode) rotary = 1; else rotary = -1;
      encval = 0;
    }
  }
}

void MuteScreen(bool setting) {
  if (!setting && screenmute) {
    screenmute = false;
    setupmode = true;
    tft.writecommand(0x11);
    analogWrite(CONTRASTPIN, ContrastSet * 2 + 27);
    if (band < BAND_GAP) {
      if (afscreen) BuildAFScreen();
      else if (advancedRDS) BuildAdvancedRDS();
      else BuildDisplay();
    } else {
      BuildDisplay();
    }
    setupmode = false;
  } else if (setting && !screenmute) {
    screenmute = true;
    analogWrite(CONTRASTPIN, 0);
    tft.writecommand(0x10);
  }
}

void DefaultSettings(byte userhardwaremodel) {
  EEPROM.writeByte(EE_BYTE_CHECKBYTE, EE_CHECKBYTE_VALUE);
  if (userhardwaremodel == BASE_ILI9341) EEPROM.writeUInt(EE_UINT16_FREQUENCY_FM, 10000); else EEPROM.writeUInt(EE_UINT16_FREQUENCY_FM, 8900);
  EEPROM.writeUInt(EE_UINT16_FREQUENCY_OIRT, FREQ_FM_OIRT_START);
  EEPROM.writeByte(EE_BYTE_VOLSET, 0);
  EEPROM.writeUInt(EE_UINT16_CONVERTERSET, 0);
  EEPROM.writeUInt(EE_UINT16_FMLOWEDGESET, 875);
  EEPROM.writeUInt(EE_UINT16_FMHIGHEDGESET, 1080);
  EEPROM.writeByte(EE_BYTE_CONTRASTSET, 50);
  EEPROM.writeByte(EE_BYTE_STEREOLEVEL, 0);
  if (userhardwaremodel == BASE_ILI9341) EEPROM.writeByte(EE_BYTE_BANDFM, FM_BAND_ALL); else EEPROM.writeByte(EE_BYTE_BANDFM, FM_BAND_FM);
  EEPROM.writeByte(EE_BYTE_BANDAM, AM_BAND_ALL);
  EEPROM.writeByte(EE_BYTE_HIGHCUTLEVEL, 70);
  EEPROM.writeByte(EE_BYTE_HIGHCUTOFFSET, 0);
  EEPROM.writeByte(EE_BYTE_LEVELOFFSET, 0);
  EEPROM.writeByte(EE_BYTE_RTBUFFER, 1);
  EEPROM.writeByte(EE_BYTE_EDGEBEEP, 0);
  EEPROM.writeByte(EE_BYTE_SOFTMUTEAM, 0);
  EEPROM.writeByte(EE_BYTE_SOFTMUTEFM, 0);
  EEPROM.writeUInt(EE_UINT16_FREQUENCY_AM, 828);
  EEPROM.writeByte(EE_BYTE_LANGUAGE, 0);
  EEPROM.writeByte(EE_BYTE_SHOWRDSERRORS, 1);
  EEPROM.writeByte(EE_BYTE_TEF, 0);
  if (userhardwaremodel == BASE_ILI9341) EEPROM.writeByte(EE_BYTE_DISPLAYFLIP, 0); else EEPROM.writeByte(EE_BYTE_DISPLAYFLIP, 1);
  EEPROM.writeByte(EE_BYTE_ROTARYMODE, 0);
  EEPROM.writeByte(EE_BYTE_STEPSIZE, 0);
  EEPROM.writeByte(EE_BYTE_TUNEMODE, 0);
  EEPROM.writeByte(EE_BYTE_OPTENC, 0);
  EEPROM.writeByte(EE_BYTE_IMSSET, 1);
  EEPROM.writeByte(EE_BYTE_EQSET, 1);
  EEPROM.writeByte(EE_BYTE_BAND, BAND_FM);
  EEPROM.writeByte(EE_BYTE_LOWLEVELSET, -15);
  EEPROM.writeByte(EE_BYTE_MEMORYPOS, 0);
  EEPROM.writeByte(EE_BYTE_REGION, 0);
  EEPROM.writeByte(EE_BYTE_RDS_UNDERSCORE, 0);
  EEPROM.writeByte(EE_BYTE_USBMODE, 0);
  EEPROM.writeByte(EE_BYTE_WIFI, 0);
  EEPROM.writeByte(EE_BYTE_SUBNETCLIENT, 1);
  EEPROM.writeByte(EE_BYTE_SHOWSWMIBAND, 1);
  EEPROM.writeByte(EE_BYTE_RDS_FILTER, 0);
  EEPROM.writeByte(EE_BYTE_RDS_PIERRORS, 0);
  if (userhardwaremodel == BASE_ILI9341) EEPROM.writeUInt(EE_UINT16_FREQUENCY_LW, 180); else EEPROM.writeUInt(EE_UINT16_FREQUENCY_LW, 164);
  if (userhardwaremodel == BASE_ILI9341) EEPROM.writeUInt(EE_UINT16_FREQUENCY_MW, 540); else EEPROM.writeUInt(EE_UINT16_FREQUENCY_MW, 639);
  if (userhardwaremodel == BASE_ILI9341) EEPROM.writeUInt(EE_UINT16_FREQUENCY_SW, 1800); else EEPROM.writeUInt(EE_UINT16_FREQUENCY_SW, 5000);
#ifdef HAS_AIR_BAND
  EEPROM.writeUInt(EE_UINT16_FREQUENCY_AIR, 135350);
#endif
  EEPROM.writeString(EE_STRING_XDRGTK_KEY, "password");
  if (userhardwaremodel == BASE_ILI9341) EEPROM.writeByte(EE_BYTE_USESQUELCH, 1); else EEPROM.writeByte(EE_BYTE_USESQUELCH, 0);
  EEPROM.writeByte(EE_BYTE_SHOWMODULATION, 1);
  EEPROM.writeByte(EE_BYTE_AM_NB, 0);
  EEPROM.writeByte(EE_BYTE_FM_NB, 0);
  EEPROM.writeByte(EE_BYTE_AUDIOMODE, 0);
  if (userhardwaremodel == BASE_ILI9341) EEPROM.writeByte(EE_BYTE_TOUCH_ROTATING, 0); else EEPROM.writeByte(EE_BYTE_TOUCH_ROTATING, 1);
  EEPROM.writeUInt(EE_UINT16_LOWEDGEOIRTSET, 0);
  EEPROM.writeUInt(EE_UINT16_HIGHEDGEOIRTSET, 0);
  EEPROM.writeByte(EE_BYTE_HARDWARE_MODEL, userhardwaremodel);
  EEPROM.writeByte(EE_BYTE_POWEROPTIONS, 1);
  EEPROM.writeByte(EE_BYTE_CURRENTTHEME, 0);
  EEPROM.writeByte(EE_BYTE_FMDEFAULTSTEPSIZE, 1);
  EEPROM.writeByte(EE_BYTE_SCREENSAVERSET, 0);
  EEPROM.writeInt(EE_INT16_AMLEVELOFFSET, 0);
  EEPROM.writeByte(EE_BYTE_UNIT, 0);
  EEPROM.writeByte(EE_BYTE_AF, 0);
  EEPROM.writeByte(EE_BYTE_STEREO, 1);
  EEPROM.writeByte(EE_BYTE_BATTERY_OPTIONS, BATTERY_VALUE);
  EEPROM.writeByte(EE_BYTE_AM_CO_DECT, 100);
  EEPROM.writeByte(EE_BYTE_AM_CO_DECT_COUNT, 3);
  EEPROM.writeByte(EE_BYTE_AM_RF_GAIN, 0);
  EEPROM.writeByte(EE_BYTE_SORTAF, 1);
  EEPROM.writeByte(EE_BYTE_STATIONLISTID, 1);
  EEPROM.writeByte(EE_BYTE_FM_DEEMPHASIS, DEEMPHASIS_50);
  EEPROM.writeByte(EE_BYTE_BWSET_FM, 0);
  EEPROM.writeByte(EE_BYTE_BWSET_AM, 2);
  EEPROM.writeByte(EE_BYTE_BANDAUTOSW, 0);
  EEPROM.writeByte(EE_BYTE_FASTPS, 1);
  EEPROM.writeByte(EE_BYTE_TOT, 0);
  EEPROM.writeByte(EE_BYTE_MWREGION, 0);
#ifdef HAS_AIR_BAND
  EEPROM.writeByte(EE_BYTE_AIRSTEPSIZE, 0);
#endif
  EEPROM.writeByte(EE_BYTE_SPISPEED, 0);
  EEPROM.writeByte(EE_BYTE_AMSCANSENS, 4);
  EEPROM.writeByte(EE_BYTE_FMSCANSENS, 4);
  EEPROM.writeByte(EE_BYTE_FREQFONT, 3);
  EEPROM.writeByte(EE_BYTE_SKIN, 0);
  EEPROM.writeByte(EE_BYTE_XDRGTKMUTE, 0);
  EEPROM.writeByte(EE_BYTE_FMAGC, 92);
  EEPROM.writeByte(EE_BYTE_AMAGC, 100);
  EEPROM.writeByte(EE_BYTE_FMSI, 1);
  EEPROM.writeByte(EE_BYTE_SCANSTART, 0);
  EEPROM.writeByte(EE_BYTE_SCANSTOP, 9);
  EEPROM.writeByte(EE_BYTE_SCANHOLD, 5);
  EEPROM.writeByte(EE_BYTE_SCANMEM, 1);
  EEPROM.writeByte(EE_BYTE_SCANCANCEL, 0);
  EEPROM.writeByte(EE_BYTE_SCANMUTE, 0);
  EEPROM.writeByte(EE_BYTE_AUTOSQUELCH, 0);
  EEPROM.writeByte(EE_BYTE_LONGBANDPRESS, 0);

  for (int i = 0; i < EE_PRESETS_CNT; i++) {
    EEPROM.writeByte(i + EE_PRESETS_BAND_START, BAND_FM);
    EEPROM.writeUInt((i * 4) + EE_PRESETS_FREQUENCY_START, EE_PRESETS_FREQUENCY);
    EEPROM.writeByte(i + EE_PRESET_BW_START, 0);
    EEPROM.writeByte(i + EE_PRESET_MS_START, 1);

    for (int y = 0; y < 9; y++) {
      EEPROM.writeByte((i * 9) + y + EE_PRESETS_RDSPS_START, '\0');
    }

    for (int y = 0; y < 5; y++) {
      EEPROM.writeByte((i * 5) + y + EE_PRESETS_RDSPI_START, '\0');
    }
  }

  EEPROM.commit();
}

void tftReplace(int8_t offset, const String & textold, const String & text, int16_t x, int16_t y, int color, int smoothcolor, int background, uint8_t fontsize) {
  const uint8_t *selectedFont = nullptr;
  if (language == LANGUAGE_CHS) {
    if (fontsize == 16) selectedFont = FONT16_CHS;
    if (fontsize == 28) selectedFont = FONT28_CHS;
  } else {
    if (fontsize == 16) selectedFont = FONT16;
    if (fontsize == 28) selectedFont = FONT28;
  }
  if (fontsize == 48) selectedFont = FONT48;

  tft.loadFont(selectedFont);
  tft.setTextColor(background, background, false);

  switch (offset) {
    case -1: tft.setTextDatum(TL_DATUM); break;
    case 0: tft.setTextDatum(TC_DATUM); break;
    case 1: tft.setTextDatum(TR_DATUM); break;
  }

  tft.drawString(textold, x, y);
  tft.setTextColor(color, smoothcolor, false);

  switch (offset) {
    case -1: tft.setTextDatum(TL_DATUM); break;
    case 0: tft.setTextDatum(TC_DATUM); break;
    case 1: tft.setTextDatum(TR_DATUM); break;
  }

  String modifiedText = text;
  modifiedText.replace("\n", " ");

  tft.drawString(modifiedText, x, y);
  tft.unloadFont();
}

void tftPrint(int8_t offset, const String & text, int16_t x, int16_t y, int color, int smoothcolor, uint8_t fontsize) {
  const uint8_t *selectedFont = nullptr;
  if (language == LANGUAGE_CHS) {
    if (fontsize == 16) selectedFont = FONT16_CHS;
    if (fontsize == 28) selectedFont = FONT28_CHS;
  } else {
    if (fontsize == 16) selectedFont = FONT16;
    if (fontsize == 28) selectedFont = FONT28;
  }

  if (fontsize == 48) selectedFont = FONT48;

  tft.loadFont(selectedFont);

  tft.setTextColor(color, smoothcolor, (fontsize == 52 ? true : false));

  switch (offset) {
    case -1: tft.setTextDatum(TL_DATUM); break;
    case 0: tft.setTextDatum(TC_DATUM); break;
    case 1: tft.setTextDatum(TR_DATUM); break;
  }

  String modifiedText = text;
  modifiedText.replace("\n", " ");

  tft.drawString(modifiedText, x, y, 1);
  tft.unloadFont();
}

void deepSleep() {
  analogWrite(SMETERPIN, 0);
  pinMode (STANDBYLED, OUTPUT);
  digitalWrite(STANDBYLED, LOW);
  MuteScreen(1);
  StoreFrequency();
  radio.power(1);
  esp_sleep_enable_ext0_wakeup(GPIO_NUM_34, LOW);
  esp_deep_sleep_start();
}

void UpdateFonts(bool mode) {
  switch (mode) {
    case 0:                                 // Use in radio mode
      RadiotextSprite.unloadFont();
      RDSSprite.unloadFont();

      if (language == LANGUAGE_CHS) {
        RadiotextSprite.loadFont(FONT16_CHS);
        RDSSprite.loadFont(FONT16_CHS);
      } else {
        RadiotextSprite.loadFont(FONT16);
        RDSSprite.loadFont(FONT16);
      }
      break;

    case 1:                                 // Use in menu mode
      FullLineSprite.unloadFont();
      OneBigLineSprite.unloadFont();
      if (language == LANGUAGE_CHS) {
        FullLineSprite.loadFont(FONT16_CHS);
        OneBigLineSprite.loadFont(FONT28_CHS);
      } else {
        FullLineSprite.loadFont(FONT16);
        OneBigLineSprite.loadFont(FONT28);
      }
      break;

    case 2:                                 // Unload all
      FullLineSprite.unloadFont();
      OneBigLineSprite.unloadFont();
      RadiotextSprite.unloadFont();
      RDSSprite.unloadFont();
      break;
  }
}

void cancelDXScan() {
  tunemode = scanmodeold;
  scandxmode = false;
  if (scanmute) {
    radio.setUnMute();
    tft.drawBitmap(92, 4, Speaker, 26, 22, GreyoutColor);

    if (!flashing) {
      tft.drawRoundRect(1, 79, 42, 20, 5, ActiveColor);
      tftPrint(0, "MEM", 22, 82, ActiveColor, ActiveColorSmooth, 16);
    }

    SQ = false;
    Squelchold = -2;
  }

  ShowTuneMode();
  ShowMemoryPos();
}

void endMenu() {
  radio.clearRDS(fullsearchrds);
  menu = false;
  menuopen = false;
  LowLevelInit = true;
  submenu = false;
  menuoption = ITEM1;
  menupage = INDEX;
  menuitem = 0;
  EEPROM.writeByte(EE_BYTE_VOLSET, VolSet);
  EEPROM.writeUInt(EE_UINT16_CONVERTERSET, ConverterSet);
  EEPROM.writeUInt(EE_UINT16_FMLOWEDGESET, LowEdgeSet);
  EEPROM.writeUInt(EE_UINT16_FMHIGHEDGESET, HighEdgeSet);
  EEPROM.writeByte(EE_BYTE_CONTRASTSET, ContrastSet);
  EEPROM.writeByte(EE_BYTE_STEREOLEVEL, StereoLevel);
  EEPROM.writeByte(EE_BYTE_BANDFM, bandFM);
  EEPROM.writeByte(EE_BYTE_BANDAM, bandAM);
  EEPROM.writeByte(EE_BYTE_HIGHCUTLEVEL, HighCutLevel);
  EEPROM.writeByte(EE_BYTE_HIGHCUTOFFSET, HighCutOffset);
  EEPROM.writeByte(EE_BYTE_LEVELOFFSET, LevelOffset);
  EEPROM.writeByte(EE_BYTE_RTBUFFER, radio.rds.rtbuffer);
  EEPROM.writeByte(EE_BYTE_EDGEBEEP, edgebeep);
  EEPROM.writeByte(EE_BYTE_SOFTMUTEAM, softmuteam);
  EEPROM.writeByte(EE_BYTE_SOFTMUTEFM, softmutefm);
  EEPROM.writeByte(EE_BYTE_LANGUAGE, language);
  EEPROM.writeByte(EE_BYTE_SHOWRDSERRORS, showrdserrors);
  EEPROM.writeByte(EE_BYTE_LOWLEVELSET, LowLevelSet);
  EEPROM.writeByte(EE_BYTE_REGION, region);
  EEPROM.writeByte(EE_BYTE_RDS_UNDERSCORE, radio.underscore);
  EEPROM.writeByte(EE_BYTE_USBMODE, USBmode);
  EEPROM.writeByte(EE_BYTE_WIFI, wifi);
  EEPROM.writeByte(EE_BYTE_SUBNETCLIENT, subnetclient);
  EEPROM.writeByte(EE_BYTE_SHOWSWMIBAND, showSWMIBand);
  EEPROM.writeByte(EE_BYTE_RDS_FILTER, radio.rds.filter);
  EEPROM.writeByte(EE_BYTE_RDS_PIERRORS, radio.rds.pierrors);
  EEPROM.writeByte(EE_BYTE_USESQUELCH, usesquelch);
  EEPROM.writeByte(EE_BYTE_SHOWMODULATION, showmodulation);
  EEPROM.writeByte(EE_BYTE_AM_NB, amnb);
  EEPROM.writeByte(EE_BYTE_FM_NB, fmnb);
  EEPROM.writeByte(EE_BYTE_AUDIOMODE, audiomode);
  EEPROM.writeByte(EE_BYTE_TOUCH_ROTATING, touchrotating);
  EEPROM.writeUInt(EE_UINT16_LOWEDGEOIRTSET, LowEdgeOIRTSet);
  EEPROM.writeUInt(EE_UINT16_HIGHEDGEOIRTSET, HighEdgeOIRTSet);
  EEPROM.writeByte(EE_BYTE_HARDWARE_MODEL, hardwaremodel);
  EEPROM.writeByte(EE_BYTE_POWEROPTIONS, poweroptions);
  EEPROM.writeByte(EE_BYTE_CURRENTTHEME, CurrentTheme);
  EEPROM.writeByte(EE_BYTE_FMDEFAULTSTEPSIZE, fmdefaultstepsize);
  EEPROM.writeByte(EE_BYTE_SCREENSAVERSET, screensaverset);
  EEPROM.writeInt(EE_INT16_AMLEVELOFFSET, AMLevelOffset);
  EEPROM.writeByte(EE_BYTE_UNIT, unit);
  EEPROM.writeByte(EE_BYTE_AF, af);
  EEPROM.writeByte(EE_BYTE_STEREO, StereoToggle);
  EEPROM.writeByte(EE_BYTE_BATTERY_OPTIONS, batteryoptions);
  EEPROM.writeByte(EE_BYTE_AM_CO_DECT, amcodect);
  EEPROM.writeByte(EE_BYTE_AM_CO_DECT_COUNT, amcodectcount);
  EEPROM.writeByte(EE_BYTE_AM_RF_GAIN, amgain);
  EEPROM.writeByte(EE_BYTE_SORTAF, radio.rds.sortaf);
  EEPROM.writeByte(EE_BYTE_STATIONLISTID, stationlistid);
  EEPROM.writeByte(EE_BYTE_FM_DEEMPHASIS, fmdeemphasis);
  EEPROM.writeByte(EE_BYTE_FASTPS, radio.rds.fastps);
  EEPROM.writeByte(EE_BYTE_TOT, tot);
  EEPROM.writeByte(EE_BYTE_MWREGION, mwstepsize);
#ifdef HAS_AIR_BAND
  EEPROM.writeByte(EE_BYTE_AIRSTEPSIZE, airstepsize);
#endif
  EEPROM.writeByte(EE_BYTE_SPISPEED, spispeed);
  EEPROM.writeByte(EE_BYTE_AMSCANSENS, amscansens);
  EEPROM.writeByte(EE_BYTE_FMSCANSENS, fmscansens);
  EEPROM.writeByte(EE_BYTE_FREQFONT, freqfont);
  EEPROM.writeByte(EE_BYTE_SKIN, CurrentSkin);
  EEPROM.writeByte(EE_BYTE_XDRGTKMUTE, XDRGTKMuteScreen);
  EEPROM.writeByte(EE_BYTE_FMAGC, fmagc);
  EEPROM.writeByte(EE_BYTE_AMAGC, amagc);
  EEPROM.writeByte(EE_BYTE_FMSI, fmsi);
  EEPROM.writeByte(EE_BYTE_SCANSTART, scanstart);
  EEPROM.writeByte(EE_BYTE_SCANSTOP, scanstop);
  EEPROM.writeByte(EE_BYTE_SCANHOLD, scanhold);
  EEPROM.writeByte(EE_BYTE_SCANMEM, scanmem);
  EEPROM.writeByte(EE_BYTE_SCANCANCEL, scancancel);
  EEPROM.writeByte(EE_BYTE_SCANMUTE, scanmute);
  EEPROM.writeByte(EE_BYTE_AUTOSQUELCH, autosquelch);
  EEPROM.writeByte(EE_BYTE_LONGBANDPRESS, longbandpress);
  EEPROM.commit();
  if (af == 2) radio.rds.afreg = true; else radio.rds.afreg = false;
  Serial.end();
  if (wifi) remoteip = IPAddress (WiFi.localIP()[0], WiFi.localIP()[1], WiFi.localIP()[2], subnetclient);
  if (USBmode) Serial.begin(19200); else Serial.begin(115200);

  UpdateFonts(0);
  FullLineSprite.unloadFont();
  OneBigLineSprite.unloadFont();
  BuildDisplay();
}

void startFMDXScan() {
  memorypos = scanstart;
  scanmodeold = tunemode;
  if (scanmem) {
    tunemode = TUNE_MEM;
    if (band != BAND_FM) {
      band = BAND_FM;
      SelectBand();
    }
    if (menu) endMenu();
    DoMemoryPosTune();
  } else {
    tunemode = TUNE_MAN;
    if (band != BAND_FM) {
      band = BAND_FM;
      SelectBand();
      endMenu();
    }
    if (menu) endMenu();
    TuneUp();
    ShowFreq(0);
  }
  if (scanmute) {
    radio.setMute();
    tft.drawBitmap(92, 4, Speaker, 26, 22, PrimaryColor);
    SQ = true;
    Squelchold = -2;
  }
  scantimer = millis();
  scandxmode = true;
}

void setAutoSpeedSPI() {
  switch (frequency / 10) {
    case 875 ... 877: tft.setSPISpeed(28); break;
    case 878 ... 881: tft.setSPISpeed(24); break;
    case 882 ... 892: tft.setSPISpeed(42); break;
    case 893 ... 899: tft.setSPISpeed(31); break;
    case 900 ... 904: tft.setSPISpeed(12); break;
    case 905 ... 906: tft.setSPISpeed(16); break;
    case 907 ... 910: tft.setSPISpeed(11); break;
    case 911 ... 916: tft.setSPISpeed(15); break;
    case 917 ... 921: tft.setSPISpeed(24); break;
    case 922 ... 928: tft.setSPISpeed(13); break;
    case 929: tft.setSPISpeed(11); break;
    case 930 ... 932: tft.setSPISpeed(13); break;
    case 933 ... 939: tft.setSPISpeed(18); break;
    case 940 ... 941: tft.setSPISpeed(12); break;
    case 942: tft.setSPISpeed(17); break;
    case 943 ... 949: tft.setSPISpeed(15); break;
    case 950: tft.setSPISpeed(19); break;
    case 951: tft.setSPISpeed(15); break;
    case 952 ... 960: tft.setSPISpeed(22); break;
    case 961 ... 965: tft.setSPISpeed(15); break;
    case 966 ... 973: tft.setSPISpeed(22); break;
    case 974 ... 979: tft.setSPISpeed(17); break;
    case 980 ... 982: tft.setSPISpeed(20); break;
    case 983 ... 987: tft.setSPISpeed(18); break;
    case 988 ... 993: tft.setSPISpeed(11); break;
    case 994 ... 996: tft.setSPISpeed(18); break;
    case 997 ... 1005: tft.setSPISpeed(11); break;
    case 1006: tft.setSPISpeed(13); break;
    case 1007 ... 1011: tft.setSPISpeed(11); break;
    case 1012 ... 1016: tft.setSPISpeed(18); break;
    case 1017 ... 1026: tft.setSPISpeed(13); break;
    case 1027 ... 1035: tft.setSPISpeed(23); break;
    case 1036 ... 1038: tft.setSPISpeed(15); break;
    case 1039 ... 1042: tft.setSPISpeed(12); break;
    case 1043 ... 1047: tft.setSPISpeed(23); break;
    case 1048 ... 1050: tft.setSPISpeed(28); break;
    case 1051 ... 1062: tft.setSPISpeed(15); break;
    case 1063 ... 1068: tft.setSPISpeed(18); break;
    case 1069 ... 1074: tft.setSPISpeed(14); break;
    case 1075: tft.setSPISpeed(17); break;
    case 1076 ... 1080: tft.setSPISpeed(15); break;
    default: tft.setSPISpeed(30); break;
  }
}
