 #include <Arduino.h>
 #include <NTPClient.h>
// change next line to use with another board/shield
#include <WiFi.h>
//#include <WiFi.h> // for WiFi shield
//#include <WiFi101.h> // for WiFi 101 shield or MKR1000
#include <WiFiUdp.h>
  const String FirmwareVersion="010310";
//Format                _X.XX__    
//NIXIE CLOCK MCU107 by GRA & AFCH (fominalec@gmail.com)
//1.0.31 27.04.2017
//Added Antipoisoning effect - slot machine
//1.0.3 17.02.2017
// Added: time synchronizing each 10 seconds
//1.02 17.10.2016
//Fixed: RGB color controls
//Update to Arduino IDE 1.6.12 (Time.h replaced to TimeLib.h)
//1.01
//Added RGB LEDs lock(by UP and Down Buttons)
//Added Down and Up buttons pause and resume self testing
//25.09.2016 update to HW ver 1.1
//25.05.2016

 
#include <SPI.h>
#include <Wire.h>
//#include <ClickButton.h>
//#include <TimeLib.h>
//#include <Tone.h>
// #include <EEPROM.h>
#include <ESP32Time.h>
#include <RTClib.h>

#define Anode0Pin 10
#define Anode1Pin 3
#define Anode2Pin 8

#define Anode0ON digitalWrite(Anode0Pin,HIGH)
#define Anode0OFF digitalWrite(Anode0Pin,LOW)

#define Anode1ON digitalWrite(Anode1Pin,HIGH)
#define Anode1OFF digitalWrite(Anode1Pin,LOW)

#define Anode2ON digitalWrite(Anode2Pin,HIGH)
#define Anode2OFF digitalWrite(Anode2Pin,LOW)

String updateDateString();
String updateDisplayString();
void doDotBlink();
void checkAlarmTime();
String PreZero(int digit);
word doEditBlink(int pos);
byte decToBcd(byte val);
String antiPoisoning2(String fromStr, String toStr);
String getTimeNow();
String antiPoisoning2(String fromStr, String toStr);

//char* parseSong(char *p);

const byte LEpin= 7; //pin Latch Enabled data accepted while HI level
//const byte DHVpin=5; // off/on MAX1771 Driver  Hight Voltage(DHV) 110-220V 
//const byte RedLedPin=9; //MCU WDM output for red LEDs 9-g
//const byte GreenLedPin=6; //MCU WDM output for green LEDs 6-b
//const byte BlueLedPin=3; //MCU WDM output for blue LEDs 3-r
const byte pinSet=-1;
const byte pinUp=4;
const byte pinDown=2;
//const byte pinBuzzer=2;
//const byte pinUpperDots=12; //HIGH value light a dots
//const byte pinLowerDots=4;  //HIGH value light a dots
const word fpsLimit=16666; // 1/60*1.000.000 //limit maximum refresh rate on 60 fps
bool RTC_present;


String stringToDisplay="000000";// Conten of this string will be displayed on tubes (must be 6 chars length)
int menuPosition=0; // 0 - time
                    // 1 - date
                    // 2 - alarm
                    // 3 - 12/24 hours mode
                    
byte blinkMask=B00000000; //bit mask for blinkin digits (1 - blink, 0 - constant light)

//                      0      1      2      3      4      5      6      7      8       9
//word SymbolArray[10]={65534, 65533, 65531, 65527, 65519, 65503, 65471, 65407, 65279, 65023};
word SymbolArray[10]={1022, 1021, 1019, 1015, 1007, 991, 959, 895, 767, 511};

byte dotPattern=B00000000; //bit mask for separeting dots 
                          //B00000000 - turn off up and down dots 
                          //B1100000 - turn off all dots

#define DS1307_ADDRESS 0x68
byte zero = 0x00; //workaround for issue #527
int RTC_hours, RTC_minutes, RTC_seconds, RTC_day, RTC_month, RTC_year, RTC_day_of_week;

//--    ------------0--------1--------2-------3--------4--------5--------6--------7--------8--------9--------10-------11-------12-------13-------14
//         names:  Time,   Date,   Alarm,   12/24    hours,   mintues, seconds,  day,    month,   year,    hour,   minute,   second alarm01  hour_format 
//                  1        1        1       1        1        1        1        1        1        1        1        1        1        1        1
int parent[15]={    0,       0,       0,      0,       1,       1,       1,       2,       2,       2,       3,       3,       3,       3,       4};
int firstChild[15]={4,       7,       10,     14,      0,       0,       0,       0,       0,       0,       0,       0,       0,       0,       0};
int lastChild[15]={ 6,       9,       13,     14,      0,       0,       0,       0,       0,       0,       0,       0,       0,       0,       0};
int value[15]={     0,       0,       0,      0,       0,       0,       0,       0,       0,       0,       0,       0,       0,       0,      24};
int maxValue[15]={  0,       0,       0,      0,      23,      59,      59,      31,      12,      99,      23,      59,      59,       1,      24};
int minValue[15]={  0,       0,       0,      12,     00,      00,      00,       1,       1,      00,      00,      00,      00,       0,      12};
byte blinkPattern[15]={
                    B00000000, 
                             B00000000, 
                                      B00000000, 
                                              B00000000, 
                                                      B00000011, 
                                                                B00001100, 
                                                                          B00110000, 
                                                                                  B00000011, 
                                                                                           B00001100, 
                                                                                                    B00110000, 
                                                                                                             B00000011, 
                                                                                                                      B00001100, 
                                                                                                                                B00110000,
                                                                                                                                        B11000000,  
                                                                                                                                            B00001100};
#define TimeIndex        0 
#define DateIndex        1 
#define AlarmIndex       2 
#define hModeIndex       3 
#define TimeHoursIndex   4 
#define TimeMintuesIndex 5
#define TimeSecondsIndex 6
#define DateDayIndex     7
#define DateMonthIndex   8
#define DateYearIndex    9 
#define AlarmHourIndex   10
#define AlarmMinuteIndex 11
#define AlarmSecondIndex 12
#define Alarm01          13
#define hModeValueIndex  14

bool editMode=false;

