#include <Arduino.h>
#include <Wire.h>
#include <Adafruit_SSD1306.h>
#include <EEPROM.h>
#define OLED_SDA 5 // Change to your desired SDA pin
#define OLED_SCL 4 // Change to your desired SCL pin
// GPIO pins for buttons
#define OK_BUTTON_PIN 13 // DEFAULT IT'S HIGH SET to LOW
#define UP_BUTTON_PIN 14 // DEFAULT IT'S HIGH SET to LOW
#define DOWN_BUTTON_PIN 12 // DEFAULT IT'S HIGH SET to LOW
// SH110X OLED Display
#define OLED_RESET -1
#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
#define SSD1306_I2C_ADDRESS 0x3C
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
const int MAX_MENU_SETUP_ITEMS = 2;
int selectedDigit = 0;
bool shouldBlink = true;
int pinDigits[4] = {0, 0, 0, 0};
bool settingPIN = false;
bool changingPIN = false;
int enteredPIN[4] = {0, 0, 0, 0};
int savedPIN[4] = {1, 2, 3, 4}; // Default PIN
bool upButtonPressed = false;
bool okButtonPressed = false;
bool downButtonPressed = false;
int lastSetupMenuInteraction = 0;
// Define the possible menu states
enum MenuState {
MainMenu,
SetupMenu
};
MenuState currentMenuState = MainMenu;
int selectedMenuItem = 0;
enum SetupMenuState {
SystemMenu,
BackToMain
};
SetupMenuState currentSetupMenuState = SystemMenu;
int selectedSetupMenuItem = 0;
// Function prototypes
void splachScreen();
void displaySetupMenu();
void handleSetupMenu();
void handleMenuStats();
void handleOKButton();
void handleSetPIN();
void displaySetPIN();
void handleChangePIN();
void displayChangePIN();
void setup() {
Serial.begin(115200); // Initialize Serial
Wire.begin(OLED_SDA, OLED_SCL); // Initialize I2C with custom pins
EEPROM.begin(4096); // Specify the size of EEPROM (4096 bytes for 4kb AT24C328)
// Initialize SH1106G OLED Display
if (!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) {
Serial.println(F("Error: SSD1306 OLED Display allocation failed"));
} else {
Serial.println(F("OLED display initialized"));
}
splachScreen();
pinMode(UP_BUTTON_PIN, INPUT_PULLUP);
pinMode(DOWN_BUTTON_PIN, INPUT_PULLUP);
pinMode(OK_BUTTON_PIN, INPUT_PULLUP);
}
void splachScreen() {
display.clearDisplay();
display.setTextSize(2);
display.setTextColor(SSD1306_WHITE);
display.setCursor(17, 25);
display.print("PAKFONES");
display.display();
delay(1000);
display.clearDisplay();
display.setTextSize(1);
display.setTextColor(SSD1306_WHITE);
display.setCursor(40, 25);
display.print("LOADING");
display.setCursor(53, 35);
for (int i = 0; i < 3; i++) {
delay(600);
display.print(".");
display.display();
}
}
void displayMainMenu() {
display.clearDisplay();
display.setTextSize(1);
display.setTextColor(SSD1306_WHITE);
display.setCursor(40, 25);
display.print("MAIN MENU");
display.display();
}
// Function to handle the Setup Menu
void displaySetupMenu() {
display.clearDisplay(); // Clear the display
display.setTextSize(1);
display.setCursor(7, 3); // Adjust the vertical position
display.print("=== SETTING MENU ===");
// Increase the space between title and menu items
int verticalSpacing = 3; // Adjust to your preferred spacing
// Define the setup menu items
String setupMenuItems[] = {"SYSTEM SETTINGS", "EXIT"};
// Calculate the y-coordinate for the selected
int selectedY = 15 + selectedSetupMenuItem * 10;
// Number of items that can fit on the screen
int itemsPerPage = 2;
// Calculate the first visible item based on the selectedSetupMenuItem
int firstVisibleItem = selectedSetupMenuItem - itemsPerPage / 2;
// Ensure the firstVisibleItem is within bounds
if (firstVisibleItem + itemsPerPage > MAX_MENU_SETUP_ITEMS) {
firstVisibleItem = MAX_MENU_SETUP_ITEMS - itemsPerPage;
}
if (firstVisibleItem < 0) {
firstVisibleItem = 0;
}
// Calculate the last visible item
int lastVisibleItem = firstVisibleItem + itemsPerPage - 1;
// Draw the scrolling ">" shape before the selected item
for (int i = 0; i < itemsPerPage; i++) {
display.setCursor(0, 15 + i * 10 + verticalSpacing); // Add the verticalSpacing
if (i + firstVisibleItem == selectedSetupMenuItem) {
display.print(">");
} else {
display.print(" ");
}
}
// Draw the menu item names with extra space
for (int i = 0; i < itemsPerPage; i++) {
int itemIndex = i + firstVisibleItem;
display.setCursor(10, 15 + i * 10 + verticalSpacing); // Add the verticalSpacing
display.print(setupMenuItems[itemIndex]);
}
display.display(); // Update the display
//delay(50);
}
// Function to handle Setup menu menu
void handleSetupMenu() {
// Wait for ok button to be realesed
while (digitalRead(OK_BUTTON_PIN) == LOW) {delay(50);}
// Display the Control Center menu
displaySetupMenu();
// Serial.println("Entering handleSetupMenuMenu() loop");
// Determine the action based on the selected Control Center menu item
while (true) {
// Adjust menu selection using UP button
if (digitalRead(UP_BUTTON_PIN) == LOW) {
upButtonPressed = true;
////beep(); // Beep on button press
}
if (upButtonPressed) {
// Serial.println("Up button pressed");
selectedSetupMenuItem = (selectedSetupMenuItem - 1 + MAX_MENU_SETUP_ITEMS) % MAX_MENU_SETUP_ITEMS;
upButtonPressed = false;
displaySetupMenu();
delay(149); // Adjust the delay to slow down the scrolling
}
// Adjust menu selection using DOWN button
if (digitalRead(DOWN_BUTTON_PIN) == LOW) {
downButtonPressed = true;
//beep(); // Beep on button press
}
if (downButtonPressed) {
// Serial.println("Down button pressed");
selectedSetupMenuItem = (selectedSetupMenuItem + 1) % MAX_MENU_SETUP_ITEMS;
downButtonPressed = false;
displaySetupMenu();
delay(149); // Adjust the delay to slow down the scrolling
}
// Check if the OK button is pressed
bool okButtonPressed = (digitalRead(OK_BUTTON_PIN) == LOW);
if (okButtonPressed) {
//beep(); // Beep on button press
// Determine the action based on the selected Setup menu item
switch (selectedSetupMenuItem) {
case SystemMenu: // Implement actions for OK button in AutoFill state
currentSetupMenuState = SystemMenu;
Serial.println("System menu activated");
return; // Exit the loop after processing the OK button
case BackToMain:// Implement actions for OK button in BackToMain state
currentMenuState = MainMenu;
Serial.println("BackToMain clicked - Returning to Main Menu");
return; // Exit the loop after processing the OK button
}
delay(149); // Avoid continuous button presses
}
// delay(50); // Adjust the delay based on your button behavior
}
}
// Function to handle OK button
void handleOKButton() {
//// Serial.println("Handling OK Button");
int okButtonState = digitalRead(OK_BUTTON_PIN);
// // Serial.print("OK Button State: ");
// // Serial.println(okButtonState);
if (okButtonState == LOW && !okButtonPressed) {
// Serial.println("OK Button Pressed");
unsigned long buttonPressStartTime = millis();
bool setupMenuActivated = false;
bool beeped = false; // Flag to track whether the beep has been played
while (digitalRead(OK_BUTTON_PIN) == LOW && millis() - buttonPressStartTime < 1000) {
// Beep only once during the button press
if (!beeped) {
//beep(); // Beep on the initial button press
beeped = true; // Set the flag to true after beeping
}
// Continue holding the button
}
if (millis() - buttonPressStartTime >= 1000) {
// Serial.println("Setup Menu Activated");
setupMenuActivated = true;
}
if (setupMenuActivated) {
// Serial.println("Entering Setup Menu");
currentMenuState = SetupMenu;
selectedSetupMenuItem = 0;
lastSetupMenuInteraction = millis();
displaySetupMenu();
// Wait for the OK button to be released to avoid accidental clicks
while (digitalRead(OK_BUTTON_PIN) == LOW) {
delay(50);
}
// Reset the flag when the button is released
okButtonPressed = false;
// Add a delay to ensure the Setup Menu stays on the screen
//delay(50);
}
}
}
void handleMenuStats() {
switch (currentMenuState) {
case MainMenu:
displayMainMenu();
break;
case SetupMenu:
displaySetupMenu();
handleSetupMenu();
break;
default:
Serial.println("Unhandled menu state.");
break;
}
}
void handleSetPIN() {
}
void displaySetPIN() {
}
void handleChangePIN() {
}
void displayChangePIN() {
}
void loop() {
handleMenuStats(); // Handle Menu States
handleOKButton();
}
Loading
esp32-s3-devkitc-1
esp32-s3-devkitc-1