#include <Wire.h>
#include <EEPROM.h>
// #include <BleGamepad.h> // при загрузці нa реально Arduino даний фрагмент розкоментувати a class BleGamepad закоментувати
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#include "esp32-hal-timer.h"
#include <RotaryEncoder.h>

// #include "INA219_WE.h"
// INA219_WE ina219(0x40); 

// Additional elements
  
  // constants-variable-arrays  
    
    bool Vibrgyro;
    //  СПІЛЬНІ КОНСТАНТИ ПІД ХОД ДЛЯ БАГ ФУНК
    
    #define zero_void -1
    #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 gyro 14
    #define profil 15
    #define data_available 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
  
    // Ae_BatR();
    // Піни карта
    // #define b_mein 25
    #define b_emul_dpad 1
    #define b_handle 4
    #define b_triger_r 23
    #define b_analog_l 33
    #define b_on_off 14
    #define b_emul_dpad 26
    // RotaryEncoder encoder(27, 14, RotaryEncoder::LatchMode::TWO03);
    #define b_sw 25 //  кнопка енко
    #define p_dt 32
    #define p_clk 33
    // 
    #define thandle_touch_read 27
    
    // Mf_EncoderButton();
    // #define click 13
    #define press_b_e 20
    #define hold_b_e 21
    #define reset_status 23
    #define take_but_pos 24
    #define button_pressed 25
    
    
    // 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 set_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};
    
    // Mf_encoderRotationSpeed()
    // Ae_encoderInterrupt_fastRotation()
    // #define data_available 16 // дані доступні
    #define check_rotation 20
    #define get_rotation 21
    #define rotated_r 22
    #define rotated_l 23
    #define rotated_r_fast 24
    #define rotated_l_fast 25
    volatile int8_t g_encFast;
    
    // 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
    
    // Ae_displayRefresh()
    // #define reset 11
    #define clear_display 20
    #define print_display 21
    
    // Ae_autoShutdown()
    // #define reset 11
    #define change_time 20
    #define get_time 21
    
    // Md_movingButtons()
    #define choice_bat_waiting 20
    #define button_selection_complete 21
  
  // c-v-a
  
  // Function prototypes
    
    // int8_t Md_addres(int8_t addNumb = 0, int8_t acceptedCommand = 0, int8_t acceptedData = 0);
    byte Md_cursor(byte acceptedCommand, byte* arr = nullptr);
    byte Md_p_Buttons(byte receivedData = 0, byte selectedButton = 0);
    int Md_movingButtons(int acceptedCommand = 0);  
    byte Mf_EncoderButton(byte acceptedCommand = 0);
    byte Md_Display(byte Receiving = 0);
    byte Ae_displayRefresh(byte acceptedCommand = 0);
    byte Ae_autoShutdown(byte acceptedCommand = 0, byte acceptedData = 0);
    
  // Fp
  
// Ae 

//  сlass BleGamepad Пустишка для того щоб не нагружати код і час компіляції 100=30
  
  #define HAT_CENTERED 0
  
  class BleGamepad {
   
   public:
      BleGamepad(const char* deviceName, const char* deviceManufacturer, uint8_t batteryLevel) {
          //  Нічого не робить
      }

      void press(uint8_t button) {
          //  Нічого не робить
      }

      void release(uint8_t button) {
          //  Нічого не робить
      }

      void setLeftTrigger(uint16_t value) {
          //  Нічого не робить
      }

      void setRightTrigger(uint16_t value) {
          //  Нічого не робить
      }
      
      bool isConnected() {
        //  Повертає false для симуляції відсутності з'єднання
        return false;
      }
      
      void  setZ(uint16_t value){

      }
      
      void  setRZ(uint16_t value){

      }
    
      void sendReport() {
          //  Нічого не робить
      }

      void setHat1(uint8_t value) {
          //  Нічого не робить
      }

      void setLeftThumb(int16_t x, int16_t y) {
          //  Нічого не робить
      }

      void setRightThumb(int16_t x, int16_t y) {
          //  Нічого не робить
      }

      void pressSelect() {
          //  Нічого не робить
      }

      void releaseSelect() {
          //  Нічого не робить
      }

      void pressStart() {
          //  Нічого не робить
      }

      void releaseStart() {
          //  Нічого не робить
      }      
        
        void begin() {
            //  Нічого не робить
        }

        void end() {
            //  Нічого не робить
        }
  };

// 

Adafruit_SSD1306 display(128, 64, &Wire, -1);
BleGamepad bleGamepad("FS G36", "UA", 100);
RotaryEncoder encoder(p_dt, p_clk, RotaryEncoder::LatchMode::TWO03);// test