long downTime=0;
long upTime=0;
const long settingDelay=150;
bool BlinkUp=false;
bool BlinkDown=false;
unsigned long enteringEditModeTime=0;
bool RGBLedsOn=false;
byte RGBLEDsEEPROMAddress=0; 
byte HourFormatEEPROMAddress=1;
byte AlarmTimeEEPROMAddress=2;//3,4,5
byte AlarmArmedEEPROMAddress=6;
byte LEDsLockEEPROMAddress=7;   
byte LEDsRedValueEEPROMAddress=8; 
byte LEDsGreenValueEEPROMAddress=9; 
byte LEDsBlueValueEEPROMAddress=10;   

//buttons pins declarations
//ClickButton setButton(pinSet, LOW, CLICKBTN_PULLUP);
//ClickButton upButton(pinUp, LOW, CLICKBTN_PULLUP);
//ClickButton downButton(pinDown, LOW, CLICKBTN_PULLUP);
///////////////////

//Tone tone1;
#define isdigit(n) (n >= '0' && n <= '9')
//char *song = "MissionImp:d=16,o=6,b=95:32d,32d#,32d,32d#,32d,32d#,32d,32d#,32d,32d,32d#,32e,32f,32f#,32g,g,8p,g,8p,a#,p,c7,p,g,8p,g,8p,f,p,f#,p,g,8p,g,8p,a#,p,c7,p,g,8p,g,8p,f,p,f#,p,a#,g,2d,32p,a#,g,2c#,32p,a#,g,2c,a#5,8c,2p,32p,a#5,g5,2f#,32p,a#5,g5,2f,32p,a#5,g5,2e,d#,8d";
//char *song = "PinkPanther:d=4,o=5,b=160:8d#,8e,2p,8f#,8g,2p,8d#,8e,16p,8f#,8g,16p,8c6,8b,16p,8d#,8e,16p,8b,2a#,2p,16a,16g,16e,16d,2e";
//char *song="VanessaMae:d=4,o=6,b=70:32c7,32b,16c7,32g,32p,32g,32p,32d#,32p,32d#,32p,32c,32p,32c,32p,32c7,32b,16c7,32g#,32p,32g#,32p,32f,32p,16f,32c,32p,32c,32p,32c7,32b,16c7,32g,32p,32g,32p,32d#,32p,32d#,32p,32c,32p,32c,32p,32g,32f,32d#,32d,32c,32d,32d#,32c,32d#,32f,16g,8p,16d7,32c7,32d7,32a#,32d7,32a,32d7,32g,32d7,32d7,32p,32d7,32p,32d7,32p,16d7,32c7,32d7,32a#,32d7,32a,32d7,32g,32d7,32d7,32p,32d7,32p,32d7,32p,32g,32f,32d#,32d,32c,32d,32d#,32c,32d#,32f,16c";
//char *song="DasBoot:d=4,o=5,b=100:d#.4,8d4,8c4,8d4,8d#4,8g4,a#.4,8a4,8g4,8a4,8a#4,8d,2f.,p,f.4,8e4,8d4,8e4,8f4,8a4,c.,8b4,8a4,8b4,8c,8e,2g.,2p";
//char *song="Scatman:d=4,o=5,b=200:8b,16b,32p,8b,16b,32p,8b,2d6,16p,16c#.6,16p.,8d6,16p,16c#6,8b,16p,8f#,2p.,16c#6,8p,16d.6,16p.,16c#6,16b,8p,8f#,2p,32p,2d6,16p,16c#6,8p,16d.6,16p.,16c#6,16a.,16p.,8e,2p.,16c#6,8p,16d.6,16p.,16c#6,16b,8p,8b,16b,32p,8b,16b,32p,8b,2d6,16p,16c#.6,16p.,8d6,16p,16c#6,8b,16p,8f#,2p.,16c#6,8p,16d.6,16p.,16c#6,16b,8p,8f#,2p,32p,2d6,16p,16c#6,8p,16d.6,16p.,16c#6,16a.,16p.,8e,2p.,16c#6,8p,16d.6,16p.,16c#6,16a,8p,8e,2p,32p,16f#.6,16p.,16b.,16p.";
//char *song="Popcorn:d=4,o=5,b=160:8c6,8a#,8c6,8g,8d#,8g,c,8c6,8a#,8c6,8g,8d#,8g,c,8c6,8d6,8d#6,16c6,8d#6,16c6,8d#6,8d6,16a#,8d6,16a#,8d6,8c6,8a#,8g,8a#,c6";
//char *song="WeWishYou:d=4,o=5,b=200:d,g,8g,8a,8g,8f#,e,e,e,a,8a,8b,8a,8g,f#,d,d,b,8b,8c6,8b,8a,g,e,d,e,a,f#,2g,d,g,8g,8a,8g,8f#,e,e,e,a,8a,8b,8a,8g,f#,d,d,b,8b,8c6,8b,8a,g,e,d,e,a,f#,1g,d,g,g,g,2f#,f#,g,f#,e,2d,a,b,8a,8a,8g,8g,d6,d,d,e,a,f#,2g";
//#define OCTAVE_OFFSET 0
char *p;

// int notes[] = { 0,
// NOTE_C4, NOTE_CS4, NOTE_D4, NOTE_DS4, NOTE_E4, NOTE_F4, NOTE_FS4, NOTE_G4, NOTE_GS4, NOTE_A4, NOTE_AS4, NOTE_B4,
// NOTE_C5, NOTE_CS5, NOTE_D5, NOTE_DS5, NOTE_E5, NOTE_F5, NOTE_FS5, NOTE_G5, NOTE_GS5, NOTE_A5, NOTE_AS5, NOTE_B5,
// NOTE_C6, NOTE_CS6, NOTE_D6, NOTE_DS6, NOTE_E6, NOTE_F6, NOTE_FS6, NOTE_G6, NOTE_GS6, NOTE_A6, NOTE_AS6, NOTE_B6,
// NOTE_C7, NOTE_CS7, NOTE_D7, NOTE_DS7, NOTE_E7, NOTE_F7, NOTE_FS7, NOTE_G7, NOTE_GS7, NOTE_A7, NOTE_AS7, NOTE_B7
// };

