#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#include <EEPROM.h>
#define SCREEN_WIDTH 128  // OLED display width, in pixels
#define SCREEN_HEIGHT 64  // OLED display height, in pixels
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, -1);

//Profiles 1  
  
  //Profiles
  #define t_sp 1//не міняти число!
  #define t_mp 2//не міняти число!
  #define r_off 0 // = off
  #define r_on 12 // = on
  #define get_name 20
  #define get_name_a_f 21
  #define change_letter 22
  
  
  //*prof()
  #define direct_p_sp 20
  #define direct_p_mp 21
  #define act_dir 22
  #define activate_p_sp 23
  #define activate_p_mp 24
  #define eeprom_initialization 25
   
  
  class Profiles {
    public:
      Profiles(int deZoH, byte senHor, int deZoV, byte senVer, String name, byte tape, byte na)
       : deadZoneHor(deZoH),
        sensitivityHor(senHor),
        deadZoneVer(deZoV),
        sensitivityVer(senVer),
        status(r_off),
        name(name),
        tape(tape),
        namber(na),
        buttonArray{0, 33, 14, 27, 26, 25, 16, 17, 5, 23, 2} {//при глюках замінити на memcpy(buttonArray, defaultButtonArray, sizeof(buttonArray));
      }
      
      int getDeZoHor() {   //get
       
       return deadZoneHor;
      
      } 
      
      byte getSenHor() {
      
       return sensitivityHor;
      
      }
      
      int getDeZoVer() {
       
       return deadZoneVer;
      
      }
      
      byte getSenVer() {
       
       return sensitivityVer;
      
      }
      
      byte getStatus() {
       
       returnstatus;
      
      }
      
      String getName() {
       
       return name;
      
      } 
      
      byte getTape() {
       
       return tape;
      
      }
      
      byte getNamber() {
       
       return namber;
     
      }
      
      int setDeZoHor(int deZoH) {//set
       
       if (deadZoneHor != deZoH) {sensitivityHor = 0;}
       deadZoneHor = deZoH; 
       
       return 0;
      } 
      
      byte setSenHor(byte senHor) {
       
       sensitivityHor = senHor;
       
       return 0;
      }
      
      int setDeZoVer(int deZoV) {
       
        if (deadZoneVer != deZoV) {sensitivityVer = 0;}
        deadZoneVer = deZoV;
       
       return 0;  
      }
      
      byte setSenVer(byte senVer) {
       
       sensitivityVer = senVer;
       
       return 0;
      }
      
      byte setStatus(byte st) {
      
      status = st;
      
       return 0;
      }
      
      byte setTape(byte tape) {
       
       tape = tape;
       
       return 0;
      }
      
      byte setNamber(byte na) {
      
       namber = na;
       
       return 0;
      }
      
      String nameProfiles(byte acceptedCommand, byte index = 0, char Letter = ' '){
       
        if (status == r_on && tmr < millis()){
         
         tmr = millis()+600;
         Flag = !Flag;
        
        }
        
        else if (status == r_off && !Flag){
         
         Flag = 1;
         
        }
        
        switch (acceptedCommand) {
        
          case get_name: 
            
            return name;
          
          break;
          
          case get_name_a_f: 
           
           if (Flag) {
            
            return name;
           
           } 
           else { 
            
            return "";
           
           }
           
           break;
          
          case change_letter: 
            
             name[index] = Letter;
          
           break;
        
        
         return "";
        
        }
      
      
       return "";
      }
      
      
      byte centroName() {
        
        for (int i = 19; i >= 0; i--) {
         
          if (name[i] != ' '){
           
           return 61-i*3;
           break;
          }
        
        }
        
       return 0;
      
      }
      
      byte getNamberTape(){
       
       return tape * 10 +namber;//логіка роботи тип може бути 1 або 2 множимо на 10 щоб не збігалася числа
      
      }
      
      void resetButtons(){
       
        for (int i = 0; i < sizeof(defButton); i++) {
              
         buttonArray[i] = defButton[i];
               
        }
      
      }
    
      void copyFrom(const Profiles& other) {//використовується для копіювання шаблона
        
        deadZoneHor = other.deadZoneHor;
        sensitivityHor = other.sensitivityHor;
        deadZoneVer = other.deadZoneVer;
        sensitivityVer = other.sensitivityVer;
        tape = other.tape;
        namber = other.namber;
       status = other.status;
        name = other.name;
        memcpy(buttonArray, other.buttonArray, sizeof(buttonArray));
      
      }
     
      bool operator!=(const Profiles& other) const { //використовується для порівняння шаблону
    
        return  (deadZoneHor != other.deadZoneHor) ||
                (sensitivityHor != other.sensitivityHor) ||
                (deadZoneVer != other.deadZoneVer) ||
                (sensitivityVer != other.sensitivityVer) ||
                (tape != other.tape) ||
                (namber != other.namber) ||
                (status != other.status) ||
                (name != other.name) ||
                (memcmp(buttonArray, other.buttonArray, sizeof(buttonArray)) != 0);
      
      }
      
      String name;
      byte buttonArray[11]; 
      static byte defButton[11];
      static uint32_t tmr;// перемінні для функціїnameProfiles(get_name_a_f) не переносити будуть глюки
      byte Flag;
      int deadZoneHor;//(primary початкова) початок руху
      byte sensitivityHor;
      int deadZoneVer;
      byte sensitivityVer;
      byte tape;
      byte namber;
      byte status;
  
    private:
      
      
  };
  
  // Ініціалізуємо статичну змінну класу Profiles
  uint32_t Profiles::tmr = 0;
  byte Profiles::defButton[11] = {0, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14};
  
  Profiles profilSeve(0, 0, 0, 0, 0, "0", 0, 0);
  
  Profiles profilSpOne(2000, 100, 2556, 92, "CodMW", t_sp, 1);
  Profiles profilSpTwo(166, 120, 1965, 112, "Batl3", t_sp, 2);
  Profiles profilSpThree(2000, 100, 2556, 92, "SP 33", t_sp, 3);
  Profiles profilSpFour(166, 120, 1965, 112, "SP 44", t_sp, 4);
  Profiles profilSpFive(2000, 100, 2556, 92, "SP 55", t_sp, 5);
  Profiles profilSpSix(166, 120, 1965, 112, "SP 66", t_sp, 6);
  Profiles profilSpSeven(2000, 100, 2556, 92, "SP 77", t_sp, 7);
  
  Profiles profilMpOne(2000, 100, 2556, 92, "0                   ", t_mp, 1);
  Profiles profilMpTwo(166, 120, 1965, 112, "Xmen                ", t_mp, 2);
  Profiles profilMpThree(2000, 100, 2556, 92, "Mp 3                ", t_mp, 3);
  Profiles profilMpFour(166, 120, 1965, 112, "Mp 4                ", t_mp, 4);
  Profiles profilMpFive(2000, 100, 2556, 92, "Mp 5                ", t_mp, 5);
  Profiles profilMpSix(166, 120, 1965, 112, "Mp 6                ", t_mp, 6);
  Profiles profilMpSeven(2000, 100, 2556, 92, "Mp 7                ", t_mp, 7);
 
  
  Profiles *prof(byte acceptedCommand, byte number = 0){ 
   
   static byte acting = 1;
  
   Profiles *profArray[] = {&profilSeve, &profilSpOne, &profilSpTwo, &profilSpThree, &profilSpFour, &profilSpFive, &profilSpSix, &profilSpSeven,
                       
   &profilMpOne, &profilMpTwo, &profilMpThree, &profilMpFour, &profilMpFive, &profilMpSix, &profilMpSeven};
    
    
    
    if (acceptedCommand == act_dir) {//скерування до активного профілю
    
     return profArray[acting];
   
    } 
    
    else if (acceptedCommand == direct_p_sp) {//скеровує до стандартного профіля Для певних настройок
    
     return profArray[number];
   
    }
    
    else if (acceptedCommand == direct_p_mp) {//скеровує до власного профіля Для певних настройок
    
     return profArray[number+7];
   
    }  
   
    else if (acceptedCommand == activate_p_sp || acceptedCommand == activate_p_mp) {//вибраний профіль активується

     for (int i = 1; i < 15; i++){ 
    
       profArray[i]->setStatus(r_off);

     }
  
     if (acceptedCommand == activate_p_sp ) {
       
       profArray[number] -> setStatus(r_on);
       acting = number;
      
     }
      
     else  {
      
       profArray[number+7] -> setStatus(r_on);
       acting = number+7;
      
     }
      
      
      EEPROM.put(0, acting);
      EEPROM.commit();
      //Serial.println("EEPROM");
      //Serial.println(EEPROM.get(0, acting));
    } 
    
    else if (acceptedCommand == eeprom_initialization) {
     
     EEPROM.get(0, acting);
    
    if (acting == 255) {
      
      acting = 1; 
   
    }
     
     profArray[acting] -> setStatus(r_on);
    
    }  
   
   
   return 0;
  }