// Profiles class 
  
  // constants-variable-arrays c-v-a
    
    #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
    #define delete_letter 23
    
    // *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
    #define rerecording 26//  test
    
    uint32_t tmrProf = 0;
  
  // c-v-a
  
  class Profiles {
    
    public:
      Profiles(int deZoH, byte senHor, int deZoV, byte senVer, char* nameProf, byte tpProf, byte nabProf)
       : deadZoneHor(deZoH),
         sensitivityHor(senHor),
         deadZoneVer(deZoV),
         sensitivityVer(senVer),
         tape(tpProf),
         namber(nabProf),
         status(r_off),
         gamepadButton{12, 13, 14, 4, 15, 26, 33, 13, 23, 27} //  test Md_resetButtons()!!! Select Start окрема функція геймпада тому 10 елементів
          {     // при глюках замінити на memcpy(gamepadButton, defaultgamepadButton, sizeof(gamepadButton));
         
            strncpy(nameArray, nameProf, 20); // даємо назву профілю через конструктор
            nameArray[20] = '\0';
            
            letterIndicator = [this]() -> byte {// переміна зберігає собі кількість букв в назві потрібно для зміни імен
              
              for (int i = 19; i >= 0; i--) {
                if (this->nameArray[i] != ' ') {
                  return i + 1;
                }
              }
              
              return 20;
              
            }();
         
          }
     
      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;
      
      }
    
      const char* nameProfiles(byte acceptedCommand, char Letter = ' '){// функція працює з іменем профілю та буквами також виконує мигання якщо стан профілю активний
       
        char baldness[] = "";// baldness ​беззмістовність   return baldness; аналог  return 0;
        
        if (status == r_on && tmrProf < millis()){// якщо стан профілю активний буде виконуватися мигання
         
         tmrProf = millis()+600;
         Flag = !Flag;
        
        }
        
        else if (status == r_off && !Flag){// захист можливий розрив функції переміна флаг може бути фолс
         
         Flag = 1;
         
        }
        
        switch (acceptedCommand) {
        
          case get_name: // беремо ім'я
            
            return nameArray;
          
          break;
          
          case get_name_a_f:// при даній команді ім'я активного профілю буде мигати
           
           if (Flag) {
            
            return nameArray;
           
           } 
           else { 
            
            return baldness;
           
           }
           
           break;
          
          case change_letter:// міняємо букву
            
            if (letterIndicator != 20){
             
             nameArray[letterIndicator] = Letter;
             letterIndicator++;
            
            }
           
           break;
          
          case delete_letter:// видаляємо букву
             
            if (letterIndicator){
             
             letterIndicator--;
             nameArray[letterIndicator] = ' ';
             
            }
           
           break;
          
         return baldness;
        
        }
      
       return baldness;
      
      }
      
      
      byte centroName() {// центрує набране ім'я в рамці інфо дисплей
        
        for (int i = 19; i >= 0; i--) {
         
          if (nameArray[i] != ' '){
           
           return 61-i*3;
           break;
          }
        
        }
        
       return 0;
      
      }
      
      byte getNamberTape(){// повертає номер і тип одночасно
       
       return tape * 10 +namber;// логіка роботи тип може бути 1 або 2 множимо на 10 щоб не збігалася числа
      
      }
      
      
      
      void checkName() {// якщо немає імені то вставляє власне ім'я залежно від номеру профіля
        
        bool allSpaces = true; //  Припускаємо, що всі символи - пробіли
        
        for(int i = 0; i < 20; i++) { //  Останній символ не перевіряємо
            if(nameArray[i] != ' ') {
                allSpaces = false;
                break;
            }
        }

        if(allSpaces) {
            snprintf(nameArray, 21, "My profile %d", namber); //  Форматуємо нову назву
        }
      
      }

      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;
        memcpy(gamepadButton, other.gamepadButton, sizeof(gamepadButton));
        memcpy(nameArray, other.nameArray, sizeof(nameArray)); 
      }

      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) ||
                (memcmp(gamepadButton, other.gamepadButton, sizeof(gamepadButton)) != 0) ||
                (memcmp(nameArray, other.nameArray, sizeof(nameArray)) != 0); 
      }
      
      //  prof(act_dir)->sensitivityHor;
      char nameArray[21];
      byte gamepadButton[10]; 
      byte Flag;
      int deadZoneHor;// (primary початкова) початок руху
      byte sensitivityHor;
      int deadZoneVer;
      byte sensitivityVer;
      byte tape;
      byte namber;
      byte status;
      byte letterIndicator;
    
    private:

  };
  
  //  Profile designers конструктори класу Profiles
 
    Profiles profilSeve(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, "05461               ", t_mp, 1);
    Profiles profilMpTwo(166, 120, 1965, 112, "Xmen   74           ", 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);

  // Pd
  
  Profiles *prof(byte acceptedCommand, byte number = 0){ 
   
    
    Profiles *profArray[] = {
    
     &profilSeve, &profilSpOne, &profilSpTwo, &profilSpThree, &profilSpFour, &profilSpFive, &profilSpSix, &profilSpSeven,               
     &profilMpOne, &profilMpTwo, &profilMpThree, &profilMpFour, &profilMpFive, &profilMpSix, &profilMpSeven
   
    };
   
    static byte acting = []() -> byte {// одноразова інт пер лямбда функція оскільки метод не повертає значення потрібно зробити так
      
      byte temp;
      int tempProfSize = 7 * sizeof(Profiles);
      int tempProfSizebutArr = 7 * sizeof(profArray[1]->gamepadButton);
      
      EEPROM.get(7 * sizeof(Profiles) + 1, temp); //  Читаємо значення з EEPROM
      
      if (!temp) {// TEST захист від мп0
       
       return 8;
      
      }
      
      return temp; //  Повертаємо прочитане значення
    
    }();
   
    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(7 * sizeof(Profiles) + 1, acting);
      EEPROM.commit();
      // Serial.println(sizeof(Profiles));
      // Serial.println(EEPROM.get(0, acting));
    } 
    
    else if (acceptedCommand == eeprom_initialization) {
      
      int tempProfSize = 7 * sizeof(Profiles);
      int tempProfSizebutArr = 7 * sizeof(profArray[1]->gamepadButton);
      int sizebutArr = sizeof(profArray[1]->gamepadButton);
     
     // Serial.println("sizeof(Profiles)");
     // Serial.println(sizeof(Profiles));
 
      if (acting == 255 || Ae_BatR(13)) {//  test ( Ae_BatR(13) ) Якщо правда то це самий перший запуск потрібно зберегти в профілі і перемінну енергонезалежну пам'ять подальші збереження будуть виконуватися при виході з настройок якщо вибрати так
  
        acting = 8; 
        
        EEPROM.put(0 * sizeof(Profiles), profilMpOne);
        EEPROM.put(1 * sizeof(Profiles), profilMpTwo);
        EEPROM.put(2 * sizeof(Profiles), profilMpThree);
        EEPROM.put(3 * sizeof(Profiles), profilMpFour);
        EEPROM.put(4 * sizeof(Profiles), profilMpFive);
        EEPROM.put(5 * sizeof(Profiles), profilMpSix);
        EEPROM.put(6 * sizeof(Profiles), profilMpSeven);

        //  Зберігаємо gamepadButton кожного профілю окремо
        EEPROM.put(tempProfSize + 0 * sizebutArr, profArray[1]->gamepadButton);
        EEPROM.put(tempProfSize + 1 * sizebutArr, profArray[2]->gamepadButton);
        EEPROM.put(tempProfSize + 2 * sizebutArr, profArray[3]->gamepadButton);
        EEPROM.put(tempProfSize + 3 * sizebutArr, profArray[4]->gamepadButton);
        EEPROM.put(tempProfSize + 4 * sizebutArr, profArray[5]->gamepadButton);
        EEPROM.put(tempProfSize + 5 * sizebutArr, profArray[6]->gamepadButton);
        EEPROM.put(tempProfSize + 6 * sizebutArr, profArray[7]->gamepadButton);

        //  Зберігаємо значення acting після всіх Profiles та їх gamepadButton
        EEPROM.put(tempProfSize + tempProfSizebutArr, acting);
        EEPROM.commit();
        
        /*
        for (int i = 0; i <= 6; i++){ // варіант з циклом for можливо буде працювати не в симуляторі
        
          EEPROM.put(i * sizeof(Profiles), profArray[i+8]);
          EEPROM.put(tempProfSize + i * sizebutArr, profArray[i+1]->gamepadButton);
          Serial.println(i);
       
        }
       
       EEPROM.put(tempProfSize + tempProfSizebutArr, acting);
       EEPROM.commit();
       */
      }
      
      else{// якщо Дані були вже збережені раніше то повертаємо їх з енергонезалежної пам'яті
        /*
        delay(500);
        for (int i = 0; i <= 6; i++){ 
        
          EEPROM.get(i * sizeof(Profiles), profArray[i+8]);
          EEPROM.get(tempProfSize + i * sizebutArr, profArray[i+1]->gamepadButton);
         
        }
        */
        /*
        EEPROM.get(0 * sizeof(Profiles), profilMpOne);
        EEPROM.get(1 * sizeof(Profiles), profilMpTwo);
        EEPROM.get(2 * sizeof(Profiles), profilMpThree);
        EEPROM.get(3 * sizeof(Profiles), profilMpFour);
        EEPROM.get(4 * sizeof(Profiles), profilMpFive);
        EEPROM.get(5 * sizeof(Profiles), profilMpSix);
        EEPROM.get(6 * sizeof(Profiles), profilMpSeven);
        
        EEPROM.get(tempProfSize + 0 * sizebutArr, profArray[1]->gamepadButton);
        EEPROM.get(tempProfSize + 1 * sizebutArr, profArray[2]->gamepadButton);
        EEPROM.get(tempProfSize + 2 * sizebutArr, profArray[3]->gamepadButton);
        EEPROM.get(tempProfSize + 3 * sizebutArr, profArray[4]->gamepadButton);
        EEPROM.get(tempProfSize + 4 * sizebutArr, profArray[5]->gamepadButton);
        EEPROM.get(tempProfSize + 5 * sizebutArr, profArray[6]->gamepadButton);
        EEPROM.get(tempProfSize + 6 * sizebutArr, profArray[7]->gamepadButton);
        */
      
      }
      /*
      for (int i = 0; i <= 6; i++){ 
       
       EEPROM.get(i * sizeof(Profiles), *profArray[i+8]);  // *profArray[i+8]???
       Serial.println(i);
      
      }
      */
      
      profArray[acting] -> setStatus(r_on);
 
    }  
  
   return 0;
  }
 
// P

// Button debounce class
 
  class DebButton {
    
    private:
      
      byte pin;       
      uint32_t tmr; 
        
    public:
      
      //  Конструктор класу, ініціалізація піна, номера кнопки геймпада та часу захисту від випадкових спрацьовувань
      DebButton(int p, int dt = 300) {
        
        pin = p;
        tmr = dt;
        pinMode(pin, INPUT_PULLUP);
      
      }
     
      //  Метод для обробки натискання кнопки
      
      bool press() {
        
        static bool buttonState;  
        
        if (!digitalRead(pin) && !buttonState && millis() > tmr) {// після натську кнопки буде повернення true
          Serial.println("1111111"); 
          buttonState = true; // тепер переміна буде правда
          tmr = millis() + 300;// даємо час кнопці для заспокоєння від брязкaiту при натиску
          return true;
        
        }
        
        else if (buttonState && digitalRead(pin) && millis() > tmr) {// пісня відпущення кнопки буде повернення брехня
          Serial.println("222222222"); 
          buttonState = false;// тепер переміна буде брехня
          tmr = millis() + 300;// даємо час кнопці для заспокоєння від брязкaiту при відпуску
          return false;
        
        }
        
        return buttonState;// постійно  повертаємо стан кнопки
         
     }
  };
  
  DebButton debButton[] = {
    
    DebButton(19), 
    DebButton(18), 
    DebButton(5)
   
  };
  
// 
 