// int fireforks[]={0,0,1,//1
//                 -1,0,0,//2
//                  0,1,0,//3
//                  0,0,-1,//4
//                  1,0,0,//5
//                  0,-1,0}; //array with RGB rules (0 - do nothing, -1 - decrese, +1 - increse

void setRTCDateTime(byte h, byte m, byte s, byte d, byte mon, byte y, byte w=1);

int functionDownButton=0;
int functionUpButton=0;
bool LEDsLock=false;

//ESP32Time tijd(3600);
DS1307 rtc;
const char *ssid     = "iot";
const char *password = "Rijnstraat214";

WiFiUDP ntpUDP;
NTPClient timeClient(ntpUDP);

void doTest();
void getRTCTime();
void modesChanger();
void doIndication();

void setTime(int RTC_hours, int RTC_minutes, int RTC_seconds, int RTC_day, int RTC_month, int RTC_year)
{
  tijd.setTime(RTC_seconds,RTC_minutes,RTC_hours,RTC_day,RTC_month,RTC_year);
}
/*******************************************************************************************************
Init Programm
*******************************************************************************************************/
void setup() 
{
 // digitalWrite(DHVpin, LOW);    // off MAX1771 Driver  Hight Voltage(DHV) 110-220V
   
  Wire.begin();
  Wire.setPins(0,1);
  rtc.begin();
  //setRTCDateTime(23,40,00,25,7,15,1);
  
  Serial.begin(115200);
  WiFi.begin(ssid, password);

  while ( WiFi.status() != WL_CONNECTED ) {
    delay ( 500 );
    Serial.print ( "." );
  }
  timeClient.begin(); 
  // if (!rtc.isrunning()) {
  //   Serial.println("RTC is NOT running!");
  //   // following line sets the RTC to the date & time this sketch was compiled
  //   rtc.adjust(DateTime(__DATE__, __TIME__));
  // }

    // if (EEPROM.read(HourFormatEEPROMAddress)!=12) value[hModeValueIndex]=24; else value[hModeValueIndex]=12;
  //  if (EEPROM.read(RGBLEDsEEPROMAddress)!=0) RGBLedsOn=true; else RGBLedsOn=false;
    // if (EEPROM.read(AlarmTimeEEPROMAddress)==255) value[AlarmHourIndex]=0; else value[AlarmHourIndex]=EEPROM.read(AlarmTimeEEPROMAddress);
    // if (EEPROM.read(AlarmTimeEEPROMAddress+1)==255) value[AlarmMinuteIndex]=0; else value[AlarmMinuteIndex]=EEPROM.read(AlarmTimeEEPROMAddress+1);
    // if (EEPROM.read(AlarmTimeEEPROMAddress+2)==255) value[AlarmSecondIndex]=0; else value[AlarmSecondIndex]=EEPROM.read(AlarmTimeEEPROMAddress+2);
    // if (EEPROM.read(AlarmArmedEEPROMAddress)==255) value[Alarm01]=0; else value[Alarm01]=EEPROM.read(AlarmArmedEEPROMAddress);
    // if (EEPROM.read(LEDsLockEEPROMAddress)==255) LEDsLock=false; else LEDsLock=EEPROM.read(LEDsLockEEPROMAddress);
    // Serial.print("led lock=");
    // Serial.println(LEDsLock);
    
  // pinMode(RedLedPin, OUTPUT);
  // pinMode(GreenLedPin, OUTPUT);
  // pinMode(BlueLedPin, OUTPUT);
  
  // pinMode(pinUpperDots, OUTPUT);
  // pinMode(pinLowerDots, OUTPUT);

  //digitalWrite(pinUpperDots, HIGH);
  //while(1);
    
  // tone1.begin(pinBuzzer);
  // song=parseSong(song);
  
  pinMode(LEpin, OUTPUT);
  //pinMode(DHVpin, OUTPUT);
  
 // SPI setup

  SPI.begin(5,9,6); // 
  SPI.setDataMode (SPI_MODE3); // Mode 3 SPI
  SPI.setClockDivider(SPI_CLOCK_DIV128); // SCK = 16MHz/128= 125kHz
 
  pinMode(Anode0Pin, OUTPUT);
  pinMode(Anode1Pin, OUTPUT);
  pinMode(Anode2Pin, OUTPUT);
  //buttons pins inits
  // pinMode(pinSet,  INPUT_PULLUP);
  // pinMode(pinUp,  INPUT_PULLUP);
  // pinMode(pinDown,  INPUT_PULLUP);
  ////////////////////////////
  //pinMode(pinBuzzer, OUTPUT);
  
  //buttons objects inits
  // setButton.debounceTime   = 20;   // Debounce timer in ms
  // setButton.multiclickTime = 30;  // Time limit for multi clicks
  // setButton.longClickTime  = 2000; // time until "held-down clicks" register
  
  // upButton.debounceTime   = 20;   // Debounce timer in ms
  // upButton.multiclickTime = 30;  // Time limit for multi clicks
  // upButton.longClickTime  = 2000; // time until "held-down clicks" register

  // downButton.debounceTime   = 20;   // Debounce timer in ms
  // downButton.multiclickTime = 30;  // Time limit for multi clicks
  // downButton.longClickTime  = 2000; // time until "held-down clicks" register
  
  //
  //digitalWrite(DHVpin, HIGH); // on MAX1771 Driver  Hight Voltage(DHV) 110-220V
  //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
  doTest();
  //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
  // if (LEDsLock==1)
  //   {
  //     setLEDsFromEEPROM();
  //   }
  getRTCTime();
  byte prevSeconds=RTC_seconds;
  unsigned long RTC_ReadingStartTime=millis();
  RTC_present=true;
  while(prevSeconds==RTC_seconds)
  {
    getRTCTime();
    //Serial.println(RTC_seconds);
    if ((millis()-RTC_ReadingStartTime)>3000)
    {
      Serial.println(F("Warning! RTC DON'T RESPOND!"));
      RTC_present=false;
      break;
    }
  }
  setTime(RTC_hours, RTC_minutes, RTC_seconds, RTC_day, RTC_month, RTC_year);
//  digitalWrite(DHVpin, LOW); // off MAX1771 Driver  Hight Voltage(DHV) 110-220V
  //setRTCDateTime(RTC_hours,RTC_minutes,RTC_seconds,RTC_day,RTC_month,RTC_year,1); //записываем только что считанное время в RTC чтобы запустить новую микросхему
//  digitalWrite(DHVpin, HIGH); // on MAX1771 Driver  Hight Voltage(DHV) 110-220V
  //p=song;
}