//P

//Additional_elements 2
  
  bool Vibrgyro;
  // СПІЛЬНІ КОНСТАНТИ ПІД ХОД ДЛЯ БАГ ФУНК
  #define no_action 0 // НЕМА ДІЇ
  #define no_data 0 // немає даних
  #define no_indication 0   // немає вказівки
  #define off 0 
  #define get_status 1               // получити настройки
  #define yes 1
  #define save_settings 4           // зберехти настройки
  #define reset 11
  #define on 12
  #define click 13
  #define execute_code 14// execution without comman - виконання без команди
  #define gyro 15
  #define profil 16
  
  #define melody_start 1
  #define melody_off_power 2

  #define x_axis_hor 1
  #define y_axis_ver 2
  #define z_axis_ver 3


  #define get_y 2
  #define get_z 3
  #define get_vibr 4
  
   //Піни карта
  //#define b_mein 25
  #define b_triger 33
  #define b_analog 32
  #define b_on_off 14
  #define b_emul_dpad 26
  #define b_sw 32
  #define p_dt 34
  #define p_clk 35
 
  #define thandle_touch_button 27

 //Mf_EncoderButton();
  
  //#define click 13
  #define press 20
  #define hold 21
  #define reset_status 23
 
 
 //Md_Display(byte Receiving) {
  
  #define info_display 20
  #define menu 21 
  #define confirm_selection 22 

  #define lang_eng 25
  #define lang_ukr 26 
  #define click_in_dis_on 27

  //Md_MainDisplayENG();
  
  #define menu_off 21
  #define menu_start 22
  
  //byte Md_addres();
  
  //#define click 13
  #define back 20
  #define address_entered 21
  #define get_add 22
  #define int_add 23
  #define add_status 24
  #define int_add_last 25
  #define address_deleted 26
  #define click_reset_off 27
  
  //int Md_cursor();
  //#define reset 11
  #define selection_inversion 21
  #define freeze_position 22
  #define get_pos 23
  #define return_pos 24
  #define cursor_type_one 25
  #define cursor_type_two 26
 
  byte noData[1];
  byte posOne[] = {1};
  byte posTwo[] = {2};
  byte posThree[] = {3};
  byte posFour[] = {4};
  byte posFive[] = {5};
  byte posSix[] = {6};
  byte posEight[] = {7};
  
  //Ae_InterruptReadPinDtEncoder()
  //Mf_Encoder();
  #define rotated_rights 20
  #define rotated_left 21
  
  //MdAf_confirmYesNo()
  //MdAf_consenDisplay()
  #define choice_yes 20
  #define choice_no 21
  
  
  //MdAf_profileStorage()
  #define copy_profile 20
  #define return_save 21
  #define check_changes 22
  #define recorded_changes 23//зафіксовані зміни
  
  //Mf_Buttons()
  //#define reset 11
  #define next_animation 20
  
  byte bluetoothSimulation = 1;//TEST
    
  //int8_t Md_addres(int8_t addNumb = 0, int8_t acceptedCommand = 0, int8_t acceptedData = 0);
  byte Md_p_Buttons(byte receivedData = 0, byte selectedButton = 0);
  int Md_movingButtons(int acceptedCommand = 0);  
  byte Mf_EncoderButton(byte acceptedCommand = 0);
  byte MdAf_infoDisplay(byte acceptedCommand = 0);
  
  int8_t Ae_Countdown(int8_t acceptedCommand){
    
   static uint32_t tmr;
   
   if (!tmr) {tmr = (acceptedCommand+1) * 1000 + millis();}
   
   else if (acceptedCommand == reset) { tmr = 0;}
   acceptedCommand = ((tmr - millis()) / 1200) - 1;
   //Serial.println(acceptedCommand);
   
   return acceptedCommand;
  }
 
  byte Ae_BatR(byte Taking) {
   return !digitalRead(Taking);
  }
 
  void Ae_InterruptReadPinDtEncoder() {  //дивитися на початку в void setup працюэ разом з attachInterrupt(digitalPinToInterrupt(p_dt), Ae_InterruptReadPinDtEncoder, CHANGE);

   static int8_t clkStateCurrent;
   static int8_t clkStateLast;

   clkStateCurrent = digitalRead(p_clk);

    if ((clkStateLast == LOW) && (clkStateCurrent == HIGH)) {

      if (digitalRead(p_dt) == HIGH) {      
        
        Mf_encoderActionStorage(rotated_rights);
                  
      } else {
         
         Mf_encoderActionStorage(rotated_left);
                  
      }
    }

    clkStateLast = clkStateCurrent;       

  }

  void buttonOnOff(){

   if (!digitalRead(13)) { 
    
    delay(400); 
    esp_deep_sleep_start(); 
   
   }
  
   delay(100);

  }

//Ae