// Button gamepad class
  
  // constants-variable-arrays
    
    #define touch_dead_zone 50
    #define analog_dead_zone 2600
    
    // ButGamepad(byte gBT, byte gBN, byte pRT, byte n)
    #define button_gamepad 20
    #define trigger_gamepad 21
    #define tactile_read 22
    #define touch_read 23
    #define analog_read 24
    
    #define trigger_r 12
    #define trigger_l 13

    // byte (*gamepadPressPtr)(byte);
    #define  press_gamepad_button 20
    #define  press_check 21
    #define  gamepad_button_pressed 22
    #define  button_get_name 23
  
  // c-v-a   
  
  class ButGamepad {
    
    private:
      
      byte gamepadButtonType;
      byte gamepadButtonName;       
      byte pinReadType;
      byte numb;
    
    public:
      
      typedef byte (ButGamepad::*GamepadPressMethod)(byte);
      
      GamepadPressMethod gamepadPressPtr;

      // Bluetooth gamepad push button
        
        byte tactilePress(byte acceptedCommand) {
        
          static byte flagPress; 
          static byte buttonCheckFlag;
          
          if (acceptedCommand == press_gamepad_button) {
            
            if (debButton[numb].press()) {
            
              if (!flagPress) {
              
               bleGamepad.press(gamepadButtonName);
               flagPress = 1; 
              
              }            
            
            }
          
            else if (flagPress){
              
             flagPress = 0; 
             bleGamepad.release(gamepadButtonName);
          
            }
          
          }
          
          else if (acceptedCommand == press_check) {
           
            if (debButton[numb].press() && !buttonCheckFlag) {
               
               Serial.println("preset----------1");
               buttonCheckFlag = 1;
               return gamepad_button_pressed;
              
            }
            
            else if (buttonCheckFlag && !debButton[numb].press()){
             
             buttonCheckFlag = 0; 
            
            } 
          
          }
          
          else if (acceptedCommand == button_get_name) {
            
            return gamepadButtonName;
           
          }
          
          return 0;
        
        }
        
        byte touchPress(byte acceptedCommand) {
        
          static byte flagPress; 
          static byte buttonCheckFlag;
          
          if (acceptedCommand == press_gamepad_button) {
            
            if (touchPinButtonRead(numb)) {
            
              if (!flagPress) {
              
               flagPress = 1; 
               bleGamepad.press(gamepadButtonName);
            
              }
            
            }
          
            else if (flagPress){
              
             flagPress = 0; 
             bleGamepad.release(gamepadButtonName);
          
            }
          
          }
          
          else if (acceptedCommand == press_check) {
        
            if (touchPinButtonRead(numb) && !buttonCheckFlag) {
            
              buttonCheckFlag = 1;
              return gamepad_button_pressed;
               
            }
          
            else if (buttonCheckFlag && !touchPinButtonRead(numb)){
              
             buttonCheckFlag = 0; 
            
            }
          
          }        
          
          else if (acceptedCommand == button_get_name) {
           
           return gamepadButtonName;
             
          }
                
          return 0;        
        
        }
        
        byte analogReadPress(byte acceptedCommand) {
        
          static byte flagPress; 
          static byte buttonCheckFlag;          
          
          if (acceptedCommand == press_gamepad_button) {
            
            if (analogPinButtonRead(numb)) {
            
              if (!flagPress) {
              
               flagPress = 1; 
               bleGamepad.press(gamepadButtonName);
            
              }
            
            }
          
            else if (flagPress){
              
             flagPress = 0;  
             bleGamepad.release(gamepadButtonName);
          
            }
          
          }
          
          else if (acceptedCommand == press_check) {
            
            if (analogPinButtonRead(numb) && !buttonCheckFlag) {
            
              buttonCheckFlag = 1;
              return gamepad_button_pressed;
             
            }
          
            else if (buttonCheckFlag && analogPinButtonRead(numb)){
              
             buttonCheckFlag = 0;  
            
            }
          
          }          
          
          else if (acceptedCommand == button_get_name) {
            
            return gamepadButtonName;       
          
          }           
          
          return 0;             
        
        }          
      
      //     
      
      // Bluetooth gamepad right trigger pressure
        
        byte analogReadTriggerRightPress(byte acceptedCommand) {  
          
          static byte flagPress; 
          static byte buttonCheckFlag;
          
          if (acceptedCommand == press_gamepad_button) {
            
            if (analogRead(numb) > analog_dead_zone) { // test
              
              int temp = analogRead(numb);
              temp = map(temp, analog_dead_zone, 4095, 0, 32767);
              temp = constrain(temp, 0, 32767);
              
              bleGamepad.setRightTrigger(temp);
              flagPress = 1; 
              
            }
              
            else if (flagPress) { 
              
              flagPress = 0;
              bleGamepad.setRightTrigger(0);// test
            
            }
          
          }
          
          
          else if (acceptedCommand == press_check) {
            
            if (analogPinButtonRead(numb) && !buttonCheckFlag) {
            
              buttonCheckFlag = 1;
              return gamepad_button_pressed;
             
            }
          
            else if (buttonCheckFlag && analogPinButtonRead(numb)){
              
             buttonCheckFlag = 0;  
            
            }
          
          }    
          
          else if (acceptedCommand == button_get_name) {
            
            return gamepadButtonName;                      
             
          }
          
          return 0;
        
        }      
        
        byte touchReadTriggerRightPress(byte acceptedCommand) {
        
          static byte flagPress; 
          static byte buttonCheckFlag;
          
          if (acceptedCommand == press_gamepad_button) {        
          
            if (touchPinButtonRead(numb)) {
            
              if (!flagPress) { 
                
                flagPress = 1; 
                bleGamepad.setRightTrigger(32767);                     
              
              }
              
            }
          
            else if (flagPress){
              
              flagPress = 0; 
              bleGamepad.setRightTrigger(0);
          
            }
          
          }
          
          else if (acceptedCommand == press_check) {
        
            if (touchPinButtonRead(numb) && !buttonCheckFlag) {
            
              buttonCheckFlag = 1;
              return gamepad_button_pressed;
               
            }
          
            else if (buttonCheckFlag && !touchPinButtonRead(numb)){
              
             buttonCheckFlag = 0; 
            
            }
          
          }       

          else if (acceptedCommand == button_get_name) {        
          
            return gamepadButtonName;          
          
          }             
          
          return 0;        
        
        }      
        
        byte tactileReadTriggerRightPress(byte acceptedCommand) {
        
          static byte flagPress; 
          static byte buttonCheckFlag; 
          
          if (acceptedCommand == press_gamepad_button) { 
            
            if (debButton[numb].press()) {
            
             bleGamepad.setRightTrigger(32767);
             flagPress = 1; 
            
            }
          
            else if (flagPress){
              
             flagPress = 0; 
             bleGamepad.setRightTrigger(0);
          
            }
          
          }
          
          else if (acceptedCommand == press_check) {
           
            if (debButton[numb].press() && !buttonCheckFlag) {
            
               buttonCheckFlag = 1;
               return gamepad_button_pressed;
              
            }
            
            else if (buttonCheckFlag && !debButton[numb].press()){
             
             buttonCheckFlag = 0; 
            
            } 
          
          }
          
          else if (acceptedCommand == button_get_name) { 
            
            return gamepadButtonName;                      
            
          }
          
          return 0;        
                
        }      
        
      //   

      // Bluetooth gamepad left trigger pressure 
        
        byte analogReadTriggerLeftPress(byte acceptedCommand) {  
          
          static byte flagPress; 
          static byte buttonCheckFlag;
          
          if (acceptedCommand == press_gamepad_button) {
            
            if (analogRead(numb) > analog_dead_zone) { // test
              
              int temp = analogRead(numb);
              temp = map(temp, analog_dead_zone, 4095, 0, 32767);
              temp = constrain(temp, 0, 32767);
              
              bleGamepad.setLeftTrigger(temp);
              flagPress = 1; 
              
            }
              
            else if (flagPress) { 
              
              flagPress = 0;
              bleGamepad.setLeftTrigger(0);// test
            
            }
          
          }
          
          else if (acceptedCommand == press_check) {
            
            if (analogPinButtonRead(numb) && !buttonCheckFlag) {
            
              buttonCheckFlag = 1;
              return gamepad_button_pressed;
             
            }
          
            else if (buttonCheckFlag && analogPinButtonRead(numb)){
              
             buttonCheckFlag = 0;  
            
            }
          
          }    
          
          else if (acceptedCommand == button_get_name) {
            
            return gamepadButtonName;                      
             
          }
          
          return 0;
        
        }      
        
        byte touchReadTriggerLeftPress(byte acceptedCommand) {
        
          static byte flagPress; 
          static byte buttonCheckFlag;
          
          if (acceptedCommand == press_gamepad_button) {        
          
            if (touchPinButtonRead(numb)) {
            
              if (!flagPress) { 
                
                flagPress = 1; 
                bleGamepad.setLeftTrigger(32767);                     
              
              }
              
            }
          
            else if (flagPress){
              
              flagPress = 0; 
              bleGamepad.setLeftTrigger(0);
          
            }
          
          }
          
          else if (acceptedCommand == press_check) {
        
            if (touchPinButtonRead(numb) && !buttonCheckFlag) {
            
              buttonCheckFlag = 1;
              return gamepad_button_pressed;
               
            }
          
            else if (buttonCheckFlag && !touchPinButtonRead(numb)){
              
             buttonCheckFlag = 0; 
            
            }
          
          }        

          else if (acceptedCommand == button_get_name) {        
          
            return gamepadButtonName;          
          
          }             
          
          return 0;        
        
        }      
        
        byte tactileReadTriggerLeftPress(byte acceptedCommand) {
        
          static byte flagPress; 
          static byte buttonCheckFlag; 
          
          if (acceptedCommand == press_gamepad_button) { 
            
            if (debButton[numb].press()) {
            
             bleGamepad.setLeftTrigger(32767);
             flagPress = 1; 
            
            }
          
            else if (flagPress){
              
             flagPress = 0; 
             bleGamepad.setLeftTrigger(0);
          
            }
          
          }
          
          else if (acceptedCommand == press_check) {
           
            if (debButton[numb].press() && !buttonCheckFlag) {
            
               buttonCheckFlag = 1;
               return gamepad_button_pressed;
              
            }
            
            else if (buttonCheckFlag && !debButton[numb].press()){
             
             buttonCheckFlag = 0; 
            
            } 
          
          }
          
          else if (acceptedCommand == button_get_name) { 
            
            return gamepadButtonName;                      
            
          }
          
          return 0;        
                
        }  
      
      //  

      byte buttonReinstall(byte newButton){

        gamepadButtonName = newButton;
        
        if (newButton != trigger_r && newButton != trigger_l) {
        
          if (pinReadType == tactile_read) {
         
           gamepadPressPtr = &ButGamepad::tactilePress;
        
          }
         
          else if (pinReadType == touch_read) {
         
           gamepadPressPtr = &ButGamepad::touchPress;
        
          }
        
          else if (pinReadType == analog_read) {
         
           gamepadPressPtr = &ButGamepad::analogReadPress;
            
          }
          
        }
        
        else if (newButton == trigger_r || newButton == trigger_l) {
        
          if (gamepadButtonName == trigger_r) {
         
            if (pinReadType == analog_read) {
           
              gamepadPressPtr = &ButGamepad::analogReadTriggerRightPress;
        
            }
            
            else if (pinReadType == tactile_read) {
           
              gamepadPressPtr = &ButGamepad::tactileReadTriggerRightPress;
        
            } 
          
            else if (pinReadType == touch_read) {
           
              gamepadPressPtr = &ButGamepad::touchReadTriggerRightPress;
        
            } 
          
          }
          
          else if (gamepadButtonName == trigger_l) {
         
            if (pinReadType == analog_read) {
           
              gamepadPressPtr = &ButGamepad::analogReadTriggerLeftPress;
        
            }
            
            else if (pinReadType == tactile_read) {
           
              gamepadPressPtr = &ButGamepad::tactileReadTriggerLeftPress;
        
            } 
          
            else if (pinReadType == touch_read) {
           
              gamepadPressPtr = &ButGamepad::touchReadTriggerLeftPress;
        
            } 
          
          }         
        
        }   
        
        return 0;   
      
      }
      
      byte invokeGamepadPress(byte acceptedCommand) { //  Метод для виклику функції через вказівник на метод
        
        return (this->*gamepadPressPtr)(acceptedCommand);
      
      }        
      
      byte touchPinButtonRead(byte receivedData){
    
        if (touchRead(receivedData) < touch_dead_zone) {
        
          return true;
        
        }
        
        return false;
      
      }
      
      byte analogPinButtonRead(byte receivedData){
    
        if (analogRead(numb) > 2600) {
        
          return true;
        
        }
        
        return false;
      
      }
      
      ButGamepad(byte gBT, byte gBN, byte pRT, byte n) {
        
        
        gamepadButtonType = gBT;
        gamepadButtonName = gBN;
        pinReadType = pRT;   
        numb = n;
        
        if (gBT == button_gamepad) {// вибір яким способом буде натиснути кнопка геймпада кнопка(1...11) = tactile touch analog
        
          if (pRT == tactile_read) {
         
           gamepadPressPtr = &ButGamepad::tactilePress;
        
          }
         
          else if (pRT == touch_read) {
         
           gamepadPressPtr = &ButGamepad::touchPress;
        
          }
        
          else if (pRT == analog_read) {
         
           gamepadPressPtr = &ButGamepad::analogReadPress;
            
          }
          
        }
        
        else if (gBT == trigger_gamepad) {// вибір яким способом буде натиснути курок(R L)геймпада курок(R L) = tactile touch analog
        
          if (gBN == trigger_r) {
         
            if (pRT == analog_read) {
           
              gamepadPressPtr = &ButGamepad::analogReadTriggerRightPress;
        
            }
            
            else if (pRT == touch_read) {
           
              gamepadPressPtr = &ButGamepad::touchReadTriggerRightPress;
        
            } 
          
            else if (pRT == tactile_read) {
           
              gamepadPressPtr = &ButGamepad::tactileReadTriggerRightPress;
        
            } 
          
          }
          
          else if (gBN == trigger_l) {
         
            if (pRT == analog_read) {
           
              gamepadPressPtr = &ButGamepad::analogReadTriggerLeftPress;
        
            }
            
            else if (pRT ==  touch_read) {
           
              gamepadPressPtr = &ButGamepad::touchReadTriggerLeftPress;
        
            } 
          
            else if (pRT == tactile_read) {
           
              gamepadPressPtr = &ButGamepad::tactileReadTriggerLeftPress;
        
            } 
          
          }         
        
        }   
        
      }
      
  };//  Button gamepad
  
  ButGamepad butGamepad[] = {// test
   
    ButGamepad(button_gamepad, 1, tactile_read, 0),
    ButGamepad(button_gamepad, 2, tactile_read, 1),
    ButGamepad(button_gamepad, 3, tactile_read, 2),
    /*
    ButGamepad(button_gamepad, 4, touch_read, 19),
    ButGamepad(button_gamepad, 5, analog_read, 20),
    ButGamepad(trigger_gamepad, trigger_r, analog_read, 20), 
    ButGamepad(trigger_gamepad, trigger_l, analog_read, 21) 
    */
  };
  