int rotator=0; //index in array with RGB "rules" (increse by one on each 255 cycles)
int cycle=0; //cycles counter
int RedLight=255;
int GreenLight=0;
int BlueLight=0;
unsigned long prevTime=0; // time of lase tube was lit
unsigned long prevTime4FireWorks=0;  //time of last RGB changed
//int minuteL=0; //младшая цифра минут

//antipoisoning transaction 
bool modeChangedByUser=false;
bool transactionInProgress=false; 
#define timeModePeriod 60000
#define dateModePeriod 5000
long modesChangePeriod=timeModePeriod;
//antipoisoning end

/***************************************************************************************************************
MAIN Programm
***************************************************************************************************************/
void loop() {
timeClient.update();
//  if (((millis()%60000)==0)&&(RTC_present)) //synchronize with RTC every 10 seconds
//  {
//   getRTCTime();
//   setTime(RTC_hours, RTC_minutes, RTC_seconds, RTC_day, RTC_month, RTC_year);
//   Serial.println("sync:");
//   Serial.println(RTC_seconds);
//  }
  
  //p=playmusic(p);
  
  // if ((millis()-prevTime4FireWorks)>5)
  // {
  //   rotateFireWorks(); //change color (by 1 step)
  //   prevTime4FireWorks=millis();
  // }

  // if ((menuPosition==TimeIndex) || (modeChangedByUser==false) ) modesChanger();  
  doIndication();
  
  // setButton.Update();
  // upButton.Update();
  // downButton.Update();
  // if (editMode==false) 
  //   {
  //     blinkMask=B00000000;
      
  //   } else if ((millis()-enteringEditModeTime)>60000) 
  //   {
  //     editMode=false;
  //     menuPosition=firstChild[menuPosition];
  //     blinkMask=blinkPattern[menuPosition];
  //   }
  // if (setButton.clicks>0) //short click
  //   {
  //     modeChangedByUser=true;
  //     p=0; //shut off music )))
  //     //tone1.play(1000,100);
  //     enteringEditModeTime=millis();
  //     menuPosition=menuPosition+1;
  //     if (menuPosition==hModeIndex+1) menuPosition=TimeIndex;
  //     Serial.print(F("menuPosition="));
  //     Serial.println(menuPosition);
  //     Serial.print(F("value="));
  //     Serial.println(value[menuPosition]);
      
  //     blinkMask=blinkPattern[menuPosition];
  //     if ((parent[menuPosition-1]!=0) and (lastChild[parent[menuPosition-1]-1]==(menuPosition-1))) 
  //     {
  //       if ((parent[menuPosition-1]-1==1) && (!isValidDate())) 
  //         {
  //           menuPosition=DateDayIndex;
  //           return;
  //         }
  //       editMode=false;
  //       menuPosition=parent[menuPosition-1]-1;
  //       if (menuPosition==TimeIndex) setTime(value[TimeHoursIndex], value[TimeMintuesIndex], value[TimeSecondsIndex], day(), month(), year());
  //       if (menuPosition==DateIndex) setTime(hour(), minute(), second(),value[DateDayIndex], value[DateMonthIndex], 2000+value[DateYearIndex]);
  //       if (menuPosition==AlarmIndex) {EEPROM.write(AlarmTimeEEPROMAddress,value[AlarmHourIndex]); EEPROM.write(AlarmTimeEEPROMAddress+1,value[AlarmMinuteIndex]); EEPROM.write(AlarmTimeEEPROMAddress+2,value[AlarmSecondIndex]); EEPROM.write(AlarmArmedEEPROMAddress, value[Alarm01]);};
  //       if (menuPosition==hModeIndex) EEPROM.write(HourFormatEEPROMAddress, value[hModeValueIndex]);
  //      // digitalWrite(DHVpin, LOW); // off MAX1771 Driver  Hight Voltage(DHV) 110-220V
  //       setRTCDateTime(hour(),minute(),second(),day(),month(),year()%1000,1);
  //      // digitalWrite(DHVpin, HIGH); // on MAX1771 Driver  Hight Voltage(DHV) 110-220V
  //     }
  //     value[menuPosition]=extractDigits(blinkMask);
  //   }
  // if (setButton.clicks<0) //long click
  //   {
  //     tone1.play(1000,100);
  //     if (!editMode) 
  //     {
  //       enteringEditModeTime=millis();
  //       if (menuPosition==TimeIndex) stringToDisplay=PreZero(hour())+PreZero(minute())+PreZero(second()); //temporary enabled 24 hour format while settings
  //     }
  //     menuPosition=firstChild[menuPosition];
  //     if (menuPosition==AlarmHourIndex) {value[Alarm01]=1; /*digitalWrite(pinUpperDots, HIGH);*/dotPattern=B10000000;}
  //     editMode=!editMode;
  //     blinkMask=blinkPattern[menuPosition];
  //     value[menuPosition]=extractDigits(blinkMask);
  //   }
   
  // if (upButton.clicks != 0) functionUpButton = upButton.clicks;  
   
  // if (upButton.clicks>0) 
  //   {
  //     modeChangedByUser=true;
  //     p=0; //shut off music )))
  //     tone1.play(1000,100);
  //     incrementValue();
  //     if (!editMode) 
  //       {
  //         LEDsLock=false;
  //         EEPROM.write(LEDsLockEEPROMAddress, 0);
  //       }
  //   }
  
  // if (functionUpButton == -1 && upButton.depressed == true)   
  // {
  //  BlinkUp=false;
  //  if (editMode==true) 
  //  {
  //    if ( (millis() - upTime) > settingDelay)
  //   {
  //    upTime = millis();// + settingDelay;
  //     incrementValue();
  //   }
  //  }
  // } else BlinkUp=true;
  
  // if (downButton.clicks != 0) functionDownButton = downButton.clicks;
  
  // if (downButton.clicks>0) 
  //   {
  //     modeChangedByUser=true;
  //     p=0; //shut off music )))
  //     tone1.play(1000,100);
  //     dicrementValue();
  //     if (!editMode) 
  //     {
  //       LEDsLock=true;
  //       EEPROM.write(LEDsLockEEPROMAddress, 1);
  //       EEPROM.write(LEDsRedValueEEPROMAddress, RedLight);
  //       EEPROM.write(LEDsGreenValueEEPROMAddress, GreenLight);
  //       EEPROM.write(LEDsBlueValueEEPROMAddress, BlueLight);
  //     }
  //   }
  
  // if (functionDownButton == -1 && downButton.depressed == true)   
  // {
  //  BlinkDown=false;
  //  if (editMode==true) 
  //  {
  //    if ( (millis() - downTime) > settingDelay)
  //   {
  //    downTime = millis();// + settingDelay;
  //     dicrementValue();
  //   }
  //  }
  // } else BlinkDown=true;
  
  // if (!editMode)
  // {
  //   if (upButton.clicks<0)
  //     {
  //       tone1.play(1000,100);
  //       RGBLedsOn=true;
  //       EEPROM.write(RGBLEDsEEPROMAddress,1);
  //       Serial.println("RGB=on");
  //       setLEDsFromEEPROM();
  //     }
  //   if (downButton.clicks<0)
  //   {
  //     tone1.play(1000,100);
  //     RGBLedsOn=false;
  //     EEPROM.write(RGBLEDsEEPROMAddress,0);
  //     Serial.println("RGB=off");
  //   }
  // }
   
  static bool updateDateTime=false;
  switch (menuPosition)
  {
       case TimeIndex: //time mode
        if (!transactionInProgress) stringToDisplay=updateDisplayString();
       doDotBlink();
       //checkAlarmTime();
       break;
    case DateIndex: //date mode
      if (!transactionInProgress) stringToDisplay=updateDateString();
      dotPattern=B01000000;//turn on lower dots
      /*digitalWrite(pinUpperDots, LOW);
      digitalWrite(pinLowerDots, HIGH);*/
      //checkAlarmTime();
      break;
    // case AlarmIndex: //alarm mode
    //   stringToDisplay=PreZero(value[AlarmHourIndex])+PreZero(value[AlarmMinuteIndex])+PreZero(value[AlarmSecondIndex]);
    //  if (value[Alarm01]==1) /*digitalWrite(pinUpperDots, HIGH);*/ dotPattern=B10000000; //turn on upper dots
    //        else 
    //        {
    //          /*digitalWrite(pinUpperDots, LOW);
    //          digitalWrite(pinLowerDots, LOW);*/
    //          dotPattern=B00000000; //turn off upper dots
    //        }
    //   //checkAlarmTime();
    //   break;
    // case hModeIndex: //12/24 hours mode
    //   stringToDisplay="00"+String(value[hModeValueIndex])+"00";
    //   dotPattern=B00000000;//turn off all dots
    //   /*digitalWrite(pinUpperDots, LOW);
    //   digitalWrite(pinLowerDots, LOW);*/
    //   //checkAlarmTime();
    //   break;
  }
}

