#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()