// Bdc

//Additional functions
  
  byte Ae_BatR(byte Taking) {// васна функція зчитує дані кнопки нагадування потрібно зробити власний клас кнопка додати debouns
  
    if (!digitalRead(Taking)) {
      
      Ae_autoShutdown(reset); 
    
    }
    
    return !digitalRead(Taking);

  }

  byte Ae_autoShutdown(byte acceptedCommand, byte acceptedData){
    
    static uint32_t timerMagnifier = 3 * 60000;
    static uint32_t tmr = timerMagnifier;
    
    if (acceptedCommand) {
      
      if (acceptedCommand == reset) { 
        
        tmr = timerMagnifier + millis();
        
      }
      
      else if (acceptedCommand == change_time) { 
        
        timerMagnifier = acceptedData * 60000;
        
      }
      
      else if (acceptedCommand == get_time) { 
        
        return timerMagnifier / 60000;
        
      }
    
    }
    
    else if (tmr < millis()){
      
      delay(400); 
      esp_deep_sleep_start();
    
    }
  
    return 0;
  
  }
  
  void Ae_buttonOnOff(){

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

  }
  
  byte Ae_displayRefresh(byte acceptedCommand){// 
    
    static byte clearRefresh = 1; 
    
    if(acceptedCommand == reset && !clearRefresh) {
      
      clearRefresh = 1; 

    }
    
    else if(clearRefresh) {
      
      if(acceptedCommand == clear_display && clearRefresh <= 14) {
      
      clearRefresh++;
      display.clearDisplay();
      
      } 

      if(acceptedCommand == print_display && clearRefresh <= 14) {
      
      clearRefresh++;
      display.display();
      
      } 
      
      if(acceptedCommand == print_display && clearRefresh > 14) {
      
      clearRefresh = 0;
      display.display();
      
      } 
    
    }
    
    /*
      if(acceptedCommand == clear_display) {
      
      display.clearDisplay();
      
      } 

      else if(acceptedCommand == print_display) {
      
      display.display();
      
      } 
    */
    return 0;
  
  }
  
  void gyroStart(){
    /*
    mpu.initialize();
    delay(10);
    mpu.dmpInitialize();
    mpu.setFullScaleAccelRange(MPU6050_ACCEL_FS_2);
    mpu.setFullScaleGyroRange(MPU6050_GYRO_FS_250);
    
    static byte flag = []() -> byte {
      byte temp;
      EEPROM.get(7 * sizeof(Profiles) + 1, temp); 
      
      return !temp; 
    }();
  
    */
    static byte flag = 1;// TECT
    long offsets[6];
  
  
    if(Ae_BatR(b_triger_r) && Ae_BatR(b_analog_l)){
    
      byte temp = 10;
    
      while(temp > 0){
        
        display.clearDisplay();
        
        display.setCursor(0, 16);
        display.println("  Calibration starts");
        display.println();
        display.print  ("          ");
        display.println(temp);
        
        display.display();
        Ae_buttonOnOff(); 
        temp--;
        delay(1000);
        
      }
      
      display.clearDisplay();
      display.setCursor(2, 16);
      display.println(" Wait for completion");
      display.display();
      delay(2000);// TE
      /*
      mpu.setXAccelOffset(0);
      mpu.setYAccelOffset(0);
      mpu.setZAccelOffset(0);
      mpu.setXGyroOffset(0);
      mpu.setYGyroOffset(0);
      mpu.setZGyroOffset(0);
      delay(10);
      
      mpu.CalibrateAccel(60);// не забудьте додати рестарт при помилках калібровки
      mpu.CalibrateGyro(120);
      delay(10);
      
      offsets[0] = mpu.getXAccelOffset();
      offsets[1] = mpu.getYAccelOffset();
      offsets[2] = mpu.getZAccelOffset();
      offsets[3] = mpu.getXGyroOffset();
      offsets[4] = mpu.getYGyroOffset();
      offsets[5] = mpu.getZGyroOffset();
      */
      flag = 1;
      /*
      EEPROM.put(7 * sizeof(Profiles) + 1, flag);
      EEPROM.put(7 * sizeof(Profiles) + 2, offsets);
      EEPROM.commit();
      */

      display.clearDisplay();
      display.setCursor(4, 16);
      display.println("Calibration complete");
      display.display();
    
    }
    
    else if(!flag){
    
    display.clearDisplay();
    
    display.setCursor(1, 16);
    display.println("Gyroscope calibration");
    display.println("     not done");
    
    display.display();
    
    while(1){
      
      Ae_buttonOnOff(); 
    
    }
    
    }
    
    else if(flag){
      /*
      EEPROM.get(7 * sizeof(Profiles) + 2, offsets);
    
      mpu.setXAccelOffset(offsets[0]);
      mpu.setYAccelOffset(offsets[1]);
      mpu.setZAccelOffset(offsets[2]);
      mpu.setXGyroOffset(offsets[3]);
      mpu.setYGyroOffset(offsets[4]);
      mpu.setZGyroOffset(offsets[5]);
      */
    }

  }
  
  void startAnimation(){
    
    display.clearDisplay();
    display.invertDisplay(0);
    display.setCursor(-2, 28);
    display.println("        FS G36      ");
    display.display();
    delay(500);
    display.clearDisplay();
    display.display();
    
  }
  
  void Ae_encoderInterrupt_fastRotation() {// функція викликається періодично тільки при обертанні працює в приривані  функція виконує дві дії оновлює стан енкодера і провіряє швидкість обертання
    
    encoder.tick(); //  Оновлення стану енкодер
  
    static uint32_t tmr;
    static int seveEncoder;
    
    if (seveEncoder != encoder.getPosition() && tmr < millis()) {// якщо enc obeртається перезаписує новий стан запускаємо таймер
      
      Ae_displayRefresh(reset);
      seveEncoder = encoder.getPosition();// записуємо свіжі дані
      tmr = millis() + 20;
    
    }
    
    else if (seveEncoder != encoder.getPosition() && tmr > millis() && !g_encFast) {// якщо встигнемо получити два сигнала enkодера то записуємо необхідне значення для подальшого опрацювання
      
      if (seveEncoder < encoder.getPosition()) {// в глобально переміну g_encFast записуються необхідне значення і дальше в функції Mf_encoderRotationSpeed відбувається скиданн на 0 
        
       g_encFast = 1;
    
      }
        
      else if (seveEncoder > encoder.getPosition()) {
        
       g_encFast = -1;
      
      }
      
      Ae_displayRefresh(reset);
      seveEncoder = encoder.getPosition();// записуємо свіжі дані
      tmr = millis() + 20;// перезапускаємо таймер щоб не повертатися до першого пункту if
    
    }
    
  }
  