String PreZero(int digit)
{
  if (digit<10) return String("0")+String(digit);
    else return String(digit);
}

void rotateFireWorks()
{
  // if (!RGBLedsOn)
  // {
  //   analogWrite(RedLedPin,0 );
  //   analogWrite(GreenLedPin,0);
  //   analogWrite(BlueLedPin,0); 
  //   return;
  // }
  // if (LEDsLock) return;
  // RedLight=RedLight+fireforks[rotator*3];
  // GreenLight=GreenLight+fireforks[rotator*3+1];
  // BlueLight=BlueLight+fireforks[rotator*3+2];
  // analogWrite(RedLedPin,RedLight );
  // analogWrite(GreenLedPin,GreenLight);
  // analogWrite(BlueLedPin,BlueLight);  
  // cycle=cycle+1;
  // if (cycle==255)
  // {  
  //   rotator=rotator+1;
  //   cycle=0;
  // }
  // if (rotator>5) rotator=0;
}


void doIndication()
{
  static byte b=1;
 
  static unsigned long lastTimeInterval1Started;
  if ((micros()-lastTimeInterval1Started)>5000)
  {
   lastTimeInterval1Started=micros();
   Anode0OFF; Anode1OFF; Anode2OFF;
   unsigned long var32;
   unsigned long tmpVar; 

   int curTube=b*2-2;
   //stringToDisplay="000000";
   var32=SymbolArray[stringToDisplay.substring(curTube, curTube+1).toInt()];
   tmpVar=SymbolArray[stringToDisplay.substring(curTube+1, curTube+2).toInt()];

   var32|=doEditBlink(curTube);
   tmpVar|=doEditBlink(curTube+1);
   //Serial.println(var32);

   var32 |= tmpVar<<10;

   digitalWrite(LEpin, LOW);    // allow data input (Transparent mode)
    
   SPI.transfer(var32>>16); //[A3][A2][A1][A0][RC9][RC8][RC7][RC6]      - A5-A0 - anodes
   SPI.transfer(var32>>8); //[RC5][RC4][RC3][RC2][RC1][RC0][LC9][RC8]  - RC9-RC0 - Right tubes cathodes
   SPI.transfer(var32);

   digitalWrite(LEpin, HIGH);     // latching data 
    
   switch (b)
   {
    case 1:{Anode0ON; Anode1OFF; Anode2OFF; break;};
    case 2:{Anode0OFF; Anode1ON; Anode2OFF; break;};
    case 3:{Anode0OFF; Anode1OFF; Anode2ON; break;};
   }
    b=b+1;
    if (b==4) {b=1;}
  }
}

