#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#define SCREEN_WIDTH 128 // OLED display width, in pixels
#define SCREEN_HEIGHT 64 // OLED display height, in pixels
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, -1);
//Profiles 1
//Profiles
#define t_sp 1//не міняти число!
#define t_mp 2//не міняти число!
#define r_off 0 // = off
#define r_on 12 // = on
#define get_name 20
#define get_name_a_f 21
#define change_letter 22
//*prof()
#define direct_p_sp 20
#define direct_p_mp 21
#define act_dir 22
#define activate_p_sp 23
#define activate_p_mp 24
class Profiles {
public:
Profiles(int deZoH, byte senHor, int deZoV, byte senVer, byte st, String name, byte tape, byte na) {
_deadZoneHor = deZoH;
_sensitivityHor = senHor;
_deadZoneVer = deZoV;
_sensitivityVer = senVer;
_status = st;
_name = name;
_tape = tape;
_namber = na;
}
int getDeZoHor() { //get
return _deadZoneHor;
}
byte getSenHor() {
return _sensitivityHor;
}
int getDeZoVer() {
return _deadZoneVer;
}
byte getSenVer() {
return _sensitivityVer;
}
byte getStatus() {
return _status;
}
String getName() {
return _name;
}
byte getTape() {
return _tape;
}
byte getNamber() {
return _namber;
}
int setDeZoHor(int deZoH) {//set
if (_deadZoneHor != deZoH) {_sensitivityHor = 0;}
_deadZoneHor = deZoH;
}
byte setSenHor(byte senHor) {
_sensitivityHor = senHor;
}
int setDeZoVer(int deZoV) {
if (_deadZoneVer != deZoV) {_sensitivityVer = 0;}
_deadZoneVer = deZoV;
}
byte setSenVer(byte senVer) {
_sensitivityVer = senVer;
}
byte setStatus(byte st) {
_status = st;
}
byte setTape(byte tape) {
_tape = tape;
}
byte setNamber(byte na) {
_namber = na;
}
String nameProfiles(byte acceptedCommand, byte index = 0, char Letter = ' '){
if (_status == r_on && tmr < millis()){
tmr = millis()+600;
Flag = !Flag;
}
else if (_status == r_off && !Flag){
Flag = 1;
}
switch (acceptedCommand) {
case get_name:
return _name;
break;
case get_name_a_f:
if (Flag) {
return _name;
}
else {
return "";
}
break;
case change_letter:
_name[index] = Letter;
break;
return "";
}
return "";
}
byte centroName() {
for (int i = 19; i >= 0; i--) {
if (_name[i] != ' '){
return 61-i*3;
break;
}
}
return 0;
}
byte getNamberTape(){
return _tape * 10 +_namber;//логіка роботи тип може бути 1 або 2 множимо на 10 щоб не збігалася числа
}
void copyFrom(const Profiles& other) {//використовується для копіювання шаблона
_deadZoneHor = other._deadZoneHor;
_sensitivityHor = other._sensitivityHor;
_deadZoneVer = other._deadZoneVer;
_sensitivityVer = other._sensitivityVer;
_tape = other._tape;
_namber = other._namber;
_status = other._status;
_name = other._name;
}
bool operator!=(const Profiles& other) const { //використовується для порівняння шаблону
return (_deadZoneHor != other._deadZoneHor) ||
(_sensitivityHor != other._sensitivityHor) ||
(_deadZoneVer != other._deadZoneVer) ||
(_sensitivityVer != other._sensitivityVer) ||
(_tape != other._tape) ||
(_namber != other._namber) ||
(_status != other._status) ||
(_name != other._name);
}
String _name;
private:
static uint32_t tmr;// перемінні для функціїnameProfiles(get_name_a_f) не переносити будуть глюки
byte Flag;
int _deadZoneHor;//(primary початкова) початок руху
byte _sensitivityHor;
int _deadZoneVer;
byte _sensitivityVer;
byte _tape;
byte _namber;
byte _status;
};
// Ініціалізуємо статичну змінну класу Profiles
uint32_t Profiles::tmr = 0;
Profiles profilSeve(0, 0, 0, 0, 0, "0", 0, 0);
Profiles profilSpOne(2000, 100, 2556, 92, r_off, "CodMW", t_sp, 1);
Profiles profilSpTwo(166, 120, 1965, 112, r_off, "Batl3", t_sp, 2);
Profiles profilSpThree(2000, 100, 2556, 92, r_off, "SP 33", t_sp, 3);
Profiles profilSpFour(166, 120, 1965, 112, r_off, "SP 44", t_sp, 4);
Profiles profilSpFive(2000, 100, 2556, 92, r_off, "SP 55", t_sp, 5);
Profiles profilSpSix(166, 120, 1965, 112, r_off, "SP 66", t_sp, 6);
Profiles profilSpSeven(2000, 100, 2556, 92, r_off, "SP 77", t_sp, 7);
Profiles profilMpOne(2000, 100, 2556, 92, r_on, "0 ", t_mp, 1);
Profiles profilMpTwo(166, 120, 1965, 112, r_off, "Xmen ", t_mp, 2);
Profiles profilMpThree(2000, 100, 2556, 92, r_off, "Mp 3 ", t_mp, 3);
Profiles profilMpFour(166, 120, 1965, 112, r_off, "Mp 4 ", t_mp, 4);
Profiles profilMpFive(2000, 100, 2556, 92, r_off, "Mp 5 ", t_mp, 5);
Profiles profilMpSix(166, 120, 1965, 112, r_off, "Mp 6 ", t_mp, 6);
Profiles profilMpSeven(2000, 100, 2556, 92, r_off, "Mp 7 ", t_mp, 7);
Profiles *prof(byte acceptedCommand, byte number = 0){
static byte acting = 7+1;
Profiles *prof[] = {&profilSeve, &profilSpOne, &profilSpTwo, &profilSpThree, &profilSpFour, &profilSpFive, &profilSpSix, &profilSpSeven,
&profilMpOne, &profilMpTwo, &profilMpThree, &profilMpFour, &profilMpFive, &profilMpSix, &profilMpSeven};
if (acceptedCommand == act_dir) {
return prof[acting];
}
else if (acceptedCommand == direct_p_sp) {
return prof[number];
}
else if (acceptedCommand == direct_p_sp) {
return prof[number];
}
else if (acceptedCommand == direct_p_mp) {
return prof[number+7];
}
else if (acceptedCommand == activate_p_sp || acceptedCommand == activate_p_mp) {
for (int i = 1; i < 15; i++){
prof [i] -> setStatus(r_off);
}
if (acceptedCommand == activate_p_sp ) {
prof[number] -> setStatus(r_on);
acting = number;
}
else {
prof[number+7] -> setStatus(r_on);
acting = number+7;
}
}
return 0;
}
//P
//Additional_elements 2
bool Vibrgyro;
// СПІЛЬНІ КОНСТАНТИ ПІД ХОД ДЛЯ БАГ ФУНК
#define no_action 0 // НЕМА ДІЇ
#define no_data 0 // немає даних
#define no_indication 0 // немає вказівки
#define no 0
#define off 0
#define get_status 1 // получити настройки
#define yes 1
#define save_settings 4 // зберехти настройки
#define reset 11
#define on 12
#define click 13
#define execute_code 14// execution without comman - виконання без команди
#define gyro 15
#define profil 16
#define melody_start 1
#define melody_off_power 2
#define x_axis_hor 1
#define y_axis_ver 2
#define z_axis_ver 3
#define get_y 2
#define get_z 3
#define get_vibr 4
//Піни карта
//#define b_mein 25
#define b_triger 33
#define b_analog 32
#define b_on_off 14
#define b_emul_dpad 26
#define b_sw 4
#define p_dt 3
#define p_clk 2
#define thandle_touch_button 27
//Mf_EncoderButton();
//#define click 13
#define press 20
#define hol_but 21
#define released 22
#define released_const 23
#define press_const 24
#define hol_const 25
#define hol_released 26
#define status_button 27
//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 int_add_ban 24
#define int_add_last 25
#define address_deleted 26
//int Md_cursor();
//#define reset 11
#define selection_inversion 21
#define freeze_position 22
#define get_pos 23
#define return_pos 24
byte noData[1];
byte posOne[] = {1};
byte posTwo[] = {2};
byte posThree[] = {3};
byte posFour[] = {4};
byte posFive[] = {5};
byte posSix[] = {6};
byte posEight[] = {7};
//Ae_InterruptReadPinDtEncoder()
//Mf_Encoder();
#define rotated_rights 20
#define rotated_left 21
//MdAf_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 animation_one 20
#define animation_two 21
#define animation_stope_one 22
#define animation_stope_two 23
#define cancel_actions 24
int8_t Md_addres(int8_t AddNumb, int8_t acceptedCommand, int8_t acceptedDataOne = 0);
byte Md_p_Buttons(byte receivedData = 0, byte selectedButton = 0);
byte buttonArray[] = {5, 6, 7, 8, 9, 10, 11, 12, 13, 14};
int8_t Ae_Countdown(int8_t acceptedCommand){
static uint32_t tmr;
if (!tmr) {tmr = (acceptedCommand+1) * 1000 + millis();}
else if (acceptedCommand == reset) { tmr = 0;}
acceptedCommand = ((tmr - millis()) / 1200) - 1;
//Serial.println(acceptedCommand);
return acceptedCommand;
}
byte Ae_BatR(byte Taking) {
return !digitalRead(Taking);
}
void Ae_InterruptReadPinDtEncoder() { //дивитися на початку в void setup працюэ разом з attachInterrupt(digitalPinToInterrupt(p_dt), Ae_InterruptReadPinDtEncoder, CHANGE);
static int8_t clkStateCurrent;
static int8_t clkStateLast;
clkStateCurrent = digitalRead(p_clk);
if ((clkStateLast == LOW) && (clkStateCurrent == HIGH)) {
if (digitalRead(p_dt) == HIGH) {
Mf_encoderActionStorage(rotated_rights);
} else {
Mf_encoderActionStorage(rotated_left);
}
}
clkStateLast = clkStateCurrent;
}
//Ae
//Main_display 3
// add1-----------------------------------------------------------------------------------------------------------
byte Md_MainDisplay() {// головна фунція виклик решта функцій дисплея
display.clearDisplay();
switch (Md_addres(1, int_add)) {
case no_action:
MdAf_BluetoothPrint(); MdAf_typeNumberPrint(); MdAf_batteryPrint();
Md_ItemOne();
break;//1
case 1:
Md_Profile();
break;//a2
//case 2: Md_Additional_effectsENG(); break;
//case 3: Md_SettingsENG(); break;
//case 4: Md_InstructionENG(); break;
case address_entered:
if (Md_addres(1, get_add) == 5) {
Md_Display(info_display);
Md_cursor(no_data, reset);
Md_addres(1, back);
}
else{
Md_cursor(no_data, reset);
}
break;
}
display.display();
}
void Md_ItemOne(){
byte Lines[] = {16, 24, 32, 40, 48 };
Md_cursor(Lines, sizeof(Lines));
display.setCursor(0, 16);
display.println(" Profile");
display.println(" Additional effects");
display.println(" Settings ");
display.println(" Instruction ");
display.println(" Close menu ");
}
//
// add2-----------------------------------------------------------------------------------------------------------
void Md_Profile() {
if (prof(act_dir)->getTape() == t_sp) {//в залежності від типу профілю вид меню міняється
switch (Md_addres(2, int_add)) {
case no_action:
Md_p_Profile();
break;
case 1:
Md_ProfileSettings();
break;//a3
case 2: break;// QR code
case 3:
Md_SelectProfile();
break;//a3
case address_entered:
if (Md_addres(2, get_add) == 4) {
Md_cursor(posOne, return_pos);
Md_addres(1, back);
}
else{
MdAf_profileStorage(copy_profile);////копіюємо профіль при доході в настройки p1 для подальшої перевірки на зміни при виході
Md_cursor(no_data, reset);
}
break;
}
}
else {
switch (Md_addres(2, int_add)) {
case no_action:
Md_p_Profile();
break;
case 1://a3
Md_ProfileSettings();
break;
case 2: //a3
Md_SelectProfile();
break;
case address_entered:
if (Md_addres(2, get_add) == 3) {
Md_cursor(posOne, return_pos);
Md_addres(1, back);
}
else{
MdAf_profileStorage(copy_profile);
Md_cursor(no_data, reset);
}
break;
}
}
}
void Md_p_Profile() {
byte LinesSp[] = {31, 39, 49, 57};
byte LinesMp[] = {35, 49, 57};
if (prof(act_dir)->getTape() == t_sp) {
Md_cursor(LinesSp, sizeof( LinesSp));
}
else {
Md_cursor(LinesMp, sizeof(LinesMp));
}
display.setCursor(3, 1);//стрілки по боках активний профіль
display.write(25);
display.setCursor(118, 1);
display.write(25);
display.drawRoundRect(0, 0, 127, 10, 2, WHITE);// РАМКА АКТИВ ПРОФ НАЗВА ГРИ
display.drawRect(0, 9, 127, 19, WHITE);
display.drawRect(10, 29, 51, 19, WHITE);// РАМКА НАСТРОЙКИ КЮАР КОД
display.setCursor(21, 1);
display.print("Active profile");
display.setCursor(98, 36); //РИСКА В лыво РАЗОМ ПОЛУЧАЭТСЯ КРИВА СТРЫЛКА
display.println("_" );
display.setCursor(93, 36);
display.println("_" );
display.setCursor(91, 36);// СТРЫЛКА ВВЕРХ РАЗОМ ПОЛУЧАЭТСЯ КРИВА СТРЫЛКА
display.write(24);
display.setCursor(91, 34);
display.write(30);
display.drawCircle(113, 42, 11, WHITE);// КРУГ НАВК Sp
display.setCursor(105, 39);
if (prof(act_dir)->getTape() == t_sp) {
display.print("Sp");
display.println(prof(act_dir)->getNamber());
}
else {
display.print("Mp");
display.println(prof(act_dir)->getNamber());
}
display.setCursor(prof(act_dir)->centroName(), 15);//функція centroName() в залежності від кількості ім'я вранці
display.println(prof(act_dir)->nameProfiles(get_name));
display.setCursor(0, 32); //РИСКА В ПРАВО РАЗОМ ПОЛУЧАЭТСЯ КРИВА СТРЫЛКА
display.println(" _" );
display.setCursor(4, 32);
display.println(" _" );
display.setCursor(66, 32);// СТРЫЛКА ВВЕРХ РАЗОМ ПОЛУЧАЭТСЯ КРИВА СТРЫЛКА
display.write(24);
display.setCursor(66, 30);
display.write(30);
if (prof(act_dir)->getTape() == t_sp) {
display.setCursor(0, 31);
display.println(" Settings " );
display.println(" QR code");
}
else {
display.setCursor(0, 35);
display.println(" Settings " );
}
display.setCursor(0, 49);
display.println(" Select profile ");
display.println(" Back" );
}
//
// add3-----------------------------------------------------------------------------------------------------------
void Md_SelectProfile() {
switch (Md_addres(3, int_add)) {
case no_action:
Md_p_SelectProfile();
break;
case 1:
Md_StandardProfiles();
break;
case 2:
Md_MyProfiles();
break;
case address_entered:
if (Md_addres(3, get_add) == 3) {
if (prof(act_dir)->getTape() == t_sp) {
Md_cursor(posThree, return_pos);
}
else{
Md_cursor(posTwo, return_pos);
}
Md_addres(2, back);
}
else{
Md_cursor(no_data, reset);
}
break;
}
}
void Md_p_SelectProfile() {
byte Lines[] = {16, 24, 32};
Md_cursor(Lines, sizeof(Lines));
display.setCursor(0, 16);
display.println(" Standard profiles" );
display.println(" My profiles");
display.println(" Back" );
}
void Md_ProfileSettings() {
if (prof(act_dir)->getTape() == t_sp) { //вид пунктiv меню якщо профіль стандартний
switch (Md_addres(3, int_add)) {
case no_action:
Md_p_ProfileSettings();
break;
case 1:
Md_Buttons();
break;//Buttons
case address_entered:
if (Md_addres(3, get_add) == 2) {
Md_cursor(posOne, return_pos);
Md_addres(2, back);
}
else{
Md_cursor(no_data, reset);
}
break;
}
}
else { // вид пунктів якщо вибрано власний профіль
if (!Md_addres(3, get_add) && MdAf_profileStorage(check_changes) == recorded_changes) {//перевірка на наявність змін
switch (MdAf_consenDisplay()) {//якщо є зміни запуститься дисплей підтвердження при виході з настройок
case choice_yes:
MdAf_profileStorage(copy_profile);//якщо виберемо так профіль повторно скопірується і функція MdAf_profileStorage перестане видавати recorded_changes
break;
case choice_no:
MdAf_profileStorage(return_save);//якщо виберемо Ні функція dAf_profileStorage перестане видавати recorded_changes і умова перестане виконуватися
break;
}
}
else{
switch (Md_addres(3, int_add)) {
case no_action: //a2
Md_p_ProfileSettings();//відображення пунктів настройки
break;
case 2://Gyroscope //a4
Md_gyroscopeSettings();
break;
case 1://Buttons
Md_Buttons();
break;
case 3://Name
Md_changeNameProfile();
break;
case 4://Reset
break;
case address_entered:
if (Md_addres(3, get_add) == 5) {
Md_cursor(posOne, return_pos); //копіюємо профіль при доході в настройки для подальшої перевірки на зміни при виході
Md_addres(2, back);
}
else{
Md_cursor(no_data, reset);
}
break;
}
}
}
}
void Md_p_ProfileSettings() {
byte LinesSp[] = {16, 24};
byte LinesMp[] = {8, 16, 24, 38, 50};
if (prof(act_dir)->getTape() == t_sp) {
Md_cursor(LinesSp, sizeof(LinesSp));
display.setCursor(0, 16);
display.println(" Buttons" );//не добавляти пункт reset не потрібно
display.println(" Back" );
}
else {
Md_cursor(LinesMp, sizeof(LinesMp));
display.drawRoundRect(9, 6, 59, 28, 0, WHITE);
display.setCursor(0, 8);
display.println(" Gyroscope" );
display.println(" Buttons" );
display.println(" Name" );
if(Md_cursor(noData, get_pos) == 4){
display.setCursor(38, 35);// КРИВА СТРЫЛКА ВВЕРХ СТРЫЛКА
display.println("_" );
display.setCursor(40, 35);
display.write(24);
}
display.setCursor(0, 38);
display.println(" Reset" );
display.setCursor(0, 50);
display.println(" Back" );
}
}
//
// add4-----------------------------------------------------------------------------------------------------------
void Md_StandardProfiles() {
switch (Md_addres(4, int_add)) {
case no_action:
Md_p_StandardProfiles();//відображення списку профілів вибір
break;
case address_entered:
if (Md_addres(4, get_add) == 8) {
Md_cursor(posOne, return_pos);
Md_addres(3, back);
}
else{
if (prof(act_dir)->getNamberTape() != prof(direct_p_sp, Md_addres(4, get_add))->getNamberTape()) {
prof(activate_p_sp, Md_addres(4, get_add));
Md_cursor(posOne, return_pos);
Md_addres(2, back);
}
else{Md_addres(4, back); }
}
break;
}
}
void Md_p_StandardProfiles(){
byte Lines[] = {0, 8, 16, 24, 32, 40, 48, 56};
Md_cursor(Lines, sizeof(Lines));
for (int i = 0; i < 7; i++) {//виводим імена профілів діючий профіль мигає
display.setCursor(6, i*8);
display.print(prof(direct_p_sp, i+1)->nameProfiles(get_name_a_f));
}
display.setCursor(0, 56);
display.println(" Back" );
}
void Md_MyProfiles(){
switch (Md_addres(4, int_add)){//третій параметр забороняє вибирати діючий профіль
case no_action:
Md_p_MyProfiles();
break;
case address_entered:
if (Md_addres(4, get_add) == 8) {//повертаємося в передній пункт
Md_cursor(posOne, return_pos);
Md_addres(3, back);
}
else{
if (prof(act_dir)->getNamberTape() != prof(direct_p_mp, Md_addres(4, get_add))->getNamberTape()) {
prof(activate_p_mp, Md_addres(4, get_add));
Md_cursor(posOne, return_pos);
Md_addres(2, back);
}
else{Md_addres(4, back); }
}
break;
}
}
void Md_p_MyProfiles() {
byte Lines[] = {0, 8, 16, 24, 32, 40, 48, 56};
Md_cursor(Lines, sizeof(Lines));
for (int i = 0; i < 7; i++) {
display.setCursor(6, i*8);
display.print(prof(direct_p_mp, i+1)->nameProfiles(get_name_a_f));
}
display.setCursor(6, 56);
display.println("Back" );
}
void Md_gyroscopeSettings(){//a3
int seveData;//використовую щоб було більш зрозуміліше
if (Md_addres(4, get_add) != 5){Md_p_gyroscopeSettings();}
switch (Md_addres(4, int_add_last, 5)) {//4
case no_action:break;
case 1:
seveData = Mf_Magnifier(prof(act_dir)->getDeZoHor(), 0, 9999, 100);
prof(act_dir)->setDeZoHor(seveData);
break;
case 2:
seveData = Mf_Magnifier(prof(act_dir)->getSenHor(), 0, 100, 100);
prof(act_dir)->setSenHor(seveData);
break;
case 3:
seveData = Mf_Magnifier(prof(act_dir)->getDeZoVer(), 0, 9999, 100);
prof(act_dir)->setDeZoVer(seveData);
break;
case 4:
seveData = Mf_Magnifier(prof(act_dir)->getSenVer(), 0, 100, 100);
prof(act_dir)->setSenVer(seveData);
break;
case 5:
Md_cursor(posOne, return_pos);
Md_addres(3, back);
break;
}
}
void Md_p_gyroscopeSettings() {
static uint32_t tmr;
static byte dashFlag;//прапорець м'ягання
if (tmr < millis()) {
tmr = millis() + 500;
dashFlag = ! dashFlag;
}
byte Lines[] = {5, 15, 34, 44, 55};
Md_cursor(Lines, sizeof(Lines));
display.setCursor(8, 5);
display.println("Dead zone ");
display.setCursor(8, 15);
display.println("Sensitivity");
display.setCursor(8, 34);
display.println("Dead zone ");
display.setCursor(8, 44);
display.println("Sensitivity");
display.setCursor(8, 55);
display.println("Back");
display.setCursor(84, 10);
display.println("H");
display.setCursor(84, 39);
display.println("V");
display.setCursor(102, 4);
display.println(prof(act_dir)->getDeZoHor());
display.setCursor(104, 17);
display.println(prof(act_dir)->getSenHor());
display.setCursor(102, 33);
display.println(prof(act_dir)->getDeZoVer());
display.setCursor(104, 46);
display.println(prof(act_dir)->getSenVer());
display.drawRoundRect(6, 2, 69, 23, 3, WHITE); //РАМКА НАВКОЛО Dead zone Sensitivity H
display.drawRoundRect(6, 31, 69, 23, 0, WHITE);//РАМКА НАВКОЛО Dead zone Sensitivity V
//H
if((Md_cursor(noData, get_pos) == 1 || Md_cursor(noData, get_pos) == 2) && !Md_addres(4, get_add)){// РАМКА НВКОЛО H
if(dashFlag){display.drawRoundRect(79, 6, 15, 15, 0, WHITE);}
}
else{display.drawRoundRect(79, 6, 15, 15, 0, WHITE);}
//V
if((Md_cursor(noData, get_pos) == 3 || Md_cursor(noData, get_pos) == 4) && !Md_addres(4, get_add)){// РАМКА НВКОЛО V
if(dashFlag){display.drawCircle(86, 42, 7, WHITE);}
}
else{display.drawCircle(86, 42, 7, WHITE);}
if(Md_addres(4, get_add) == 1){ // число рамка DZ H
if(dashFlag){display.drawRoundRect(99, 2, 29, 11, 4, WHITE);}
}
else{display.drawRoundRect(99, 2, 29, 11, 4, WHITE);}
if(Md_addres(4, get_add) == 2){ // число рамка S H
if(dashFlag){display.drawRect(101, 15, 23, 11, WHITE);}
}
else{display.drawRect(101, 15, 23, 11, WHITE);}
if(Md_addres(4, get_add) == 3){ // число рамка DZ V
if(dashFlag){display.drawRect(99, 31, 29, 11, WHITE);}
}
else{display.drawRect(99, 31, 29, 11, WHITE);}
if(Md_addres(4, get_add) == 4){ // число рамка S V
if(dashFlag){display.drawRoundRect(101, 44, 23, 11, 4, WHITE);}
}
else{display.drawRoundRect(101, 44, 23, 11, 4, WHITE);}
}
void Md_Buttons() {
static unsigned long tmr;
static byte currenState;
static byte saveButton;
static byte butFlag;
Md_p_Buttons();
switch (Md_addres(4, int_add_last, 3)) {
case no_action:
break;
case 1:
if(!butFlag){
for (int i = 0; i <= 1; i++) {
if(!digitalRead(buttonArray[i])){
butFlag = 1;
if(!saveButton){
Md_p_Buttons(animation_two, i);
butFlag = 1;
saveButton = buttonArray[i];
break;
}
else {
Md_p_Buttons(animation_stope_one, i);
buttonArray[i] = saveButton;
saveButton = 0;
Md_cursor(posOne, return_pos);
Md_addres(4, back);
break;
}
break;
}
}
}
else if(butFlag){
for (int i = 0; i <= 1; i++) {
if(digitalRead(buttonArray[i])){
break;
}
butFlag = 0;
}
}
break;
case 3:
Md_cursor(posTwo, return_pos);
Md_addres(3, back);
break;
case address_entered:
if(Md_addres(4, get_add) == 1){
Md_p_Buttons(animation_one);
}
break;
case address_deleted:
Serial.println("111111111");
Md_p_Buttons(cancel_actions);
if(saveButton){
saveButton = 0;
}
break;
}
}
byte Md_p_Buttons(byte receivedData = 0, byte selectedButton = 0){
static byte runningArrow;
static byte questionMarkFlag;
static byte animation;
static byte buttonOne;
static byte buttonTwo;
static byte accumulationL;
static byte accumulationR;
static unsigned long tmr;
const char *buttonNames[] = {
"A",
"B",
"X",
"Y",
"LB",
"RB",
"LT",
"RT",
"LA",
"RA",
};
if (receivedData == animation_two) {
buttonOne = selectedButton;
}
else if (receivedData == animation_stope_one){
buttonTwo = selectedButton;
}
if (receivedData) {
if (cancel_actions == receivedData) {
accumulationL = accumulationR = questionMarkFlag = runningArrow = buttonOne = buttonTwo = animation = 0;
}
else {
animation = receivedData;
}
}
if (animation && tmr < millis()) {
if (animation == animation_stope_two) {
accumulationL = accumulationR = questionMarkFlag = runningArrow = buttonOne = buttonTwo = animation = 0;
}
else{
tmr = millis()+400;
}
if (runningArrow < 7) {
runningArrow++;
}
else{
runningArrow = !runningArrow;
}
if ( questionMarkFlag < 2) {
questionMarkFlag++;
}
else{
questionMarkFlag = !questionMarkFlag;
}
if (animation == animation_one && accumulationL < 3) {
accumulationL++;
}
else if (accumulationL) {
accumulationL = 0;
}
if (animation == animation_two && accumulationR < 3) {
accumulationR++;
}
else if (accumulationR) {
accumulationR = 0;
}
}
//display.drawRect(0, 0, 127, 63, WHITE);// test ramka
display.drawRect(6, 5, 31, 31, WHITE); // квадрат L
display.drawRect(90, 5, 31, 31, WHITE);// квадрат R
if (accumulationL) {
display.setCursor(19, 13);
}
else if (accumulationR) {
display.setCursor(103, 13);
}
if (questionMarkFlag) {
display.println('?');
}
if (animation == animation_two) {
display.setCursor(22-strlen(buttonNames[buttonOne])*3, 13);
display.println(buttonNames[buttonOne]);
for (int i = 0; i < 8; ++i) {
display.setCursor(40+i*6, 13);
display.write(62);
}
display.setCursor(40+runningArrow*6, 13);
display.write(16);
}
else if (animation == animation_stope_one || animation == animation_stope_two) {
if (animation == animation_stope_one) {
accumulationL = accumulationR = questionMarkFlag = runningArrow = 0;
animation = animation_stope_two;
tmr = millis()+1000;
}
display.setCursor(22-strlen(buttonNames[buttonOne])*3, 13);
display.println(buttonNames[buttonOne]);
display.setCursor(106-strlen(buttonNames[buttonTwo])*3, 13);
display.println(buttonNames[buttonTwo]);
}
display.drawCircle(21, 16, 8, WHITE);//кружки над кнопками
display.drawCircle(105, 16, 8, WHITE);
display.drawRect(12, 26+accumulationL, 19, 5, WHITE);//ліва кнопка
display.fillRect(9, 30, 25, 4, WHITE);
display.drawRect(96, 26+accumulationR, 19, 5, WHITE);//права кнопка
display.fillRect(93, 30, 25, 4, WHITE);
byte Lines[] = {40, 48, 56};
Md_cursor(Lines, sizeof(Lines));
display.setCursor(0, 40);
display.println(" Move buttons");
display.println(" Reset");
display.println(" Back");
return 0;
}
void Md_changeNameProfile(){
static int8_t AxisX, AxisY, storedAction, inputIndicator, axisChange;
static uint32_t tmr;
char letterBig[5][10] = {
{'0', '1', '2', '3', '4', '5', '6', '7', '8', '9'},
{'Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I', 'O', 'P'},
{'A', 'S', 'D', 'F', 'G', 'H', 'J', 'K', 'L', '-'},
{'!', 'Z', 'X', 'C', 'V', 'B', 'N', 'M', '.', '<'},
{' ', ' ', ' ', ' ', ' ', ' ', ' ', '>', '>', '>'}
};
char letterSmall[5][10] = {
{'0', '1', '2', '3', '4', '5', '6', '7', '8', '9'},
{'q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p'},
{'a', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l', '-'},
{'!', 'z', 'x', 'c', 'v', 'b', 'n', 'm', '.', '<'},
{' ', ' ', ' ', ' ', ' ', ' ', ' ', '>', '>', '>'}
};
static char (*ptrLetter)[10] = letterSmall;//вказівник вказує в залежності від настройки на великі або малі букви
if (!inputIndicator && ptrLetter == letterSmall && !storedAction) {//якщо видаляється остання буква одноразово всі букви робляться великими
storedAction = 1;
for (int i = 19; i >= 0; i--) {
if (prof(act_dir)->nameProfiles(get_name)[i] != ' '){
inputIndicator = i+1;
break;
}
else if (!i){
ptrLetter = letterBig;
inputIndicator = 0;
break;
}
}
}
else if (inputIndicator && storedAction) {
storedAction = 0;
}
switch (Mf_EncoderButton(200)) {
case click:
switch (ptrLetter[AxisY][AxisX]) {
case '!': //міняємо величину букв
if (ptrLetter == letterBig) {
ptrLetter = letterSmall;
}
else {
ptrLetter = letterBig;
}
break;
case '>'://вихыд
AxisX = AxisY = inputIndicator = 0;
Md_cursor(posThree, return_pos);
Md_addres(3, back);
break;
case '<': //видаляємо букви
if (inputIndicator ) {
inputIndicator--;
prof(act_dir)->nameProfiles(change_letter, inputIndicator, ' ');
}
break;
default://введення вибраної букви
if (inputIndicator <= 19) {
prof(act_dir)->nameProfiles(change_letter, inputIndicator, ptrLetter [AxisY][AxisX]);
if (inputIndicator == 0) {
ptrLetter = letterSmall;
}
inputIndicator++;
}
}
break;
case hol_const://якщо кнопка зажата курсор переміщається по вертикалі
if (!axisChange) {
axisChange = !axisChange;
}
break;
case hol_released://повертаємо звичайний режим роботи
if (axisChange) {
axisChange = !axisChange;
}
if (AxisY == 4 ){//переміщаємо курсор для коректної роботи якщо останній масив
if (AxisX <= 7){
AxisX = 0;
}
else{AxisX = 9;}
}
break;
}
switch (Mf_encoderActionStorage(get_status)) {
case 0:
break;
case rotated_rights:
if (!axisChange) {AxisX--;}//\переміщення в залежності від режиму
else {AxisY--;}
if (AxisY == 4 && AxisX == 8) {//корекція курсора якщо попали на останній масив костильі)
AxisX = 0;
}
if (AxisX < 0) {
AxisX = 9;
AxisY--;
}
if (AxisY < 0) {AxisY = 4;}
break;
case rotated_left:
if (!axisChange) {AxisX++;}
else {AxisY++;}
if (AxisY == 4 && AxisX == 1) {
AxisX = 9;
}
if (AxisX > 9) {
AxisX = 0;
AxisY++;
}
if (AxisY > 4 ) {AxisY = 0;}
break;
}
Md_p_changeNameProfile(ptrLetter, inputIndicator, AxisX, AxisY);
}
byte Md_p_changeNameProfile(char letter[][10], byte inputIndicator, byte AxisX, byte AxisY){
static char tracking;//використовується для відслідковування позиції рамки
char str[] = {'!', '<', ' ', '>'};//маси використовується для мигання необхідної рамки
static byte flagBlink[5];
static uint32_t tmr, tmrInd;
display.setCursor(6, 44);///набір різних стрілок
if(letter[1][1] == 'W'){//якщо в масиві є великі букви значить стрілочка вниз
display.write(25);//стрілочка вниз малі букви
}
else{display.write(24);}//стрілочка вверх великі букви
display.setCursor(114, 54);//back
display.print('s');
display.drawPixel(120, 60, WHITE); //крапка
if(!flagBlink[0]){//кружок стрілка вниз вверх
display.drawCircle(8, 47, 5, WHITE);
}
if(!flagBlink[1]){// видалення
display.setCursor(114, 43);
display.print('x');
display.drawCircle(116, 47, 4, WHITE);
}
display.fillRect(36, 54, 54, 6, WHITE);//пробіл
if(letter[AxisY][AxisX] == ' '){//додаткова рамка якщо навели на пробіл
display.drawRect(34, 52, 58, 10, WHITE);
}
if(!flagBlink[3]){//рамка s.
display.drawRoundRect(112, 54, 9, 9, 0, WHITE);
}
for (int i = 0; i < 4; i++) {
if(tracking != letter[AxisY][AxisX]){//можливі розрив захист від зникнення рамки
flagBlink[0] = flagBlink[1] = flagBlink[2] = flagBlink[3] = tmr = 0;//якщо було переміщення обнуляємо всі переміни
tracking = letter[AxisY][AxisX];//перезаписуємо перемінно новими даними
}
if(letter[AxisY][AxisX] == str[i]){
if(tmr < millis()){
tmr = millis()+400;
flagBlink[i] = !flagBlink[i];
}
break;
}
else if(i == 3 ){//
display.drawRect(4+AxisX*12, 12+AxisY*10, 9, 11, WHITE);//рамка курса 10 вверх вниз, вліво вправо 12
break;
}
}
if(inputIndicator != 20){//вертикальна риска біля букви мигання
if(tmrInd < millis()){
tmrInd = millis()+400;
flagBlink[4] = !flagBlink[4];
}
}
if(flagBlink[4] || inputIndicator == 20){//перестає мигати якщо 20 символів
display.drawRect(2+6*inputIndicator, 0, 1, 9, WHITE);
}
display.setCursor(2, 1);//виводив ім'я профіля
display.print(prof(act_dir)->getName());
for (int i = 0; i < 4; i++) {//виводим масив букв на дисплей
for (int j = 0; j < 10; j++) {
display.setCursor(6+j*12, 14+i*10);
if(letter[i][j] != '!' && letter[i][j] != '<'){//ці знаки не можна виводити використовується для виконання дій
display.print(letter[i][j]);
}
}
}
return 0;
}
//
// Additional functions-------------------------------------------------------------------------------------------
byte MdAf_consenDisplay(){ //викликається для підтвердження вибору
static int8_t flagChoice;
switch (Mf_encoderActionStorage(get_status)) {//керування рамкою вліво вправо
case no_action:
break;
case rotated_rights:
if (flagChoice > -2) {
flagChoice--;
}
break;
case rotated_left:
if (flagChoice < 2) {
flagChoice++;
}
break;
}
if ((flagChoice == -2 || flagChoice == 2) && Mf_EncoderButton(500) == click) {// V1 якщо відбувся Клік виконується дії в залежності від вибору
if (flagChoice == -2) {//якщо вибрали ні виконуються дії//вихід виконується в любому випадку з збереженими настройками або ні
flagChoice = 0;
return choice_no;
}
else if (flagChoice == 2) {
flagChoice = 0;
return choice_yes;
}
}
MdAf_consenDisplayPrint(flagChoice);//візуальна частина коду
return 0;
}
int8_t MdAf_consenDisplayPrint(int8_t acceptedFlag){
static uint32_t tmr;
static int8_t FlagFrame;
if (tmr < millis()) {
tmr = millis() + 400;
FlagFrame = !FlagFrame;
}
display.drawRoundRect(20, 8, 87, 22, 0, WHITE); //рамка навколо слова зверху
display.setCursor(28, 15);
display.println("Confirm save");
if (FlagFrame) {
display.drawRect(52+acceptedFlag*18, 39, 21, 13, WHITE);
}
for (int i=39; i <= 75; i+=18){
display.setCursor(i,42);
display.write(27);display.write(26);
}
display.setCursor(21, 42);
display.println("NO");
display.setCursor(18, 42);
display.println(" YES");
return 0;
}
byte MdAf_profileStorage(byte acceptedCommand) {//функція викликається якщо Md_addres(3, get_add) == 1
switch (acceptedCommand) {//false якщо повертаємо збережені настройки
case return_save:
prof(act_dir)->copyFrom(profilSeve);//це означає що ми вибрали ні і повертаємо настройки
break;
case copy_profile:
profilSeve.copyFrom(*prof(act_dir));//копіювання діючий профіль перед доходом в настройки
break;
case check_changes:
if (profilSeve != *prof(act_dir)) {return recorded_changes;}
break;
}
return 0;
}
byte MdAf_reminderDisplay(byte acceptedCommand) {
static uint32_t tmr;
display.clearDisplay();
display.drawRect(0, 14, 127, 30, WHITE);// РАМКА НАВКОЛО НАЗВИ
if (acceptedCommand == reset) {
tmr = 0;
}
else if (!tmr) {
tmr = millis() + 2000;
}
else if (tmr < millis()) {
tmr = 0;
Md_Display(info_display);
}
display.setCursor(0, 16);
display.println(" Read instruction");// НАГАДУВАННЯ
display.println(" " );//27
display.println(" Make game settings " );//27
display.setCursor(60, 50);
display.print("b");
display.drawCircle(62, 53, 6, WHITE);//кружок
display.display();
}
void MdAf_infoDisplay() {
display.clearDisplay();//не забути доробити періодичне виведення
MdAf_BluetoothPrint(); MdAf_typeNumberPrint(); MdAf_batteryPrint();
display.drawRect(0, 14, 127, 19, WHITE);// РАМКА НАВКОЛО НАЗВИ
display.setCursor(prof(act_dir)->centroName(), 20);// функція centroName() в залежності від кількості ім'я вранці
display.print(prof(act_dir)->nameProfiles(get_name));
display.setCursor(44,44);
display.write(26);
display.drawRect(50, 42, 27, 11, WHITE);
display.setCursor(52,44);
display.print("Menu");
display.display();
}
void MdAf_BluetoothPrint() {
static uint32_t tmr;
static byte FlagPriS;
static byte BluTest;
display.setCursor(4, 3);
//display.write(127 + 47);
display.print("b");
if (!BluTest) {
display.drawCircle(6, 6, 6, WHITE);//кружок
}
if (BluTest) {
display.drawCircle(6, 6, 6, WHITE);//кружок
}
if (FlagPriS != 3 && tmr < millis()) {
FlagPriS++;
tmr = millis() + 1000;
}
}
void MdAf_batteryPrint() {
display.setCursor(17 * 6, 0);
display.print("123");
}
void MdAf_typeNumberPrint() {
display.setCursor(49, 0);
if (prof(act_dir)->getTape() == t_sp) {
display.print("(Sp");
display.print(prof(act_dir)->getNamber());
}
else {
display.print("(Mp");
display.print(prof(act_dir)->getNamber());
}
display.print(")");
}
//Af
//Md
//Display 4
byte Md_Display(byte Receiving) {
//static byte Regime = info_display;
static byte Regime = menu;
switch (Receiving) {
case get_status:
return Regime;
break;
case menu:
Regime = menu;
break;
case info_display:
Regime = info_display;
break;
}
return Regime;
}
//D
//Menu_functions 5
byte Md_cursor(byte* arr, byte acceptedCommand) {
static int8_t Arrow, Point = 1;
switch (acceptedCommand) {
case return_pos:
Point = arr[0];
Arrow = 0;
break;
case reset:
Arrow = 0;
Point = 1;
break;
case selection_inversion:
Arrow = !Arrow;
break;
case get_pos:
return Point;
break;
default:
switch (Mf_encoderActionStorage(get_status)) {
case no_action:
break;
case rotated_left:
if (!Arrow) {Point--;}
if (Point == 0) {Point = acceptedCommand;}
break;
case rotated_rights:
if (!Arrow) {Point++;}
if (acceptedCommand < Point) {Point = 1;}
break;
}
if (!Arrow) {
display.setCursor(0, arr[Point-1]); //21,8 максимум символів
display.write(26);
}
else if (Arrow) {
display.setCursor(0, arr[Point-1]); //21,8 максимум символів
display.write(16);
}
}
return 0;
}
int8_t Md_addres(int8_t AddNumb, int8_t acceptedCommand, int8_t acceptedData = 0) {
static byte Adr[19], modeSwitch, namb = 1;
switch (acceptedCommand) {
case back:
modeSwitch = 0;
for (int i=18; i >= 1; i--){
Adr[i] = 0;
if (i == AddNumb) {
namb = AddNumb;
break;
}
}
break;
case get_add:
return Adr[AddNumb];
break;
default://int_add
if (!modeSwitch && !Adr[AddNumb] && Mf_EncoderButton(500) == click){
Adr[namb] = Md_cursor(noData, get_pos);
if (acceptedCommand == int_add_last && acceptedData != Md_cursor(noData, get_pos)){
Md_cursor(noData, selection_inversion);
modeSwitch = !modeSwitch;
}
else {
namb++;
}
return address_entered;
}
else if (modeSwitch && Mf_EncoderButton(500) == click){
Adr[namb] = modeSwitch = 0;
Md_cursor(noData, selection_inversion);
return address_deleted;
}
}
return Adr[AddNumb];
}
int8_t Mf_encoderActionStorage(int8_t acceptedCommand) {
static int8_t operationRetention;//збереження спрацювання
if (acceptedCommand == rotated_left || acceptedCommand == rotated_rights) {
operationRetention = acceptedCommand;
}
else if (acceptedCommand == get_status ) {
acceptedCommand = operationRetention;
operationRetention = 0;
return acceptedCommand;
}
return 0;
}
int Mf_EncoderButton(int retentionAfter) {
static byte buttonState = released_const;
static uint32_t tmr;
if (Ae_BatR(b_sw)){
if (buttonState == released_const) {
buttonState = press_const;
tmr = millis() + retentionAfter;
return press;
}
else if (tmr && tmr < millis()) {
buttonState = hol_const;
tmr = 0;
return hol_but;
}
}
else if (!Ae_BatR(b_sw)){
if (buttonState == hol_const) {buttonState = released_const; return hol_released;}
else if (buttonState == press_const) {buttonState = released_const; return click;}
}
return buttonState;
}
int Mf_Magnifier(int Numeric, int Min, int Max, int Speed) {
static uint32_t tmr;
static int counter = 1;
switch (Mf_encoderActionStorage(get_status)) {
case rotated_rights:
tmr = millis()+500;
Numeric += counter;
if (Speed > counter) {
counter++;
}
break;
case rotated_left:
tmr = millis()+500;
Numeric += -counter;
if (Speed > counter) {
counter++;
}
break;
}
if (counter != 1 && tmr < millis()) {
tmr = millis()+counter/2;
counter--;
}
if (Numeric > Max) {
Numeric = Min;
} else if (Numeric < Min) {
Numeric = Max;
}
return Numeric;
}
//Mf
//Gamepad_function 6
//Gf
void setup() {
Serial.begin(9600);// В ФЫНАЛЫ НЕЗАБУТИ ЗАКОМЕНТУВАТИ!!!
Wire.begin();
//pin 34 35 обережно глюки здаєтся немож зроб INPUT_PULLUP, pin 2 дыод! esp 32
pinMode(13, OUTPUT);
digitalWrite(13, HIGH);
pinMode(b_sw, INPUT_PULLUP); //енкодер кнопка SW
pinMode(5, INPUT_PULLUP);
pinMode(6, INPUT_PULLUP);
//Ae_InterruptReadPinDtEncoder()
attachInterrupt(digitalPinToInterrupt(p_dt), Ae_InterruptReadPinDtEncoder, CHANGE);
//----------Display--------------
//display.cp437(true); //rus текст
display.begin(SSD1306_SWITCHCAPVCC, 0x3C);
display.setTextSize(1);
display.setTextColor(WHITE);
display.setTextWrap(false);
display.clearDisplay();
display.display();
}
void loop() {
switch (Md_Display(get_status)) {
case info_display:
if (Mf_EncoderButton(500) == click) {
Md_Display(menu);
}
MdAf_infoDisplay();
/*
if (bleGamepad.isConnected()) {
Gf_ModifiedButtonInput();
Gf_AnLeftAxisX();//H
Gf_AnLeftAxisY();//V
Gf_AnRightZ(get_status);//H G
Gf_AnRightRZ(get_status);//V G
bleGamepad.sendReport();
}
*/
break;
case menu:
Md_MainDisplay();
break;
}
} //void loop()