#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#include "GyverEncoder.h"
//#include <BleGamepad.h> // при загрузці нa реально Arduino даний фрагмент розкоментувати a class BleGamepad закоментувати
//#include "esp32-hal-timer.h"///потрібно для зчитування даних гіроскопа по таймеру
//#include <EEPROM.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 no 0 
      #define yes 1
      #define get_status 1              //  получити настройки
      #define save_settings 4           //  зберехти настройки
      #define reset_f 11
      #define on 12
      #define click 13
      #define gyro 14
      //#define profil 15
      #define data_available 16// дані доступні
      #define delete_data 17
      #define start 18
    //
    
    //?
      #define melody_start 1
      #define melody_off_power 2

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


      #define get_y 2
      #define get_z 3
      #define get_vibr 4
  
    //
    
    // Піни карта
      // #define b_mein 25
      #define b_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
      #define b_sw 25 //  кнопка енко // RotaryEncoder encoder(27, 14, RotaryEncoder::LatchMode::TWO03);
      #define p_dt 32
      #define p_clk 33
    // 
    
    // 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 address_deleted 22
      #define get_add 23
      #define check_button_enc 24 
      #define mode_click_input 25  
      #define mode_click_back 26      
      #define back_add 27      
      #define mode_final_choice 28
      #define address_not_entered 0
      
    //
    
    // int Md_cursor() Md_p_cursor()
     
      #define get_pos 20
      #define set_pos 21
      #define cursor_read_encoder 24
      #define cursor_type_one 0 
      #define cursor_type_two 1
    
    //
    
    // Mf_encoder()   b
      
      #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
      #define encoder_rotates 26 // дані доступні
      #define reset_rotation 27
      volatile int8_t g_encFast;
    
    //  
    
    // MdAf_confirmYesNo() 
      
      #define choice_no 20
      #define choice_yes 21
      #define confirm_read_click 22    
      #define confirm_read_hold 23
    //
    
    // Mf_Buttons()
      // #define reset_f 11
      #define next_animation 20
    //
    
    // Ae_displayRefresh()
      //#define no_data 0 //  немає даних
      #define clear_display 20
      #define print_display 21
      #define refresh 22
    
    //
    
    // Ae_autoShutdown()
      // #define reset_f 11
      #define change_time 20
      #define get_time 21
    //
    
    // Md_movingButtons()
      
      #define choice_bat_waiting 20
      #define button_selection_complete 21
      #define return_default 22
      #define check_batton 23
    
    //
    
    // Button gamepad class
    
      #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
      
      // byte (*gamepadPressPtr)();
      #define read_button_state 20
      #define press_check 21
      #define gamepad_button_pressed 22
      #define button_get_name 23
    
      
      //byte buttonGamepadPressRelease();
      #define press_button 20
      #define release_button 21
      #define dpad_check 22
      #define dpad_center 23  
    //  
    
    // Profiles class 
      
      #define t_sp 1// не міняти число!
      #define t_mp 2// не міняти число!
      #define r_off 0 //  = off
      #define r_on 12 //  = on
      
      //nameProfiles(byte acceptedCommand, char Letter = ' ')
      #define get_name 20
      #define get_name_a_f 21
      #define change_letter 22
      #define delete_letter 23
      
      // *prof()
      #define act_dir 22
      #define activate_p_sp 23
      #define activate_p_mp 24
      #define eeprom_initialization 25
      #define activate_p 26
      #define copy_profile 27
      
      #define copy_profilerofile 28
      #define not_save 29
      #define save_changes 30
      #define acting_copy_compare 31
      #define acting_copy_differs 32  // зафіксовані зміни    
      
      //listButton[18]
      #define button_1 1
      #define button_2 2
      #define button_3 3
      #define button_4 4
      #define button_5 5
      #define button_6 6
      #define button_7 7
      #define button_8 8    
      #define button_9 9
      #define button_10 10

      #define button_select 11
      #define button_start 12

      #define dpad_up 13
      #define dpad_down 14
      #define dpad_left 15
      #define dpad_right 16
      
      #define trigger_r 17
      #define trigger_l 18      
      uint32_t tmrProf = 0;
    
    //
    
  // c-v-a  
  
  // Function prototypes
    
    byte Md_addres(byte acceptedCommand = 0, byte addNumb = 0, byte additionalCommand = 0);
    byte Md_p_Buttons(byte receivedData = 0, byte selectedButton = 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);
    byte buttonGamepadPressRelease(byte command = 0, byte buttonName = 0);
    byte Md_cursor(byte acceptedCommand = 0, byte data = 0, byte* arr = nullptr);
    byte MdAf_confirmYesNo(byte acceptedCommand = 0, byte azixX = 0, byte azixY = 0);
  
  // Fp
  
// Ae 

//  (пуcті класи) Пустишки для того щоб не нагружати код і час компіляції 100=30

  #define HAT_CENTERED 0
  #define HAT_UP 1
  #define HAT_UP_RIGHT 2
  #define HAT_RIGHT 3
  #define HAT_DOWN_RIGHT 4
  #define HAT_DOWN 5
  #define HAT_DOWN_LEFT 6
  #define HAT_LEFT 7
  #define HAT_UP_LEFT 8

 class BleGamepadConfiguration {
  public:
    void setAutoReport(int value) {
        // Нічого не робить
    }

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

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

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

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

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

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

    void setWhichAxes(bool x, bool y, bool z, bool rx, bool ry, bool rz, bool slider1, bool slider2) {
        // Нічого не робить
    }
  };

  
  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(BleGamepadConfiguration* config) {
          // Нічого не робить
      }

      void end() {
          // Нічого не робить
      }
      
      // Додаткові методи-пустишки

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

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

      void setAxes(bool leftX, bool leftY, bool rightX, bool rightY, bool leftTrigger, bool rightTrigger, bool zAxis, bool rzAxis) {
          // Нічого не робить
      }

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

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

      void setRumble(uint16_t leftMotor, uint16_t rightMotor) {
          // Нічого не робить
      }
  };
 


// 

Adafruit_SSD1306 display(128, 64, &Wire, -1);
BleGamepadConfiguration bleGamepadConfig;//потрібно для настройок геймпада
BleGamepad bleGamepad("FS G36", "UA", 100);
Encoder enc(p_clk, p_dt);