// Af

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

         Md_ItemOne();
        
         break;// 1
       
        case 1:
          
          Md_Profile();
         
         break;
        
        case 2:
          
          Md_GeneralSettings();
         
         break;
        
        case 3:
          
          // qr-код ссылка на інструкцію
         
         break;
        
        case 4:
         
          Md_Display(info_display);
          Md_cursor(set_pos, posOne);
          Md_addres(1, back);         
          Ae_displayRefresh(reset);
          
         break;
        
        case address_entered:
          
          Md_cursor(set_pos, posOne);
          
         break;
      
      }
     
    }
    
    void Md_ItemOne(){
      
        byte Lines[] = {22, 32, 42, 52};
        Md_cursor(sizeof(Lines), Lines);
        
        display.setCursor(0, 22);
        display.println("  Profile");
        display.setCursor(0, 32);
        display.println("  General settings");
        display.setCursor(0, 42);
        display.println("  Instruction (!)");
        display.setCursor(0, 52);
        display.println("  Exit menu ");
    
    }
  
  // 
  
  //  add2-----------------------------------------------------------------------------------------------------------
    
    // Profile
      
      void Md_Profile() {
        
        if (prof(act_dir)->tape == 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_addres(1, back);           
              
              }
              
              
              else if (Md_addres(2, get_add) == 1) {
              
              MdAf_profileStorage(copy_profile);// // копіюємо профіль при вдоході в настройки  для подальшої перевірки на зміни при виході 
            
              } 
              
              Md_cursor(set_pos, posOne);
          
            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_addres(1, back);           
              
              }
              
              
              else if (Md_addres(2, get_add) == 1) {
              
                MdAf_profileStorage(copy_profile);// // копіюємо профіль при вдоході в настройки  для подальшої перевірки на зміни при виході 
            
              } 
              
              Md_cursor(set_pos, posOne);
          
            break;
              
          }
        }   
      
      } 
    
      void Md_p_Profile() {
          
        byte LinesSp[] = {31, 39, 49, 57};
        byte LinesMp[] = {35, 49, 57};
        
        if (prof(act_dir)->tape == t_sp) {      
          
          Md_cursor(sizeof( LinesSp), LinesSp);
        
        } 
        
        else {
          
          Md_cursor(sizeof(LinesMp), 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)->tape == t_sp) { 
        
        display.print("Sp");
        display.println(prof(act_dir)->namber);
        
        }
        else {
        
        display.print("Mp");
        display.println(prof(act_dir)->namber);
        
        }
        
        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)->tape == 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" );
        
      }
    
    //   
    
    // General settings
      
      void Md_GeneralSettings(){
        
        int seveDataTemp;// використовую щоб було більш зрозуміліше
        
        if (Md_addres(2, get_add) <= 3){
        
         Md_p_GeneralSettings();
        
        }
        
        
        if (Md_cursor(get_pos) <= 3){
          
          switch (Md_addres(2, int_add_last)) {
          
            case 1: 
              
             seveDataTemp = Mf_Magnifier(Ae_autoShutdown(get_time), 3, 15, 1);
             Ae_autoShutdown(change_time, seveDataTemp);
            
             break;
            
            case 2: 
            
            break;
            
            case 3: 
            
            break;
            
          }  
        
        }
        
        else{
          
          switch (Md_addres(2, int_add)) {
            
            case 4: 
              
            break;
            
            case 5: 
            
            break;
            
            case 6: 
              
              Md_cursor(set_pos, posTwo);
              Md_addres(1, back);
            
            break;
        
          }
        
        }
      
      }
      
      void Md_p_GeneralSettings(){
      
        int seveDataTemp = 0;
        byte Lines[] = {0, 8, 16, 24, 32, 40};
        Md_cursor(sizeof(Lines), Lines);
        
        display.setCursor(0, 0);
        display.println(" Auto shutdown-  m.");
        display.println(" Shutter-imitation ");
        display.println(" Battery-saving");
        display.println(" Gyroscope ");
        display.println(" Buttons");
        display.println(" Back" );
        
        
        if (Ae_autoShutdown(get_time) < 10){
          
          seveDataTemp = 3; 
        
        }
        
        Serial.println(seveDataTemp);
        display.setCursor(15*6+seveDataTemp, 0);
        display.print(Ae_autoShutdown(get_time));
      
      
      }
    
    // Gs
  //         
  
  //  add3-----------------------------------------------------------------------------------------------------------
    
    // Select profile
      
      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)->tape == t_sp) {  
              
              Md_cursor(set_pos, posThree);
            
            }
            
            else{
              
              Md_cursor(set_pos, posTwo);
            
            }
            
            Md_addres(2, back); 
            
            }
            
            else{ 

            Md_cursor(set_pos, posOne);
            
            } 
          
          break;
        
        }
      }
      
      void Md_p_selectProfile() {
        
        byte Lines[] = {16, 24, 32};
        Md_cursor(sizeof(Lines), Lines);
      
        display.setCursor(0, 16);
        display.println(" Standard profiles" );
        display.println(" My profiles");
        display.println(" Back" );
      
      }
    
    // Sp

    // Profile settings   
      
      void Md_profileSettings() {
        
        if (prof(act_dir)->tape == t_sp) { // вид пунктiv меню якщо профіль стандартний
          
          switch (Md_addres(3, int_add)) {
            
            case no_action: 
              
              Md_p_profileSettings();
            
            break;
            
            case 1:
              
              Md_Buttons();
            
            break;// Buttons
            
            case 2://  якщо були зміни то повернення відбудеться через функцію MdAf_profileStorage
              
              if (MdAf_profileStorage(check_changes) == recorded_changes) {// перевірка на наявність змін
            
                switch (MdAf_consenDisplay()) {// якщо є зміни запуститься дисплей підтвердження при виході з настройок
                  
                  case choice_yes:
                    
                    MdAf_profileStorage(reset);// якщо виберемо так профіль повторно скопірується комадою ресеті функція 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(set_pos, posOne);
          
            break;
          }
        }
          
        else { //  вид пунктів якщо вибрано власний профіль
  
          switch (Md_addres(3, int_add)) {
            
            case no_action: 

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

            case 4://  якщо були зміни то повернення в попередній пункт меню відбудеться через функцію MdAf_profileStorage
              
              if (MdAf_profileStorage(check_changes) == recorded_changes) {// перевірка на наявність змін
            
                switch (MdAf_consenDisplay()) {// якщо є зміни запуститься дисплей підтвердження при виході з настройок
                  
                  case choice_yes:
                    
                    MdAf_profileStorage(reset);// якщо виберемо так перестане видавати 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(set_pos, posOne);
            
              break;
            
          }
        }
      }
        
      void  Md_p_profileSettings() {
        
        byte LinesSp[] = {16, 24};
        byte LinesMp[] = {16, 24, 32, 50};
        
        if (prof(act_dir)->tape == t_sp) {      
          
          Md_cursor(sizeof(LinesSp, LinesSp));
          display.setCursor(0, 16);
          display.println(" Buttons" );// не добавляти пункт reset не потрібно
          display.println(" Back" );
        
        } else {
          Md_cursor(sizeof(LinesMp), 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" );
        }

      }
    
    // Ps
  
  //                 
  
  //  add4-----------------------------------------------------------------------------------------------------------
    
    // Standard profiles
      
      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(set_pos, posOne);
              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(set_pos, posOne);
              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(sizeof(Lines), Lines);
        Ae_displayRefresh(reset);
        
        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" );
      
      }
    
    // Sp  
    
    // My profiles  
     
      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(set_pos, posOne);
              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(set_pos, posOne);
              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(sizeof(Lines), Lines);
        Ae_displayRefresh(reset);
        
        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" );
      
      }
    
    // Mp

    // Gyroscope settings  
      
      void Md_gyroscopeSettings(){// a3
        
        int seveDataTemp;// використовую щоб було більш зрозуміліше
        
        if (Md_addres(4, add_status) == address_deleted){// відновляємо у виконанні функції Gf_GyroAnalogR після виходу з настройок мертвої зони (якщо адрес видалився)
          /*
          timerAlarmEnable(timer);
          */
        }
        
        if (Md_addres(4, get_add) != 5){// зроблено для того щоб курсор не міняв свій вигляд при виході
          
        Md_p_gyroscopeSettings();
        
        }
        
        switch (Md_addres(4, int_add_last)) {// 4
          
          case no_action:
          
          break;
          
          case 1:
            
            seveDataTemp = Mf_Magnifier(prof(act_dir)->deadZoneHor, 0, 9999, 100);
            prof(act_dir)->setDeZoHor(seveDataTemp);
          
          break;
          
          case 2:
            
            seveDataTemp = Mf_Magnifier(prof(act_dir)->sensitivityHor, 0, 100, 5);
            prof(act_dir)->setSenHor(seveDataTemp);
          
          break;
          
          case 3:
            
            seveDataTemp = Mf_Magnifier(prof(act_dir)->deadZoneVer, 0, 9999, 100);
            prof(act_dir)->setDeZoVer(seveDataTemp);
          
          break;
          
          case 4:
            
            seveDataTemp = Mf_Magnifier(prof(act_dir)->sensitivityVer, 0, 100, 5);
            prof(act_dir)->setSenVer(seveDataTemp);        
          
          break;
          
          case 5:
            
            Md_cursor(set_pos, posOne);
            Md_addres(3, back);   
          
          break;
          
          case address_entered: 
          
            if (Md_addres(4, get_add) == 1 || Md_addres(4, get_add) == 3) {// зупиняємо виконання функції Gf_GyroAnalogR  для того щоб настроїти мертву зону
            /*
            timerAlarmDisable(timer);
            */ 
            }
          
          break;
        }
      
      }
    
      void Md_p_gyroscopeSettings(){
        
        static uint32_t tmr;
        static byte dashFlag;// прапорець м'ягання
        
        if (tmr < millis()) {
          
          Ae_displayRefresh(reset);
          tmr = millis() + 500;
          dashFlag = ! dashFlag;
        
        }
      
        byte Lines[] = {5, 15, 34, 44, 55};
        Md_cursor(sizeof(Lines), 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)->deadZoneHor);
      
        display.setCursor(104, 17);
        display.println(prof(act_dir)->sensitivityHor);
        
        display.setCursor(102, 33);
        display.println(prof(act_dir)->deadZoneVer);
        
        display.setCursor(104, 46);
        display.println(prof(act_dir)->sensitivityVer);
        
        
        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(get_pos) == 1 || Md_cursor(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(get_pos) == 3 || Md_cursor(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);} 
        
      }
    
    // Gs
    
    // Buttons
    
      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);
                Md_resetButtons();// test

              break;
            
              case choice_no:

                Md_addres(4, back);
              
              break;
            
            }
            
          break;
          
          case 3:
            
            Md_cursor(set_pos, posTwo);
            Md_addres(3, back);
          
          break;
          
          case 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){// test
        
        static int8_t NumberOne;
        
        if (acceptedCommand == reset) { // скидання функції якщо не закінчили переміщення кнопок
        
          NumberOne = 0;
          return 0;
        
        }
      
        for (int i = 0; i <= 2; i++) {// test
          
          if (butGamepad[i].invokeGamepadPress(press_check) == gamepad_button_pressed) {
            Serial.println("preset 2"); 
            Md_p_Buttons(next_animation, butGamepad[i].invokeGamepadPress(button_get_name));
            
            if (!NumberOne) {
              
              NumberOne = i;
              ++NumberOne;
              break;
            
            }
            
            else {
              
              --NumberOne;
              int temp = butGamepad[NumberOne].invokeGamepadPress(button_get_name);
              butGamepad[NumberOne].buttonReinstall(butGamepad[i].invokeGamepadPress(button_get_name));
              butGamepad[i].buttonReinstall(temp);
              NumberOne = 0;
              break;
            
            }
          
          }  
        
        }
        
        return 0;
      
      }
      
      void Md_resetButtons(){// функція виконує скидання кнопок до стандартних / Select Start окрема функція геймпада/масив буде потрібно змінити в кінці test
                  
        byte defaultButton[] = {15, 5, 6, 7, 8, 9, 10, 11, 12, 13};// test

        for (int i = 0; i < sizeof(defaultButton); i++) {
          
          prof(act_dir)->gamepadButton[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(sizeof(Lines), 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()+2000;
          
          }
        
        }
      
        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()) {// всі дії виконуються по таймеру
        
        Ae_displayRefresh(reset);
        tmr = millis()+400; 
        
        }

        return 0; 
        
      }
    
    // B 
    
    // changeNameProfile
      
      void Md_changeNameProfile(){
        
        static int8_t AxisX, AxisY, delFlag;// XYнаведення на вибрану букву delFlag видалення за допомогою отримання
        static uint32_t tmr;// використовується для видалення утриманняm
        static int8_t magnitude = 1;// костилі використовується для вибору пробілу і виходу
      
        char letterBig[6][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', '-'},
          {25 , 'Z', 'X', 'C', 'V', 'B', 'N', 'M', '.', 27 },
          {' ', ' ', ' ', ' ', ' ', ' ', ' ', '>', '>', '>'}
          
        };
        
        char letterSmall[6][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', '-'},
          {24 , 'z', 'x', 'c', 'v', 'b', 'n', 'm', '.', 27 },
          {' ', ' ', ' ', ' ', ' ', ' ', ' ', '>', '>', '>'}
        
        };

        static char (*ptrLetter)[10] = letterSmall;// вказівник вказує в залежності від настройки на великі або малі букви
        
        if (Mf_EncoderButton() == click ) {// після кліку виконується видалення додавання букви
          
          if (ptrLetter[AxisY][AxisX] == 25) {
          
          ptrLetter = letterSmall;
          
          }   
          
          else if (ptrLetter[AxisY][AxisX] == 24) {
          
          ptrLetter = letterBig;
          
          }   
          
          else if (ptrLetter[AxisY][AxisX] == 27) {
            
            prof(act_dir)->nameProfiles(delete_letter);                          
            
            if (!prof(act_dir)->letterIndicator) {
                
              ptrLetter = letterBig;
              
            }
            
          }
          
          else if (ptrLetter[AxisY][AxisX] == '>') {
          
            AxisX = AxisY = delFlag = 0;
            ptrLetter = letterSmall;
            Md_cursor(set_pos, posThree);
            Md_addres(3, back);
          
          }
          
          else{ 
            
            if (!prof(act_dir)->letterIndicator) {// якщо вводиться перша буква всі букви стають малими одноразовo
                
              ptrLetter = letterSmall;
              
            }
            
            prof(act_dir)->nameProfiles(change_letter, ptrLetter[AxisY][AxisX]);
          }
          
        }   
          
        if (Mf_EncoderButton(take_but_pos) == button_pressed){// якщо утримувати кнопку можна зробити дві дії видалення букви утриманням або переміщення по осі Y
        
          if (Mf_encoderRotationSpeed(check_rotation) == data_available) {// переміщення курсу вверх-вниз якщо кнопка отримується
            
            delFlag = 1;// забороняємо видалення утриманням коли почались оберти енкод
            Mf_EncoderButton(reset);// Клік не повернеться скидаємо функцію
          
            switch (Mf_encoderRotationSpeed(get_rotation)) {
                
              case rotated_r: 
                
                AxisY--;
                
                if (AxisY < 0) {
            
                AxisY = 4;
            
                }
              
              break; 
              
              case rotated_l: 
          
                AxisY++;
                
                if (AxisY > 4) {
            
                AxisY = 0;
            
                }
              
              break;   
              
            }
          }
          
          else if(ptrLetter[AxisY][AxisX] == 27 && !delFlag) {// якщо не було обертів під час отримання кнопки І ми навелились на знак видалення і минув час починається видалення букв
          
            if (tmr < millis()) {
              
              Mf_EncoderButton(reset);
              tmr = millis()+300;
              
              prof(act_dir)->nameProfiles(delete_letter);
              
              
              if (!prof(act_dir)->letterIndicator) {
                  
                ptrLetter = letterBig;
                
              }
            
            }

          }
      
        }
        
        else if (Mf_encoderRotationSpeed(check_rotation) == data_available){// звичайний режим роботи курсор рухається вправо і вниз і повторно починає свої дії якщо дійти до кінця  і наоборот
        
          switch (Mf_encoderRotationSpeed(get_rotation)) {
            
            case 0: 
            
              break;
            
            case rotated_r: 
              
              AxisX -= magnitude;
              
              break;  
            
            case rotated_l: 
              
              AxisX += magnitude;
              
              break;   
          
          }

          if (AxisX < 0) {// тут відбувається обмеження мінімального і максимального значення перемінних X Y також змінюється амплітуда якщо y = 4
            
            magnitude = 1;
            AxisX = 9;
            AxisY--;
          
          }
          
          else if (AxisX > 9) {
            
            magnitude = 1;
            AxisX = 0;
            AxisY++;
          
          }
          
          if (AxisY < 0) {
            
            AxisY = 4;
          
          }
          
          else if (AxisY > 4 ) {
            
            AxisY = 0;
          
          } 
          
          if (AxisY == 4) {// якщо y вказує на останній рядок магнітуда збільшується до 9 так щоб після двох обертів ми покидали нижню частину
            
            if (AxisX != 0 && AxisX != 9) {// користуємо якщо X не є дев'яткою або нулем після того як переміщалися вверх-вниз курсором
              
              if (AxisX >= 7) {
              
              AxisX = 9;
              
              }
              
              else{

              AxisX = 0;
              
              }
        
            }
            
            magnitude = 9;// якщо перетворити на 9 після нуля буде дев'ятка а після дев'ятки буде перебільшення і скидання курсова наверх після оберту енкодером
            
          }
      
        }
        
        else{// захист від випадкового видалення коли хочемо почати переміщатися вверх-вниз коли знаходимося на пункті видалення
          
          Ae_displayRefresh(reset);
          tmr = millis()+400;
          delFlag = 0;
        
        }
      
        Md_p_changeNameProfile(ptrLetter, AxisX, AxisY);// віалізуємо програму
      
      }
      
      byte Md_p_changeNameProfile(char letter[][10], byte AxisX, byte AxisY){
        
        char str[] = {24, 25, 27, '>' , ' '};// маси використовується для мигання необхідної рамки
        static byte flagBlink;
        static uint32_t tmr;
        
        
        
        display.setCursor(114, 54);// back
        display.print('s'); 
        display.drawPixel(120, 60, WHITE); // крапка
        
      
        for (int i = 0; i <= 4; i++) {// виводимо рамку навколо букви якщо курсор рамку не вказує на пункти
        
        if(letter[AxisY][AxisX] == str[i]){
          
          break;
        
        }
        
        if(i == 4){// якщо елемент не дорівнює забороненим знакам то виводимо рамку
        
          display.drawRect(4+AxisX*12, 12+AxisY*10, 9, 11, WHITE);// рамка курса 10 вверх вниз, вліво вправо 12 
        }
        
        }

        if((letter[AxisY][AxisX] != 24 && letter[AxisY][AxisX] != 25) || flagBlink){// кружок стрілка вниз вверх
        
        display.drawCircle(8, 47, 5, WHITE);
        
        }
        // принцип роботи якщо навелись на додатковий знак то починаємо ним мигати за допомогою флажка
        if(letter[AxisY][AxisX] != 27 || flagBlink){//  знак видалення 
          
          display.drawCircle(116, 47, 4, WHITE);
        
        }
        
        if(letter[AxisY][AxisX] != '>' || flagBlink){// рамка s.
        
        display.drawRoundRect(112, 54, 9, 9, 0, WHITE);
        
        }
        

        display.fillRect(36, 54, 54, 6, WHITE);// пробіл
        
        if(letter[AxisY][AxisX] == ' '){// додаткова рамка якщо навели на пробіл
        
        display.drawRect(34, 52, 58, 10, WHITE);
        
        }
        
        if(tmr < millis()){// мигння рамкою
          
          Ae_displayRefresh(reset);
          tmr = millis()+400;
          flagBlink = !flagBlink;
          
        }
        
        if(!flagBlink && prof(act_dir)->letterIndicator != 20){// перестає мигати якщо 20 символів також мигаємо за допомогою flagBlink
        
          display.drawRect(2+6*prof(act_dir)->letterIndicator, 0, 1, 9, WHITE);
        
        }
        
        display.setCursor(2, 1);// виводив ім'я профіля
        display.print(prof(act_dir)->nameProfiles(get_name));
        
        for (int i = 0; i < 4; i++) {// виводим масив букв на дисплей
          
          for (int j = 0; j < 10; j++) {
            
            display.setCursor(6+j*12, 14+i*10);
            display.print(letter[i][j]);
            
          }
        }
        
      return 0; 
      
      }
    
    // cNP
  
  // 
 
  //  Md_Additional functions-------------------------------------------------------------------------------------------
    
    byte MdAf_consenDisplay(){ // викликається для підтвердження вибору
      
      static int8_t flagChoice;
      
      switch (Mf_encoderRotationSpeed(get_rotation)) {// керування рамкою вліво вправо
       
        case no_action: 
          
          break;
        
        case rotated_l: 
          
          if (flagChoice > -2) {
           
           flagChoice--;
          
          }
          
         break;
        
        case rotated_r: 
          
          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()) {//  виконує мигання рамкою навколо слова так ні
        
        Ae_displayRefresh(reset);
        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;
        
        case reset:// прост  спосіб скинути функцію перестане відправляти recorded_changes виконані зміни збережуться
           
          prof(act_dir)->checkName();// якщо видалені всі букви То встановлюється стандартне ім'я профілю
          profilSeve.copyFrom(*prof(act_dir));
          
          if (prof(act_dir)->tape == t_mp) {// якщо ми настроювали власний профіль то перезаписуємо настройки в енергонезалежну пам'ять
            Serial.println("t_mp s");
            EEPROM.put((prof(act_dir)->namber - 1) * sizeof(Profiles), *(prof(act_dir)));
            EEPROM.commit();
          
          }
          
          else if (prof(act_dir)->tape == t_sp) {
           
           int tempProfSize = 7 * sizeof(Profiles);
           Serial.println("t_mp s");
           EEPROM.put(tempProfSize + (prof(act_dir)->namber - 1) * sizeof(prof(act_dir)->gamepadButton), prof(act_dir)->gamepadButton);
           EEPROM.commit();
          }
         
         break;
      }
      
      return 0;
    }
    
    void MdAf_typeNumberPrint(){
      
      display.setCursor(49, 0);
      if (prof(act_dir)->tape == t_sp) { 
       
       display.print("(Sp");
       display.print(prof(act_dir)->namber);
       
      }
      else {
       
       display.print("(Mp");
       display.print(prof(act_dir)->namber);
      }
      display.print(")");
    }
    
    byte MdAf_confirmYesNo(byte azixX, byte azixY){
     
     // функцію можна відобразити в любому місці біля слова рецепт після завершення потрібно скинути вручну
      static byte flagChoice;
       
      if (Mf_encoderRotationSpeed(get_rotation)) {
      
       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
  
  //  Menu functions 5 
 
    byte Md_cursor(byte dataCommand, byte* arr) { 
      
      static int8_t permissionArrow, Point = 1, workPermit = 1;
          
      switch (dataCommand) {
        
        case set_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_encoderRotationSpeed(get_rotation)) {
              
              case rotated_l: 
                
                Point--;
                
                if (Point == 0) {
                  
                  Point = dataCommand;
                
                }
                
                break;
              
              case rotated_r: 
                
                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 dataCommand) {

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

      switch (dataCommand) {
        
        case back:
          
          Ae_displayRefresh(reset);
          Md_cursor(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(get_pos);// позиція курс означає набраний адрес
            namb++;

          return address_entered;
          
          }

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

    }
  
    int8_t Mf_encoderRotationSpeed(int8_t acceptedCommand) {// функція повертає бистре або повільне обертання працює разом з функцією Ae_encoderInterrupt_fastRotation() для обробки даних
      
      static int seveEncoder;// збереження позиції кондера
      
      if (acceptedCommand == check_rotation) {// перевіряємо наявність обертів спочатку перевіряється наявність даних check_rotation необхідно для економії ресурсів 
        
        if (seveEncoder != encoder.getPosition()) {
         
         return data_available;
        
        }
      
      }
      
      else if (acceptedCommand == get_rotation) {
        
        if (g_encFast > 0) {// якщо енкодер обертається з достатньою швидкістю переміна g_encFast буде 1 або -1
         
         g_encFast = 0;// скидаємо перемінно для того щоб знову визначити швидкість обертання
         return rotated_r_fast;
        
        }
        
        else if (g_encFast < 0) {
         
         g_encFast = 0;
         return rotated_l_fast;
        
        }
        
        else if (seveEncoder < encoder.getPosition()) {// залежності від сторони обертання паралельно виконується одиночне + або -
         
         seveEncoder = encoder.getPosition();
         return rotated_r;
        
        }
        
        else if (seveEncoder > encoder.getPosition()) {
         
         seveEncoder = encoder.getPosition();
         return rotated_l;
        
        }
 
      }

      return 0;
    
    }
    
    byte Mf_EncoderButton(byte acceptedCommand) {

      static byte saveData; 
      static uint32_t tmr;
      
      if (acceptedCommand){// в Kodi можемо зробити reset щоб не поверталося утримання hold_b_e або click
      
        if (acceptedCommand == reset && saveData != reset_status){// в Kodi можемо зробити reset щоб не поверталося утримання hold_b_e або click
         
         saveData = reset_status;
        
        }
        
        else if (acceptedCommand == take_but_pos && Ae_BatR(b_sw)){ // викликаємо стан кнопки якщо кнопка нажата то можемо наприклад скинути функцію і вона не поверне hold_b_e або click
        
          return button_pressed;
         
        }
      
      }
      
      else{
        
        if (!Ae_BatR(b_sw) && !saveData){// економія ресурсів виконується постійно якщо кнопка не нажата
        }

        else if (Ae_BatR(b_sw)){// якщо ми натиснули кнопку може відбутися дві події
          
          if (!saveData) {// якщо натиснули одразу повернеться натиск а потім Клік
             
            saveData = press_b_e; 
            tmr = millis() + 500; 
            return press_b_e;
          
          }
          
          else if (saveData == press_b_e && tmr < millis()) {// якщо натиснули і утримуємо і час вийшов повернеться утримання
           
            saveData = hold_b_e; 
            return hold_b_e;
        
          }
        
        }
            
        else if (saveData && !Ae_BatR(b_sw)) {// якщо бистро відпустили кнопку повертається Клік
          
          int temp = saveData;
          saveData = 0; 
          
          if (temp == press_b_e){
            
            Ae_displayRefresh(reset); 
            return click;
          
          }
        
        }
      
      } 
      
      return 0;
        
    }  
    
    int Mf_Magnifier(int Numeric, int Min, int Max, int Speed) {
   
      if (Mf_encoderRotationSpeed(check_rotation) == data_available) {  
        
        Mf_EncoderButton(reset);
        
        switch (Mf_encoderRotationSpeed(get_rotation)) {
          
          case rotated_r:
            
            Numeric++;
            
           break;
          
          case rotated_l:
            
            Numeric--;
            
           break;
          
          case rotated_r_fast:
            
            Numeric+=Speed;
            
           break;
          
          case rotated_l_fast:
            
            Numeric-=Speed;
            
           break;
        
        }
      
      }
   
      if (Numeric > Max) {
        
        Numeric = Min;
      
      } 
      
      else if (Numeric < Min) {
        
        Numeric = Max;
      
      }
     
     return Numeric;
    
    }

  //  Mf

// Md

// MdId
  
  void MdId_BluetoothPrint() {
      
    const byte bluArr[9] = {
      0b00100,
      0b00110,
      0b10101,
      0b01110,
      0b00100,
      0b01110,
      0b10101,
      0b00110,
      0b00100
    };
    
    static uint32_t tmr;
    static byte Flag;
    
    display.drawCircle(6, 6, 6, WHITE);// кружок
    // display.setCursor(4, 3);
    
    if (bleGamepad.isConnected()) {

      display.drawBitmap(1, 2, bluArr, 8, 9, WHITE);
    
    }
    
    else{
      
      if (tmr < millis()) {
        
        Ae_displayRefresh(reset);
        Flag = !Flag;
        tmr = millis() + 1000;
      
      }
      
      if (Flag) {
        
        display.drawBitmap(1, 2, bluArr, 8, 9, WHITE);
      
      }

    }
  
  }

  void MdId_battery() {
    
    const float batLevels[] = {4.15, 4.0, 3.82, 3.76, 3.65, 3.6, 3.5, 3.4, 3.3, 3.0};
    /*
    float shuntVoltage_mV = ina219.getShuntVoltage_mV();
    float busVoltage_V = ina219.getBusVoltage_V();
    float loadVoltage_V  = busVoltage_V + (shuntVoltage_mV / 1000);
    */
    static float loadVoltage_V = 3.0;//  test
    static byte chargeLevel;
    static uint32_t tmr;
    
    if (tmr < millis()) { 
      
      tmr = millis() + 60000;
     
      for (int i = 0; i <= 9 ; i++) {
    
        if (loadVoltage_V >= batLevels[i]) {
         
         if (chargeLevel != map(i, 0, 9, 0, 11)) {
          
          Ae_displayRefresh(reset);
      
         }
          
          chargeLevel = map(i, 0, 9, 0, 11);
         
         break;
        
        }
      
      }
    
    }
    
    MdId_p_battery(chargeLevel);  
  
  }

  byte MdId_p_battery(byte receivedData) {

    display.drawRect(111, 2, 1, 4, WHITE);// картинка батареї
    display.drawRect(112, 0, 16, 8, WHITE);
    
    display.fillRect(114+receivedData, 2, 12-receivedData, 4, WHITE);// шкала заряду батареї
   
   return 0;
  
  }

// MI

// info Display
   
  void infoDisplay() {

    MdId_BluetoothPrint(); 
    MdAf_typeNumberPrint();
    MdId_battery();

    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");

  }

// Id

// Display
  
  byte Md_Display(byte Receiving) { 
 
    static byte Regime = info_display; 
    // static byte Regime = menu;
   
    Ae_displayRefresh(clear_display);
 
    if (Receiving) {
    
     Regime = Receiving;
    
    }
    
    switch (Regime) {
    
      case info_display: 
          
        if (Mf_EncoderButton() == click) {
     
          Md_Display(menu);
        
        }
        
        /*
        else if (Mf_EncoderButton() == hold_b_e) {// по плану має виключати дисплей при утриманні ?
     
         display.clearDisplay();
         display.display();
        
        }
        */
        else{
        
         infoDisplay();
        
        }
      
       break;
    
      case menu:
        // Ae_displayRefresh(reset);
        Md_MainDisplay();
      
       break;

    }  
   
    Ae_displayRefresh(print_display);
     
   return 0;
  
  } 

// D

// Gamepad function
 
  void IRAM_ATTR Gf_GyroAnalogR() {

    // static uint32_t tmr;
    volatile static int GiroDedZone;
    volatile static int rightStickX;
    volatile static int rightStickY;
    static int x; // x
    static int z;  // z
    /*
    
    */
    // Serial.println(" 11111");
    // if (Ae_BatR(b_handle) && tmr < millis()) {  
      // if (Ae_BatR(b_handle) && bleGamepad.isConnected()) { 
    
    if (Ae_BatR(b_handle)) { 
      
      Ae_autoShutdown(reset);
      /*
      Quaternion q;
      VectorFloat gravity;
      VectorInt16 gyro;
      volatile static float ypr[3];
      */
      /*
      if (mpu.dmpGetCurrentFIFOPacket(fifoBuffer)) {
        
        mpu.dmpGetQuaternion(&q, fifoBuffer);
        mpu.dmpGetGyro(&gyro, fifoBuffer);
        mpu.dmpGetGravity(&gravity, &q);
        mpu.dmpGetYawPitchRoll(ypr, &q, &gravity);
        // tmr = millis() + 11;
      
      }
      */
      
      
      if (abs(x) > 1) {
        
        GiroDedZone = map(z, -150, 150, -30, 30);  
        GiroDedZone = abs(GiroDedZone);
 
        if (x < -GiroDedZone) {
          
          x = map(x, -1, -prof(act_dir)->sensitivityHor, -prof(act_dir)->deadZoneHor, -32767);
          x = constrain(x, -32767, -1);
          bleGamepad.setZ(x);
        
        }
        
        else if (x > GiroDedZone) {
          
          x = map(x, 1, prof(act_dir)->sensitivityHor, prof(act_dir)->deadZoneHor, 32767);
          x = constrain(x, 1, 32767);
          bleGamepad.setZ(x);
        
        }
      
      } 
      
      else{

       bleGamepad.setZ(0); 
      
      }
      
      if (abs(z) > 1) {
        
        GiroDedZone = map(x, -150, 150, -30, 30);  
        GiroDedZone = abs(GiroDedZone);
 
        if (z < -GiroDedZone) {
          
          z = map(z, -1, -prof(act_dir)->sensitivityHor, prof(act_dir)->deadZoneHor, 32767);
          z = constrain(z, -32767, -1);
          bleGamepad.setRZ(z);
        
        }
        
        else if (z > GiroDedZone) {
          
          z = map(z, 1, prof(act_dir)->sensitivityHor, -prof(act_dir)->deadZoneHor, -32767);
          z = constrain(z, 1, 32767);
          bleGamepad.setRZ(z);
        
        }
      
      } 
      
      else{

       bleGamepad.setRZ(0); 
      
      }  
     
     bleGamepad.sendReport();
    
    } 
    
    else if (rightStickX || rightStickY){
          
      rightStickX = rightStickY = 0;
      bleGamepad.setRightThumb(0, 0);
      bleGamepad.sendReport();
    
    }    

  }
  
  void Gf_AnLeftDpad(){
  
    static bool flag;
    int AxisX = constrain(analogRead(39), 45, 4050);
    int AxisY = constrain(analogRead(36), 45, 4050);
    
    
    if ((AxisX < 1800 || AxisX > 2200) || (AxisY < 1800 || AxisY > 2200)) {
    
      if (!Ae_BatR(b_emul_dpad)) {
      
        if (flag) {
          
          flag = 0;
          bleGamepad.setHat1(HAT_CENTERED);
        
        }
        
        AxisX = map(AxisX, 45, 4050, -32767, 32767);
        AxisY = map(AxisY, 45, 4050, -32767, 32767);
        bleGamepad.setLeftThumb(AxisX, AxisY); 
    
      }
  
      else{ 
      
        if (!flag) {
        
         flag = 1;
         bleGamepad.setLeftThumb(0, 0); 
      
        }
       
        if (AxisX < 1800 || AxisX > 2200) {
          
          AxisX = constrain(AxisX, 1800, 2200);
          AxisX = map(AxisX, 1800, 2200, 2, 4);
        
        }
        
        else{

         AxisX = 0;
        
        }
        
        if (AxisY < 1800 || AxisY > 2200) {
          
          AxisY = constrain(AxisY, 1800, 2200);
          AxisY = map(AxisY, 1800, 2200, 1, 6);
        
        }
        
        else{

         AxisY = 0;
        
        }
        
        const byte dpadArr[] = {0, 1, 3, 2, 7, 8, 5, 0, 4, 0, 6};
        bleGamepad.setHat1(dpadArr[AxisX+AxisY]);
      
      }
        
    }    
        
    else{
     
     bleGamepad.setLeftThumb(0, 0); 
     bleGamepad.setHat1(0);
    
    }    
        
  }      
 
  void Gf_gamepadButtons(){

    if (Ae_BatR(prof(act_dir)->gamepadButton[1])) {
     
     bleGamepad.pressSelect();
    
    }
    
    else{

     bleGamepad.releaseSelect();
   
    }
    
    if (Ae_BatR(prof(act_dir)->gamepadButton[2])) {
     
     bleGamepad.pressStart();
    
    }
    
    else{

     bleGamepad.releaseStart();
   
    }
    
   
    if (Ae_BatR(prof(act_dir)->gamepadButton[11])) {
     
     bleGamepad.setLeftTrigger(32767);       
    
    }
    
    else{

     bleGamepad.setLeftTrigger(0);
   
    }
    
    if (Ae_BatR(prof(act_dir)->gamepadButton[12])) {
     
     bleGamepad.setRightTrigger(32767);
    
    }
    
    else{

     bleGamepad.setRightTrigger(0);
   
    }
   
    for (int i = 3; i <= 12; i++) {
          
      if (Ae_BatR(prof(act_dir)->gamepadButton[i])) {
       
       bleGamepad.press(i);      
      
      }      
      
      else{
        
       bleGamepad.release(i);
      
      }
    
    }
  
  }

// Gf

void setup() {
  
  Serial.begin(9600);//  В ФІНАЛІ НЕЗАБУТИ ЗАКОМЕНТУВАТИ!!!
  bleGamepad.begin();
  EEPROM.begin(512);
  prof(eeprom_initialization);// ініціалізація з енергонезалежної пам'яті профілів
  
  delay(500);
  // /pinMode(3, OUTPUT);// подаємо високий сигнал на транзистор щоб заживити  модулі
  // digitalWrite(3, HIGH);
  // pin 2 глючить встроєний резистор
 
 
  /*
  pinMode(32, INPUT_PULLUP);
  pinMode(15, INPUT_PULLUP);
  pinMode(5, INPUT_PULLUP);
  pinMode(13, INPUT_PULLUP);
  */
  pinMode(25, INPUT_PULLUP);
  
  byte pinsArr[] = {12, 13, 14, 4, 15};
  pinMode(26, OUTPUT);// test
  digitalWrite(26, HIGH);
  pinMode(27, OUTPUT);// test
  digitalWrite(27, LOW);
  /*
  
  byte pinsWithPullup[] = {33, 13, 27, 26, 25, 16, 17, 5, 23, 2, 18, 19, 32, 15, 4, 12, 14};// добавити 1

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

  }
  
  esp_sleep_enable_ext0_wakeup(GPIO_NUM_13, 0);
  
  hw_timer_t * timer = NULL;
  timer = timerBegin(0, 80, true); //  Таймер 0, прескалер 80 (для ESP32), true для повторення таймера
  timerAttachInterrupt(timer, &Gf_GyroAnalogR, true); //  Встановлюємо функцію, яка буде викликана таймером
  timerAlarmWrite(timer, 11000, true); //  Встановлюємо час спрацьовування таймера (11 мілісекунд)
  timerAlarmEnable(timer); //  Вмикаємо таймер
  
  ina219.setADCMode(BIT_MODE_12); //  Устанавливаем разрешение АЦП 12 бит
  ina219.setPGain(PG_40); //  Ток в пределах 400 мА
  ina219.setBusRange(BRNG_16); //  Напряжение до 16 В
  
  */
  
  attachInterrupt(digitalPinToInterrupt(p_dt), Ae_encoderInterrupt_fastRotation, CHANGE);
  attachInterrupt(digitalPinToInterrupt(p_clk), Ae_encoderInterrupt_fastRotation, CHANGE);
  

  // ----------Display--------------
  display.begin(SSD1306_SWITCHCAPVCC, 0x3C);
  display.setTextSize(1);
  display.setTextColor(WHITE);
  // gyroStart();// при потребі проводимо калібровку якщо калібровка виконана виконуємо старт функції гіроскопа
  // startAnimation();// анімація при включенні до робити в кінці

}


void loop() {
  
 
  // Ae_autoShutdown();
  // Ae_buttonOnOff();
  // Ae_batteryCheck();
  Md_Display();
  
  /*
  if (bleGamepad.isConnected()) {
    
    // Gf_GyroAnalogR();
    Gf_AnLeftDpad();
    Gf_gamepadButtons();
    bleGamepad.sendReport();
  
  }
*/
}// void loop()