byte CheckButtonsState()
{
  static boolean buttonsWasChecked;
  static unsigned long startBuzzTime;
  static unsigned long lastTimeButtonsPressed;
  if ((digitalRead(pinSet)==0)||(digitalRead(pinUp)==0)||(digitalRead(pinDown)==0))
  {
    if (buttonsWasChecked==false) startBuzzTime=millis();
    buttonsWasChecked=true;
  } else buttonsWasChecked=false;
  // if (millis()-startBuzzTime<30) 
  //   {
  //     digitalWrite(pinBuzzer, HIGH);
  //   } else
  //   {
  //     digitalWrite(pinBuzzer, LOW);
  //   }
  return 0;
}

void doTest()
{
  String testStringArray[12]={"000000","111111","222222","333333","444444","555555","666666","777777","888888","999999","",""};
  testStringArray[10]=FirmwareVersion;
  Serial.println(testStringArray[10]);
  
  Serial.print(F("Firmware version: "));
  Serial.println(FirmwareVersion.substring(1,2)+"."+FirmwareVersion.substring(2,4));
  Serial.println(F("Start Test"));
  
  // p=song;
  // parseSong(p);
   
  // analogWrite(RedLedPin,255);
  // delay(1000);
  // analogWrite(RedLedPin,0);
  // analogWrite(GreenLedPin,255);
  // delay(1000);
  // analogWrite(GreenLedPin,0);
  // analogWrite(BlueLedPin,255);
  // delay(1000); 

  //if (Uinput<10) testStringArray[10]="000"+String(int(Uinput*100)); else testStringArray[10]="00"+String(int(Uinput*100));
  
  int dlay=500;
  bool test=1;
  byte strIndex=-1;
  unsigned long startOfTest=millis();
  bool digitsLock=false;
  byte b=1;
  while (test)
  {
    // if (digitalRead(pinDown)==0) digitsLock=true;
    // if (digitalRead(pinUp)==0) digitsLock=false;
    
    for (int i=0; i<10; i++)
    {
      if ((millis()-startOfTest)>dlay) 
      {
        startOfTest=millis();
        if (!digitsLock) strIndex=strIndex+1;
        if (strIndex==10) dlay=3000;
        if (strIndex==11) test=0;
     
        stringToDisplay=testStringArray[strIndex];
        Serial.print("stringToDisplay=");
        Serial.println(stringToDisplay);
        Serial.print("strIndex=");
        Serial.println(strIndex);
        Serial.print("i=");
        Serial.println(i);
      }
   
      unsigned long var32=0;
      unsigned long tmpVar=0;
      int curTube=b*2-2;
      var32=SymbolArray[stringToDisplay.substring(curTube, curTube+1).toInt()];
      tmpVar=SymbolArray[stringToDisplay.substring(curTube+1, curTube+2).toInt()];

      var32 |= tmpVar<<10;

      digitalWrite(LEpin, LOW);    // allow data input (Transparent mode)
    
      SPI.transfer(var32>>16); //[A3][A2][A1][A0][RC9][RC8][RC7][RC6]      - A5-A0 - anodes
      SPI.transfer(var32>>8); //[RC5][RC4][RC3][RC2][RC1][RC0][LC9][RC8]  - RC9-RC0 - Right tubes cathodes
      SPI.transfer(var32);

      digitalWrite(LEpin, HIGH);     // latching data

      switch (b)
      {
        case 1:{Anode0ON; Anode1OFF; Anode2OFF; break;};
        case 2:{Anode0OFF; Anode1ON; Anode2OFF; break;};
        case 3:{Anode0OFF; Anode1OFF; Anode2ON; break;};
      }
     b=b+1;
     if (b==4) {b=1;}
     delayMicroseconds(2000);
    }; 
  }
  Serial.println(F("Stop Test"));
}
void doDotBlink()
{
  static unsigned long lastTimeBlink=millis();
  static bool dotState=0;
  if ((millis()-lastTimeBlink)>1000) 
  {
    lastTimeBlink=millis();
    dotState=!dotState;
    if (dotState) 
      {
        dotPattern=B11000000;
        /*digitalWrite(pinUpperDots, HIGH);
        digitalWrite(pinLowerDots, HIGH);*/
      }
      else 
      {
        dotPattern=B00000000;
        /*digitalWrite(pinUpperDots, LOW); 
        digitalWrite(pinLowerDots, LOW);*/
      }
  }
}

void setRTCDateTime(byte h, byte m, byte s, byte d, byte mon, byte y, byte w)
{
  Wire.beginTransmission(DS1307_ADDRESS);
  Wire.write(zero); //stop Oscillator

  Wire.write(decToBcd(s));
  Wire.write(decToBcd(m));
  Wire.write(decToBcd(h));
  Wire.write(decToBcd(w));
  Wire.write(decToBcd(d));
  Wire.write(decToBcd(mon));
  Wire.write(decToBcd(y));

  Wire.write(zero); //start 

  Wire.endTransmission();

}

byte decToBcd(byte val){
// Convert normal decimal numbers to binary coded decimal
  return ( (val/10*16) + (val%10) );
}

byte bcdToDec(byte val)  {
// Convert binary coded decimal to normal decimal numbers
  return ( (val/16*10) + (val%16) );
}

void getRTCTime()
{
  DateTime now = timeClient.;
  // char buf[20];
  // Serial.println(tijd.tostr(buf));
  // Wire.beginTransmission(DS1307_ADDRESS);
  // Wire.write(zero);
  // Wire.endTransmission();

  // Wire.requestFrom(DS1307_ADDRESS, 7);

  RTC_seconds = now.second();
  RTC_minutes = now.minute();
  RTC_hours = now.hour();
  RTC_day_of_week = now.dayOfWeek();
  RTC_day = now.day();
  RTC_month = now.month();
  RTC_year = now.year();
}