// Profiles class 
  
  
  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)
        
        {    
         
        for (byte i = 0; i < 18; i++) {//стандартний порядок кнопок
         
         listButton[i] = i + 1;
        
        }            
          
          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); //  Форматуємо нову назву
        }
      
      }

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

  };
  
  //  Profile designers конструктори класу Profiles
 
    Profiles profil[] = {// test 
      
      Profiles (0, 0, 0, 0, "0", 0, 0),// використовується для перевірки чи були зміни
      Profiles (2000, 100, 2556, 92, "CodMW", t_sp, 1),
      Profiles (166, 120, 1965, 112, "Batl3", t_sp, 2),
      Profiles (2000, 100, 2556, 92, "SP 33", t_sp, 3),
      Profiles (166, 120, 1965, 112, "SP 44", t_sp, 4),
      Profiles (2000, 100, 2556, 92, "SP 55", t_sp, 5),
      Profiles (166, 120, 1965, 112, "SP 66", t_sp, 6),
      Profiles (2000, 100, 2556, 92, "SP 77", t_sp, 7),
      
      Profiles (2000, 100, 2556, 92, "05461               ", t_mp, 1),
      Profiles (166, 120, 1965, 112, "Xmen   74           ", t_mp, 2),
      Profiles (2000, 100, 2556, 92, "Mp 3                ", t_mp, 3),
      Profiles (166, 120, 1965, 112, "Mp 4                ", t_mp, 4),
      Profiles (2000, 100, 2556, 92, "Mp 5                ", t_mp, 5),
      Profiles (166, 120, 1965, 112, "Mp 6                ", t_mp, 6),
      Profiles (2000, 100, 2556, 92, "Mp 7                ", t_mp, 7)
    
    };
  
  // Pd
  
  
  Profiles* prof(byte acceptedCommand, byte number = 0) { 
    
    static byte acting = 9;
    static byte returnResult;
    
    if (acceptedCommand == act_dir) { // Скеровування до активного профілю
         
      return &profil[acting];
          
    }
      
    else if (acceptedCommand == activate_p) {// вибраний профіль активується

      for (int i = 1; i < 15; i++) {
  
       profil[i].setStatus(r_off);
      
      }
  
      acting = number;
      profil[acting].setStatus(r_on);
       
    }
   
    else if (acceptedCommand == copy_profile) { //виконується одноразово при наборі адресу при заході в настройки див. адрес 2    
     
     profil[0] = profil[acting];
   
    }
   
    else if (acceptedCommand == acting_copy_compare) {    
      
      if (!returnResult && profil[0] != profil[acting]) {//Якщо хоч один з копійованих пунктів відрізняється умова буде правдива
        
        returnResult = acting_copy_differs;//Дана зміна використовується щоб скоротити час виконання коду
        
      }  
        
      return (Profiles*)&returnResult;
    
    }    
    
    else if (acceptedCommand == save_changes) { 
      
      returnResult = 0;
      profil[0] = profil[acting];//зроблено для того щоб при другому виклику умова if (!returnResult && profil[0] != profil[acting]) не виконалась. виконається вихід
      prof(act_dir)->checkName();// якщо видалені всі букви То встановлюється стандартне ім'я профілю   
      
    }        
    
    else if (acceptedCommand == not_save) { 
     
      returnResult = 0;
      profil[acting] = profil[0];
     
    }        
    
    return nullptr; 
  
  }
    
// P

// Button debounce class
 
  class DebButton {
    
    private:
      
      byte pin;       
      uint32_t tmr; 
      bool buttonState;  
    
    public:
      
      //  Конструктор класу, ініціалізація піна, номера кнопки геймпада та часу захисту від випадкових спрацьовувань
      DebButton(int p, int dt = 300) {
        
        pin = p;
        tmr = dt;
        pinMode(pin, INPUT_PULLUP);
      
      }
     
      //  Метод для обробки натискання кнопки
      bool press() {
        
        if (!digitalRead(pin) && !buttonState && millis() > tmr) {// після натську кнопки буде повернення true
         
          buttonState = true; // тепер переміна буде правда
          tmr = millis() + 300;// даємо час кнопці для заспокоєння від брязкaiту при натиску
          
        }
        
        else if (buttonState && digitalRead(pin) && millis() > tmr) {// пісня відпущення кнопки буде повернення брехня
          
          buttonState = false;// тепер переміна буде брехня
          tmr = millis() + 300;// даємо час кнопці для заспокоєння від брязкaiту при відпуску
          
        }
        
        return buttonState;// постійно  повертаємо стан кнопки
         
      }
  };
  
  DebButton DebButtonEncoder(b_sw);// b_sw25
  
  /*
  DebButton debButton[] = {
    
    DebButton(19), 
    DebButton(18), 
    DebButton(5)
   
  };
 */ 
// 
 
