#include <Wire.h>
#include <EEPROM.h>
// #include <BleGamepad.h> // при загрузці нa реально Arduino даний фрагмент розкоментувати a class BleGamepad закоментувати
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#include "esp32-hal-timer.h"
#include <RotaryEncoder.h>
// #include "INA219_WE.h"
// INA219_WE ina219(0x40);
// Additional elements
// constants-variable-arrays
bool Vibrgyro;
// СПІЛЬНІ КОНСТАНТИ ПІД ХОД ДЛЯ БАГ ФУНК
#define zero_void -1
#define no_action 0 // НЕМА ДІЇ
#define no_data 0 // немає даних
#define no_indication 0 // немає вказівки
#define off 0
#define get_status 1 // получити настройки
#define yes 1
#define save_settings 4 // зберехти настройки
#define reset 11
#define on 12
#define click 13
#define gyro 14
#define profil 15
#define data_available 16// дані доступні
#define melody_start 1
#define melody_off_power 2
#define x_axis_hor 1
#define y_axis_ver 2
#define z_axis_ver 3
#define get_y 2
#define get_z 3
#define get_vibr 4
// Ae_BatR();
// Піни карта
// #define b_mein 25
#define b_emul_dpad 1
#define b_handle 4
#define b_triger_r 23
#define b_analog_l 33
#define b_on_off 14
#define b_emul_dpad 26
// RotaryEncoder encoder(27, 14, RotaryEncoder::LatchMode::TWO03);
#define b_sw 25 // кнопка енко
#define p_dt 32
#define p_clk 33
//
#define thandle_touch_read 27
// Mf_EncoderButton();
// #define click 13
#define press_b_e 20
#define hold_b_e 21
#define reset_status 23
#define take_but_pos 24
#define button_pressed 25
// Md_Display(byte Receiving) {
#define info_display 20
#define menu 21
#define confirm_selection 22
#define lang_eng 25
#define lang_ukr 26
#define click_in_dis_on 27
// Md_MainDisplayENG();
#define menu_off 21
#define menu_start 22
// byte Md_addres();
// #define click 13
#define back 20
#define address_entered 21
#define get_add 22
#define int_add 23
#define add_status 24
#define int_add_last 25
#define address_deleted 26
#define click_reset_off 27
// int Md_cursor();
// #define reset 11
#define selection_inversion 21
#define freeze_position 22
#define get_pos 23
#define set_pos 24
#define cursor_type_one 25
#define cursor_type_two 26
byte noData[1];
byte posOne[] = {1};
byte posTwo[] = {2};
byte posThree[] = {3};
byte posFour[] = {4};
byte posFive[] = {5};
byte posSix[] = {6};
byte posEight[] = {7};
// Mf_encoderRotationSpeed()
// Ae_encoderInterrupt_fastRotation()
// #define data_available 16 // дані доступні
#define check_rotation 20
#define get_rotation 21
#define rotated_r 22
#define rotated_l 23
#define rotated_r_fast 24
#define rotated_l_fast 25
volatile int8_t g_encFast;
// MdAf_confirmYesNo()
// MdAf_consenDisplay()
#define choice_yes 20
#define choice_no 21
// MdAf_profileStorage()
#define copy_profile 20
#define return_save 21
#define check_changes 22
#define recorded_changes 23// зафіксовані зміни
// Mf_Buttons()
// #define reset 11
#define next_animation 20
// Ae_displayRefresh()
// #define reset 11
#define clear_display 20
#define print_display 21
// Ae_autoShutdown()
// #define reset 11
#define change_time 20
#define get_time 21
// Md_movingButtons()
#define choice_bat_waiting 20
#define button_selection_complete 21
// c-v-a
// Function prototypes
// int8_t Md_addres(int8_t addNumb = 0, int8_t acceptedCommand = 0, int8_t acceptedData = 0);
byte Md_cursor(byte acceptedCommand, byte* arr = nullptr);
byte Md_p_Buttons(byte receivedData = 0, byte selectedButton = 0);
int Md_movingButtons(int acceptedCommand = 0);
byte Mf_EncoderButton(byte acceptedCommand = 0);
byte Md_Display(byte Receiving = 0);
byte Ae_displayRefresh(byte acceptedCommand = 0);
byte Ae_autoShutdown(byte acceptedCommand = 0, byte acceptedData = 0);
// Fp
// Ae
// сlass BleGamepad Пустишка для того щоб не нагружати код і час компіляції 100=30
#define HAT_CENTERED 0
class BleGamepad {
public:
BleGamepad(const char* deviceName, const char* deviceManufacturer, uint8_t batteryLevel) {
// Нічого не робить
}
void press(uint8_t button) {
// Нічого не робить
}
void release(uint8_t button) {
// Нічого не робить
}
void setLeftTrigger(uint16_t value) {
// Нічого не робить
}
void setRightTrigger(uint16_t value) {
// Нічого не робить
}
bool isConnected() {
// Повертає false для симуляції відсутності з'єднання
return false;
}
void setZ(uint16_t value){
}
void setRZ(uint16_t value){
}
void sendReport() {
// Нічого не робить
}
void setHat1(uint8_t value) {
// Нічого не робить
}
void setLeftThumb(int16_t x, int16_t y) {
// Нічого не робить
}
void setRightThumb(int16_t x, int16_t y) {
// Нічого не робить
}
void pressSelect() {
// Нічого не робить
}
void releaseSelect() {
// Нічого не робить
}
void pressStart() {
// Нічого не робить
}
void releaseStart() {
// Нічого не робить
}
void begin() {
// Нічого не робить
}
void end() {
// Нічого не робить
}
};
//
Adafruit_SSD1306 display(128, 64, &Wire, -1);
BleGamepad bleGamepad("FS G36", "UA", 100);
RotaryEncoder encoder(p_dt, p_clk, RotaryEncoder::LatchMode::TWO03);// test
// Profiles class
// constants-variable-arrays c-v-a
#define t_sp 1// не міняти число!
#define t_mp 2// не міняти число!
#define r_off 0 // = off
#define r_on 12 // = on
#define get_name 20
#define get_name_a_f 21
#define change_letter 22
#define delete_letter 23
// *prof()
#define direct_p_sp 20
#define direct_p_mp 21
#define act_dir 22
#define activate_p_sp 23
#define activate_p_mp 24
#define eeprom_initialization 25
#define rerecording 26// test
uint32_t tmrProf = 0;
// c-v-a
class Profiles {
public:
Profiles(int deZoH, byte senHor, int deZoV, byte senVer, char* nameProf, byte tpProf, byte nabProf)
: deadZoneHor(deZoH),
sensitivityHor(senHor),
deadZoneVer(deZoV),
sensitivityVer(senVer),
tape(tpProf),
namber(nabProf),
status(r_off),
gamepadButton{12, 13, 14, 4, 15, 26, 33, 13, 23, 27} // test Md_resetButtons()!!! Select Start окрема функція геймпада тому 10 елементів
{ // при глюках замінити на memcpy(gamepadButton, defaultgamepadButton, sizeof(gamepadButton));
strncpy(nameArray, nameProf, 20); // даємо назву профілю через конструктор
nameArray[20] = '\0';
letterIndicator = [this]() -> byte {// переміна зберігає собі кількість букв в назві потрібно для зміни імен
for (int i = 19; i >= 0; i--) {
if (this->nameArray[i] != ' ') {
return i + 1;
}
}
return 20;
}();
}
int setDeZoHor(int deZoH) {// set
if (deadZoneHor != deZoH) {
sensitivityHor = 0;
}
deadZoneHor = deZoH;
return 0;
}
byte setSenHor(byte senHor) {
sensitivityHor = senHor;
return 0;
}
int setDeZoVer(int deZoV) {
if (deadZoneVer != deZoV) {sensitivityVer = 0;}
deadZoneVer = deZoV;
return 0;
}
byte setSenVer(byte senVer) {
sensitivityVer = senVer;
return 0;
}
byte setStatus(byte st) {
status = st;
return 0;
}
const char* nameProfiles(byte acceptedCommand, char Letter = ' '){// функція працює з іменем профілю та буквами також виконує мигання якщо стан профілю активний
char baldness[] = "";// baldness беззмістовність return baldness; аналог return 0;
if (status == r_on && tmrProf < millis()){// якщо стан профілю активний буде виконуватися мигання
tmrProf = millis()+600;
Flag = !Flag;
}
else if (status == r_off && !Flag){// захист можливий розрив функції переміна флаг може бути фолс
Flag = 1;
}
switch (acceptedCommand) {
case get_name: // беремо ім'я
return nameArray;
break;
case get_name_a_f:// при даній команді ім'я активного профілю буде мигати
if (Flag) {
return nameArray;
}
else {
return baldness;
}
break;
case change_letter:// міняємо букву
if (letterIndicator != 20){
nameArray[letterIndicator] = Letter;
letterIndicator++;
}
break;
case delete_letter:// видаляємо букву
if (letterIndicator){
letterIndicator--;
nameArray[letterIndicator] = ' ';
}
break;
return baldness;
}
return baldness;
}
byte centroName() {// центрує набране ім'я в рамці інфо дисплей
for (int i = 19; i >= 0; i--) {
if (nameArray[i] != ' '){
return 61-i*3;
break;
}
}
return 0;
}
byte getNamberTape(){// повертає номер і тип одночасно
return tape * 10 +namber;// логіка роботи тип може бути 1 або 2 множимо на 10 щоб не збігалася числа
}
void checkName() {// якщо немає імені то вставляє власне ім'я залежно від номеру профіля
bool allSpaces = true; // Припускаємо, що всі символи - пробіли
for(int i = 0; i < 20; i++) { // Останній символ не перевіряємо
if(nameArray[i] != ' ') {
allSpaces = false;
break;
}
}
if(allSpaces) {
snprintf(nameArray, 21, "My profile %d", namber); // Форматуємо нову назву
}
}
void copyFrom(const Profiles& other) {
deadZoneHor = other.deadZoneHor;
sensitivityHor = other.sensitivityHor;
deadZoneVer = other.deadZoneVer;
sensitivityVer = other.sensitivityVer;
tape = other.tape;
namber = other.namber;
status = other.status;
memcpy(gamepadButton, other.gamepadButton, sizeof(gamepadButton));
memcpy(nameArray, other.nameArray, sizeof(nameArray));
}
bool operator!=(const Profiles& other) const {
return (deadZoneHor != other.deadZoneHor) ||
(sensitivityHor != other.sensitivityHor) ||
(deadZoneVer != other.deadZoneVer) ||
(sensitivityVer != other.sensitivityVer) ||
(tape != other.tape) ||
(namber != other.namber) ||
(status != other.status) ||
(memcmp(gamepadButton, other.gamepadButton, sizeof(gamepadButton)) != 0) ||
(memcmp(nameArray, other.nameArray, sizeof(nameArray)) != 0);
}
// prof(act_dir)->sensitivityHor;
char nameArray[21];
byte gamepadButton[10];
byte Flag;
int deadZoneHor;// (primary початкова) початок руху
byte sensitivityHor;
int deadZoneVer;
byte sensitivityVer;
byte tape;
byte namber;
byte status;
byte letterIndicator;
private:
};
// Profile designers конструктори класу Profiles
Profiles profilSeve(0, 0, 0, 0, "0", 0, 0);// використовується для перевірки чи були зміни
Profiles profilSpOne(2000, 100, 2556, 92, "CodMW", t_sp, 1);
Profiles profilSpTwo(166, 120, 1965, 112, "Batl3", t_sp, 2);
Profiles profilSpThree(2000, 100, 2556, 92, "SP 33", t_sp, 3);
Profiles profilSpFour(166, 120, 1965, 112, "SP 44", t_sp, 4);
Profiles profilSpFive(2000, 100, 2556, 92, "SP 55", t_sp, 5);
Profiles profilSpSix(166, 120, 1965, 112, "SP 66", t_sp, 6);
Profiles profilSpSeven(2000, 100, 2556, 92, "SP 77", t_sp, 7);
Profiles profilMpOne(2000, 100, 2556, 92, "05461 ", t_mp, 1);
Profiles profilMpTwo(166, 120, 1965, 112, "Xmen 74 ", t_mp, 2);
Profiles profilMpThree(2000, 100, 2556, 92, "Mp 3 ", t_mp, 3);
Profiles profilMpFour(166, 120, 1965, 112, "Mp 4 ", t_mp, 4);
Profiles profilMpFive(2000, 100, 2556, 92, "Mp 5 ", t_mp, 5);
Profiles profilMpSix(166, 120, 1965, 112, "Mp 6 ", t_mp, 6);
Profiles profilMpSeven(2000, 100, 2556, 92, "Mp 7 ", t_mp, 7);
// Pd
Profiles *prof(byte acceptedCommand, byte number = 0){
Profiles *profArray[] = {
&profilSeve, &profilSpOne, &profilSpTwo, &profilSpThree, &profilSpFour, &profilSpFive, &profilSpSix, &profilSpSeven,
&profilMpOne, &profilMpTwo, &profilMpThree, &profilMpFour, &profilMpFive, &profilMpSix, &profilMpSeven
};
static byte acting = []() -> byte {// одноразова інт пер лямбда функція оскільки метод не повертає значення потрібно зробити так
byte temp;
int tempProfSize = 7 * sizeof(Profiles);
int tempProfSizebutArr = 7 * sizeof(profArray[1]->gamepadButton);
EEPROM.get(7 * sizeof(Profiles) + 1, temp); // Читаємо значення з EEPROM
if (!temp) {// TEST захист від мп0
return 8;
}
return temp; // Повертаємо прочитане значення
}();
if (acceptedCommand == act_dir) {// скерування до активного профілю
return profArray[acting];
}
else if (acceptedCommand == direct_p_sp) {// скеровує до стандартного профіля Для певних настройок
return profArray[number];
}
else if (acceptedCommand == direct_p_mp) {// скеровує до власного профіля Для певних настройок
return profArray[number+7];
}
else if (acceptedCommand == activate_p_sp || acceptedCommand == activate_p_mp) {// вибраний профіль активується
for (int i = 1; i < 15; i++){
profArray[i]->setStatus(r_off);
}
if (acceptedCommand == activate_p_sp ) {
profArray[number] -> setStatus(r_on);
acting = number;
}
else {
profArray[number+7] -> setStatus(r_on);
acting = number+7;
}
EEPROM.put(7 * sizeof(Profiles) + 1, acting);
EEPROM.commit();
// Serial.println(sizeof(Profiles));
// Serial.println(EEPROM.get(0, acting));
}
else if (acceptedCommand == eeprom_initialization) {
int tempProfSize = 7 * sizeof(Profiles);
int tempProfSizebutArr = 7 * sizeof(profArray[1]->gamepadButton);
int sizebutArr = sizeof(profArray[1]->gamepadButton);
// Serial.println("sizeof(Profiles)");
// Serial.println(sizeof(Profiles));
if (acting == 255 || Ae_BatR(13)) {// test ( Ae_BatR(13) ) Якщо правда то це самий перший запуск потрібно зберегти в профілі і перемінну енергонезалежну пам'ять подальші збереження будуть виконуватися при виході з настройок якщо вибрати так
acting = 8;
EEPROM.put(0 * sizeof(Profiles), profilMpOne);
EEPROM.put(1 * sizeof(Profiles), profilMpTwo);
EEPROM.put(2 * sizeof(Profiles), profilMpThree);
EEPROM.put(3 * sizeof(Profiles), profilMpFour);
EEPROM.put(4 * sizeof(Profiles), profilMpFive);
EEPROM.put(5 * sizeof(Profiles), profilMpSix);
EEPROM.put(6 * sizeof(Profiles), profilMpSeven);
// Зберігаємо gamepadButton кожного профілю окремо
EEPROM.put(tempProfSize + 0 * sizebutArr, profArray[1]->gamepadButton);
EEPROM.put(tempProfSize + 1 * sizebutArr, profArray[2]->gamepadButton);
EEPROM.put(tempProfSize + 2 * sizebutArr, profArray[3]->gamepadButton);
EEPROM.put(tempProfSize + 3 * sizebutArr, profArray[4]->gamepadButton);
EEPROM.put(tempProfSize + 4 * sizebutArr, profArray[5]->gamepadButton);
EEPROM.put(tempProfSize + 5 * sizebutArr, profArray[6]->gamepadButton);
EEPROM.put(tempProfSize + 6 * sizebutArr, profArray[7]->gamepadButton);
// Зберігаємо значення acting після всіх Profiles та їх gamepadButton
EEPROM.put(tempProfSize + tempProfSizebutArr, acting);
EEPROM.commit();
/*
for (int i = 0; i <= 6; i++){ // варіант з циклом for можливо буде працювати не в симуляторі
EEPROM.put(i * sizeof(Profiles), profArray[i+8]);
EEPROM.put(tempProfSize + i * sizebutArr, profArray[i+1]->gamepadButton);
Serial.println(i);
}
EEPROM.put(tempProfSize + tempProfSizebutArr, acting);
EEPROM.commit();
*/
}
else{// якщо Дані були вже збережені раніше то повертаємо їх з енергонезалежної пам'яті
/*
delay(500);
for (int i = 0; i <= 6; i++){
EEPROM.get(i * sizeof(Profiles), profArray[i+8]);
EEPROM.get(tempProfSize + i * sizebutArr, profArray[i+1]->gamepadButton);
}
*/
/*
EEPROM.get(0 * sizeof(Profiles), profilMpOne);
EEPROM.get(1 * sizeof(Profiles), profilMpTwo);
EEPROM.get(2 * sizeof(Profiles), profilMpThree);
EEPROM.get(3 * sizeof(Profiles), profilMpFour);
EEPROM.get(4 * sizeof(Profiles), profilMpFive);
EEPROM.get(5 * sizeof(Profiles), profilMpSix);
EEPROM.get(6 * sizeof(Profiles), profilMpSeven);
EEPROM.get(tempProfSize + 0 * sizebutArr, profArray[1]->gamepadButton);
EEPROM.get(tempProfSize + 1 * sizebutArr, profArray[2]->gamepadButton);
EEPROM.get(tempProfSize + 2 * sizebutArr, profArray[3]->gamepadButton);
EEPROM.get(tempProfSize + 3 * sizebutArr, profArray[4]->gamepadButton);
EEPROM.get(tempProfSize + 4 * sizebutArr, profArray[5]->gamepadButton);
EEPROM.get(tempProfSize + 5 * sizebutArr, profArray[6]->gamepadButton);
EEPROM.get(tempProfSize + 6 * sizebutArr, profArray[7]->gamepadButton);
*/
}
/*
for (int i = 0; i <= 6; i++){
EEPROM.get(i * sizeof(Profiles), *profArray[i+8]); // *profArray[i+8]???
Serial.println(i);
}
*/
profArray[acting] -> setStatus(r_on);
}
return 0;
}
// P
// Button debounce class
class DebButton {
private:
byte pin;
uint32_t tmr;
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 debButton[] = {
DebButton(19),
DebButton(18),
DebButton(5)
};
//
// Button gamepad class
// constants-variable-arrays
#define touch_dead_zone 50
#define analog_dead_zone 2600
// ButGamepad(byte gBT, byte gBN, byte pRT, byte n)
#define button_gamepad 20
#define trigger_gamepad 21
#define tactile_read 22
#define touch_read 23
#define analog_read 24
#define 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 trigger_r 11
#define trigger_l 12
#define button_select 13
#define button_start 14
// byte (*gamepadPressPtr)(byte);
#define press_gamepad_button 20
#define press_check 21
#define gamepad_button_pressed 22
#define button_get_name 23
// c-v-a
class ButGamepad {
private:
byte gamepadButtonType;
byte gamepadButtonName;
byte pinReadType;
byte numb;
byte flagPress;
byte buttonCheckFlag;
//вказівник вказує на одну з вибраних функцій які ми вибираємо конструкторi
typedef byte (ButGamepad::*GamepadPressMethod)(byte);
GamepadPressMethod gamepadPressPtr;
//функції використовуються всередині класу обробка натиску кнопки
byte tactilePinButtonRead(byte receivedData){
if (debButton[receivedData].press()) {
return true;
}
return false;
}
byte touchPinButtonRead(byte receivedData){
if (touchRead(receivedData) < touch_dead_zone) {
return true;
}
return false;
}
byte analogPinButtonRead(byte receivedData){
if (analogRead(receivedData) > 2600) {
return true;
}
return false;
}
public:
//конструктор проводимо настройку при першому запуску
ButGamepad(byte gBT, byte gBN, byte pRT, byte n) {
gamepadButtonType = gBT;
gamepadButtonName = gBN;
pinReadType = pRT;
numb = n;
if (gBT == button_gamepad) {// вибір яким способом буде натиснути кнопка геймпада кнопка(1...11) = tactile touch analog
if (pRT == tactile_read) {
if(gamepadButtonName == button_select){
gamepadPressPtr = &ButGamepad::selectButtonPress;
}
else if(gamepadButtonName == button_start){
gamepadPressPtr = &ButGamepad::startButtonPress;
}
else{
gamepadPressPtr = &ButGamepad::tactilePress;
}
}
else if (pRT == touch_read) {
gamepadPressPtr = &ButGamepad::touchPress;
}
else if (pRT == analog_read) {
gamepadPressPtr = &ButGamepad::analogReadPress;
}
}
else if (gBT == trigger_gamepad) {// вибір яким способом буде натиснути курок(R L)геймпада курок(R L) = tactile touch analog
if (gBN == trigger_r) {
if (pRT == analog_read) {
gamepadPressPtr = &ButGamepad::analogReadTriggerRightPress;
}
else if (pRT == touch_read) {
gamepadPressPtr = &ButGamepad::touchReadTriggerRightPress;
}
else if (pRT == tactile_read) {
gamepadPressPtr = &ButGamepad::tactileReadTriggerRightPress;
}
}
else if (gBN == trigger_l) {
if (pRT == analog_read) {
gamepadPressPtr = &ButGamepad::analogReadTriggerLeftPress;
}
else if (pRT == touch_read) {
gamepadPressPtr = &ButGamepad::touchReadTriggerLeftPress;
}
else if (pRT == tactile_read) {
gamepadPressPtr = &ButGamepad::tactileReadTriggerLeftPress;
}
}
}
}
//функції які викликаються через вказівник зроблено для того щоб в циклі фор викликати різні функції по черзі
// Bluetooth gamepad push button
byte selectButtonPress(byte acceptedCommand) {
if (acceptedCommand == press_gamepad_button) {
if (tactilePinButtonRead(numb)) {
if (!flagPress) {
bleGamepad.pressSelect();
flagPress = 1;
}
}
else if (flagPress){
flagPress = 0;
bleGamepad.releaseSelect();
}
}
return 0;
}
byte startButtonPress(byte acceptedCommand) {
if (acceptedCommand == press_gamepad_button) {
if (tactilePinButtonRead(numb)) {
if (!flagPress) {
bleGamepad.pressStart();
flagPress = 1;
}
}
else if (flagPress){
flagPress = 0;
bleGamepad.releaseStart();
}
}
return 0;
}
byte tactilePress(byte acceptedCommand) {
if (acceptedCommand == press_gamepad_button) {
if (tactilePinButtonRead(numb)) {
if (!flagPress) {
bleGamepad.press(gamepadButtonName);
flagPress = 1;
}
}
else if (flagPress){
flagPress = 0;
bleGamepad.release(gamepadButtonName);
}
}
else if (acceptedCommand == press_check) {
if (tactilePinButtonRead(numb) && !buttonCheckFlag) {
buttonCheckFlag = 1;
return gamepad_button_pressed;
}
else if (buttonCheckFlag && !tactilePinButtonRead(numb)){
buttonCheckFlag = 0;
}
}
else if (acceptedCommand == button_get_name) {
return gamepadButtonName;
}
return 0;
}
byte touchPress(byte acceptedCommand) {
if (acceptedCommand == press_gamepad_button) {
if (touchPinButtonRead(numb)) {
if (!flagPress) {
flagPress = 1;
bleGamepad.press(gamepadButtonName);
}
}
else if (flagPress){
flagPress = 0;
bleGamepad.release(gamepadButtonName);
}
}
else if (acceptedCommand == press_check) {
if (touchPinButtonRead(numb) && !buttonCheckFlag) {
buttonCheckFlag = 1;
return gamepad_button_pressed;
}
else if (buttonCheckFlag && !touchPinButtonRead(numb)){
buttonCheckFlag = 0;
}
}
else if (acceptedCommand == button_get_name) {
return gamepadButtonName;
}
return 0;
}
byte analogReadPress(byte acceptedCommand) {
if (acceptedCommand == press_gamepad_button) {
if (analogPinButtonRead(numb)) {
if (!flagPress) {
flagPress = 1;
bleGamepad.press(gamepadButtonName);
}
}
else if (flagPress){
flagPress = 0;
bleGamepad.release(gamepadButtonName);
}
}
else if (acceptedCommand == press_check) {
if (analogPinButtonRead(numb) && !buttonCheckFlag) {
buttonCheckFlag = 1;
return gamepad_button_pressed;
}
else if (buttonCheckFlag && !analogPinButtonRead(numb)){
buttonCheckFlag = 0;
}
}
else if (acceptedCommand == button_get_name) {
return gamepadButtonName;
}
return 0;
}
//
// Bluetooth gamepad right trigger pressure
byte analogReadTriggerRightPress(byte acceptedCommand) {
if (acceptedCommand == press_gamepad_button) {
if (analogRead(numb) > analog_dead_zone) { // test
int temp = analogRead(numb);
temp = map(temp, analog_dead_zone, 4095, 0, 32767);
temp = constrain(temp, 0, 32767);
bleGamepad.setRightTrigger(temp);
flagPress = 1;
}
else if (flagPress) {
flagPress = 0;
bleGamepad.setRightTrigger(0);// test
}
}
else if (acceptedCommand == press_check) {
if (analogPinButtonRead(numb) && !buttonCheckFlag) {
buttonCheckFlag = 1;
return gamepad_button_pressed;
}
else if (buttonCheckFlag && !analogPinButtonRead(numb)){
buttonCheckFlag = 0;
}
}
else if (acceptedCommand == button_get_name) {
return gamepadButtonName;
}
return 0;
}
byte touchReadTriggerRightPress(byte acceptedCommand) {
if (acceptedCommand == press_gamepad_button) {
if (touchPinButtonRead(numb)) {
if (!flagPress) {
flagPress = 1;
bleGamepad.setRightTrigger(32767);
}
}
else if (flagPress){
flagPress = 0;
bleGamepad.setRightTrigger(0);
}
}
else if (acceptedCommand == press_check) {
if (touchPinButtonRead(numb) && !buttonCheckFlag) {
buttonCheckFlag = 1;
return gamepad_button_pressed;
}
else if (buttonCheckFlag && !touchPinButtonRead(numb)){
buttonCheckFlag = 0;
}
}
else if (acceptedCommand == button_get_name) {
return gamepadButtonName;
}
return 0;
}
byte tactileReadTriggerRightPress(byte acceptedCommand) {
if (acceptedCommand == press_gamepad_button) {
if (tactilePinButtonRead(numb)) {
bleGamepad.setRightTrigger(32767);
flagPress = 1;
}
else if (flagPress){
flagPress = 0;
bleGamepad.setRightTrigger(0);
}
}
else if (acceptedCommand == press_check) {
if (tactilePinButtonRead(numb) && !buttonCheckFlag) {
buttonCheckFlag = 1;
return gamepad_button_pressed;
}
else if (buttonCheckFlag && !tactilePinButtonRead(numb)){
buttonCheckFlag = 0;
}
}
else if (acceptedCommand == button_get_name) {
return gamepadButtonName;
}
return 0;
}
//
// Bluetooth gamepad left trigger pressure
byte analogReadTriggerLeftPress(byte acceptedCommand) {
if (acceptedCommand == press_gamepad_button) {
if (analogRead(numb) > analog_dead_zone) { // test
int temp = analogRead(numb);
temp = map(temp, analog_dead_zone, 4095, 0, 32767);
temp = constrain(temp, 0, 32767);
bleGamepad.setLeftTrigger(temp);
flagPress = 1;
}
else if (flagPress) {
flagPress = 0;
bleGamepad.setLeftTrigger(0);// test
}
}
else if (acceptedCommand == press_check) {
if (analogPinButtonRead(numb) && !buttonCheckFlag) {
buttonCheckFlag = 1;
return gamepad_button_pressed;
}
else if (buttonCheckFlag && !analogPinButtonRead(numb)){
buttonCheckFlag = 0;
}
}
else if (acceptedCommand == button_get_name) {
return gamepadButtonName;
}
return 0;
}
byte touchReadTriggerLeftPress(byte acceptedCommand) {
if (acceptedCommand == press_gamepad_button) {
if (touchPinButtonRead(numb)) {
if (!flagPress) {
flagPress = 1;
bleGamepad.setLeftTrigger(32767);
}
}
else if (flagPress){
flagPress = 0;
bleGamepad.setLeftTrigger(0);
}
}
else if (acceptedCommand == press_check) {
if (touchPinButtonRead(numb) && !buttonCheckFlag) {
buttonCheckFlag = 1;
return gamepad_button_pressed;
}
else if (buttonCheckFlag && !touchPinButtonRead(numb)){
buttonCheckFlag = 0;
}
}
else if (acceptedCommand == button_get_name) {
return gamepadButtonName;
}
return 0;
}
byte tactileReadTriggerLeftPress(byte acceptedCommand) {
if (acceptedCommand == press_gamepad_button) {
if (tactilePinButtonRead(numb)) {
bleGamepad.setLeftTrigger(32767);
flagPress = 1;
}
else if (flagPress){
flagPress = 0;
bleGamepad.setLeftTrigger(0);
}
}
else if (acceptedCommand == press_check) {
if (tactilePinButtonRead(numb) && !buttonCheckFlag) {
buttonCheckFlag = 1;
return gamepad_button_pressed;
}
else if (buttonCheckFlag && !tactilePinButtonRead(numb)){
buttonCheckFlag = 0;
}
}
else if (acceptedCommand == button_get_name) {
return gamepadButtonName;
}
return 0;
}
//
//використовується для переінціалізації вказівника на функцію заміна кнопок місцями
byte buttonReinstall(byte newButton){
gamepadButtonName = newButton;
if (newButton != trigger_r && newButton != trigger_l) {
if (pinReadType == tactile_read) {
gamepadPressPtr = &ButGamepad::tactilePress;
}
else if (pinReadType == touch_read) {
gamepadPressPtr = &ButGamepad::touchPress;
}
else if (pinReadType == analog_read) {
gamepadPressPtr = &ButGamepad::analogReadPress;
}
}
else if (newButton == trigger_r || newButton == trigger_l) {
if (newButton == trigger_r) {
if (pinReadType == analog_read) {
gamepadPressPtr = &ButGamepad::analogReadTriggerRightPress;
}
else if (pinReadType == tactile_read) {
gamepadPressPtr = &ButGamepad::tactileReadTriggerRightPress;
}
else if (pinReadType == touch_read) {
gamepadPressPtr = &ButGamepad::touchReadTriggerRightPress;
}
}
else if (newButton == trigger_l) {
if (pinReadType == analog_read) {
gamepadPressPtr = &ButGamepad::analogReadTriggerLeftPress;
}
else if (pinReadType == tactile_read) {
gamepadPressPtr = &ButGamepad::tactileReadTriggerLeftPress;
}
else if (pinReadType == touch_read) {
gamepadPressPtr = &ButGamepad::touchReadTriggerLeftPress;
}
}
}
return 0;
}
//функція повертає вказівник який вказує на функцію яка була вибрана через конструктор
byte gamepadBatton(byte acceptedCommand) { // Метод для виклику функції через вказівник на метод
return (this->*gamepadPressPtr)(acceptedCommand);
}
};// Button gamepad
//створюємо екземпляри класу настроюємо вказівник на необхідну функцію
ButGamepad butGamepad[] = {// test
ButGamepad(button_gamepad, button_1, tactile_read, 0),
ButGamepad(button_gamepad, button_2, tactile_read, 1),
ButGamepad(button_gamepad, button_3, tactile_read, 2),
ButGamepad(button_gamepad, button_4, touch_read, 19)
ButGamepad(trigger_gamepad, trigger _r, analog_read, 4)
//ButGamepad(trigger_gamepad, trigger_r, analog_read, 4),
//ButGamepad(trigger_gamepad, trigger_l, analog_read, ?),
//ButGamepad(button_gamepad, button_select, tactile_read, 13),
//ButGamepad(button_gamepad, button_start, tactile_read, 14)
/*
чорновик
butGamepad[i].gamepadBatton(press)
Serial.print("----------");
Serial.println(numb);
ButGamepad(button_gamepad, 4, touch_read, 19),
ButGamepad(button_gamepad, 5, analog_read, 20),
ButGamepad(trigger_gamepad, trigger_r, analog_read, 20),
ButGamepad(trigger_gamepad, trigger_l, analog_read, 21)
*/
};
// Bdc
//Additional functions
byte Ae_BatR(byte Taking) {// васна функція зчитує дані кнопки нагадування потрібно зробити власний клас кнопка додати debouns
if (!digitalRead(Taking)) {
Ae_autoShutdown(reset);
}
return !digitalRead(Taking);
}
byte Ae_autoShutdown(byte acceptedCommand, byte acceptedData){
static uint32_t timerMagnifier = 3 * 60000;
static uint32_t tmr = timerMagnifier;
if (acceptedCommand) {
if (acceptedCommand == reset) {
tmr = timerMagnifier + millis();
}
else if (acceptedCommand == change_time) {
timerMagnifier = acceptedData * 60000;
}
else if (acceptedCommand == get_time) {
return timerMagnifier / 60000;
}
}
else if (tmr < millis()){
delay(400);
esp_deep_sleep_start();
}
return 0;
}
void Ae_buttonOnOff(){
if (!digitalRead(13)) {
delay(400);
esp_deep_sleep_start();
}
delay(100);
}
byte Ae_displayRefresh(byte acceptedCommand){//
static byte clearRefresh = 1;
if(acceptedCommand == reset && !clearRefresh) {
clearRefresh = 1;
}
else if(clearRefresh) {
if(acceptedCommand == clear_display && clearRefresh <= 14) {
clearRefresh++;
display.clearDisplay();
}
if(acceptedCommand == print_display && clearRefresh <= 14) {
clearRefresh++;
display.display();
}
if(acceptedCommand == print_display && clearRefresh > 14) {
clearRefresh = 0;
display.display();
}
}
/*
if(acceptedCommand == clear_display) {
display.clearDisplay();
}
else if(acceptedCommand == print_display) {
display.display();
}
*/
return 0;
}
void gyroStart(){
/*
mpu.initialize();
delay(10);
mpu.dmpInitialize();
mpu.setFullScaleAccelRange(MPU6050_ACCEL_FS_2);
mpu.setFullScaleGyroRange(MPU6050_GYRO_FS_250);
static byte flag = []() -> byte {
byte temp;
EEPROM.get(7 * sizeof(Profiles) + 1, temp);
return !temp;
}();
*/
static byte flag = 1;// TECT
long offsets[6];
if(Ae_BatR(b_triger_r) && Ae_BatR(b_analog_l)){
byte temp = 10;
while(temp > 0){
display.clearDisplay();
display.setCursor(0, 16);
display.println(" Calibration starts");
display.println();
display.print (" ");
display.println(temp);
display.display();
Ae_buttonOnOff();
temp--;
delay(1000);
}
display.clearDisplay();
display.setCursor(2, 16);
display.println(" Wait for completion");
display.display();
delay(2000);// TE
/*
mpu.setXAccelOffset(0);
mpu.setYAccelOffset(0);
mpu.setZAccelOffset(0);
mpu.setXGyroOffset(0);
mpu.setYGyroOffset(0);
mpu.setZGyroOffset(0);
delay(10);
mpu.CalibrateAccel(60);// не забудьте додати рестарт при помилках калібровки
mpu.CalibrateGyro(120);
delay(10);
offsets[0] = mpu.getXAccelOffset();
offsets[1] = mpu.getYAccelOffset();
offsets[2] = mpu.getZAccelOffset();
offsets[3] = mpu.getXGyroOffset();
offsets[4] = mpu.getYGyroOffset();
offsets[5] = mpu.getZGyroOffset();
*/
flag = 1;
/*
EEPROM.put(7 * sizeof(Profiles) + 1, flag);
EEPROM.put(7 * sizeof(Profiles) + 2, offsets);
EEPROM.commit();
*/
display.clearDisplay();
display.setCursor(4, 16);
display.println("Calibration complete");
display.display();
}
else if(!flag){
display.clearDisplay();
display.setCursor(1, 16);
display.println("Gyroscope calibration");
display.println(" not done");
display.display();
while(1){
Ae_buttonOnOff();
}
}
else if(flag){
/*
EEPROM.get(7 * sizeof(Profiles) + 2, offsets);
mpu.setXAccelOffset(offsets[0]);
mpu.setYAccelOffset(offsets[1]);
mpu.setZAccelOffset(offsets[2]);
mpu.setXGyroOffset(offsets[3]);
mpu.setYGyroOffset(offsets[4]);
mpu.setZGyroOffset(offsets[5]);
*/
}
}
void startAnimation(){
display.clearDisplay();
display.invertDisplay(0);
display.setCursor(-2, 28);
display.println(" FS G36 ");
display.display();
delay(500);
display.clearDisplay();
display.display();
}
void Ae_encoderInterrupt_fastRotation() {// функція викликається періодично тільки при обертанні працює в приривані функція виконує дві дії оновлює стан енкодера і провіряє швидкість обертання
encoder.tick(); // Оновлення стану енкодер
static uint32_t tmr;
static int seveEncoder;
if (seveEncoder != encoder.getPosition() && tmr < millis()) {// якщо enc obeртається перезаписує новий стан запускаємо таймер
Ae_displayRefresh(reset);
seveEncoder = encoder.getPosition();// записуємо свіжі дані
tmr = millis() + 20;
}
else if (seveEncoder != encoder.getPosition() && tmr > millis() && !g_encFast) {// якщо встигнемо получити два сигнала enkодера то записуємо необхідне значення для подальшого опрацювання
if (seveEncoder < encoder.getPosition()) {// в глобально переміну g_encFast записуються необхідне значення і дальше в функції Mf_encoderRotationSpeed відбувається скиданн на 0
g_encFast = 1;
}
else if (seveEncoder > encoder.getPosition()) {
g_encFast = -1;
}
Ae_displayRefresh(reset);
seveEncoder = encoder.getPosition();// записуємо свіжі дані
tmr = millis() + 20;// перезапускаємо таймер щоб не повертатися до першого пункту if
}
}
// Af
// Main display
// add1-----------------------------------------------------------------------------------------------------------
void Md_MainDisplay() {// головна фунція виклик решта функцій дисплея
switch (Md_addres(1, int_add)) {
case no_action:
MdId_BluetoothPrint();
MdAf_typeNumberPrint();
MdId_battery();
Md_ItemOne();
break;// 1
case 1:
Md_Profile();
break;
case 2:
Md_GeneralSettings();
break;
case 3:
// qr-код ссылка на інструкцію
break;
case 4:
Md_Display(info_display);
Md_cursor(set_pos, posOne);
Md_addres(1, back);
Ae_displayRefresh(reset);
break;
case address_entered:
Md_cursor(set_pos, posOne);
break;
}
}
void Md_ItemOne(){
byte Lines[] = {22, 32, 42, 52};
Md_cursor(sizeof(Lines), Lines);
display.setCursor(0, 22);
display.println(" Profile");
display.setCursor(0, 32);
display.println(" General settings");
display.setCursor(0, 42);
display.println(" Instruction (!)");
display.setCursor(0, 52);
display.println(" Exit menu ");
}
//
// add2-----------------------------------------------------------------------------------------------------------
// Profile
void Md_Profile() {
if (prof(act_dir)->tape == t_sp) {// в залежності від типу профілю вид меню міняється
switch (Md_addres(2, int_add)) {
case no_action:
Md_p_Profile();
break;
case 1:
Md_profileSettings();
break;// a3
case 2:// QR code
break;
case 3:
Md_selectProfile();
break;// a3
case address_entered:
if (Md_addres(2, get_add) == 4) {
Md_addres(1, back);
}
else if (Md_addres(2, get_add) == 1) {
MdAf_profileStorage(copy_profile);// // копіюємо профіль при вдоході в настройки для подальшої перевірки на зміни при виході
}
Md_cursor(set_pos, posOne);
break;
}
}
else {
switch (Md_addres(2, int_add)) {
case no_action:
Md_p_Profile();
break;
case 1:// a3
Md_profileSettings();
break;
case 2: // a3
Md_selectProfile();
break;
case address_entered:
if (Md_addres(2, get_add) == 3) {
Md_addres(1, back);
}
else if (Md_addres(2, get_add) == 1) {
MdAf_profileStorage(copy_profile);// // копіюємо профіль при вдоході в настройки для подальшої перевірки на зміни при виході
}
Md_cursor(set_pos, posOne);
break;
}
}
}
void Md_p_Profile() {
byte LinesSp[] = {31, 39, 49, 57};
byte LinesMp[] = {35, 49, 57};
if (prof(act_dir)->tape == t_sp) {
Md_cursor(sizeof( LinesSp), LinesSp);
}
else {
Md_cursor(sizeof(LinesMp), LinesMp);
}
display.setCursor(3, 1);// стрілки по боках активний профіль
display.write(25);
display.setCursor(118, 1);
display.write(25);
display.drawRoundRect(0, 0, 127, 10, 2, WHITE);// РАМКА АКТИВ ПРОФ НАЗВА ГРИ
display.drawRect(0, 9, 127, 19, WHITE);
display.drawRect(10, 29, 51, 19, WHITE);// РАМКА НАСТРОЙКИ КЮАР КОД
display.setCursor(21, 1);
display.print("Active profile");
display.setCursor(98, 36); // РИСКА В лыво РАЗОМ ПОЛУЧАЭТСЯ КРИВА СТРЫЛКА
display.println("_" );
display.setCursor(93, 36);
display.println("_" );
display.setCursor(91, 36);// СТРЫЛКА ВВЕРХ РАЗОМ ПОЛУЧАЭТСЯ КРИВА СТРЫЛКА
display.write(24);
display.setCursor(91, 34);
display.write(30);
display.drawCircle(113, 42, 11, WHITE);// КРУГ НАВК Sp
display.setCursor(105, 39);
if (prof(act_dir)->tape == t_sp) {
display.print("Sp");
display.println(prof(act_dir)->namber);
}
else {
display.print("Mp");
display.println(prof(act_dir)->namber);
}
display.setCursor(prof(act_dir)->centroName(), 15);// функція centroName() в залежності від кількості ім'я вранці
display.println(prof(act_dir)->nameProfiles(get_name));
display.setCursor(0, 32); // РИСКА В ПРАВО РАЗОМ ПОЛУЧАЭТСЯ КРИВА СТРЫЛКА
display.println(" _" );
display.setCursor(4, 32);
display.println(" _" );
display.setCursor(66, 32);// СТРЫЛКА ВВЕРХ РАЗОМ ПОЛУЧАЭТСЯ КРИВА СТРЫЛКА
display.write(24);
display.setCursor(66, 30);
display.write(30);
if (prof(act_dir)->tape == t_sp) {
display.setCursor(0, 31);
display.println(" Settings " );
display.println(" QR code");
}
else {
display.setCursor(0, 35);
display.println(" Settings " );
}
display.setCursor(0, 49);
display.println(" Select profile ");
display.println(" Back" );
}
//
// General settings
void Md_GeneralSettings(){
int seveDataTemp;// використовую щоб було більш зрозуміліше
if (Md_addres(2, get_add) <= 3){
Md_p_GeneralSettings();
}
if (Md_cursor(get_pos) <= 3){
switch (Md_addres(2, int_add_last)) {
case 1:
seveDataTemp = Mf_Magnifier(Ae_autoShutdown(get_time), 3, 15, 1);
Ae_autoShutdown(change_time, seveDataTemp);
break;
case 2:
break;
case 3:
break;
}
}
else{
switch (Md_addres(2, int_add)) {
case 4:
break;
case 5:
break;
case 6:
Md_cursor(set_pos, posTwo);
Md_addres(1, back);
break;
}
}
}
void Md_p_GeneralSettings(){
int seveDataTemp = 0;
byte Lines[] = {0, 8, 16, 24, 32, 40};
Md_cursor(sizeof(Lines), Lines);
display.setCursor(0, 0);
display.println(" Auto shutdown- m.");
display.println(" Shutter-imitation ");
display.println(" Battery-saving");
display.println(" Gyroscope ");
display.println(" Buttons");
display.println(" Back" );
if (Ae_autoShutdown(get_time) < 10){
seveDataTemp = 3;
}
Serial.println(seveDataTemp);
display.setCursor(15*6+seveDataTemp, 0);
display.print(Ae_autoShutdown(get_time));
}
// Gs
//
// add3-----------------------------------------------------------------------------------------------------------
// Select profile
void Md_selectProfile() {
switch (Md_addres(3, int_add)) {
case no_action:
Md_p_selectProfile();
break;
case 1:
Md_standardProfiles();
break;
case 2:
Md_MyProfiles();
break;
case address_entered:
if (Md_addres(3, get_add) == 3) {
if (prof(act_dir)->tape == t_sp) {
Md_cursor(set_pos, posThree);
}
else{
Md_cursor(set_pos, posTwo);
}
Md_addres(2, back);
}
else{
Md_cursor(set_pos, posOne);
}
break;
}
}
void Md_p_selectProfile() {
byte Lines[] = {16, 24, 32};
Md_cursor(sizeof(Lines), Lines);
display.setCursor(0, 16);
display.println(" Standard profiles" );
display.println(" My profiles");
display.println(" Back" );
}
// Sp
// Profile settings
void Md_profileSettings() {
if (prof(act_dir)->tape == t_sp) { // вид пунктiv меню якщо профіль стандартний
switch (Md_addres(3, int_add)) {
case no_action:
Md_p_profileSettings();
break;
case 1:
Md_Buttons();
break;// Buttons
case 2:// якщо були зміни то повернення відбудеться через функцію MdAf_profileStorage
if (MdAf_profileStorage(check_changes) == recorded_changes) {// перевірка на наявність змін
switch (MdAf_consenDisplay()) {// якщо є зміни запуститься дисплей підтвердження при виході з настройок
case choice_yes:
MdAf_profileStorage(reset);// якщо виберемо так профіль повторно скопірується комадою ресеті функція MdAf_profileStorage перестане видавати recorded_changes
Md_addres(2, back);
break;
case choice_no:
MdAf_profileStorage(return_save);// якщо виберемо Ні функція dAf_profileStorage перестане видавати recorded_changes і умова перестане виконуватися
Md_addres(2, back);
break;
}
}else{
Md_addres(2, back);
}
break;
case address_entered:
Md_cursor(set_pos, posOne);
break;
}
}
else { // вид пунктів якщо вибрано власний профіль
switch (Md_addres(3, int_add)) {
case no_action:
Md_p_profileSettings();// відображення пунктів настройки
break;
case 1:// Gyroscope
Md_gyroscopeSettings();
break;
case 2:// Buttons
Md_Buttons();
break;
case 3:// Name
Md_changeNameProfile();
break;
case 4:// якщо були зміни то повернення в попередній пункт меню відбудеться через функцію MdAf_profileStorage
if (MdAf_profileStorage(check_changes) == recorded_changes) {// перевірка на наявність змін
switch (MdAf_consenDisplay()) {// якщо є зміни запуститься дисплей підтвердження при виході з настройок
case choice_yes:
MdAf_profileStorage(reset);// якщо виберемо так перестане видавати recorded_changes
Md_addres(2, back);
break;
case choice_no:
MdAf_profileStorage(return_save);// якщо виберемо Ні функція dAf_profileStorage перестане видавати recorded_changes і умова перестане виконуватися
Md_addres(2, back);
break;
}
}
else{// якщо змін не було то просто повертаємося
Md_addres(2, back);
}
break;
case address_entered:
Md_cursor(set_pos, posOne);
break;
}
}
}
void Md_p_profileSettings() {
byte LinesSp[] = {16, 24};
byte LinesMp[] = {16, 24, 32, 50};
if (prof(act_dir)->tape == t_sp) {
Md_cursor(sizeof(LinesSp, LinesSp));
display.setCursor(0, 16);
display.println(" Buttons" );// не добавляти пункт reset не потрібно
display.println(" Back" );
} else {
Md_cursor(sizeof(LinesMp), LinesMp);
display.drawRoundRect(9, 14, 59, 28, 0, WHITE);
display.setCursor(0, 16);
display.println(" Gyroscope" );
display.println(" Buttons" );
display.println(" Name" );
display.setCursor(0, 50);
display.println(" Back" );
}
}
// Ps
//
// add4-----------------------------------------------------------------------------------------------------------
// Standard profiles
void Md_standardProfiles(){
switch (Md_addres(4, int_add)) {
case no_action:
Md_p_standardProfiles();// відображення списку профілів вибір
break;
case address_entered:
if (Md_addres(4, get_add) == 8) {
Md_cursor(set_pos, posOne);
Md_addres(3, back);
}
else{
if (prof(act_dir)->getNamberTape() != prof(direct_p_sp, Md_addres(4, get_add))->getNamberTape()) {
prof(activate_p_sp, Md_addres(4, get_add));
Md_cursor(set_pos, posOne);
Md_addres(2, back);
}
else{Md_addres(4, back); }
}
break;
}
}
void Md_p_standardProfiles(){
byte Lines[] = {0, 8, 16, 24, 32, 40, 48, 56};
Md_cursor(sizeof(Lines), Lines);
Ae_displayRefresh(reset);
for (int i = 0; i < 7; i++) {// виводим імена профілів діючий профіль мигає
display.setCursor(6, i*8);
display.print(prof(direct_p_sp, i+1)->nameProfiles(get_name_a_f));
}
display.setCursor(0, 56);
display.println(" Back" );
}
// Sp
// My profiles
void Md_MyProfiles(){
switch (Md_addres(4, int_add)){// третій параметр забороняє вибирати діючий профіль
case no_action:
Md_p_MyProfiles();
break;
case address_entered:
if (Md_addres(4, get_add) == 8) {// повертаємося в передній пункт
Md_cursor(set_pos, posOne);
Md_addres(3, back);
}
else{// якщо вибраний профіль не є діючий виконуємо заміну якщо так просто повертаємося
if (prof(act_dir)->getNamberTape() != prof(direct_p_mp, Md_addres(4, get_add))->getNamberTape()) {
prof(activate_p_mp, Md_addres(4, get_add));
Md_cursor(set_pos, posOne);
Md_addres(2, back);// не міняти двоєчку будуть глюки
}
else{Md_addres(4, back);}
}
break;
}
}
void Md_p_MyProfiles() {
byte Lines[] = {0, 8, 16, 24, 32, 40, 48, 56};
Md_cursor(sizeof(Lines), Lines);
Ae_displayRefresh(reset);
for (int i = 0; i < 7; i++) {
display.setCursor(6, i*8);
display.print(prof(direct_p_mp, i+1)->nameProfiles(get_name_a_f));
}
display.setCursor(6, 56);
display.println("Back" );
}
// Mp
// Gyroscope settings
void Md_gyroscopeSettings(){// a3
int seveDataTemp;// використовую щоб було більш зрозуміліше
if (Md_addres(4, add_status) == address_deleted){// відновляємо у виконанні функції Gf_GyroAnalogR після виходу з настройок мертвої зони (якщо адрес видалився)
/*
timerAlarmEnable(timer);
*/
}
if (Md_addres(4, get_add) != 5){// зроблено для того щоб курсор не міняв свій вигляд при виході
Md_p_gyroscopeSettings();
}
switch (Md_addres(4, int_add_last)) {// 4
case no_action:
break;
case 1:
seveDataTemp = Mf_Magnifier(prof(act_dir)->deadZoneHor, 0, 9999, 100);
prof(act_dir)->setDeZoHor(seveDataTemp);
break;
case 2:
seveDataTemp = Mf_Magnifier(prof(act_dir)->sensitivityHor, 0, 100, 5);
prof(act_dir)->setSenHor(seveDataTemp);
break;
case 3:
seveDataTemp = Mf_Magnifier(prof(act_dir)->deadZoneVer, 0, 9999, 100);
prof(act_dir)->setDeZoVer(seveDataTemp);
break;
case 4:
seveDataTemp = Mf_Magnifier(prof(act_dir)->sensitivityVer, 0, 100, 5);
prof(act_dir)->setSenVer(seveDataTemp);
break;
case 5:
Md_cursor(set_pos, posOne);
Md_addres(3, back);
break;
case address_entered:
if (Md_addres(4, get_add) == 1 || Md_addres(4, get_add) == 3) {// зупиняємо виконання функції Gf_GyroAnalogR для того щоб настроїти мертву зону
/*
timerAlarmDisable(timer);
*/
}
break;
}
}
void Md_p_gyroscopeSettings(){
static uint32_t tmr;
static byte dashFlag;// прапорець м'ягання
if (tmr < millis()) {
Ae_displayRefresh(reset);
tmr = millis() + 500;
dashFlag = ! dashFlag;
}
byte Lines[] = {5, 15, 34, 44, 55};
Md_cursor(sizeof(Lines), Lines);
display.setCursor(8, 5);
display.println("Dead zone ");
display.setCursor(8, 15);
display.println("Sensitivity");
display.setCursor(8, 34);
display.println("Dead zone ");
display.setCursor(8, 44);
display.println("Sensitivity");
display.setCursor(8, 55);
display.println("Back");
display.setCursor(84, 10);
display.println("H");
display.setCursor(84, 39);
display.println("V");
display.setCursor(102, 4);
display.println(prof(act_dir)->deadZoneHor);
display.setCursor(104, 17);
display.println(prof(act_dir)->sensitivityHor);
display.setCursor(102, 33);
display.println(prof(act_dir)->deadZoneVer);
display.setCursor(104, 46);
display.println(prof(act_dir)->sensitivityVer);
display.drawRoundRect(6, 2, 69, 23, 3, WHITE); // РАМКА НАВКОЛО Dead zone Sensitivity H
display.drawRoundRect(6, 31, 69, 23, 0, WHITE);// РАМКА НАВКОЛО Dead zone Sensitivity V
// H
if((Md_cursor(get_pos) == 1 || Md_cursor(get_pos) == 2) && !Md_addres(4, get_add)){// РАМКА НВКОЛО H
if(dashFlag){display.drawRoundRect(79, 6, 15, 15, 0, WHITE);}
}
else{display.drawRoundRect(79, 6, 15, 15, 0, WHITE);}
// V
if((Md_cursor(get_pos) == 3 || Md_cursor(get_pos) == 4) && !Md_addres(4, get_add)){// РАМКА НВКОЛО V
if(dashFlag){display.drawCircle(86, 42, 7, WHITE);}
}
else{display.drawCircle(86, 42, 7, WHITE);}
if(Md_addres(4, get_add) == 1){ // число рамка DZ H
if(dashFlag){display.drawRoundRect(99, 2, 29, 11, 4, WHITE);}
}
else{display.drawRoundRect(99, 2, 29, 11, 4, WHITE);}
if(Md_addres(4, get_add) == 2){ // число рамка S H
if(dashFlag){display.drawRect(101, 15, 23, 11, WHITE);}
}
else{display.drawRect(101, 15, 23, 11, WHITE);}
if(Md_addres(4, get_add) == 3){ // число рамка DZ V
if(dashFlag){display.drawRect(99, 31, 29, 11, WHITE);}
}
else{display.drawRect(99, 31, 29, 11, WHITE);}
if(Md_addres(4, get_add) == 4){ // число рамка S V
if(dashFlag){display.drawRoundRect(101, 44, 23, 11, 4, WHITE);}
}
else{display.drawRoundRect(101, 44, 23, 11, 4, WHITE);}
}
// Gs
// Buttons
void Md_Buttons(){// замінити if на Switch в кінці при використанні свіч глюки
Md_p_Buttons();
if(Md_addres(no_data, add_status) == address_deleted){// якщо адрес був видалений скидає функції
Md_p_Buttons(reset);
Md_movingButtons(reset);
}
switch (Md_addres(4, int_add_last)) {
case no_action:
break;
case 1:
Md_movingButtons();
break;
case 2:
switch (MdAf_confirmYesNo(37, 46)) {// скидання кнопок
case no_action:
break;
case choice_yes:
Md_addres(4, back);
Md_resetButtons();// test
break;
case choice_no:
Md_addres(4, back);
break;
}
break;
case 3:
Md_cursor(set_pos, posTwo);
Md_addres(3, back);
break;
case address_entered:
if(Md_addres(4, get_add) == 1){
Md_p_Buttons(next_animation);
}
else if(Md_addres(4, get_add) == 2){
Md_addres(no_data, click_reset_off);// потрібно для того щоб Клік працював тепер в функції MdAf_confirmYesNo(37, 46)
}
break;
}
}
int Md_movingButtons(int acceptedCommand){// test
static int8_t saveButton;
if (acceptedCommand == reset) { // скидання функції якщо не закінчили переміщення кнопок
saveButton = 0;
return 0;
}
// Serial.print("temp = ");
//Serial.println(temp);
for (int i = 0; i <= 2; i++) {// test
int temp = butGamepad[i].gamepadBatton(press_check);//test
if (temp == gamepad_button_pressed) {
Md_p_Buttons(next_animation, butGamepad[i].gamepadBatton(button_get_name));
if (!saveButton) {
saveButton = i;
++saveButton;
}
else {
--saveButton;
int temp = butGamepad[saveButton].gamepadBatton(button_get_name);
butGamepad[saveButton].buttonReinstall(butGamepad[i].gamepadBatton(button_get_name));
butGamepad[i].buttonReinstall(temp);
saveButton = 0;
}
break;
}
}
return 0;
}
void Md_resetButtons(){// функція виконує скидання кнопок до стандартних / Select Start окрема функція геймпада/масив буде потрібно змінити в кінці test
byte defaultButton[] = {15, 5, 6, 7, 8, 9, 10, 11, 12, 13};// test
for (int i = 0; i < sizeof(defaultButton); i++) {
prof(act_dir)->gamepadButton[i] = defaultButton[i];
}
}
byte Md_p_Buttons(byte receivedData, byte selectedButton){
// бегуща стрілка. анімація. кнопка один збереження. крапка 2 збереження. анімація кнопка ліва. анімація кнопка права
static byte runningArrow, animation, buttonOne, buttonTwo, accumulationL, accumulationR;
static unsigned long tmr; // таймер для виконання анімації
const char *buttonNames[] = {// масив імена кнопок виводим при натиску
"A",
"B",
"X",
"Y",
"Z",
"C",
"A1",
"A2",
"RB",
"LB",
"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(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 == reset) {
animation = accumulationL = accumulationR = runningArrow = 0;
}
else if (receivedData == next_animation) {// в коді викликаємо функцію переключаємо анімацію
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(4, back);//скидаємо адрес по завершенню роботи
}
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(reset);
tmr = millis()+400;
}
return 0;
}
// B
// changeNameProfile
void Md_changeNameProfile(){
static int8_t AxisX, AxisY, delFlag;// XYнаведення на вибрану букву delFlag видалення за допомогою отримання
static uint32_t tmr;// використовується для видалення утриманняm
static int8_t magnitude = 1;// костилі використовується для вибору пробілу і виходу
char letterBig[6][10] = {
{'0', '1', '2', '3', '4', '5', '6', '7', '8', '9'},
{'Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I', 'O', 'P'},
{'A', 'S', 'D', 'F', 'G', 'H', 'J', 'K', 'L', '-'},
{25 , 'Z', 'X', 'C', 'V', 'B', 'N', 'M', '.', 27 },
{' ', ' ', ' ', ' ', ' ', ' ', ' ', '>', '>', '>'}
};
char letterSmall[6][10] = {
{'0', '1', '2', '3', '4', '5', '6', '7', '8', '9'},
{'q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p'},
{'a', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l', '-'},
{24 , 'z', 'x', 'c', 'v', 'b', 'n', 'm', '.', 27 },
{' ', ' ', ' ', ' ', ' ', ' ', ' ', '>', '>', '>'}
};
static char (*ptrLetter)[10] = letterSmall;// вказівник вказує в залежності від настройки на великі або малі букви
if (Mf_EncoderButton() == click ) {// після кліку виконується видалення додавання букви
if (ptrLetter[AxisY][AxisX] == 25) {
ptrLetter = letterSmall;
}
else if (ptrLetter[AxisY][AxisX] == 24) {
ptrLetter = letterBig;
}
else if (ptrLetter[AxisY][AxisX] == 27) {
prof(act_dir)->nameProfiles(delete_letter);
if (!prof(act_dir)->letterIndicator) {
ptrLetter = letterBig;
}
}
else if (ptrLetter[AxisY][AxisX] == '>') {
AxisX = AxisY = delFlag = 0;
ptrLetter = letterSmall;
Md_cursor(set_pos, posThree);
Md_addres(3, back);
}
else{
if (!prof(act_dir)->letterIndicator) {// якщо вводиться перша буква всі букви стають малими одноразовo
ptrLetter = letterSmall;
}
prof(act_dir)->nameProfiles(change_letter, ptrLetter[AxisY][AxisX]);
}
}
if (Mf_EncoderButton(take_but_pos) == button_pressed){// якщо утримувати кнопку можна зробити дві дії видалення букви утриманням або переміщення по осі Y
if (Mf_encoderRotationSpeed(check_rotation) == data_available) {// переміщення курсу вверх-вниз якщо кнопка отримується
delFlag = 1;// забороняємо видалення утриманням коли почались оберти енкод
Mf_EncoderButton(reset);// Клік не повернеться скидаємо функцію
switch (Mf_encoderRotationSpeed(get_rotation)) {
case rotated_r:
AxisY--;
if (AxisY < 0) {
AxisY = 4;
}
break;
case rotated_l:
AxisY++;
if (AxisY > 4) {
AxisY = 0;
}
break;
}
}
else if(ptrLetter[AxisY][AxisX] == 27 && !delFlag) {// якщо не було обертів під час отримання кнопки І ми навелились на знак видалення і минув час починається видалення букв
if (tmr < millis()) {
Mf_EncoderButton(reset);
tmr = millis()+300;
prof(act_dir)->nameProfiles(delete_letter);
if (!prof(act_dir)->letterIndicator) {
ptrLetter = letterBig;
}
}
}
}
else if (Mf_encoderRotationSpeed(check_rotation) == data_available){// звичайний режим роботи курсор рухається вправо і вниз і повторно починає свої дії якщо дійти до кінця і наоборот
switch (Mf_encoderRotationSpeed(get_rotation)) {
case 0:
break;
case rotated_r:
AxisX -= magnitude;
break;
case rotated_l:
AxisX += magnitude;
break;
}
if (AxisX < 0) {// тут відбувається обмеження мінімального і максимального значення перемінних X Y також змінюється амплітуда якщо y = 4
magnitude = 1;
AxisX = 9;
AxisY--;
}
else if (AxisX > 9) {
magnitude = 1;
AxisX = 0;
AxisY++;
}
if (AxisY < 0) {
AxisY = 4;
}
else if (AxisY > 4 ) {
AxisY = 0;
}
if (AxisY == 4) {// якщо y вказує на останній рядок магнітуда збільшується до 9 так щоб після двох обертів ми покидали нижню частину
if (AxisX != 0 && AxisX != 9) {// користуємо якщо X не є дев'яткою або нулем після того як переміщалися вверх-вниз курсором
if (AxisX >= 7) {
AxisX = 9;
}
else{
AxisX = 0;
}
}
magnitude = 9;// якщо перетворити на 9 після нуля буде дев'ятка а після дев'ятки буде перебільшення і скидання курсова наверх після оберту енкодером
}
}
else{// захист від випадкового видалення коли хочемо почати переміщатися вверх-вниз коли знаходимося на пункті видалення
Ae_displayRefresh(reset);
tmr = millis()+400;
delFlag = 0;
}
Md_p_changeNameProfile(ptrLetter, AxisX, AxisY);// віалізуємо програму
}
byte Md_p_changeNameProfile(char letter[][10], byte AxisX, byte AxisY){
char str[] = {24, 25, 27, '>' , ' '};// маси використовується для мигання необхідної рамки
static byte flagBlink;
static uint32_t tmr;
display.setCursor(114, 54);// back
display.print('s');
display.drawPixel(120, 60, WHITE); // крапка
for (int i = 0; i <= 4; i++) {// виводимо рамку навколо букви якщо курсор рамку не вказує на пункти
if(letter[AxisY][AxisX] == str[i]){
break;
}
if(i == 4){// якщо елемент не дорівнює забороненим знакам то виводимо рамку
display.drawRect(4+AxisX*12, 12+AxisY*10, 9, 11, WHITE);// рамка курса 10 вверх вниз, вліво вправо 12
}
}
if((letter[AxisY][AxisX] != 24 && letter[AxisY][AxisX] != 25) || flagBlink){// кружок стрілка вниз вверх
display.drawCircle(8, 47, 5, WHITE);
}
// принцип роботи якщо навелись на додатковий знак то починаємо ним мигати за допомогою флажка
if(letter[AxisY][AxisX] != 27 || flagBlink){// знак видалення
display.drawCircle(116, 47, 4, WHITE);
}
if(letter[AxisY][AxisX] != '>' || flagBlink){// рамка s.
display.drawRoundRect(112, 54, 9, 9, 0, WHITE);
}
display.fillRect(36, 54, 54, 6, WHITE);// пробіл
if(letter[AxisY][AxisX] == ' '){// додаткова рамка якщо навели на пробіл
display.drawRect(34, 52, 58, 10, WHITE);
}
if(tmr < millis()){// мигння рамкою
Ae_displayRefresh(reset);
tmr = millis()+400;
flagBlink = !flagBlink;
}
if(!flagBlink && prof(act_dir)->letterIndicator != 20){// перестає мигати якщо 20 символів також мигаємо за допомогою flagBlink
display.drawRect(2+6*prof(act_dir)->letterIndicator, 0, 1, 9, WHITE);
}
display.setCursor(2, 1);// виводив ім'я профіля
display.print(prof(act_dir)->nameProfiles(get_name));
for (int i = 0; i < 4; i++) {// виводим масив букв на дисплей
for (int j = 0; j < 10; j++) {
display.setCursor(6+j*12, 14+i*10);
display.print(letter[i][j]);
}
}
return 0;
}
// cNP
//
// Md_Additional functions-------------------------------------------------------------------------------------------
byte MdAf_consenDisplay(){ // викликається для підтвердження вибору
static int8_t flagChoice;
switch (Mf_encoderRotationSpeed(get_rotation)) {// керування рамкою вліво вправо
case no_action:
break;
case rotated_l:
if (flagChoice > -2) {
flagChoice--;
}
break;
case rotated_r:
if (flagChoice < 2) {
flagChoice++;
}
break;
}
if ((flagChoice == -2 || flagChoice == 2) && Mf_EncoderButton() == click) {// V1 якщо відбувся Клік виконується дії в залежності від вибору
if (flagChoice == -2) {// якщо вибрали ні виконуються дії// вихід виконується в любому випадку з збереженими настройками або ні
flagChoice = 0;
return choice_no;
}
else if (flagChoice == 2) {
flagChoice = 0;
return choice_yes;
}
}
MdAf_p_consenDisplay(flagChoice);// візуальна частина коду
return 0;
}
int8_t MdAf_p_consenDisplay(int8_t acceptedFlag){
static uint32_t tmr;
static int8_t FlagFrame;
display.drawRoundRect(20, 8, 87, 22, 0, WHITE); // рамка навколо слова зверху
display.setCursor(25, 15);
display.println("Save settings");
if (tmr < millis()) {// виконує мигання рамкою навколо слова так ні
Ae_displayRefresh(reset);
tmr = millis() + 400;
FlagFrame = !FlagFrame;
}
if (FlagFrame) {// виводим рамку навколо слова і мигаємо нею
display.drawRect(52+acceptedFlag*18, 39, 21, 13, WHITE);// переміна приймає число від -2 до +2 І в залежності від числа міняє координати рамки
}
for (int i=39; i <= 75; i+=18){// відображаємо стрілки вліво вправо
display.setCursor(i,42);
display.write(27);display.write(26);
}
display.setCursor(21, 42);
display.println("NO");
display.setCursor(18, 42);
display.println(" YES");
return 0;
}
byte MdAf_profileStorage(byte acceptedCommand){// функція викликається якщо Md_addres(3, get_add) == 1
switch (acceptedCommand) {// false якщо повертаємо збережені настройки
case return_save:
prof(act_dir)->copyFrom(profilSeve);// це означає що ми вибрали ні і повертаємо настройки
break;
case copy_profile:
profilSeve.copyFrom(*prof(act_dir));// копіювання діючий профіль
break;
case check_changes:
if (profilSeve != *prof(act_dir)) {// провіряємо зміни
return recorded_changes;
}
break;
case reset:// прост спосіб скинути функцію перестане відправляти recorded_changes виконані зміни збережуться
prof(act_dir)->checkName();// якщо видалені всі букви То встановлюється стандартне ім'я профілю
profilSeve.copyFrom(*prof(act_dir));
if (prof(act_dir)->tape == t_mp) {// якщо ми настроювали власний профіль то перезаписуємо настройки в енергонезалежну пам'ять
Serial.println("t_mp s");
EEPROM.put((prof(act_dir)->namber - 1) * sizeof(Profiles), *(prof(act_dir)));
EEPROM.commit();
}
else if (prof(act_dir)->tape == t_sp) {
int tempProfSize = 7 * sizeof(Profiles);
Serial.println("t_mp s");
EEPROM.put(tempProfSize + (prof(act_dir)->namber - 1) * sizeof(prof(act_dir)->gamepadButton), prof(act_dir)->gamepadButton);
EEPROM.commit();
}
break;
}
return 0;
}
void MdAf_typeNumberPrint(){
display.setCursor(49, 0);
if (prof(act_dir)->tape == t_sp) {
display.print("(Sp");
display.print(prof(act_dir)->namber);
}
else {
display.print("(Mp");
display.print(prof(act_dir)->namber);
}
display.print(")");
}
byte MdAf_confirmYesNo(byte azixX, byte azixY){
// функцію можна відобразити в любому місці біля слова рецепт після завершення потрібно скинути вручну
static byte flagChoice;
if (Mf_encoderRotationSpeed(get_rotation)) {
flagChoice = !flagChoice;
}
if (Mf_EncoderButton() == click) {
byte temp = flagChoice;
flagChoice = 0;
if (!temp) {
Serial.print("yes");
return choice_no;
}else{
return choice_yes;
}
}
display.setCursor(azixX+4, azixY+4);
display.println("NO YES");
if(!flagChoice) {
display.drawRect(azixX+2, azixY+2, 15, 11, WHITE);// NO
}else{
display.drawRect(azixX+32, azixY+2, 21, 11, WHITE);// YES
}
display.drawRect(37, 46, 55, 15, WHITE);// рамка навколо так ні
// MdAf_p_confirmYesNo(flagChoice, 37, 46);
return 0;
}
// Md_Af
// Menu functions 5
byte Md_cursor(byte dataCommand, byte* arr) {
static int8_t permissionArrow, Point = 1;
switch (dataCommand) {
case set_pos: //вказуємо позицію курс при переходах вперед або назад по адресу
Point = arr[0];
permissionArrow = 0;
break;
case cursor_type_two: //перемінна permissionArrow міняє вид курсора в залежності від вибора і відповідає за дозвіл для переміщення курсу вверх вниз
permissionArrow = 1;
break;
case cursor_type_one:
permissionArrow = 0;
break;
case get_pos: //беремо позицію курсора для того щоб використати при наборі адресу
return Point;
break;
default:
if(!permissionArrow){//переміщаємо курси якщо є дозвіл
switch (Mf_encoderRotationSpeed(get_rotation)) {
case rotated_l:
Point--;
if (Point == 0) {
Point = dataCommand;
}
break;
case rotated_r:
Point++;
if (dataCommand < Point) {
Point = 1;
}
break;
}
}
if (!permissionArrow) {//відображаємо курсор одним з двох видів
display.setCursor(0, arr[Point-1]); // 21,8 максимум символів
display.write(26);
}
else if (permissionArrow) {
display.setCursor(0, arr[Point-1]); // 21,8 максимум символів
display.write(16);
}
}
return 0;
}
int8_t Md_addres(int8_t addNumb, int8_t dataCommand) {
static byte adr[19], modeSwitch = 1, namb = 1, workPermit = 1, del;
switch (dataCommand) {
case back:
Ae_displayRefresh(reset);
Md_cursor(cursor_type_one);
workPermit = modeSwitch = 1;
for (int i=18; i >= 1; i--){// команда back виконує видалення всіх адресів до числа вказаного в addNumb
adr[i] = 0;
if (i == addNumb) {
namb = addNumb;
break;
}
}
break;
case get_add:
return adr[addNumb];
break;
case add_status:// якщо адрес видалявся потрібно іноді обнуляти функції
if (del){
del = 0;
return address_deleted;
}
break;
case click_reset_off:// заборон кнопці нкодера скидати адрес кнопку перенаправ. для викорис в іншій фун
workPermit = 0;
break;
case int_add:// при тій команді відбувається набір адреса з подальшим набором при натиску кнопки енкодера
if (!adr[addNumb] && Mf_EncoderButton() == click){// набір адреса
adr[namb] = Md_cursor(get_pos);// позиція курс означає набраний адрес
namb++;
return address_entered;
}
break;
case int_add_last:// набір адреса з подальшим скиданням при натиску
if (workPermit && Mf_EncoderButton() == click){// набір адреса
if (modeSwitch){
adr[namb] = Md_cursor(get_pos);// позиція курс означає набраний адрес
Md_cursor(cursor_type_two);// міняємо вид курсора
modeSwitch = 0;// міняємо флажок наступний кліп буде означати скидання адресу
return address_entered;
}
else if (!modeSwitch){
adr[namb] = 0;
del = modeSwitch = 1;
Md_cursor(cursor_type_one);// міняємо вид курсора
}
}
break;
}
return adr[addNumb];// функція постійно повертає адрес вказаний в параметрах
}
int8_t Mf_encoderRotationSpeed(int8_t acceptedCommand) {// функція повертає бистре або повільне обертання працює разом з функцією Ae_encoderInterrupt_fastRotation() для обробки даних
static int seveEncoder;// збереження позиції кондера
if (acceptedCommand == check_rotation) {// перевіряємо наявність обертів спочатку перевіряється наявність даних check_rotation необхідно для економії ресурсів
if (seveEncoder != encoder.getPosition()) {
return data_available;
}
}
else if (acceptedCommand == get_rotation) {
if (g_encFast > 0) {// якщо енкодер обертається з достатньою швидкістю переміна g_encFast буде 1 або -1
g_encFast = 0;// скидаємо перемінно для того щоб знову визначити швидкість обертання
return rotated_r_fast;
}
else if (g_encFast < 0) {
g_encFast = 0;
return rotated_l_fast;
}
else if (seveEncoder < encoder.getPosition()) {// залежності від сторони обертання паралельно виконується одиночне + або -
seveEncoder = encoder.getPosition();
return rotated_r;
}
else if (seveEncoder > encoder.getPosition()) {
seveEncoder = encoder.getPosition();
return rotated_l;
}
}
return 0;
}
byte Mf_EncoderButton(byte acceptedCommand) {
static byte saveData;
static uint32_t tmr;
if (acceptedCommand){// в Kodi можемо зробити reset щоб не поверталося утримання hold_b_e або click
if (acceptedCommand == reset && saveData != reset_status){// в Kodi можемо зробити reset щоб не поверталося утримання hold_b_e або click
saveData = reset_status;
}
else if (acceptedCommand == take_but_pos && Ae_BatR(b_sw)){ // викликаємо стан кнопки якщо кнопка нажата то можемо наприклад скинути функцію і вона не поверне hold_b_e або click
return button_pressed;
}
}
else{
if (!Ae_BatR(b_sw) && !saveData){// економія ресурсів виконується постійно якщо кнопка не нажата
}
else if (Ae_BatR(b_sw)){// якщо ми натиснули кнопку може відбутися дві події
if (!saveData) {// якщо натиснули одразу повернеться натиск а потім Клік
saveData = press_b_e;
tmr = millis() + 500;
return press_b_e;
}
else if (saveData == press_b_e && tmr < millis()) {// якщо натиснули і утримуємо і час вийшов повернеться утримання
saveData = hold_b_e;
return hold_b_e;
}
}
else if (saveData && !Ae_BatR(b_sw)) {// якщо бистро відпустили кнопку повертається Клік
int temp = saveData;
saveData = 0;
if (temp == press_b_e){
Ae_displayRefresh(reset);
return click;
}
}
}
return 0;
}
int Mf_Magnifier(int Numeric, int Min, int Max, int Speed) {
if (Mf_encoderRotationSpeed(check_rotation) == data_available) {
Mf_EncoderButton(reset);
switch (Mf_encoderRotationSpeed(get_rotation)) {
case rotated_r:
Numeric++;
break;
case rotated_l:
Numeric--;
break;
case rotated_r_fast:
Numeric+=Speed;
break;
case rotated_l_fast:
Numeric-=Speed;
break;
}
}
if (Numeric > Max) {
Numeric = Min;
}
else if (Numeric < Min) {
Numeric = Max;
}
return Numeric;
}
// Mf
// Md
// MdId
void MdId_BluetoothPrint() {
const byte bluArr[9] = {
0b00100,
0b00110,
0b10101,
0b01110,
0b00100,
0b01110,
0b10101,
0b00110,
0b00100
};
static uint32_t tmr;
static byte Flag;
display.drawCircle(6, 6, 6, WHITE);// кружок
// display.setCursor(4, 3);
if (bleGamepad.isConnected()) {
display.drawBitmap(1, 2, bluArr, 8, 9, WHITE);
}
else{
if (tmr < millis()) {
Ae_displayRefresh(reset);
Flag = !Flag;
tmr = millis() + 1000;
}
if (Flag) {
display.drawBitmap(1, 2, bluArr, 8, 9, WHITE);
}
}
}
void MdId_battery() {
const float batLevels[] = {4.15, 4.0, 3.82, 3.76, 3.65, 3.6, 3.5, 3.4, 3.3, 3.0};
/*
float shuntVoltage_mV = ina219.getShuntVoltage_mV();
float busVoltage_V = ina219.getBusVoltage_V();
float loadVoltage_V = busVoltage_V + (shuntVoltage_mV / 1000);
*/
static float loadVoltage_V = 3.0;// test
static byte chargeLevel;
static uint32_t tmr;
if (tmr < millis()) {
tmr = millis() + 60000;
for (int i = 0; i <= 9 ; i++) {
if (loadVoltage_V >= batLevels[i]) {
if (chargeLevel != map(i, 0, 9, 0, 11)) {
Ae_displayRefresh(reset);
}
chargeLevel = map(i, 0, 9, 0, 11);
break;
}
}
}
MdId_p_battery(chargeLevel);
}
byte MdId_p_battery(byte receivedData) {
display.drawRect(111, 2, 1, 4, WHITE);// картинка батареї
display.drawRect(112, 0, 16, 8, WHITE);
display.fillRect(114+receivedData, 2, 12-receivedData, 4, WHITE);// шкала заряду батареї
return 0;
}
// MI
// info Display
void infoDisplay() {
MdId_BluetoothPrint();
MdAf_typeNumberPrint();
MdId_battery();
display.drawRect(0, 14, 127, 19, WHITE);// РАМКА НАВКОЛО НАЗВИ
display.setCursor(prof(act_dir)->centroName(), 20);// функція centroName() в залежності від кількості ім'я вранці
display.print(prof(act_dir)->nameProfiles(get_name));
display.setCursor(44,44);
display.write(26);
display.drawRect(50, 42, 27, 11, WHITE);
display.setCursor(52,44);
display.print("Menu");
}
// Id
// Display
byte Md_Display(byte Receiving) {
static byte Regime = info_display;
// static byte Regime = menu;
Ae_displayRefresh(clear_display);
if (Receiving) {
Regime = Receiving;
}
switch (Regime) {
case info_display:
if (Mf_EncoderButton() == click) {
Md_Display(menu);
}
/*
else if (Mf_EncoderButton() == hold_b_e) {// по плану має виключати дисплей при утриманні ?
display.clearDisplay();
display.display();
}
*/
else{
infoDisplay();
}
break;
case menu:
// Ae_displayRefresh(reset);
Md_MainDisplay();
break;
}
Ae_displayRefresh(print_display);
return 0;
}
// D
// Gamepad function
void IRAM_ATTR Gf_GyroAnalogR() {
// static uint32_t tmr;
volatile static int GiroDedZone;
volatile static int rightStickX;
volatile static int rightStickY;
static int x; // x
static int z; // z
/*
*/
// Serial.println(" 11111");
// if (Ae_BatR(b_handle) && tmr < millis()) {
// if (Ae_BatR(b_handle) && bleGamepad.isConnected()) {
if (Ae_BatR(b_handle)) {
Ae_autoShutdown(reset);
/*
Quaternion q;
VectorFloat gravity;
VectorInt16 gyro;
volatile static float ypr[3];
*/
/*
if (mpu.dmpGetCurrentFIFOPacket(fifoBuffer)) {
mpu.dmpGetQuaternion(&q, fifoBuffer);
mpu.dmpGetGyro(&gyro, fifoBuffer);
mpu.dmpGetGravity(&gravity, &q);
mpu.dmpGetYawPitchRoll(ypr, &q, &gravity);
// tmr = millis() + 11;
}
*/
if (abs(x) > 1) {
GiroDedZone = map(z, -150, 150, -30, 30);
GiroDedZone = abs(GiroDedZone);
if (x < -GiroDedZone) {
x = map(x, -1, -prof(act_dir)->sensitivityHor, -prof(act_dir)->deadZoneHor, -32767);
x = constrain(x, -32767, -1);
bleGamepad.setZ(x);
}
else if (x > GiroDedZone) {
x = map(x, 1, prof(act_dir)->sensitivityHor, prof(act_dir)->deadZoneHor, 32767);
x = constrain(x, 1, 32767);
bleGamepad.setZ(x);
}
}
else{
bleGamepad.setZ(0);
}
if (abs(z) > 1) {
GiroDedZone = map(x, -150, 150, -30, 30);
GiroDedZone = abs(GiroDedZone);
if (z < -GiroDedZone) {
z = map(z, -1, -prof(act_dir)->sensitivityHor, prof(act_dir)->deadZoneHor, 32767);
z = constrain(z, -32767, -1);
bleGamepad.setRZ(z);
}
else if (z > GiroDedZone) {
z = map(z, 1, prof(act_dir)->sensitivityHor, -prof(act_dir)->deadZoneHor, -32767);
z = constrain(z, 1, 32767);
bleGamepad.setRZ(z);
}
}
else{
bleGamepad.setRZ(0);
}
bleGamepad.sendReport();
}
else if (rightStickX || rightStickY){
rightStickX = rightStickY = 0;
bleGamepad.setRightThumb(0, 0);
bleGamepad.sendReport();
}
}
void Gf_AnLeftDpad(){
static bool flag;
int AxisX = constrain(analogRead(39), 45, 4050);
int AxisY = constrain(analogRead(36), 45, 4050);
if ((AxisX < 1800 || AxisX > 2200) || (AxisY < 1800 || AxisY > 2200)) {
if (!Ae_BatR(b_emul_dpad)) {
if (flag) {
flag = 0;
bleGamepad.setHat1(HAT_CENTERED);
}
AxisX = map(AxisX, 45, 4050, -32767, 32767);
AxisY = map(AxisY, 45, 4050, -32767, 32767);
bleGamepad.setLeftThumb(AxisX, AxisY);
}
else{
if (!flag) {
flag = 1;
bleGamepad.setLeftThumb(0, 0);
}
if (AxisX < 1800 || AxisX > 2200) {
AxisX = constrain(AxisX, 1800, 2200);
AxisX = map(AxisX, 1800, 2200, 2, 4);
}
else{
AxisX = 0;
}
if (AxisY < 1800 || AxisY > 2200) {
AxisY = constrain(AxisY, 1800, 2200);
AxisY = map(AxisY, 1800, 2200, 1, 6);
}
else{
AxisY = 0;
}
const byte dpadArr[] = {0, 1, 3, 2, 7, 8, 5, 0, 4, 0, 6};
bleGamepad.setHat1(dpadArr[AxisX+AxisY]);
}
}
else{
bleGamepad.setLeftThumb(0, 0);
bleGamepad.setHat1(0);
}
}
void Gf_gamepadButtons(){
if (Ae_BatR(prof(act_dir)->gamepadButton[1])) {
bleGamepad.pressSelect();
}
else{
bleGamepad.releaseSelect();
}
if (Ae_BatR(prof(act_dir)->gamepadButton[2])) {
bleGamepad.pressStart();
}
else{
bleGamepad.releaseStart();
}
if (Ae_BatR(prof(act_dir)->gamepadButton[11])) {
bleGamepad.setLeftTrigger(32767);
}
else{
bleGamepad.setLeftTrigger(0);
}
if (Ae_BatR(prof(act_dir)->gamepadButton[12])) {
bleGamepad.setRightTrigger(32767);
}
else{
bleGamepad.setRightTrigger(0);
}
for (int i = 3; i <= 12; i++) {
if (Ae_BatR(prof(act_dir)->gamepadButton[i])) {
bleGamepad.press(i);
}
else{
bleGamepad.release(i);
}
}
}
// Gf
void setup() {
Serial.begin(9600);// В ФІНАЛІ НЕЗАБУТИ ЗАКОМЕНТУВАТИ!!!
bleGamepad.begin();
EEPROM.begin(512);
prof(eeprom_initialization);// ініціалізація з енергонезалежної пам'яті профілів
delay(500);
// /pinMode(3, OUTPUT);// подаємо високий сигнал на транзистор щоб заживити модулі
// digitalWrite(3, HIGH);
// pin 2 глючить встроєний резистор
/*
pinMode(32, INPUT_PULLUP);
pinMode(15, INPUT_PULLUP);
pinMode(5, INPUT_PULLUP);
pinMode(13, INPUT_PULLUP);
*/
pinMode(25, INPUT_PULLUP);
byte pinsArr[] = {12, 13, 14, 4, 15};
pinMode(26, OUTPUT);// test
digitalWrite(26, HIGH);
pinMode(27, OUTPUT);// test
digitalWrite(27, LOW);
/*
byte pinsWithPullup[] = {33, 13, 27, 26, 25, 16, 17, 5, 23, 2, 18, 19, 32, 15, 4, 12, 14};// добавити 1
for (int i = 0; i < sizeof(pinsWithPullup); i++) {
pinMode(pinsWithPullup[i], INPUT_PULLUP);
}
esp_sleep_enable_ext0_wakeup(GPIO_NUM_13, 0);
hw_timer_t * timer = NULL;
timer = timerBegin(0, 80, true); // Таймер 0, прескалер 80 (для ESP32), true для повторення таймера
timerAttachInterrupt(timer, &Gf_GyroAnalogR, true); // Встановлюємо функцію, яка буде викликана таймером
timerAlarmWrite(timer, 11000, true); // Встановлюємо час спрацьовування таймера (11 мілісекунд)
timerAlarmEnable(timer); // Вмикаємо таймер
ina219.setADCMode(BIT_MODE_12); // Устанавливаем разрешение АЦП 12 бит
ina219.setPGain(PG_40); // Ток в пределах 400 мА
ina219.setBusRange(BRNG_16); // Напряжение до 16 В
*/
attachInterrupt(digitalPinToInterrupt(p_dt), Ae_encoderInterrupt_fastRotation, CHANGE);
attachInterrupt(digitalPinToInterrupt(p_clk), Ae_encoderInterrupt_fastRotation, CHANGE);
// ----------Display--------------
display.begin(SSD1306_SWITCHCAPVCC, 0x3C);
display.setTextSize(1);
display.setTextColor(WHITE);
// gyroStart();// при потребі проводимо калібровку якщо калібровка виконана виконуємо старт функції гіроскопа
// startAnimation();// анімація при включенні до робити в кінці
}
void loop() {
// Ae_autoShutdown();
// Ae_buttonOnOff();
// Ae_batteryCheck();
Md_Display();
/*
if (bleGamepad.isConnected()) {
// Gf_GyroAnalogR();
Gf_AnLeftDpad();
Gf_gamepadButtons();
bleGamepad.sendReport();
}
*/
}// void loop()