word doEditBlink(int pos)
{
  if (!BlinkUp) return 0;
  if (!BlinkDown) return 0;
  //if (pos==5) return 0xFFFF; //need to be deleted for testing purpose only!
  int lowBit=blinkMask>>pos;
  lowBit=lowBit&B00000001;
  
  static unsigned long lastTimeEditBlink=millis();
  static bool blinkState=false;
  word mask=0;
  static int tmp=0;//blinkMask;
  if ((millis()-lastTimeEditBlink)>300) 
  {
    lastTimeEditBlink=millis();
    blinkState=!blinkState;

    if (blinkState) tmp= 0;
      else tmp=blinkMask;
  }
  // if (((dotPattern&~tmp)>>6)&1==1) digitalWrite(pinLowerDots, HIGH);
  //     else digitalWrite(pinLowerDots, LOW);
  // if (((dotPattern&~tmp)>>7)&1==1) digitalWrite(pinUpperDots, HIGH);
  //     else digitalWrite(pinUpperDots, LOW);
      
  if ((blinkState==true) && (lowBit==1)) mask=0xFFFF;//mask=B11111111;
  //Serial.println(mask);
  return mask;
}

int extractDigits(byte b)
{
  String tmp="1";
  /*Serial.print("blink pattern= ");
  Serial.println(b);
  Serial.print("stringToDisplay= ");
  Serial.println(stringToDisplay);*/
  if (b==B00000011) 
    {
    tmp=stringToDisplay.substring(0,2);
    /*Serial.print("stringToDisplay1= ");
    Serial.println(stringToDisplay);*/
    }
  if (b==B00001100) 
    {
    tmp=stringToDisplay.substring(2,4);
    /*Serial.print("stringToDisplay2= ");
    Serial.println(stringToDisplay);*/
    }
  if (b==B00110000) 
    {
      tmp=stringToDisplay.substring(4);
      /*Serial.print("stringToDisplay3= ");
      Serial.println(stringToDisplay);*/
    }
  /*Serial.print("stringToDisplay4= ");
  Serial.println(stringToDisplay);*/
  return tmp.toInt();
}

void injectDigits(byte b, int value)
{
  if (b==B00000011) stringToDisplay=PreZero(value)+stringToDisplay.substring(2);
  if (b==B00001100) stringToDisplay=stringToDisplay.substring(0,2)+PreZero(value)+stringToDisplay.substring(4);
  if (b==B00110000) stringToDisplay=stringToDisplay.substring(0,4)+PreZero(value);
}

bool isValidDate()
{
  int days[12]={31,28,31,30,31,30,31,31,30,31,30,31};
  if (value[DateYearIndex]%4==0) days[1]=29;
  if (value[DateDayIndex]>days[value[DateMonthIndex]-1]) return false;
    else return true;
  
}

// byte default_dur = 4;
// byte default_oct = 6;
// int bpm = 63;
// int num;
// long wholenote;
// long duration;
// byte note;
// byte scale;
// char* parseSong(char *p)
// {
//   // Absolutely no error checking in here
//   // format: d=N,o=N,b=NNN:
//   // find the start (skip name, etc)

//   while(*p != ':') p++;    // ignore name
//   p++;                     // skip ':'

//   // get default duration
//   if(*p == 'd')
//   {
//     p++; p++;              // skip "d="
//     num = 0;
//     while(isdigit(*p))
//     {
//       num = (num * 10) + (*p++ - '0');
//     }
//     if(num > 0) default_dur = num;
//     p++;                   // skip comma
//   }

//   // get default octave
//   if(*p == 'o')
//   {
//     p++; p++;              // skip "o="
//     num = *p++ - '0';
//     if(num >= 3 && num <=7) default_oct = num;
//     p++;                   // skip comma
//   }

//   // get BPM
//   if(*p == 'b')
//   {
//     p++; p++;              // skip "b="
//     num = 0;
//     while(isdigit(*p))
//     {
//       num = (num * 10) + (*p++ - '0');
//     }
//     bpm = num;
//     p++;                   // skip colon
//   }

//   // BPM usually expresses the number of quarter notes per minute
//   wholenote = (60 * 1000L / bpm) * 4;  // this is the time for whole note (in milliseconds)
//   return p;
// }

 // now begin note loop
//  static unsigned long lastTimeNotePlaying=0;
//  char* playmusic(char *p)
//   {
//      if(*p==0) 
//       {
//         return p;
//       }
//     if (millis()-lastTimeNotePlaying>duration) 
//         lastTimeNotePlaying=millis();
//       else return p;
//     // first, get note duration, if available
//     num = 0;
//     while(isdigit(*p))
//     {
//       num = (num * 10) + (*p++ - '0');
//     }
    
//     if(num) duration = wholenote / num;
//     else duration = wholenote / default_dur;  // we will need to check if we are a dotted note after

//     // now get the note
//     note = 0;

//     switch(*p)
//     {
//       case 'c':
//         note = 1;
//         break;
//       case 'd':
//         note = 3;
//         break;
//       case 'e':
//         note = 5;
//         break;
//       case 'f':
//         note = 6;
//         break;
//       case 'g':
//         note = 8;
//         break;
//       case 'a':
//         note = 10;
//         break;
//       case 'b':
//         note = 12;
//         break;
//       case 'p':
//       default:
//         note = 0;
//     }
//     p++;

//     // now, get optional '#' sharp
//     if(*p == '#')
//     {
//       note++;
//       p++;
//     }

//     // now, get optional '.' dotted note
//     if(*p == '.')
//     {
//       duration += duration/2;
//       p++;
//     }
  
//     // now, get scale
//     if(isdigit(*p))
//     {
//       scale = *p - '0';
//       p++;
//     }
//     else
//     {
//       scale = default_oct;
//     }

//     scale += OCTAVE_OFFSET;

//     if(*p == ',')
//       p++;       // skip comma for next note (or we may be at the end)

//     // now play the note