// Button gamepad class
  
  class ButGamepad {
    
    private:
      
      byte gamepadButtonName;
      byte pinReadType;
      byte numb;
      byte flagPress; 
      byte buttonCheckFlag;
      DebButton* debButton = nullptr;
      
      //вказівник вказує на одну з вибраних функцій які ми вибираємо конструкторi
      typedef byte (ButGamepad::*GamepadPressMethod)(byte);
      
      GamepadPressMethod gamepadPressPtr;     
      
      //функції використовуються всередині класу обробка натиску кнопки
      
        byte tactilePinButtonRead() {
          
          if (debButton && debButton->press()) { // Перевірка та виклик методу
            
            return true;
          
          }
          
          return false;
        
        } 
        
        byte touchPinButtonRead(){
      
          if (touchRead(numb) < touch_dead_zone) {
          
            return true;
          
          }
          
          return false;
        
        }
        
        byte analogPinButtonRead(){
      
          if (analogRead(numb) > 2600) {
                          
            return true;
          
          }
          
          return false;
        
        }    
      
      //
    
    public:
      
      //конструктор проводимо настройку при першому запуску
      
      ButGamepad(byte gBN, byte pRT, byte n){
        
        gamepadButtonName = gBN;
        pinReadType = pRT;      
        numb = n;
        
        if (pinReadType == tactile_read) {
         
         debButton = new DebButton(numb);
        
        }
        
        if (gamepadButtonName == trigger_r || gamepadButtonName == trigger_l) {// вибір яким способом буде натиснути курок(R L)геймпада курок(R L) = tactile touch analog
        
          if (gamepadButtonName == trigger_r) {
         
            if (pinReadType == analog_read) {
           
              gamepadPressPtr = &ButGamepad::analogReadTriggerRightPress;
        
            }
            
            else if (pinReadType == touch_read) {
           
              gamepadPressPtr = &ButGamepad::touchReadTriggerRightPress;
        
            } 
          
            else if (pinReadType == tactile_read) {
           
              gamepadPressPtr = &ButGamepad::tactileReadTriggerRightPress;
        
            } 
          
          }
          
          else if (gamepadButtonName == trigger_l) {
         
            if (pinReadType == analog_read) {
           
              gamepadPressPtr = &ButGamepad::analogReadTriggerLeftPress;
        
            }
            
            else if (pinReadType ==  touch_read) {
           
              gamepadPressPtr = &ButGamepad::touchReadTriggerLeftPress;
        
            } 
          
            else if (pinReadType == tactile_read) {
           
              gamepadPressPtr = &ButGamepad::tactileReadTriggerLeftPress;
        
            } 
          
          }    
          
        }
        
        else {// вибір яким способом буде натиснути кнопка геймпада кнопка(1...12) = tactile touch analog
          
          if (pinReadType == tactile_read) {
            
            gamepadPressPtr = &ButGamepad::tactilePress;
          
          }
         
          else if (pinReadType == touch_read) {
           
          
           gamepadPressPtr = &ButGamepad::touchPress;
        
          }
        
          else if (pinReadType == analog_read) {
           
          
           gamepadPressPtr = &ButGamepad::analogReadPress;
            
          }        
     
        
        }   
        
      }
      
      //          функції які викликаються через вказівник зроблено для того щоб в циклі фор викликати різні функції по черзі      
      // Bluetooth gamepad push button
        
        byte tactilePress(byte acceptedCommand) {
        
          if (acceptedCommand == read_button_state) {
            
            if (tactilePinButtonRead()) {
            
              if (!flagPress) {
               
               buttonGamepadPressRelease(press_button, gamepadButtonName);
               flagPress = 1; 
              
              }            
            
            }
          
            else if (flagPress){
              
             flagPress = 0; 
             buttonGamepadPressRelease(release_button, gamepadButtonName);
          
            }
          
          }
          
          else if (acceptedCommand == press_check) {
           
            if (tactilePinButtonRead() && !buttonCheckFlag) {
               
              buttonCheckFlag = 1;
              return gamepad_button_pressed;
              
            }
            
            else if (buttonCheckFlag && !tactilePinButtonRead()){
             
             buttonCheckFlag = 0; 
            
            } 
          
          }
          
          else if (acceptedCommand == button_get_name) {
            
            return gamepadButtonName;
           
          }
          
          return 0;
        
        }
        
        byte touchPress(byte acceptedCommand) {
        
          if (acceptedCommand == read_button_state) {
            
            if (touchPinButtonRead()) {
            
              if (!flagPress) {
              
               flagPress = 1; 
               buttonGamepadPressRelease(press_button, gamepadButtonName);
            
              }
            
            }
          
            else if (flagPress){
              
             flagPress = 0; 
             buttonGamepadPressRelease(release_button, gamepadButtonName);
          
            }
          
          }
          
          else if (acceptedCommand == press_check) {
        
            if (touchPinButtonRead() && !buttonCheckFlag) {
            
              buttonCheckFlag = 1;
              return gamepad_button_pressed;
               
            }
          
            else if (buttonCheckFlag && !touchPinButtonRead()){
              
             buttonCheckFlag = 0; 
            
            }
          
          }        
          
          else if (acceptedCommand == button_get_name) {
           
           return gamepadButtonName;
             
          }
                
          return 0;        
        
        }
        
        byte analogReadPress(byte acceptedCommand) {
        
          
          if (acceptedCommand == read_button_state) {
            
            if (analogPinButtonRead()) {
            
              if (!flagPress) {
              
               flagPress = 1; 
               buttonGamepadPressRelease(press_button, gamepadButtonName);
            
              }
            
            }
          
            else if (flagPress){
              
             flagPress = 0;  
             buttonGamepadPressRelease(release_button, gamepadButtonName);
          
            }
          
          }
          
          else if (acceptedCommand == press_check) {
            
            if (analogPinButtonRead() && !buttonCheckFlag) {
             
              buttonCheckFlag = 1;
              return gamepad_button_pressed;
             
            }
          
            else if (buttonCheckFlag && !analogPinButtonRead()){
              
             buttonCheckFlag = 0;  
            
            }
          
          }          
          
          else if (acceptedCommand == button_get_name) {
            
            return gamepadButtonName;       
          
          }           
          
          return 0;             
        
        }          
      
      //     
      
      // Bluetooth gamepad right trigger pressure
        
        byte analogReadTriggerRightPress(byte acceptedCommand) {  
          
          if (acceptedCommand == read_button_state) {
            
            int temp = analogRead(numb);
            Serial.print("---"); Serial.print(temp);
            Serial.print("---"); Serial.println(numb);
            
            if (temp > analog_dead_zone) { // test
              
              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() && !buttonCheckFlag) {
            
              buttonCheckFlag = 1;
              return gamepad_button_pressed;
             
            }
          
            else if (buttonCheckFlag && !analogPinButtonRead()){
              
             buttonCheckFlag = 0;  
            
            }
          
          }    
          
          else if (acceptedCommand == button_get_name) {
            
            return gamepadButtonName;                      
             
          }
          
          return 0;
        
        }      
        
        byte touchReadTriggerRightPress(byte acceptedCommand) {
        
          if (acceptedCommand == read_button_state) {        
          
            if (touchPinButtonRead()) {
            
              if (!flagPress) { 
                
                flagPress = 1; 
                bleGamepad.setRightTrigger(32767);                     
              
              }
              
            }
          
            else if (flagPress){
              
              flagPress = 0; 
              bleGamepad.setRightTrigger(0);
          
            }
          
          }
          
          else if (acceptedCommand == press_check) {
        
            if (touchPinButtonRead() && !buttonCheckFlag) {
            
              buttonCheckFlag = 1;
              return gamepad_button_pressed;
               
            }
          
            else if (buttonCheckFlag && !touchPinButtonRead()){
              
             buttonCheckFlag = 0; 
            
            }
          
          }       

          else if (acceptedCommand == button_get_name) {        
          
            return gamepadButtonName;          
          
          }             
          
          return 0;        
        
        }      
        
        byte tactileReadTriggerRightPress(byte acceptedCommand) {
        
          if (acceptedCommand == read_button_state) { 
            
            if (tactilePinButtonRead()) {
            
             bleGamepad.setRightTrigger(32767);
             flagPress = 1; 
            
            }
          
            else if (flagPress){
              
             flagPress = 0; 
             bleGamepad.setRightTrigger(0);
          
            }
          
          }
          
          else if (acceptedCommand == press_check) {
           
            if (tactilePinButtonRead() && !buttonCheckFlag) {
            
               buttonCheckFlag = 1;
               return gamepad_button_pressed;
              
            }
            
            else if (buttonCheckFlag && !tactilePinButtonRead()){
             
             buttonCheckFlag = 0; 
            
            } 
          
          }
          
          else if (acceptedCommand == button_get_name) { 
            
            return gamepadButtonName;                      
            
          }
          
          return 0;        
                
        }      
        
      //   

      // Bluetooth gamepad left trigger pressure 
        
        byte analogReadTriggerLeftPress(byte acceptedCommand) {  
          
          if (acceptedCommand == read_button_state) {
            
            int temp = analogRead(numb);

            if (temp > analog_dead_zone) { // test
              
              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() && !buttonCheckFlag) {
            
              buttonCheckFlag = 1;
              return gamepad_button_pressed;
             
            }
          
            else if (buttonCheckFlag && !analogPinButtonRead()){
              
             buttonCheckFlag = 0;  
            
            }
          
          }    
          
          else if (acceptedCommand == button_get_name) {
            
            return gamepadButtonName;                      
             
          }
          
          return 0;
        
        }      
        
        byte touchReadTriggerLeftPress(byte acceptedCommand) {
        
          if (acceptedCommand == read_button_state) {        
          
            if (touchPinButtonRead()) {
            
              if (!flagPress) { 
                
                flagPress = 1; 
                bleGamepad.setLeftTrigger(32767);                     
              
              }
              
            }
          
            else if (flagPress){
              
              flagPress = 0; 
              bleGamepad.setLeftTrigger(0);
          
            }
          
          }
          
          else if (acceptedCommand == press_check) {
        
            if (touchPinButtonRead() && !buttonCheckFlag) {
            
              buttonCheckFlag = 1;
              return gamepad_button_pressed;
               
            }
          
            else if (buttonCheckFlag && !touchPinButtonRead()){
              
             buttonCheckFlag = 0; 
            
            }
          
          }        

          else if (acceptedCommand == button_get_name) {        
          
            return gamepadButtonName;          
          
          }             
          
          return 0;        
        
        }      
        
        byte tactileReadTriggerLeftPress(byte acceptedCommand) {
        
          if (acceptedCommand == read_button_state) { 
            
            if (tactilePinButtonRead()) {
            
             bleGamepad.setLeftTrigger(32767);
             flagPress = 1; 
            
            }
          
            else if (flagPress){
              
             flagPress = 0; 
             bleGamepad.setLeftTrigger(0);
          
            }
          
          }
          
          else if (acceptedCommand == press_check) {
           
            if (tactilePinButtonRead() && !buttonCheckFlag) {
            
               buttonCheckFlag = 1;
               return gamepad_button_pressed;
              
            }
            
            else if (buttonCheckFlag && !tactilePinButtonRead()){
             
             buttonCheckFlag = 0; 
            
            } 
          
          }
          
          else if (acceptedCommand == button_get_name) { 
            
            return gamepadButtonName;                      
            
          }
          
          return 0;        
                
        }  
      
      //  
      
      //використовується для переінціалізації  вказівника на функцію заміна кнопок місцями
      byte buttonReinstall(byte newButton){

        gamepadButtonName = newButton;
        
        if (gamepadButtonName == trigger_r || gamepadButtonName == trigger_l) {// вибір яким способом буде натиснути курок(R L)геймпада курок(R L) = tactile touch analog
        
          if (gamepadButtonName == trigger_r) {
         
            if (pinReadType == analog_read) {
           
              gamepadPressPtr = &ButGamepad::analogReadTriggerRightPress;
        
            }
            
            else if (pinReadType == touch_read) {
           
              gamepadPressPtr = &ButGamepad::touchReadTriggerRightPress;
        
            } 
          
            else if (pinReadType == tactile_read) {
           
              gamepadPressPtr = &ButGamepad::tactileReadTriggerRightPress;
        
            } 
          
          }
          
          else if (gamepadButtonName == trigger_l) {
         
            if (pinReadType == analog_read) {
           
              gamepadPressPtr = &ButGamepad::analogReadTriggerLeftPress;
        
            }
            
            else if (pinReadType ==  touch_read) {
           
              gamepadPressPtr = &ButGamepad::touchReadTriggerLeftPress;
        
            } 
          
            else if (pinReadType == tactile_read) {
           
              gamepadPressPtr = &ButGamepad::tactileReadTriggerLeftPress;
        
            } 
          
          }    
          
        }
        
        else {// вибір яким способом буде натиснути кнопка геймпада кнопка(1...12) = tactile touch analog
          
          if (pinReadType == tactile_read) {
           
            gamepadPressPtr = &ButGamepad::tactilePress;
          
          }
         
          else if (pinReadType == touch_read) {
         
           gamepadPressPtr = &ButGamepad::touchPress;
        
          }
        
          else if (pinReadType == analog_read) {
         
           gamepadPressPtr = &ButGamepad::analogReadPress;
            
          }        
     
        
        }   
        
        return 0;   
      
      }
      
      //функція повертає вказівник який вказує на  функцію яка була вибрана через конструктор
      byte gamepadBatton(byte acceptedCommand) { //  Метод для виклику функції через вказівник на метод
        
        return (this->*gamepadPressPtr)(acceptedCommand);
      
      }          
    
  };//  Button gamepad
  
  //створюємо екземпляри класу настроюємо вказівник на необхідну функцію
  //ButGamepad(1(reinstall!), 2, 3) 1-вибираємо курок чи кнопка 2-вибираємо чим будемо натискати сенсорна-звичайна кнопка або аналог 3-номер піна
  
  ButGamepad butGamepad[] = {// test
    
    ButGamepad(prof(act_dir)->listButton[0], tactile_read, 13),
    ButGamepad(prof(act_dir)->listButton[1], tactile_read, 14),
    ButGamepad(prof(act_dir)->listButton[2], tactile_read, 13+false),
    ButGamepad(prof(act_dir)->listButton[3], tactile_read, 16),
    ButGamepad(prof(act_dir)->listButton[4], tactile_read, 17),
    ButGamepad(prof(act_dir)->listButton[5], tactile_read, 5),
    ButGamepad(prof(act_dir)->listButton[6], tactile_read, 19),
    ButGamepad(prof(act_dir)->listButton[7], tactile_read, 13),
    ButGamepad(prof(act_dir)->listButton[8], tactile_read, 18),
    ButGamepad(prof(act_dir)->listButton[9], tactile_read, 23),

    ButGamepad(prof(act_dir)->listButton[10], tactile_read, 13+false),  // button_select
    ButGamepad(prof(act_dir)->listButton[11], tactile_read, 26), // button_start

    ButGamepad(prof(act_dir)->listButton[12], tactile_read, 13+false),  // dpad_up 
    ButGamepad(prof(act_dir)->listButton[13], tactile_read, 12), // dpad_down
    ButGamepad(prof(act_dir)->listButton[14], tactile_read, 13+false), // dpad_left 
    ButGamepad(prof(act_dir)->listButton[15], tactile_read, 27), // dpad_right


    ButGamepad(prof(act_dir)->listButton[16], analog_read, 15),  // trigger_r
    ButGamepad(prof(act_dir)->listButton[17], analog_read, 4)   // trigger_l
  
  };
 
  byte buttonGamepadPressRelease(byte command, byte buttonName) {//власна функція яка натискає кнопки звичайні  кнопки Select Start d-пад
    
    static byte x = 1;
    static byte y = 1; 
    
    byte dPad[3][3] = {
      
      {HAT_UP_LEFT, HAT_UP, HAT_UP_RIGHT},
      {HAT_LEFT, HAT_CENTERED, HAT_RIGHT},
      {HAT_DOWN_LEFT, HAT_DOWN, HAT_DOWN_RIGHT}
    
    };
    
    if (command == press_button) {

      if (buttonName <= button_10 ) {//7-16//звичайні кнопки
          
        bleGamepad.press(buttonName);
    
      }
    
      else if (buttonName == button_select || buttonName == button_start) {//5-6//кнопки Старт Select
          
        if (buttonName == button_select) {
        
          bleGamepad.pressSelect();
      
        }
        
        else if (buttonName == button_start) {
        
          bleGamepad.pressStart();
      
        }  
      
      }  
      
      else{//кнопки Dpad
        
        if (dpad_up == buttonName || dpad_down == buttonName){
          
          x = map(buttonName, 13, 14, 0, 2);
        
        }          
        
        else if (dpad_left == buttonName || dpad_right == buttonName) {
          
          y = map(buttonName, 15, 16, 0, 2);
        
        }
        
        bleGamepad.setHat1(dPad[x][y]);
        
      }  
      
    }
    
    else if (command == release_button) {

      if (buttonName <= button_10 ) {//7-16//звичайні кнопки
          
        bleGamepad.release(buttonName);
    
      }
    
      else if (buttonName == button_select || buttonName == button_start) {//5-6//кнопки Старт Select
          
        if (buttonName == button_select) {
        
          bleGamepad.releaseSelect();
      
        }
        
        else if (buttonName == button_start) {
        
          bleGamepad.releaseStart();
      
        }  
      
      }
      
      else{//кнопки Dpad
        
        if (dpad_up == buttonName || dpad_down == buttonName) {
          
          x = 1;
        
        }          
        
        else if (dpad_left == buttonName || dpad_right == buttonName) {
          
          y = 1;
        
        }
        
        bleGamepad.setHat1(dPad[x][y]);
        
      }  
    
    }
    
    return 0;
    
  }    
    
  
