Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #include <Wire.h>
- #include <Adafruit_GFX.h>
- #include <Adafruit_SSD1306.h>
- // === OLED ===
- #define SCREEN_WIDTH 128
- #define SCREEN_HEIGHT 64
- #define OLED_RESET -1
- #define OLED_ADDR 0x3C
- Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
- // === Input Pins ===
- const uint8_t INPUT_PINS[4] = {7, 6, 5, 4};
- const uint8_t ENCODER_PIN_A = 2;
- const uint8_t ENCODER_PIN_B = 3;
- const uint8_t ENCODER_BUTTON = 8;
- // === Analog Inputs ===
- const uint8_t SENSOR_PIN = A1;
- const uint8_t BATTERY_PIN = A0;
- // === Relay Outputs ===
- const uint8_t RELAY_PINS[4] = {10, 11, 12, 13};
- // === Rotary Encoder State ===
- volatile int encoderPos = 0;
- int lastReportedPos = 0;
- // === Menu Navigation State ===
- #define MAX_MENU_DEPTH 4
- struct MenuNode {
- const char* label;
- void (*action)();
- MenuNode* parent;
- MenuNode** children;
- uint8_t childCount;
- };
- MenuNode* currentMenu = nullptr;
- uint8_t currentIndex = 0;
- MenuNode* menuStack[MAX_MENU_DEPTH];
- uint8_t indexStack[MAX_MENU_DEPTH];
- uint8_t menuDepth = 0;
- MenuNode backNode = {"\u2190 Back", nullptr, nullptr, nullptr, 0};
- // === Encoder ISR ===
- void encoderISR() {
- static bool lastA = LOW;
- bool A = digitalRead(ENCODER_PIN_A);
- bool B = digitalRead(ENCODER_PIN_B);
- if (A != lastA && A == HIGH) {
- if (B == LOW) encoderPos++;
- else encoderPos--;
- }
- lastA = A;
- }
- void renderMenu() {
- display.clearDisplay();
- display.setTextSize(1);
- display.setTextColor(SSD1306_WHITE);
- for (uint8_t i = 0; i < currentMenu->childCount; i++) {
- int y = i * 8;
- display.setCursor(0, y);
- if (i == currentIndex) display.print("> ");
- else display.print(" ");
- char label[18];
- strncpy(label, currentMenu->children[i]->label, 16);
- label[16] = '\0';
- display.println(label);
- }
- display.display();
- }
- void enterMenu(MenuNode* menu) {
- if (menuDepth < MAX_MENU_DEPTH - 1) {
- menuStack[menuDepth] = currentMenu;
- indexStack[menuDepth] = currentIndex;
- menuDepth++;
- static MenuNode* augmentedChildren[8];
- for (uint8_t i = 0; i < menu->childCount; i++) {
- augmentedChildren[i] = menu->children[i];
- }
- backNode.parent = menu->parent;
- augmentedChildren[menu->childCount] = &backNode;
- currentMenu = menu;
- currentMenu->children = augmentedChildren;
- currentMenu->childCount += 1;
- currentIndex = 0;
- renderMenu();
- }
- }
- void handleEncoder() {
- static int lastPos = 0;
- if (encoderPos != lastPos) {
- int delta = encoderPos - lastPos;
- lastPos = encoderPos;
- currentIndex = (currentIndex + delta + currentMenu->childCount) % currentMenu->childCount;
- renderMenu();
- }
- static bool lastButtonState = HIGH;
- bool buttonState = digitalRead(ENCODER_BUTTON);
- if (buttonState == LOW && lastButtonState == HIGH) {
- delay(50); // Debounce
- MenuNode* selected = currentMenu->children[currentIndex];
- if (selected == &backNode) {
- if (menuDepth > 0) {
- menuDepth--;
- currentMenu = menuStack[menuDepth];
- currentIndex = indexStack[menuDepth];
- renderMenu();
- }
- } else if (selected->childCount > 0) {
- enterMenu(selected);
- } else if (selected->action) {
- selected->action();
- renderMenu();
- }
- }
- lastButtonState = buttonState;
- }
- void showStatus() {
- Serial.println("Status screen");
- }
- void saveSettings() {
- Serial.println("Settings saved (placeholder)");
- }
- // === Menu Structure ===
- MenuNode* inputItems[] = {
- new MenuNode{"Input 1 -> Relay Map", nullptr, nullptr, nullptr, 0},
- new MenuNode{"Input 2 -> Relay Map", nullptr, nullptr, nullptr, 0},
- new MenuNode{"Input 3 -> Relay Map", nullptr, nullptr, nullptr, 0},
- new MenuNode{"Input 4 -> Relay Map", nullptr, nullptr, nullptr, 0}
- };
- MenuNode inputConfig = {"Input Config", nullptr, nullptr, inputItems, 4};
- MenuNode* rootItems[] = {
- new MenuNode{"View Status", showStatus, nullptr, nullptr, 0},
- &inputConfig,
- new MenuNode{"Save Settings", saveSettings, nullptr, nullptr, 0}
- };
- MenuNode root = {"Main Menu", nullptr, nullptr, rootItems, 3};
- void setup() {
- Serial.begin(9600);
- for (uint8_t i = 0; i < 4; i++) {
- pinMode(INPUT_PINS[i], INPUT_PULLUP);
- pinMode(RELAY_PINS[i], OUTPUT);
- digitalWrite(RELAY_PINS[i], LOW);
- }
- pinMode(ENCODER_PIN_A, INPUT_PULLUP);
- pinMode(ENCODER_PIN_B, INPUT_PULLUP);
- pinMode(ENCODER_BUTTON, INPUT);
- if (!display.begin(SSD1306_SWITCHCAPVCC, OLED_ADDR)) {
- Serial.println(F("OLED init failed"));
- while (true);
- }
- display.clearDisplay();
- display.setTextSize(1);
- display.setTextColor(SSD1306_WHITE);
- display.setCursor(0, 0);
- display.println(F("System Booting..."));
- display.display();
- delay(1000);
- currentMenu = &root;
- renderMenu();
- attachInterrupt(digitalPinToInterrupt(ENCODER_PIN_A), encoderISR, CHANGE);
- }
- void loop() {
- handleEncoder();
- }
Advertisement
Add Comment
Please, Sign In to add comment