//     if(note)
//     {
//       tone1.play(notes[(scale - 4) * 12 + note], duration);
//       if (millis()-lastTimeNotePlaying>duration) 
//         lastTimeNotePlaying=millis();
//       else return p;
//         tone1.stop();
//     }
//     else
//     {
//       return p;
//     }
//     Serial.println(F("Incorrect Song Format!"));
//     return 0; //error
//   }
  
  
void incrementValue()
  {
   enteringEditModeTime=millis();
      if (editMode==true)
      {
       if(menuPosition!=hModeValueIndex) // 12/24 hour mode menu position
       value[menuPosition]=value[menuPosition]+1; else value[menuPosition]=value[menuPosition]+12;
       if (value[menuPosition]>maxValue[menuPosition])  value[menuPosition]=minValue[menuPosition];
       if (menuPosition==Alarm01) 
        {
         if (value[menuPosition]==1) /*digitalWrite(pinUpperDots, HIGH);*/dotPattern=B10000000;//turn on all dots
           /*else digitalWrite(pinUpperDots, LOW); */ dotPattern=B00000000; //turn off all dots
        }
      injectDigits(blinkMask, value[menuPosition]);
      } 
  }
  
void dicrementValue()
{
      enteringEditModeTime=millis();
      if (editMode==true)
      {
        if (menuPosition!=hModeValueIndex) value[menuPosition]=value[menuPosition]-1; else value[menuPosition]=value[menuPosition]-12;
      if (value[menuPosition]<minValue[menuPosition]) value[menuPosition]=maxValue[menuPosition];
      if (menuPosition==Alarm01) 
        {
         if (value[menuPosition]==1) /*digitalWrite(pinUpperDots, HIGH);*/ dotPattern=B10000000;//turn on upper dots включаем верхние точки
           else /*digitalWrite(pinUpperDots, LOW);*/ dotPattern=B00000000; //turn off upper dots
        }
      injectDigits(blinkMask, value[menuPosition]);
      }
}

bool Alarm1SecondBlock=false;
unsigned long lastTimeAlarmTriggired=0;
void checkAlarmTime()
{
//  if (value[Alarm01]==0) return;
//  if ((Alarm1SecondBlock==true) && ((millis()-lastTimeAlarmTriggired)>1000)) Alarm1SecondBlock=false; 
//  if (Alarm1SecondBlock==true) return;
//  if ((hour()==value[AlarmHourIndex]) && (minute()==value[AlarmMinuteIndex]) && (second()==value[AlarmSecondIndex]))
//    {
//      lastTimeAlarmTriggired=millis();
//      Alarm1SecondBlock=true;
//      Serial.println(F("Wake up, Neo!"));
//      p=song;
//    }
}

void setLEDsFromEEPROM()
{
  // digitalWrite(RedLedPin, EEPROM.read(LEDsRedValueEEPROMAddress));
  // digitalWrite(GreenLedPin, EEPROM.read(LEDsGreenValueEEPROMAddress));
  // digitalWrite(BlueLedPin, EEPROM.read(LEDsBlueValueEEPROMAddress));
}


void modesChanger()
{
  if (editMode==true) return;
  static unsigned long lastTimeModeChanged=millis();
  static unsigned long lastTimeAntiPoisoningIterate=millis();
  if ((millis()-lastTimeModeChanged)>modesChangePeriod) 
  {
    lastTimeModeChanged=millis();
    if (menuPosition==TimeIndex) {menuPosition=DateIndex; modesChangePeriod=dateModePeriod;}
      else {menuPosition=TimeIndex; modesChangePeriod=timeModePeriod;}
    if (modeChangedByUser==true) 
    {
      menuPosition=TimeIndex;
    }
    modeChangedByUser=false;
  }
  if ((millis()-lastTimeModeChanged)<2000) 
  {
    if ((millis()-lastTimeAntiPoisoningIterate)>100)  
    {
      lastTimeAntiPoisoningIterate=millis();
      DateTime time = time;
      if (menuPosition==TimeIndex)
        stringToDisplay=antiPoisoning2(PreZero(tijd.getDay())+PreZero(tijd.getMonth())+PreZero(tijd.getYear()%1000), getTimeNow());
      else stringToDisplay=antiPoisoning2(getTimeNow(), PreZero(tijd.getDay())+PreZero(tijd.getMonth())+PreZero(tijd.getYear()%1000));
     // Serial.println("StrTDInToModeChng="+stringToDisplay);
    }
  } else transactionInProgress=false;
}

String antiPoisoning2(String fromStr, String toStr)
{
  //static bool transactionInProgress=false;
  //byte fromDigits[6];
  static byte toDigits[6];
  static byte currentDigits[6];
  static byte iterationCounter=0;
  if (!transactionInProgress) 
  {
    transactionInProgress=true;
    for (int i=0; i<6; i++)
    {
      currentDigits[i]=fromStr.substring(i, i+1).toInt();
      toDigits[i]=toStr.substring(i, i+1).toInt();
    }
  }
  for (int i=0; i<6; i++)
  {
    if (iterationCounter<10) currentDigits[i]++;
      else if (currentDigits[i]!=toDigits[i]) currentDigits[i]++;
    if (currentDigits[i]==10) currentDigits[i]=0;
  }
  iterationCounter++;
  if (iterationCounter==20)
  {
    iterationCounter=0;
    transactionInProgress=false;
  }
  String tmpStr;
  for (int i=0; i<6; i++)
    tmpStr+=currentDigits[i];
  return tmpStr;
}

String updateDisplayString()
{
  static  unsigned long lastTimeStringWasUpdated;
  if ((millis()-lastTimeStringWasUpdated)>1000)
  {
    lastTimeStringWasUpdated=millis();
    return getTimeNow();
  }
  return stringToDisplay;
}

String getTimeNow()
{
  // DateTime time = rtc.now();
  if (value[hModeValueIndex]==24) return PreZero(tijd.getHour())+PreZero(tijd.getMinute())+PreZero(tijd.getSecond());
      else return PreZero(tijd.getHour())+PreZero(tijd.getMinute())+PreZero(tijd.getSecond());
}

String updateDateString()
{
  // DateTime time = tijd.now();
  static unsigned long lastTimeDateUpdate=millis();
  static String DateString=PreZero(tijd.getDay())+PreZero(tijd.getMonth())+PreZero(tijd.getYear()%1000);
  if ((millis()-lastTimeDateUpdate)>1000) 
  {
    lastTimeDateUpdate=millis();
    DateString=PreZero(tijd.getDay())+PreZero(tijd.getMonth())+PreZero(tijd.getYear()%1000); 
  }
 return DateString;
}