// Bdc

// Additional functions
  
  byte Ae_BatR(byte Taking) {// васна функція зчитує дані кнопки нагадування потрібно зробити власний клас кнопка додати debouns
  
    if (!digitalRead(Taking)) {
      
      Ae_autoShutdown(reset_f); 
    
    }
    
    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_f) { 
        
        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 savedCommand = clear_display; 
    
    if(acceptedCommand == refresh ) {
      
      savedCommand = clear_display; 

    }
    
    else if(savedCommand) {
      
      if(acceptedCommand == clear_display && savedCommand == clear_display) {
      
        savedCommand = print_display;
        display.clearDisplay();
       
      } 

      else if(acceptedCommand == print_display && savedCommand == print_display) {
      
        savedCommand = no_data;
        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 isr() {
   
   enc.tick();  // Оновлюємо стан енкодера в перериванні
  
  } 
  
// Af

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

        
         break;//
       
        case 1:
          
          if (prof(act_dir)->tape == t_sp) {
           
           Md_ProfileSp();
          
          }
          
          else{

           Md_ProfileMp();      
          
          }
        
         break;
        
        case 2:
          
          //Md_GeneralSettings();
         
         break;
        
        case 3:
          
          // qr-код ссылка на інструкцію
         
         break;
        
        case 4: //back
         
          Md_Display(info_display);
          Md_cursor(set_pos, 1);
          Md_addres(back_add, 1);         
          Ae_displayRefresh(refresh);
          
         break;
        
        case address_entered:
          
          Md_cursor(set_pos, 1);
          
         break;
      
      }
     
    }
    
    void Md_itemOne(){
      
        byte Lines[] = {22, 32, 42, 52};
        Md_cursor(cursor_read_encoder, 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 Sp
      
      void Md_ProfileSp() {
    
        switch (Md_addres(get_add, 2, check_button_enc)) {
            
          case address_not_entered: 
            
            Md_p_ProfileSp();
            
           break;
              
          case 1:
            
            Md_profileSettingsSp();
            
           break;
              
          case 2: // QR code 
            
            // Додайте код для обробки QR-коду тут, якщо потрібно
           break;
              
          case 3:
            
            Md_selectProfile();
          
           break;
              
          case 4: //back
            
            Md_cursor(set_pos, Md_addres(get_add, 1));
            Md_addres(back_add, 1);  
          
           break;          
          
          case address_entered:
            
           (Md_addres(get_add, 2) == 1) ? (void)prof(copy_profile) : (void)0;
            
           Md_cursor(set_pos, 1);
           
           break;
        
        }
     
      }
 
      void Md_p_ProfileSp() {
          
        byte LinesSp[] = {31, 39, 49, 57};
       
        Md_cursor(cursor_read_encoder, sizeof(LinesSp), LinesSp);
        
        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);
        
        
        display.print("Sp");
        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);
        
        
        display.setCursor(0, 31);
        display.println("  Settings   " );
        display.println("  QR code");
        
       
        display.setCursor(0, 49);
        display.println(" Select profile ");
        display.println(" Back" );
        
      }
    
    //   
    
    // Profile Mp
      
      void Md_ProfileMp() {
        
        switch (Md_addres(get_add, 2, check_button_enc)) {
          
          case address_not_entered: 
            
            Md_p_ProfileMp();
           
           break;
              
          case 1:
            
            Md_profileSettingsMp();
          
           break;
              
          case 2:
            
            Md_selectProfile();
            
           break;
              
          case 3: //back
            
            Md_cursor(set_pos, Md_addres(get_add, 1));
            Md_addres(back_add, 1); 
            
           break;         
          
          case address_entered:
            
            Md_cursor(set_pos, 1);
            
           break;
        
        }
      
      }
 
      void Md_p_ProfileMp() {
          
        byte LinesMp[] = {35, 49, 57};
        
        Md_cursor(cursor_read_encoder, 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);
        
        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);
        
        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(get_add, 2) <= 3){
        
         Md_p_GeneralSettings();
        
        }
        
        if (Md_cursor(get_pos) <= 3){
          
          switch (Md_addres(2, input_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(get_add, 2, check_button_enc)) {
            
            case 4: 
              
            break;
            
            case 5: 
            
            break;
            
            case 6: 
              
              Md_cursor(set_pos, 2);
              Md_addres(back_add, 1);
            
            break;
        
          }
        
        }
      
      }
      
      void Md_p_GeneralSettings(){
      
        int seveDataTemp = 0;
        byte Lines[] = {0, 8, 16, 24, 32, 40};
        Md_cursor(cursor_read_encoder, 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-----------------------------------------------------------------------------------------------------------
    
    // Profile settings Sp   
      
      void Md_profileSettingsSp() {
        
        switch (Md_addres(get_add, 3, check_button_enc)) {
          
          case address_not_entered: 
            
            Md_p_profileSettingsSp();
          
           break;
          
          case 1:
            
            Md_Buttons();
          
           break;// Buttons
          
          case 2:// back  //якщо були зміни то повернення відбудеться через функцію prof MdAf_profileStorage 
              
            if (*(byte*)prof(acting_copy_compare) == acting_copy_differs) {// перевірка на наявність змін
          
              switch (MdAf_consenDisplay()) {//після вибору перестане видавати  *(byte*)prof(acting_copy_compare) == acting_copy_differs
                  
                case choice_yes:
                  
                  prof(save_changes);
                  
                 break;
                
                case choice_no: 
                    
                  prof(not_save); 
                
                 break;           
              
              }    
             
             break;//якщо умова правда то повернення не виконається
            
            }
            
             Md_cursor(set_pos, Md_addres(get_add, 2));  
             Md_addres(back_add, 2);
              
           break;
          
          case address_entered: 
            
            Md_cursor(set_pos, 1);        
           
           break;
        
        }
        
      }
        
      void  Md_p_profileSettingsSp() {
        
        byte LinesSp[] = {16, 24};
        
        Md_cursor(cursor_read_encoder, sizeof(LinesSp), LinesSp);
          
        display.setCursor(0, 16);
        display.println(" Buttons" );
        display.println(" Back" );
       
      }
    
    //     
    
    // Profile settings Mp  
      
      void Md_profileSettingsMp(){
        
        switch (Md_addres(get_add, 3, check_button_enc)) {
          
          case address_not_entered: 

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

          case 4://  якщо були зміни то повернення в попередній пункт меню відбудеться через функцію MdAf_profileStorage
            
            if (prof(acting_copy_compare)) {// перевірка на наявність змін
          
              switch (MdAf_consenDisplay()) {// якщо є зміни запуститься дисплей підтвердження при виході з настройок
                
                case choice_yes:
                  
                  prof(save_changes); 
                  Md_addres(back_add, 2);
                  
                  break;
                
                case choice_no:
                  
                  prof(not_save);// якщо виберемо Ні функція  перестане видавати acting_copy_differs і  умова перестане  виконуватися 
                  Md_addres(back_add, 2);
                
                  break;
              
              }
            
            }
            
            else{// якщо змін не було то просто повертаємося
              
              Md_addres(back_add, 2);
              
            }
            
            break;
          
          case address_entered: 
    
            Md_cursor(set_pos, 1);
          
            break;
          
        }
        
      }
        
      void  Md_p_profileSettingsMp() {
        
        byte LinesMp[] = {16, 24, 32, 50};
        
        Md_cursor(cursor_read_encoder, 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" );
        
      }
    
    //    
    
    // Select profile
      
      void Md_selectProfile() {
      
        switch (Md_addres(get_add, 3, check_button_enc)) {
          
          case address_not_entered: 
            
            Md_p_selectProfile();
          
           break;
          
          case 1: 
            
            Md_standardProfiles();
          
           break;
          
          case 2: 
          
            Md_myProfiles();
          
           break;
          
          case 3: //back 
            
            Md_cursor(set_pos, Md_addres(get_add, 2));
            Md_addres(back_add, 2); 
            
           break;          
          
          case address_entered: 
    
            Md_cursor(set_pos, 1);
          
           break;          
        
        }
      
      }
      
      void Md_p_selectProfile() {
        
        byte Lines[] = {16, 24, 32};
        Md_cursor(cursor_read_encoder, sizeof(Lines), Lines);
      
        display.setCursor(0, 16);
        display.println(" Standard profiles" );
        display.println(" My profiles");
        display.println(" Back" );
      
      }
    
    // Sp

  //                 
  
  //  add4-----------------------------------------------------------------------------------------------------------
    
    // Standard profiles
      
      void Md_standardProfiles(){
      
        switch (Md_addres(get_add, 4, check_button_enc)) {
          
          case address_not_entered: 
            
            Md_p_standardProfiles();// відображення списку профілів вибір
          
          break;
          
          case 8: //back 
           
           Md_cursor(set_pos, Md_addres(get_add, 3));
           Md_addres(back_add, 3); 
            
          break;          
         
          case address_entered: 
           
            if(Md_addres(get_add, 4) != 8){
              
              prof(activate_p, Md_addres(get_add, 4));
              Md_cursor(set_pos, 1);
              Md_addres(back_add, 2); 
          
            }
          
          break;
  
        }
      
      }
      
      void Md_p_standardProfiles(){
        
        byte Lines[] = {0, 8, 16, 24, 32, 40, 48, 56};
        Md_cursor(cursor_read_encoder, sizeof(Lines), Lines);
       
        for (int i = 0; i < 7; i++) {// виводим імена профілів діючий профіль мигає
        
          display.setCursor(6, i*8);
          display.print(profil[i+1].nameProfiles(get_name_a_f));
          
        }
        
        display.setCursor(0, 56);
        display.println(" Back" );
      
      }
    
    // Sp  
    
    // My profiles  
     
      void Md_myProfiles(){
      
        switch (Md_addres(get_add, 4, check_button_enc)){// третій параметр забороняє вибирати діючий профіль
          
          case address_not_entered: 
            
            Md_p_MyProfiles();
            
           break;
          
          case 8: //back 
            
            Md_cursor(set_pos, Md_addres(get_add, 3));
            Md_addres(back_add, 3);
           
           break;          
          
          case address_entered: 
          
            if (Md_addres(get_add, 4) != 8) {
              
              prof(activate_p, Md_addres(get_add, 4)+7);
              Md_cursor(set_pos, 1);
              Md_addres(back_add, 2);// не міняти двоєчку будуть глюки             
            
            }
            
           break;
          
        }
      
      }
      
      void Md_p_MyProfiles() {
        
        byte Lines[] = {0, 8, 16, 24, 32, 40, 48, 56};
        Md_cursor(cursor_read_encoder, sizeof(Lines), Lines);
         
        for (int i = 0; i < 7; i++) {
        
         display.setCursor(6, i*8);
         display.print(profil[i+8].nameProfiles(get_name_a_f));
        
        }
        
        display.setCursor(6, 56);
        display.println("Back" );
      
      }
    
    // Mp

    // Gyroscope settings  
      
      void Md_gyroscopeSettings(){
        
        int seveDataTemp;// використовую щоб було більш зрозуміліше
        
        Md_p_gyroscopeSettings();//відображаємо пункти меню постійно
        
        switch (Md_addres(get_add, 4, check_button_enc)) {
          
          case address_not_entered:
          
           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: //back
            
            Md_cursor(set_pos, Md_addres(get_add, 3));
            Md_addres(back_add, 3);   
          
           break;
          
          case address_entered: 
          
            Md_addres(mode_click_back);
            
            /*
            if (Md_addres(get_add, 4) == 1 || Md_addres(get_add, 4) == 3) {// test зупиняємо виконання функції Gf_GyroAnalogR  для того щоб настроїти мертву зону
            
            timerAlarmDisable(timer);
            
            }
            */
           
           break;
        
        }
      
      }
    
      void Md_p_gyroscopeSettings(){
        
        static uint32_t tmr;
        static byte dashFlag;// прапорець м'ягання
        
        if (tmr < millis()) {
          
          Ae_displayRefresh(refresh);
          tmr = millis() + 500;
          dashFlag = ! dashFlag;
        
        }
      
        byte Lines[] = {5, 15, 34, 44, 55};
        Md_cursor(cursor_read_encoder, 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(get_add, 4)){//  РАМКА  НВКОЛО 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(get_add, 4)){//  РАМКА  НВКОЛО V
        
        if(dashFlag){display.drawCircle(86, 42, 7, WHITE);}
        
        }
        
        else{display.drawCircle(86, 42, 7, WHITE);}   
        
        
        if(Md_addres(get_add, 4) == 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(get_add, 4) == 2){ //  число рамка S H
        
        if(dashFlag){display.drawRect(101, 15, 23, 11, WHITE);}
        
        }
        
        else{display.drawRect(101, 15, 23, 11, WHITE);}
        
        if(Md_addres(get_add, 4) == 3){ //  число рамка DZ V
        
        if(dashFlag){display.drawRect(99, 31, 29, 11, WHITE);}
        
        }
        
        else{display.drawRect(99, 31, 29, 11, WHITE);}

        if(Md_addres(get_add, 4) == 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(){

        Md_p_Buttons();
      
        switch (Md_addres(get_add, 4, check_button_enc)) {
          
          case address_not_entered:

           break;
          
          case 1:
            
            Md_movingButtons(check_batton);
              
           break;
          
          case 2: // Reset
           
            Md_movingButtons(return_default);
            
           break;
          
          case 3: //back
            
            Md_cursor(set_pos, Md_addres(get_add, 3));
            Md_addres(back_add, 3);
          
           break;
          
          case address_entered:
            
            if(Md_addres(get_add, 4) == 1){
              
              Md_addres(mode_click_back);
              Md_p_Buttons(next_animation);
             
            }
            
            else if(Md_addres(get_add, 4) == 2){
              
              Md_addres(mode_final_choice);
             
            }            
           
           break;

          case address_deleted:
            
            Md_movingButtons(delete_data);               
          
           break;        
        
        }
        
      }
      
      int Md_movingButtons(int acceptedCommand){// test
        
        static int8_t sequenceNumber;
        
        switch (acceptedCommand) {
          
          case check_batton: 
          
            for (int i = 0; i < sizeof(butGamepad) / sizeof(butGamepad[0]); i++) {
            
              if (butGamepad[i].gamepadBatton(press_check) == gamepad_button_pressed) {
                
                Md_p_Buttons(next_animation, butGamepad[i].gamepadBatton(button_get_name));
                
                if (!sequenceNumber) {
                  
                  sequenceNumber = i+1;
                  
                }
                
                else {
                  
                  int savedButton1 = prof(act_dir)->listButton[sequenceNumber-1];//зберігаємо елементи масиву в тимчасовій переміні
                  int savedButton2 = prof(act_dir)->listButton[i];
                  
                  prof(act_dir)->listButton[i] = savedButton1;                //міняємо елементи масиву місцями
                  prof(act_dir)->listButton[sequenceNumber-1] = savedButton2;
                  
                  sequenceNumber = 0;
                  
                  for (int i = 0; i < 18; i++) {     //використовуючи нові дані перевстановлюємо кнопки місцями
              
                    butGamepad[i].buttonReinstall(prof(act_dir)->listButton[i]);
                  
                  } 
                
                }
              
               break;
              
              }  
            
            }              
            
           break;        
        
          case return_default:
          
            switch (MdAf_confirmYesNo(confirm_read_click, 37, 46)) {
              
              case choice_yes:
               
                for (int i = 0; i < sizeof(butGamepad) / sizeof(butGamepad[0]); i++) {
                  
                  prof(act_dir)->listButton[i] = i+1; 
                  butGamepad[i].buttonReinstall(i+1);
                
                }                  
                
                Md_addres(back_add, 4);
               
               break;
              
              case choice_no: 
                
               Md_addres(back_add, 4);
                  
              break;           
            
            }            
            
           break;
          
          case delete_data:         
           
            Md_p_Buttons(delete_data);
            sequenceNumber = 0;
            return 0;           
           
           break;
        
        }
        
        
        return 0;
      
      }
      
      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",
          "Z",          
          "C",          
          "A1",
          "A2",
          "RB",
          "LB",
          "Se",
          "St",          
          "dU",
          "dD",   
          "dL",
          "dR",          
          "RT",
          "LT"         
        
        };
        
        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(cursor_read_encoder, sizeof(Lines), Lines);
        
        display.setCursor(0, 40);// понятно
        display.println(" Move buttons");
        display.println(" Reset");      
        display.println(" Back");
        
        if (!receivedData && !animation) {// якщо фаlс то закінчуємо роботу функції економія ресурсів
          
          return 0;
        
        }
        
        if (receivedData == delete_data) {
        
         animation = accumulationL = accumulationR = runningArrow = 0;
        
        }  
        
        else if (receivedData == next_animation) {// в коді викликаємо функцію переключаємо анімацію
          
          Ae_displayRefresh(refresh);
          accumulationL = accumulationR = runningArrow = 0;
          
          if (animation != 3) {
          
           animation++;
          
          }
          if (animation == 2) {
          
           buttonOne = selectedButton - 1;
          
          }
          else if (animation == 3) {
          
           buttonTwo = selectedButton - 1;
           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;
          Md_addres(back_add, 4);//скидаємо адрес по завершенню роботи
        
        }
        
        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+i*6, 23);
           display.write(60);
          
          } 
        
          display.setCursor(40+runningArrow*6, 13);// трикутник переміщається по углових скобках анімація
          display.write(16);
          display.setCursor(83-runningArrow*6, 23);// трикутник переміщається по углових скобках анімація
          display.write(17);
        
        }
        
        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(refresh);
         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, 3);
            Md_addres(back_add, 3);
          
          }
          
          else{ 
            
            if (!prof(act_dir)->letterIndicator) {// якщо вводиться перша буква всі букви стають малими одноразовo
                
              ptrLetter = letterSmall;
              
            }
            
            prof(act_dir)->nameProfiles(change_letter, ptrLetter[AxisY][AxisX]);
          }
          
        }   
          
        byte rotatesSeve = Mf_encoder(get_rotation);
        
        if (Mf_EncoderButton(take_but_pos) == button_pressed){// якщо утримувати кнопку можна зробити дві дії видалення букви утриманням або переміщення по осі Y
        
          if (rotatesSeve) {// переміщення курсу вверх-вниз якщо кнопка отримується
            
            delFlag = 1;// забороняємо видалення утриманням коли почались оберти енкод
            Mf_EncoderButton(reset_f);// Клік не повернеться скидаємо функцію
          
            switch (rotatesSeve) {
                
              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_f);
              tmr = millis()+300;
              
              prof(act_dir)->nameProfiles(delete_letter);
              
              
              if (!prof(act_dir)->letterIndicator) {
                  
                ptrLetter = letterBig;
                
              }
            
            }

          }
      
        }
        
        else if (rotatesSeve){// звичайний режим роботи курсор рухається вправо і вниз і повторно починає свої дії якщо дійти до кінця  і наоборот
        
          switch (rotatesSeve) {
            
            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(refresh);
          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(refresh);
          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-------------------------------------------------------------------------------------------
    
    // MdAf_consenDisplay
      
      byte MdAf_consenDisplay(){ // викликається для підтвердження вибору
        
        switch (MdAf_confirmYesNo(confirm_read_hold, 37, 46)) {
          
          case choice_yes:
            
            prof(save_changes);// перестане видавати тру
            
           break;
          
          case choice_no: 
               
            prof(not_save);// якщо виберемо Ні функція  перестане видавати acting_copy_differs і  умова перестане  виконуватися 
           
           break;           
        
        }     
            
        MdAf_p_consenDisplay();// візуальна частина коду
      
       return 0;
      
      }
        
      void MdAf_p_consenDisplay(){
        
        display.drawRoundRect(20, 8, 87, 22, 0, WHITE); // рамка навколо слова зверху
        display.setCursor(25, 15); 
        display.println("Save settings");
        
      
      }
    
    //
    
    void MdAf_typeNumberPrint(){
      
      char name[2][3] = {"Sp", "Mp"};
      
      display.setCursor(49, 0);
      display.print("(   )");
      
      display.setCursor(55, 0);
      display.print(name[prof(act_dir)->tape-1]);//tape може бути t_sp = 1 t_mp = 2 
      display.print(prof(act_dir)->namber);
       
    }
    
    // MdAf_confirmYesNo 
      
      byte MdAf_confirmYesNo(byte acceptedCommand, byte azixX, byte azixY){
      
        const byte choiceOption[] = {choice_no, choice_yes};
        
        static byte flagChoice;
          
        if (Mf_encoder(get_rotation)) {
        
          flagChoice = !flagChoice;
        
        }        
      
        switch (acceptedCommand) {
          
          case confirm_read_click:
          
            if (Mf_EncoderButton() == click) {
            
             byte choice = flagChoice;
             flagChoice = 0;
             return choiceOption[choice];
            
            }              
            
           break;
          
          case confirm_read_hold:
            
            if (Mf_EncoderButton() == hold_b_e) {
            
             byte choice = flagChoice;
             flagChoice = 0;
             return choiceOption[choice];
            
            }                   
            
           break;         
        
        }  
        
        MdAf_p_confirmYesNo(flagChoice, azixX, azixY);
       
        return 0;
      
      }  
        
      byte MdAf_p_confirmYesNo( byte choice, byte azixX, byte azixY){ 
        
        const byte frameSize[] = {15, 21};
        const byte framePosition[] = {2, 32};
        
        display.setCursor(azixX+4, azixY+4);
        display.println("NO   YES");
        
        display.drawRect(azixX+framePosition[choice], azixY+2, frameSize[choice], 11, WHITE);// yesNO
        
        display.drawRect(azixX, azixY, 55, 15, WHITE);// рамка навколо так ні
        
        return 0;
      
      } 

    //
  
  //  Md_Af
  
  //  Menu functions 5 
 
    // Cursor 
      
      byte Md_cursor(byte acceptedCommand, byte data, byte* arr) { 
      
        static int8_t point = 1;
        static int8_t cursor = cursor_type_one;

        switch (acceptedCommand) {
          
          case cursor_read_encoder: 
            
            if(cursor == cursor_type_one){//переміщаємо encoder якщо є дозвіл
            
              switch (Mf_encoder(get_rotation)) {
                
                case rotated_l: 
                  Serial.println("--");
                  point--;
                  Ae_displayRefresh(refresh);
               
                break;
                
                case rotated_r: 
                  Serial.println("++");
                  point++;
                  Ae_displayRefresh(refresh);
                
                break; 
              
              }
              
              point = (point == 0) ? data : (data < point ? 1 : point);//недаємо курсору вийти за дозволені межі
            
            }           
            
           break;  
          
          case cursor_type_one: 
              
            Mf_encoder(reset_rotation);//енкодер опрацьовується в прериванні і тому можуть появлятися непотрібні дані стрілка може скакнути 
            cursor = cursor_type_one;
            
           break;
          
          case cursor_type_two: 
              
            cursor = cursor_type_two;
            
           break;        
          
          case get_pos: 
            
            return point; 
          
           break;
          
          case set_pos: //вказуємо позицію курс при переходах вперед або назад по адресу
              
            point = data;
            cursor = cursor_type_one;
            
           break;      
        
        } 
        
        Md_p_cursor(cursor, arr[point-1]);
        
        return 0;
      
      } 
        
      byte Md_p_cursor(byte cursorPrint, byte cursorPosition) { 
        
        const byte cursorTypes[] = {26, 16}; //cursor_type_one == 0 cursor_type_two == 1
            
        display.setCursor(0, cursorPosition); 
          
        display.write(cursorTypes[cursorPrint]);//вибираємо один з двох видів курсора з таблиці символів
        
        return 0;      
      
      }
    
    //
    
    byte Md_addres(byte acceptedCommand, byte addNumb, byte additionalCommand) {//N

      static byte add[10];//для коректної роботи можна використати тільки вісім адресів 1-8
      static byte inputMode = mode_click_input;
      
      switch (acceptedCommand) {
        
        case back_add:
          
          Ae_displayRefresh(refresh);
          Md_cursor(cursor_type_one);
          inputMode = mode_click_input;
          
          for (int i=9; i >= addNumb; i--){// команда back виконує видалення всіх адресів до числа вказаного в addNumb
            
            add[i] = address_not_entered;
            
          }
          
          return address_deleted;//????
        
         break;
        
        case mode_click_back:
          
          Md_cursor(cursor_type_two);          
          Ae_displayRefresh(refresh);
          inputMode = mode_click_back;
        
         break;         
        
        case mode_final_choice:
          
          Md_cursor(cursor_type_two);          
          Ae_displayRefresh(refresh);
          inputMode = mode_final_choice;
        
         break;         
        
        case get_add:
        
          if (additionalCommand == check_button_enc){
            
            if (inputMode == mode_click_input){
            
              if (add[addNumb] == address_not_entered && Mf_EncoderButton() == click){// набір адреса
               
               add[addNumb] = Md_cursor(get_pos);
               return address_entered;
              
              }
            
            }
            
            else if (inputMode == mode_click_back){            
               
              if (add[addNumb+1] == address_not_entered && Mf_EncoderButton() == click){//якщо попадемо на нуль повертаємося
                
                Serial.println("if (mode_click_back)");
                Md_addres(back_add, addNumb);
                return address_deleted;
              
              }          
            
            }
          
          }          
          
          return add[addNumb];
        
         break;
        
      }
      
      return 0;

    }
    
    int8_t Mf_encoder(int8_t acceptedCommand) {// функція повертає бистре або повільне обертання працює разом з функцією Ae_encoderInterrupt() для обробки даних
      
      
      if (acceptedCommand == get_rotation && enc.isTurn()) {
        
        Ae_displayRefresh(refresh);
        
        if (enc.isFastR()) {// якщо енкодер обертається з достатньою швидкістю
         Serial.println("rotated_r_fast");  
         return rotated_r_fast;
        
        }
        
        else if (enc.isFastL()) {
         Serial.println("rotated_l_fast");  
         return rotated_l_fast;
        
        }
        
        else if (enc.isRight()) {
         
         return rotated_r;
        
        }
        
        else if (enc.isLeft()) {
         
         return rotated_l;
        
        }
 
      }
      
      else if (acceptedCommand == reset_rotation) {//скидання накопичених даних дані можуть мінятися Навіть якщо ми не викликаємо Mf_encoder(get_rotation); тому що обробка відбувається в перериванні
      
       Mf_encoder(get_rotation);
      
      }
      
      return 0;
    
    }
    
    byte Mf_EncoderButton(byte acceptedCommand) {

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

        else if (DebButtonEncoder.press()){// якщо ми натиснули кнопку може відбутися дві події
          
          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 && !DebButtonEncoder.press()) {// якщо бистро відпустили кнопку повертається Клік
          
          int temp = saveData;
          saveData = 0; 
          
          if (temp == press_b_e){
            
            Ae_displayRefresh(refresh); 
            return click;
          
          }
        
        }
      
      } 
      
      return 0;
        
    }  
    
    int Mf_Magnifier(int numeric, int minNam, int maxNam, int Speed) {
   
      switch (Mf_encoder(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 > maxNam) {
        
        numeric = minNam;
      
      } 
      
      else if (numeric < minNam) {
        
        numeric = maxNam;
      
      }
     
     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(refresh);
        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(refresh);
      
         }
          
          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:
        
        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_f);
      /*
      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(){
    
    for (byte i = 0; i < 18; i++) {
      
      butGamepad[i].gamepadBatton(read_button_state);  // Виконується для кожного елемента масиву
    
    }
  
  }

// Gf

void setup() {
  
  Serial.begin(9600);// test В ФІНАЛІ НЕЗАБУТИ ЗАКОМЕНТУВАТИ!!!
  
  //виконуємо настройки геймпада
    
    bleGamepadConfig.setAutoReport(0);
    bleGamepadConfig.setButtonCount(10);
    bleGamepadConfig.setIncludeStart(true);
    bleGamepadConfig.setIncludeSelect(true);
    bleGamepadConfig.setHatSwitchCount(1);
    bleGamepadConfig.setAxesminNam(-32767); 
    bleGamepadConfig.setAxesmaxNam(32767); 
    bleGamepadConfig.setWhichAxes(1, 1, 1, 1, 1, 1, 0, 0);     
    bleGamepad.begin(&bleGamepadConfig);
  
  //
  
  //EEPROM.begin(512);
  //prof(eeprom_initialization);// ініціалізація з енергонезалежної пам'яті профілів
  
 
  // pinMode(3, OUTPUT);// подаємо високий сигнал на транзистор щоб заживити  модулі test
  // digitalWrite(3, HIGH);
  // pin 2 глючить встроєний резистор
 
  /*
  
    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 В
  
  */
  // Налаштування типу енкодера та таймауту на швидкі повороти
   
   enc.setType(TYPE2);        // 2шаговий енкодер (TYPE2)
   enc.setFastTimeout(20);    // Таймаут для швидкого повороту (в мс)
  
  //
  
  //обробка даних енкодера за допомогою приривання
   
    attachInterrupt(digitalPinToInterrupt(p_clk), isr, CHANGE);  
    attachInterrupt(digitalPinToInterrupt(p_dt), isr, 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()