//Main_display 3
  
  // add1-----------------------------------------------------------------------------------------------------------
    
    void Md_MainDisplay() {// головна фунція виклик решта функцій дисплея
     
     display.clearDisplay();
      
      switch (Md_addres(1, int_add)) {
        
        case no_action: 
         
         MdAf_BluetoothPrint(); 
         MdAf_typeNumberPrint(); 
         MdAf_batteryPrint();

         Md_ItemOne();
        
         break;//1
       
        case 1:
          
          Md_Profile();
         
         break;//a2
        
        case 2:
          
          //qr-код ссылка на інструкцію
         
         break;//a2
        
        
        case address_entered:
          
            if (Md_addres(1, get_add) == 3) {
             
             Md_Display(info_display);
             Md_cursor(posOne, return_pos);
             Md_addres(1, back);         
            
            }
            
            else{
            
             Md_cursor(posOne, return_pos);
            
            } 
          
          break;
        
         
      }
     
     display.display();
    
    }
    
    void Md_ItemOne(){
      
        byte Lines[] = {22, 32, 43};
        Md_cursor(Lines, sizeof(Lines));
        
        display.setCursor(0, 22);
        display.println("  Profile");
        display.setCursor(0, 32);
        display.println("  Instruction ");
        display.setCursor(0, 43);
        display.println("  Exit menu ");
    
    }
  //
  // add2-----------------------------------------------------------------------------------------------------------
    
    void Md_Profile() {
      
      if (prof(act_dir)->getTape() == t_sp) {//в залежності від типу профілю вид меню міняється
      
        switch (Md_addres(2, int_add)) {
          
          case no_action: 
            
            Md_p_Profile();
           
           break;
          
          case 1:
           
            Md_ProfileSettings();
          
           break;//a3
          
          case 2:// QR code 
          
           break;
          
          case 3:
            
            Md_SelectProfile();
           
           break;//a3 
          
          case address_entered:
          
            if (Md_addres(2, get_add) == 4) {
            
             Md_cursor(posOne, return_pos);
             Md_addres(1, back);           
            
            }
            
            else{
             
             MdAf_profileStorage(copy_profile);////копіюємо профіль при доході в настройки p1 для подальшої перевірки на зміни при виході 
             Md_cursor(posOne, return_pos);
            
            } 
          
          break;
          
        }
      }   
      
      else {
    
        switch (Md_addres(2, int_add)) {
          
          case no_action: 
           
            Md_p_Profile();
          
           break;
          
          case 1://a3
            
            Md_ProfileSettings();
           
           break;
          
          case 2: //a3 
            
            Md_SelectProfile();
          
           break;
          
          case address_entered: 
          
            if (Md_addres(2, get_add) == 3) {
            
              Md_cursor(posOne, return_pos);
              Md_addres(1, back);
            
            }
            
            else{
             
             MdAf_profileStorage(copy_profile);
             Md_cursor(posOne, return_pos);
            
            } 
        
           break;
            
        }
      }   
    
    } 
   
    void Md_p_Profile() {
        
      byte LinesSp[] = {31, 39, 49, 57};
      byte LinesMp[] = {35, 49, 57};
      
      if (prof(act_dir)->getTape() == t_sp) {      
        
        Md_cursor(LinesSp, sizeof( LinesSp));
      
      } 
      
      else {
        
        Md_cursor(LinesMp, sizeof(LinesMp));
      
      }
      
      display.setCursor(3, 1);//стрілки по боках активний профіль
      display.write(25);
      display.setCursor(118, 1);
      display.write(25);
      
      display.drawRoundRect(0, 0, 127, 10, 2, WHITE);// РАМКА АКТИВ ПРОФ НАЗВА ГРИ
      display.drawRect(0, 9, 127, 19, WHITE);
      display.drawRect(10, 29, 51, 19, WHITE);// РАМКА НАСТРОЙКИ КЮАР КОД
      
      display.setCursor(21, 1);
      display.print("Active profile");
      
      display.setCursor(98, 36);       //РИСКА В лыво РАЗОМ ПОЛУЧАЭТСЯ КРИВА СТРЫЛКА
      display.println("_" );
      display.setCursor(93, 36);
      display.println("_" );
      display.setCursor(91, 36);// СТРЫЛКА ВВЕРХ РАЗОМ ПОЛУЧАЭТСЯ КРИВА СТРЫЛКА
      display.write(24);
      display.setCursor(91, 34);
      display.write(30);
      
      display.drawCircle(113, 42, 11, WHITE);// КРУГ НАВК Sp
      
      display.setCursor(105, 39);
      
      if (prof(act_dir)->getTape() == t_sp) { 
       
       display.print("Sp");
       display.println(prof(act_dir)->getNamber());
      
      }
      else {
       
       display.print("Mp");
       display.println(prof(act_dir)->getNamber());
      
      }
      
      display.setCursor(prof(act_dir)->centroName(), 15);//функція centroName() в залежності від кількості ім'я вранці
      display.println(prof(act_dir)->nameProfiles(get_name));
      
      display.setCursor(0, 32);       //РИСКА В ПРАВО РАЗОМ ПОЛУЧАЭТСЯ КРИВА СТРЫЛКА
      display.println("          _" );
      display.setCursor(4, 32);
      display.println("          _" );
      
      display.setCursor(66, 32);// СТРЫЛКА ВВЕРХ РАЗОМ ПОЛУЧАЭТСЯ КРИВА СТРЫЛКА
      display.write(24);
      display.setCursor(66, 30);
      display.write(30);
      
      
      
      if (prof(act_dir)->getTape() == t_sp) {      
       
       display.setCursor(0, 31);
       display.println("  Settings   " );
       display.println("  QR code");
      
      } 
      else { 
       
       display.setCursor(0, 35);
       display.println("  Settings   " );
      
      }
      
      display.setCursor(0, 49);
      display.println(" Select profile ");
      display.println(" Back" );
      
    }
    
   
    /*
    void Md_p_Settings() {
     
     display.setCursor(0, 0);
     display.println(" Hibernation ");
     display.println(" Sounds ");
     display.println(" Gamepad mode ");
     display.println(" Back" );
     
    }
   */
  //        
  // add3-----------------------------------------------------------------------------------------------------------

    void Md_SelectProfile() {
    
      switch (Md_addres(3, int_add)) {
        
        case no_action: 
          
          Md_p_SelectProfile();
         
         break;
        
        case 1: 
          
          Md_StandardProfiles();
         
         break;
        
        case 2: 
         
          Md_MyProfiles();
         
         break;
        
        case address_entered: 
         
          if (Md_addres(3, get_add) == 3) {
           
           if (prof(act_dir)->getTape() == t_sp) {  
            
            Md_cursor(posThree, return_pos);
           
           }
           
           else{
            
            Md_cursor(posTwo, return_pos);
           
           }
           
           Md_addres(2, back); 
          
          }
           
          else{ 

           Md_cursor(posOne, return_pos);
          
          } 
         
         break;
      
      }
    }
    
    void Md_p_SelectProfile() {
      
      byte Lines[] = {16, 24, 32};
      Md_cursor(Lines, sizeof(Lines));
    
      display.setCursor(0, 16);
      display.println(" Standard profiles" );
      display.println(" My profiles");
      display.println(" Back" );
    
    }
  
    void Md_ProfileSettings() {
      
      if (prof(act_dir)->getTape() == t_sp) { //вид пунктiv меню якщо профіль стандартний
        
        switch (Md_addres(3, int_add)) {
          
          case no_action: 
            
            Md_p_ProfileSettings();
           
           break;
          
          case 1:
            
            Md_Buttons();
           
           break;//Buttons
          
          case address_entered: 
         
            if (Md_addres(3, get_add) == 2) {
            
             Md_cursor(posOne, return_pos);
             Md_addres(2, back); 
            
            }
            
            else{

             Md_cursor(posOne, return_pos);
            
            } 
         
           break;
        }
      }
        
      else { // вид пунктів якщо вибрано власний профіль
 
        switch (Md_addres(3, int_add)) {
          
          case no_action: //a2

            Md_p_ProfileSettings();//відображення пунктів настройки
  
            break;
          
          case 1://Gyroscope //a4
            
            Md_gyroscopeSettings();
            
            break;
          
          case 2://Buttons
            
            Md_Buttons();
            
            break;
          
          case 3://Name
          
            Md_changeNameProfile();
          
            break;

          case 4:
            
            if (MdAf_profileStorage(check_changes) == recorded_changes) {//перевірка на наявність змін
          
              switch (MdAf_consenDisplay()) {//якщо є зміни запуститься дисплей підтвердження при виході з настройок
                
                case choice_yes:
                
                  MdAf_profileStorage(copy_profile);//якщо виберемо так профіль повторно скопірується і функція MdAf_profileStorage  перестане видавати recorded_changes
                  Md_addres(2, back);
                break;
                
                case choice_no:
                
                  MdAf_profileStorage(return_save);//якщо виберемо Ні функція dAf_profileStorage перестане видавати recorded_changes і  умова перестане  виконуватися
                  Md_addres(2, back);
                break;
              
              }
            }else{
              
              Md_addres(2, back);
              
            }
            
            break;
          
          case address_entered: 
    
            Md_cursor(posOne, return_pos);
          
            break;
          
        }
      }
    }
       
    void  Md_p_ProfileSettings() {
      
      byte LinesSp[] = {16, 24};
      byte LinesMp[] = {16, 24, 32, 50};
      
      if (prof(act_dir)->getTape() == t_sp) {      
        
        Md_cursor(LinesSp, sizeof(LinesSp));
        display.setCursor(0, 16);
        display.println(" Buttons" );//не добавляти пункт reset не потрібно
        display.println(" Back" );
      
      } else {
        Md_cursor(LinesMp, sizeof(LinesMp));

        display.drawRoundRect(9, 14, 59, 28, 0, WHITE);
        
        display.setCursor(0, 16);
        display.println("  Gyroscope" );
        display.println("  Buttons" );
        display.println("  Name" );
        
        display.setCursor(0, 50);
        display.println(" Back" );
      }

    }
  //                
  // add4-----------------------------------------------------------------------------------------------------------
    
    void Md_StandardProfiles() {
    
      
      switch (Md_addres(4, int_add)) {
        
        case no_action: 
        
          Md_p_StandardProfiles();//відображення списку профілів вибір
        
         break;
        
        case address_entered: 
         
          if (Md_addres(4, get_add) == 8) {
          
            Md_cursor(posOne, return_pos);
            Md_addres(3, back);
          
          }
          
          else{

           
            if (prof(act_dir)->getNamberTape() != prof(direct_p_sp, Md_addres(4, get_add))->getNamberTape()) {
           
             prof(activate_p_sp, Md_addres(4, get_add));
             Md_cursor(posOne, return_pos);
             Md_addres(2, back); 
            
            }
          
            else{Md_addres(4, back); }
          
          }

         break;
 
      }
    }
    
    void Md_p_StandardProfiles(){
      
      byte Lines[] = {0, 8, 16, 24, 32, 40, 48, 56};
      Md_cursor(Lines, sizeof(Lines));
    
      for (int i = 0; i < 7; i++) {//виводим імена профілів діючий профіль мигає
      
       display.setCursor(6, i*8);
       display.print(prof(direct_p_sp, i+1)->nameProfiles(get_name_a_f));
      
      }
      
      display.setCursor(0, 56);
      display.println(" Back" );
    
    }
    
    void Md_MyProfiles(){
     
      switch (Md_addres(4, int_add)){//третій параметр забороняє вибирати діючий профіль
        
        case no_action: 
           
           Md_p_MyProfiles();
          
          break;
        
        case address_entered: 
         
          if (Md_addres(4, get_add) == 8) {//повертаємося в передній пункт
          
            Md_cursor(posOne, return_pos);
            Md_addres(3, back);
          
          }
          
           else{//якщо вибраний профіль не є діючий виконуємо заміну якщо так просто повертаємося

            if (prof(act_dir)->getNamberTape() != prof(direct_p_mp, Md_addres(4, get_add))->getNamberTape()) {
           
             prof(activate_p_mp, Md_addres(4, get_add));
             Md_cursor(posOne, return_pos);
             Md_addres(2, back);//не міняти двоєчку будуть глюки
            
            }
          
            else{Md_addres(4, back);}
          
          }

         break;
        
      }
    }
    
    void  Md_p_MyProfiles() {
      
      byte Lines[] = {0, 8, 16, 24, 32, 40, 48, 56};
      Md_cursor(Lines, sizeof(Lines));
    
      for (int i = 0; i < 7; i++) {
      
       display.setCursor(6, i*8);
       display.print(prof(direct_p_mp, i+1)->nameProfiles(get_name_a_f));
      
      }
      
      display.setCursor(6, 56);
      display.println("Back" );
    
    }
   
    void Md_gyroscopeSettings(){//a3
      
      int seveData;//використовую щоб було більш зрозуміліше

      if (Md_addres(4, get_add) != 5){Md_p_gyroscopeSettings();}
      
      switch (Md_addres(4, int_add_last)) {//4
        
        case no_action:break;
        
        case 1:
          
          seveData = Mf_Magnifier(prof(act_dir)->getDeZoHor(), 0, 9999, 100);
          prof(act_dir)->setDeZoHor(seveData);
         
         break;
        case 2:
          
          seveData = Mf_Magnifier(prof(act_dir)->getSenHor(), 0, 100, 100);
          prof(act_dir)->setSenHor(seveData);
         
         break;
        case 3:
          
          seveData = Mf_Magnifier(prof(act_dir)->getDeZoVer(), 0, 9999, 100);
          prof(act_dir)->setDeZoVer(seveData);
        
         break;
        
        case 4:
          
          seveData = Mf_Magnifier(prof(act_dir)->getSenVer(), 0, 100, 100);
          prof(act_dir)->setSenVer(seveData);        
         
         break;
        
        case 5:
          
          Md_cursor(posOne, return_pos);
          Md_addres(3, back);   
         
         break;
      
      }
    }
  
    void Md_p_gyroscopeSettings(){
      
      static uint32_t tmr;
      static byte dashFlag;//прапорець м'ягання
      
      if (tmr < millis()) {
        
        tmr = millis() + 500;
        dashFlag = ! dashFlag;
      
      }
     
      byte Lines[] = {5, 15, 34, 44, 55};
      Md_cursor(Lines, sizeof(Lines));
    
      display.setCursor(8, 5);
      display.println("Dead zone ");
      display.setCursor(8, 15);
      display.println("Sensitivity");
      display.setCursor(8, 34);
      display.println("Dead zone ");
      display.setCursor(8, 44);
      display.println("Sensitivity");
      display.setCursor(8, 55);
      display.println("Back");
      
      display.setCursor(84, 10);
      display.println("H");
    
      display.setCursor(84, 39);
      display.println("V");
      
      display.setCursor(102, 4);
      display.println(prof(act_dir)->getDeZoHor());
    
      display.setCursor(104, 17);
      display.println(prof(act_dir)->getSenHor());
      
      display.setCursor(102, 33);
      display.println(prof(act_dir)->getDeZoVer());
      
      display.setCursor(104, 46);
      display.println(prof(act_dir)->getSenVer());
      
      
      display.drawRoundRect(6, 2, 69, 23, 3, WHITE); //РАМКА НАВКОЛО Dead zone Sensitivity H
      display.drawRoundRect(6, 31, 69, 23, 0, WHITE);//РАМКА НАВКОЛО Dead zone Sensitivity V
      
      //H
      if((Md_cursor(noData, get_pos) == 1 || Md_cursor(noData, get_pos) == 2) && !Md_addres(4, get_add)){// РАМКА  НВКОЛО H
       
       if(dashFlag){display.drawRoundRect(79, 6, 15, 15, 0, WHITE);}
      
      }
      
      else{display.drawRoundRect(79, 6, 15, 15, 0, WHITE);}
      
      //V
      if((Md_cursor(noData, get_pos) == 3 || Md_cursor(noData, get_pos) == 4) && !Md_addres(4, get_add)){// РАМКА  НВКОЛО V
       
       if(dashFlag){display.drawCircle(86, 42, 7, WHITE);}
      
      }
      
      else{display.drawCircle(86, 42, 7, WHITE);}   
      
      
      if(Md_addres(4, get_add) == 1){ // число рамка DZ H
       
       if(dashFlag){display.drawRoundRect(99, 2, 29, 11, 4, WHITE);}
      
      }
      
      else{display.drawRoundRect(99, 2, 29, 11, 4, WHITE);}
      
      if(Md_addres(4, get_add) == 2){ // число рамка S H
      
       if(dashFlag){display.drawRect(101, 15, 23, 11, WHITE);}
      
      }
      
      else{display.drawRect(101, 15, 23, 11, WHITE);}
      
      if(Md_addres(4, get_add) == 3){ // число рамка DZ V
      
       if(dashFlag){display.drawRect(99, 31, 29, 11, WHITE);}
      
      }
      
      else{display.drawRect(99, 31, 29, 11, WHITE);}

      if(Md_addres(4, get_add) == 4){ // число рамка S V
       
       if(dashFlag){display.drawRoundRect(101, 44, 23, 11, 4, WHITE);}
      
      }
      
      else{display.drawRoundRect(101, 44, 23, 11, 4, WHITE);} 
       
    }

    void Md_Buttons() {//замінити if на Switch в кінці при використанні свіч глюки

      Md_p_Buttons();
     
      if(Md_addres(no_data, add_status) == address_deleted){//якщо адрес був видалений скидає функцію
        
        Md_p_Buttons(reset);
        Md_movingButtons(reset);
      
      }  

      switch (Md_addres(4, int_add_last)) {
        
        case no_action:

         break;
        
        case 1:
          
          Md_movingButtons();
             
         break;
        
        case 2:
          
          switch (MdAf_confirmYesNo(37, 46)) {
            
            case no_action:

             break;
           
            case choice_yes:
              
              Md_addres(4, back);
              prof(act_dir)->resetButtons();

             break;
           
            case choice_no:

              Md_addres(4, back);
             
             break;
          
          }
          
         break;
        
        case 3:
           
          Md_cursor(posTwo, return_pos);
          Md_addres(3, back);
         
         break;
        
        case address_entered:
          
          Serial.print("address_entered");
          if(Md_addres(4, get_add) == 1){
          
           Md_p_Buttons(next_animation); 
          
          }
          
          else if(Md_addres(4, get_add) == 2){
           
           
           Md_addres(no_data, click_reset_off);//потрібно для того щоб Клік працював тепер в функції MdAf_confirmYesNo(37, 46)
          
          }
         
         break;

      }
      
    }
    
    int Md_movingButtons(int acceptedCommand){//не закінчено тест кнопки опитуються не повністю
      
      static unsigned long tmr;//таймер для захисту від тремтіння контактів кнопки
      static int8_t buttonFlag;//затвор кнопки захист від тремтіння
      static int8_t sequenceNumber;//при першому натиску зберігаємо порядковий номер піна-кнопки яка спрацювала


      if (acceptedCommand == reset) { 
       
       buttonFlag = sequenceNumber = 0;
       
       return 0;
      
      }
      
      else if (!buttonFlag && tmr < millis()) { //кнопка одноразово спрацьовує з захистом
            
        for (int i = 1; i <= 10; i++) {
          
          if (!digitalRead(prof(act_dir)->buttonArray[i])) {
            
            //Serial.println(i);
            tmr = millis()+500;
            buttonFlag = 1;
            Md_p_Buttons(next_animation, i); 
            
            if(!sequenceNumber){//якщо була натиснута перша кнопка зберігаємо порядковий номер
              
              sequenceNumber = i;
            
            }else{//якщо натиснули другу кнопку міняємо місцями елементи масиву-кнопки
              
              int temp = prof(act_dir)->buttonArray[sequenceNumber];// переміщення даних між елементами масиву Напряги мозги і поймеш
              prof(act_dir)->buttonArray[sequenceNumber] = prof(act_dir)->buttonArray[i];
              prof(act_dir)->buttonArray[i] = temp;
              buttonFlag = sequenceNumber = 0;
              Md_addres(4, back); 
              
            }

            break;
          }
        }
      }
        
      else if (buttonFlag && tmr < millis() && digitalRead(prof(act_dir)->buttonArray[sequenceNumber])) {//захист від брязки до першої кнопки захист натиску другої кнопки не потрібен програма завершує роботу
      
        buttonFlag = 0;
          
      }  
    
     return 0;
    
    }
    
    void Md_resetButtons(){///масив буде потрібно змінити в кінці
                
      const byte defaultButton[] = {0, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14};

      for (int i = 0; i < sizeof(defaultButton); i++) {
        
        prof(act_dir)->buttonArray[i] = defaultButton[i];
      
      }

    }

    byte Md_p_Buttons(byte receivedData, byte selectedButton){
      
      //бегуща стрілка. анімація. кнопка один збереження. крапка 2 збереження. анімація кнопка ліва. анімація кнопка права
      static byte runningArrow, animation, buttonOne, buttonTwo, accumulationL, accumulationR;
       
      static unsigned long tmr; //таймер для виконання анімації
      
      const char *buttonNames[] = {//масив імена кнопок виводим при натиску
        " ",
        "A",
        "B",
        "X",
        "Y",
        "LB",
        "RB",
        "LT",
        "RT",
        "LA",
        "RA",
      };
      
      display.drawRect(6, 5, 31, 31, WHITE); // квадрат L
      display.drawRect(90, 5, 31, 31, WHITE);// квадрат R
      
      display.drawCircle(21, 16, 8, WHITE);//кружки над кнопками
      display.drawCircle(105, 16, 8, WHITE);
      
      display.drawRect(12, 26+accumulationL, 19, 5, WHITE);//ліва кнопка accumulationL збільшення зменшення анімація кнопки
      display.fillRect(9, 30, 25, 4, WHITE);
      
      display.drawRect(96, 26+accumulationR, 19, 5, WHITE);//ПРАВА кнопка accumulationR збільшення зменшення анімація кнопки
      display.fillRect(93, 30, 25, 4, WHITE);
      
      byte Lines[] = {40, 48, 56};//передаємо координати переміщення функції
      Md_cursor(Lines, sizeof(Lines));
      
      display.setCursor(0, 40);//понятно
      display.println(" Move buttons");
      display.println(" Reset");      
      display.println(" Back");
      
      if (!receivedData && !animation) {//якщо фаус то закінчуємо роботу функції економія ресурсів
        
        return 0;
      
      }
      
      if (receivedData == reset) {
       
       animation = accumulationL = accumulationR = runningArrow = 0;
      
      }  
      
      else if (receivedData == next_animation) {//в коді викликаємо функцію переключаємо анімацію
        
        accumulationL = accumulationR = runningArrow = 0;
        
        if (animation != 3) {
         
         animation++;
        
        }
        if (animation == 2) {
         
         buttonOne = selectedButton;
        
        }else if (animation == 3) {
        
         buttonTwo = selectedButton;
         tmr = millis()+1000;
        
        }
      
      }
     
      if (animation == 1 && tmr < millis()) { //анімація кнопок за допомогою перемінної
       
        accumulationL++;
        
        if (accumulationL == 4) {
        
         accumulationL = 0;
        
        }
 
      }
      
      else if (animation == 2 && tmr < millis()) {
   
        accumulationR++;
        runningArrow++;
        
        if (accumulationR == 4 ) {
        
         accumulationR = 0;
        
        }
      
        if (runningArrow == 8 ) {
        
         runningArrow = 0;
        
        }
      
      }
      
      else if (animation == 3 && tmr < millis()) {//відображення другої кнопки завершення роботи з запізнення
       
        animation = 0;
    
      }
      
      if (animation == 1 ) {
        
        if (accumulationL){//знак запитання мигає якщо кнопка не натиснута
         
         display.setCursor(19, 13); 
         display.println('?');
        
        }
      
      } 

      else if (animation == 2 ) {
        
        display.setCursor(22-strlen(buttonNames[buttonOne])*3, 13);//strlen автоцентровка в колі може бути одна або дві букви
        display.println(buttonNames[buttonOne]);
       
        if(accumulationR){//знак запитання мигає якщо кнопка не натиснута
        
         display.setCursor(103, 13); 
         display.println('?');
       
        }
       
        for (int i = 0; i < 8; ++i) {//відображаємо кутові складки
        
         display.setCursor(40+i*6, 13);
         display.write(62);
      
        } 
      
        display.setCursor(40+runningArrow*6, 13);//трикутник переміщається по углових скобках анімація
        display.write(16);
      
      }
      
      else if (animation == 3 ) {//завершення програми відображення натиснутих кнопок
        
       display.setCursor(22-strlen(buttonNames[buttonOne])*3, 13);
       display.println(buttonNames[buttonOne]);
      
       display.setCursor(106-strlen(buttonNames[buttonTwo])*3, 13);
       display.println(buttonNames[buttonTwo]);

      }
      
      if (tmr < millis()) {//всі дії виконуються по таймеру
       
       tmr = millis()+400; 
      
      }

      return 0; 
      
    }
     
    void Md_changeNameProfile(){
      
      static int8_t AxisX, AxisY, storedAction, inputIndicator, axisChange;
      static uint32_t tmr;
    
     char letterBig[5][10] = {
        {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9'},
        {'Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I', 'O', 'P'},
        {'A', 'S', 'D', 'F', 'G', 'H', 'J', 'K', 'L', '-'},
        {'!', 'Z', 'X', 'C', 'V', 'B', 'N', 'M', '.', '<'},
        {' ', ' ', ' ', ' ', ' ', ' ', ' ', '>', '>', '>'}
      };
      
      char letterSmall[5][10] = {
        {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9'},
        {'q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p'},
        {'a', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l', '-'},
        {'!', 'z', 'x', 'c', 'v', 'b', 'n', 'm', '.', '<'},
        {' ', ' ', ' ', ' ', ' ', ' ', ' ', '>', '>', '>'}
      };
    
     static char (*ptrLetter)[10] = letterSmall;//вказівник вказує в залежності від настройки на великі або малі букви
       
      if (!inputIndicator && ptrLetter == letterSmall && !storedAction) {//якщо видаляється остання буква одноразово всі букви робляться великими
        
        storedAction = 1;
        
        for (int i = 19; i >= 0; i--) {
         
          if (prof(act_dir)->nameProfiles(get_name)[i] != ' '){
           
           inputIndicator = i+1;
          
           break;
          }
          
          else if (!i){
           
           ptrLetter = letterBig;
           inputIndicator = 0;
          
           break;
          
          }
        
        }
      }
      
      else if (inputIndicator && storedAction) {
        
        storedAction = 0;
      
      }
      
      switch (Mf_EncoderButton()) {
        
        case click:
          
          switch (ptrLetter[AxisY][AxisX]) {
            
            case '!': //міняємо величину букв
              
              if (ptrLetter == letterBig) {
                
                ptrLetter = letterSmall;
              
              }
              
              else {
                
                ptrLetter = letterBig;
              
              }
              
             break;
            
            case '>'://вихыд
              
              AxisX = AxisY = inputIndicator = 0;
              Md_cursor(posThree, return_pos);
              Md_addres(3, back);
  
             break;
            
            case '<': //видаляємо букви
               
              if (inputIndicator ) {
              
               inputIndicator--;
               prof(act_dir)->nameProfiles(change_letter, inputIndicator, ' ');
              
              }
              
             break;
            
            default://введення вибраної букви
              
              if (inputIndicator <= 19) {//обмеження на кількість букв
               
                prof(act_dir)->nameProfiles(change_letter, inputIndicator, ptrLetter [AxisY][AxisX]);
                
                
                if (inputIndicator == 0) {//якщо вводиться перша буква всі букви стають малими одноразовo
                 
                 ptrLetter = letterSmall;
                
                }
                
                
                inputIndicator++;
              
              }        
          
          }   
          break;

      }
      
      if (!axisChange && Mf_EncoderButton(get_status) == press && Mf_encoderActionStorage(get_status)) {///проверяем статус кнопки якщо енкодер спрацьовує то міняємо режими роботи курсора
       
       Mf_EncoderButton(reset_status);
       axisChange = 1;
       
      }
      
      else if (axisChange && !Mf_EncoderButton(get_status)) {
     
       axisChange = 0;
       
        if (AxisY == 4 ){//переміщаємо курсор для коректної роботи якщо останній масив
            
          if (AxisX <= 7){
            
            AxisX = 0;
          
          }
          
          else{
          
           AxisX = 9;
          
          }
          
        }

      }
      
      switch (Mf_encoderActionStorage(get_status)) {
        
        case 0: 
        
        break;
        
        case rotated_rights: 
          
          if (!axisChange) {AxisX--;}//\переміщення в залежності від режиму
          else {AxisY--;}  
          
          if (AxisY == 4 && AxisX == 8) {//корекція курсора якщо попали на останній масив костильі)
            AxisX = 0;
          }
          if (AxisX < 0) {
           AxisX = 9;
           AxisY--;
          }
          if (AxisY < 0) {AxisY = 4;}
        
         break;
        
        case rotated_left: 
          
          if (!axisChange) {AxisX++;}
          else {AxisY++;}  
          
          if (AxisY == 4 && AxisX == 1) {
          AxisX = 9;
          }
          if (AxisX > 9) {
           AxisX = 0;
           AxisY++;
          } 
          if (AxisY > 4 ) {AxisY = 0;} 
        
         break;   
      }
      
      Md_p_changeNameProfile(ptrLetter, inputIndicator, AxisX, AxisY);

    }
    
    byte Md_p_changeNameProfile(char letter[][10], byte inputIndicator, byte AxisX, byte AxisY){
      
      static char tracking;//використовується для відслідковування позиції рамки
      char str[] = {'!', '<', ' ', '>'};//маси використовується для мигання необхідної рамки
      static byte flagBlink[5];
      static uint32_t tmr, tmrInd;
      
      display.setCursor(6, 44);///набір різних стрілок
      
      if(letter[1][1] == 'W'){//якщо в масиві є великі букви значить стрілочка вниз
        
        display.write(25);//стрілочка вниз малі букви
      
      }
      else{display.write(24);}//стрілочка вверх великі букви
      
      display.setCursor(114, 54);//back
      display.print('s'); 
      display.drawPixel(120, 60, WHITE); //крапка
      
      if(!flagBlink[0]){//кружок стрілка вниз вверх
       
       display.drawCircle(8, 47, 5, WHITE);
      
      }
      
      if(!flagBlink[1]){// видалення
        
        display.setCursor(114, 43);
        display.print('x'); 
        display.drawCircle(116, 47, 4, WHITE);
      
      }
      
      display.fillRect(36, 54, 54, 6, WHITE);//пробіл
      
      if(letter[AxisY][AxisX] == ' '){//додаткова рамка якщо навели на пробіл
       
       display.drawRect(34, 52, 58, 10, WHITE);
      
      }
      
      if(!flagBlink[3]){//рамка s.
       
       display.drawRoundRect(112, 54, 9, 9, 0, WHITE);
      
      }
      
      for (int i = 0; i < 4; i++) {
        
        if(tracking != letter[AxisY][AxisX]){//можливі розрив захист від зникнення рамки
          
          flagBlink[0] = flagBlink[1] = flagBlink[2] = flagBlink[3] = tmr = 0;//якщо було переміщення обнуляємо всі переміни 
          tracking = letter[AxisY][AxisX];//перезаписуємо перемінно новими даними
        
        }

        if(letter[AxisY][AxisX] == str[i]){

         if(tmr < millis()){
          
          tmr = millis()+400;
          flagBlink[i] = !flagBlink[i];
         
         }
         
         break;
        }
        
        else if(i == 3 ){//
          
          display.drawRect(4+AxisX*12, 12+AxisY*10, 9, 11, WHITE);//рамка курса 10 вверх вниз, вліво вправо 12 
          break;
        
        }
      }
        
      if(inputIndicator != 20){//вертикальна риска біля букви мигання 
        
        if(tmrInd < millis()){
          
          tmrInd = millis()+400;
          flagBlink[4] = !flagBlink[4];
        
        }        
      }
      
      if(flagBlink[4] || inputIndicator == 20){//перестає мигати якщо 20 символів
       
        display.drawRect(2+6*inputIndicator, 0, 1, 9, WHITE);
      
      }
      
      display.setCursor(2, 1);//виводив ім'я профіля
      display.print(prof(act_dir)->getName());
      
      for (int i = 0; i < 4; i++) {//виводим масив букв на дисплей
        
        for (int j = 0; j < 10; j++) {
          
          display.setCursor(6+j*12, 14+i*10);
          
          if(letter[i][j] != '!' && letter[i][j] != '<'){//ці знаки не можна виводити використовується для виконання дій
           
           display.print(letter[i][j]);
          
          }
        }
      }
      
      return 0; 
    }
  
  //
  // Md_Additional functions-------------------------------------------------------------------------------------------
    
    byte MdAf_consenDisplay(){ //викликається для підтвердження вибору
      
      static int8_t flagChoice;
      
      switch (Mf_encoderActionStorage(get_status)) {//керування рамкою вліво вправо
       
        case no_action: 
          
          break;
        
        case rotated_rights: 
          
          if (flagChoice > -2) {
           
           flagChoice--;
          
          }
          
         break;
        
        case rotated_left: 
          
          if (flagChoice < 2) {
           
           flagChoice++;
          
          } 
          
         break;
      }
      
      if ((flagChoice == -2 || flagChoice == 2) && Mf_EncoderButton() == click) {// V1 якщо відбувся Клік виконується дії в залежності від вибору
        
        if (flagChoice == -2) {//якщо вибрали ні виконуються дії//вихід виконується в любому випадку з збереженими настройками або ні
           
          flagChoice = 0;
          return choice_no;
        
        }
        
        else if (flagChoice == 2) {
           
          flagChoice = 0;
          return choice_yes;
        
        }
        
      }
            
      MdAf_p_consenDisplay(flagChoice);//візуальна частина коду
    
     return 0;
    
    }
      
    int8_t MdAf_p_consenDisplay(int8_t acceptedFlag){
      
      static uint32_t tmr;
      static int8_t FlagFrame;
    
      display.drawRoundRect(20, 8, 87, 22, 0, WHITE); //рамка навколо слова зверху
      display.setCursor(25, 15); 
      display.println("Save settings");
      if (tmr < millis()) {// виконує механія рамкою навколо слова так ні
        
        tmr = millis() + 400;
        FlagFrame = !FlagFrame;
      
      }
      
      if (FlagFrame) {//виводим рамку навколо слова і мигаємо нею
       
       display.drawRect(52+acceptedFlag*18, 39, 21, 13, WHITE);//переміна приймає число від -2 до +2 І в залежності від числа міняє координати рамки
      
      }

      for (int i=39; i <= 75; i+=18){//відображаємо стрілки вліво вправо
       
       display.setCursor(i,42);
       display.write(27);display.write(26); 
      
      }
      
      display.setCursor(21, 42);
      display.println("NO");
      display.setCursor(18, 42);
      display.println("            YES");
      
      return 0;
    
    }
    
    byte MdAf_profileStorage(byte acceptedCommand) {//функція викликається якщо Md_addres(3, get_add) == 1
     
      switch (acceptedCommand) {//false якщо повертаємо збережені настройки
        
        case return_save:
           
           prof(act_dir)->copyFrom(profilSeve);//це означає що ми вибрали ні і повертаємо настройки
          
          break;
       
        case copy_profile:
           
           profilSeve.copyFrom(*prof(act_dir));//копіювання діючий профіль перед доходом в настройки
          
          break;
        
        case check_changes:
  
           if (profilSeve != *prof(act_dir)) {return recorded_changes;}
          
          break;
      }
      return 0;
    }
      
    byte MdAf_reminderDisplay(byte acceptedCommand) {

      static uint32_t tmr;

      display.clearDisplay();

      display.drawRect(0, 14, 127, 30, WHITE);// РАМКА НАВКОЛО НАЗВИ

      if (acceptedCommand == reset) {
        tmr = 0;
      }
      else if (!tmr) {
        tmr = millis() + 2000;
      }
      else if (tmr < millis()) {
        tmr = 0;
        Md_Display(info_display);
      }

      display.setCursor(0, 16);

      display.println("  Read instruction");// НАГАДУВАННЯ
      display.println("   " );//27
      display.println(" Make game settings " );//27

      display.setCursor(60, 50);
      display.print("b");

      display.drawCircle(62, 53, 6, WHITE);//кружок

      display.display();
    }

    byte MdAf_infoDisplay(byte acceptedCommand) {

      static byte flagPermit = 1;

      if (acceptedCommand) {
       
        if (acceptedCommand == reset) {
       
         flagPermit = 1;
         return 0;
        
        }
        
        else if (acceptedCommand == get_status) {

         return flagPermit;
        
        }

      }
      //if (flagPermit || !bleGamepad.isConnected()) {
      if (flagPermit) {
        
        if (flagPermit) {
         
         flagPermit = 0;
        
        }
        display.clearDisplay();//не забути доробити періодичне виведення

        MdAf_BluetoothPrint(); 
        MdAf_typeNumberPrint();
        MdAf_batteryPrint();

        display.drawRect(0, 14, 127, 19, WHITE);// РАМКА НАВКОЛО НАЗВИ

        display.setCursor(prof(act_dir)->centroName(), 20);// функція centroName() в залежності від кількості ім'я вранці
        display.print(prof(act_dir)->nameProfiles(get_name));
        
        display.setCursor(44,44);
        display.write(26);
        
        display.drawRect(50, 42, 27, 11, WHITE);
        display.setCursor(52,44);
        display.print("Menu");
        
        display.display();

      }

     return 0;
    
    }

    void MdAf_BluetoothPrint() {

      static uint32_t tmr;
      static byte Flag;
      
      display.drawCircle(6, 6, 6, WHITE);//кружок
      display.setCursor(4, 3);
      
      if (bluetoothSimulation) {

        display.print("b");
      
      }
      
      else{
        
        if (tmr < millis()) {
         
         Flag = !Flag;
         tmr = millis() + 1000;
        
        }
        
        if (Flag) {
         
         display.print("b");
        
        }

      }
  
    }

    void MdAf_batteryPrint() {

      display.setCursor(17 * 6, 0);
      display.print("123");

    }

    void MdAf_typeNumberPrint() {
      
      display.setCursor(49, 0);
      if (prof(act_dir)->getTape() == t_sp) { 
       
       display.print("(Sp");
       display.print(prof(act_dir)->getNamber());
       
      }
      else {
       
       display.print("(Mp");
       display.print(prof(act_dir)->getNamber());
      }
      display.print(")");
    }
    
    byte MdAf_confirmYesNo(byte azixX, byte azixY){
     
     //функцію можна відобразити в любому місці біля слова рецепт після завершення потрібно скинути вручну
      static byte flagChoice;
       
      if (Mf_encoderActionStorage(get_status)) {
      
       flagChoice = !flagChoice;
      
      }
      
      if (Mf_EncoderButton() == click) {
        
        byte temp = flagChoice;      
        flagChoice = 0; 
        
        if (!temp) {
         Serial.print("yes");
         return choice_no;
        
        }else{
         
         return choice_yes;
        
        }

      }
      
      display.setCursor(azixX+4, azixY+4);
      display.println("NO   YES");
      
      
      if(!flagChoice) {
      
       display.drawRect(azixX+2, azixY+2, 15, 11, WHITE);//NO
      
      }else{
      
       display.drawRect(azixX+32, azixY+2, 21, 11, WHITE);//YES
      
      }
      
      display.drawRect(37, 46, 55, 15, WHITE);//рамка навколо так ні
      //MdAf_p_confirmYesNo(flagChoice, 37, 46);
    
      return 0;
    
    } 
  
  
  // Md_Af
//Md

//Display 4
  byte Md_Display(byte Receiving) { 
     
    static byte Regime = info_display; 
    //static byte Regime = menu;
      
      switch (Receiving) {
        
        case get_status: 
          
           return Regime;
          
          break;
        
        case menu: 

          Regime = menu;
          
          break;
        
        case info_display: 
          
          Regime = info_display;
        
          break;
        
      }
    
   return Regime;
  } 

//D

//Menu_functions 5 
 
  byte Md_cursor(byte* arr, byte dataCommand) { 
    
    static int8_t permissionArrow, Point = 1, workPermit = 1;
        
    switch (dataCommand) {
      
      case return_pos: 
          
        Point = arr[0];
        permissionArrow = 0;
        
       break;
      
      case cursor_type_two: 
          
        permissionArrow = 1;
        
       break;
      
      case cursor_type_one: 
          
        permissionArrow = 0;
        
       break;
      
      case get_pos: 
         
        return Point; 
       
       break;
      
      default:

          if(!permissionArrow){
          
            switch (Mf_encoderActionStorage(get_status)) {
              case no_action: 
                
                break;
              case rotated_left: 
                Point--;
                if (Point == 0) {Point = dataCommand;}
                
                break;
              case rotated_rights: 
                Point++;
                if (dataCommand < Point) {Point = 1;}
                
                break;
            }
          
          } 
          
          if (!permissionArrow) {
            display.setCursor(0, arr[Point-1]);  //21,8 максимум символів
            display.write(26);
            }
          else if (permissionArrow) {
            display.setCursor(0, arr[Point-1]);  //21,8 максимум символів
            display.write(16);
          }   
        
        
    } 
   
   return 0;
  
  } 
    
  int8_t Md_addres(int8_t addNumb, int8_t acceptedCommand) {

    static byte adr[19], modeSwitch = 1, namb = 1, workPermit = 1, del;

    switch (acceptedCommand) {
      
      case back:
         Serial.print("case back:");
        Md_cursor(noData, cursor_type_one);
        workPermit = modeSwitch = 1;
        
        for (int i=18; i >= 1; i--){//команда back виконує видалення всіх адресів до числа вказаного в addNumb
          
          adr[i] = 0;
          
          if (i == addNumb) {
            
            namb = addNumb;
            break;
          
          }
        
        }
       
       break;
      
      case get_add:
        
        return adr[addNumb];
       
       break;
      
      case add_status:
        
        if (del){
         
         del = 0;
         return address_deleted;
        
        }
       
       break;        
      
      case click_reset_off:
        
        workPermit = 0;
         
       break; 
      
      case int_add:
        
        if (!adr[addNumb] && Mf_EncoderButton() == click){//набір адреса
        
         adr[namb] = Md_cursor(noData, get_pos);//позиція курс означає набраний адрес
         namb++;

         return address_entered;
        
        }

       break; 
      
      case int_add_last:
        
        if (workPermit && Mf_EncoderButton() == click){//набір адреса
        
          if (modeSwitch){ 
          
           adr[namb] = Md_cursor(noData, get_pos);//позиція курс означає набраний адрес
           Md_cursor(noData, cursor_type_two);//міняємо вид курсора
           modeSwitch = 0;//міняємо флажок наступний кліп буде означати скидання адресу
          
           return address_entered;
          
          }
          
          else if (!modeSwitch){
        
           adr[namb] = 0;
           del = modeSwitch = 1;
           Md_cursor(noData, cursor_type_one);//міняємо вид курсора
          
          }
        }  
        
       break; 
    
    }
    
    return adr[addNumb];

  }
 
  int8_t Mf_encoderActionStorage(int8_t acceptedCommand) {

    static int8_t operationRetention;//збереження спрацювання
  
    if (acceptedCommand == rotated_left || acceptedCommand == rotated_rights) {
    
     operationRetention = acceptedCommand;
    
    }
    
    else if (acceptedCommand == get_status) {
      
      acceptedCommand = operationRetention;
      operationRetention = 0;
      return acceptedCommand;
    
    }
    
    return 0;
  
  }
  
  
 
  byte Mf_EncoderButton(byte acceptedCommand) {

    static byte buttonState;
    static uint32_t tmr;
    
    if (acceptedCommand == reset){
     
     buttonState = reset_status;
     
    }
    
    else if (acceptedCommand == get_status){ 
     
     return buttonState;
    
    }
    
    if (Ae_BatR(b_sw) && buttonState != reset_status){
      
      if (!buttonState) {
        
        buttonState = press; 
        tmr = millis() + 500; 
        return press;
      
      }
      
      else if (tmr < millis()) {
        
        buttonState = hold; 
        tmr = 0; 
        return hold;
      
      }

    }

    else if (buttonState && !Ae_BatR(b_sw)){
      
      byte temp = buttonState;
      buttonState = 0;
 
      if (temp == press) {
        
        return click;
        
      }
      
    }  
    
    return 0;
      
  }  
 
  int Mf_Magnifier(int Numeric, int Min, int Max, int Speed) {
   
   static uint32_t tmr;
   static int counter = 1;
   
    switch (Mf_encoderActionStorage(get_status)) {
      case rotated_rights:
         tmr = millis()+500;
         Numeric += counter;
         if (Speed > counter) {
          counter++;
         }
        break;
      case rotated_left:
         tmr = millis()+500;
         Numeric += -counter;
         if (Speed > counter) {
          counter++;
         }
        break;
    }
    if (counter != 1 && tmr < millis()) {        
      tmr = millis()+counter/2;
      counter--;
    }
    
    if (Numeric > Max) {
      Numeric = Min;
    } else if (Numeric < Min) {
      Numeric = Max;
    }
   return Numeric;
  }

//Mf

//Gamepad_function 6
//Gf

void setup() {
  
  Serial.begin(9600);// В ФЫНАЛЫ НЕЗАБУТИ ЗАКОМЕНТУВАТИ!!!
  
  EEPROM.begin(1);
  prof(eeprom_initialization);
  
  byte pinsWithPullup[] = {33, 14, 27, 26, 25, 16, 17, 5, 23, 2, 18, 19, 32, 15, 13, 4};//добавити 1

  for (int i = 0; i < sizeof(pinsWithPullup); i++) {
   
    pinMode(pinsWithPullup[i], INPUT_PULLUP);

  }
  
  esp_sleep_enable_ext0_wakeup(GPIO_NUM_13, 0);
  
  pinMode(3, OUTPUT);//подаємо живлення на датчики
  digitalWrite(3, HIGH);

  //Ae_InterruptReadPinDtEncoder() зчитування енкодера по пририванню
  attachInterrupt(digitalPinToInterrupt(p_dt), Ae_InterruptReadPinDtEncoder, CHANGE);

  //----------Display--------------
  display.begin(SSD1306_SWITCHCAPVCC, 0x3C);
  display.setTextSize(1);
  display.setTextColor(WHITE);
  

}

void loop() {
  
  buttonOnOff();
   
  switch (Md_Display(get_status)) {
    
    case info_display: 
        
      if (Mf_EncoderButton() == click) {
        
        MdAf_infoDisplay(reset);
        Md_Display(menu);
      
      }
      
      else{
       
       MdAf_infoDisplay();
      
      }
     
     break;
   
    case menu:
       
      Md_MainDisplay();
    
     break;

  }  
    
  /*
  
  if (bleGamepad.isConnected()) {
    
    Gf_ModifiedButtonInput();
    Gf_AnLeftAxisX();//H
    Gf_AnLeftAxisY();//V
    Gf_AnRightZ(get_status);//H G
    Gf_AnRightRZ(get_status);//V G
    bleGamepad.sendReport();
  
  }

  */  
 
}  //void loop()