красота, можно сказать уже готовое утсройство

This commit is contained in:
Razvalyaev 2025-07-25 01:13:09 +03:00
parent 7075f11e2b
commit 8a91973100
3 changed files with 520 additions and 187 deletions

View File

@ -23,13 +23,24 @@
#define I2C_MIN_ADDR 0x50
#define I2C_MAX_ADDR 0x57
#define SDA_PIN 21
#define SCL_PIN 22
#define SDA_PIN 8
#define SCL_PIN 9
uint8_t eeprom_addr = 0;
uint16_t versionAddr = 0x54; // версия начинается с этого адреса
uint16_t startAddr = 0x04; // адрес записи строк по умолчанию
char moduleStr[32] = {0}; // буфер для модуля
char versionStr[32] = {0}; // буфер для версии
bool ensureEEPROM() {
if (eeprom_addr == 0) { // 0 - значит еще не найдена
return findEEPROM();
}
return true;
}
bool findEEPROM() {
Serial.println("Scanning for EEPROM...");
@ -49,6 +60,10 @@ bool findEEPROM() {
void eepromWriteByte(uint8_t addr, uint8_t data) {
if (!ensureEEPROM()) {
Serial.println("EEPROM not found! Write aborted.");
return;
}
Wire.beginTransmission(eeprom_addr);
Wire.write(addr);
Wire.write(data);
@ -57,6 +72,11 @@ void eepromWriteByte(uint8_t addr, uint8_t data) {
}
uint8_t eepromReadByte(uint8_t addr) {
if (!ensureEEPROM()) {
Serial.println("EEPROM not found! Write aborted.");
return 0xFF;
}
Wire.beginTransmission(eeprom_addr);
Wire.write(addr);
Wire.endTransmission();
@ -70,10 +90,27 @@ uint8_t eepromReadByte(uint8_t addr) {
}
void writeStringToEEPROM(const char* str, uint16_t addr) {
if (!ensureEEPROM()) {
Serial.println("EEPROM not found! Write aborted.");
return;
}
size_t len = strlen(str);
if (addr + len + 1 > EEPROM_SIZE)
len = EEPROM_SIZE - addr - 1;
if (addr < versionAddr) {
// Очистить всё пространство от addr до versionAddr (не включая versionAddr)
for (uint16_t i = addr; i < versionAddr; i++) {
eepromWriteByte(i, 0xFF);
}
} else {
// Очистить только область для новой строки (len + 1 — включая нулевой терминатор)
for (size_t i = 0; i < len + 1; i++) {
eepromWriteByte(addr + i, 0xFF);
}
}
Serial.print("Writing to EEPROM @ 0x");
Serial.print(addr, HEX);
Serial.print(": ");
@ -85,20 +122,54 @@ void writeStringToEEPROM(const char* str, uint16_t addr) {
eepromWriteByte(addr + len, 0); // null-терминатор
}
void readModuleFromEEPROM() {
if (!ensureEEPROM()) {
Serial.println("EEPROM not found! Write aborted.");
return;
}
memset(moduleStr, 0, sizeof(moduleStr));
for (size_t i = 0; i < sizeof(moduleStr) - 1; i++) {
uint8_t b = eepromReadByte(startAddr + i);
if (b == 0 || b == 0xFF) {
moduleStr[i] = 0;
break;
}
moduleStr[i] = (char)b;
}
moduleStr[sizeof(moduleStr)-1] = 0;
Serial.print("[EEPROM] Module read: ");
Serial.println(moduleStr);
}
void readVersionFromEEPROM() {
// Читаем строку версии из EEPROM начиная с 0
if (!ensureEEPROM()) {
Serial.println("EEPROM not found! Write aborted.");
return;
}
memset(versionStr, 0, sizeof(versionStr));
for (size_t i = 0; i < sizeof(versionStr) - 1; i++) {
uint8_t b = eepromReadByte(i);
uint8_t b = eepromReadByte(versionAddr + i);
if (b == 0 || b == 0xFF) {
versionStr[i] = 0;
break;
}
versionStr[i] = (char)b;
}
versionStr[sizeof(versionStr)-1] = 0;
versionStr[sizeof(versionStr) - 1] = 0;
Serial.print("[EEPROM] Version read: ");
Serial.println(versionStr);
}
void readAndDumpEEPROM() {
if (!ensureEEPROM()) {
Serial.println("EEPROM not found! Write aborted.");
return;
}
Serial.println("\nDumping full EEPROM contents:\n");
for (uint16_t base = 0; base < EEPROM_SIZE; base += 16) {
@ -134,8 +205,8 @@ void setup() {
bool eeprom_found = findEEPROM();
if (eeprom_found) {
readModuleFromEEPROM();
readVersionFromEEPROM();
readAndDumpEEPROM();
}
Serial.println("Ready.");
@ -171,7 +242,7 @@ void loop() {
String ver = inputBuffer.substring(4);
ver.trim();
ver.toCharArray(versionStr, sizeof(versionStr));
writeStringToEEPROM(versionStr, 0);
writeStringToEEPROM(versionStr, versionAddr);
Serial.print("Version written: ");
Serial.println(versionStr);
}

View File

@ -0,0 +1,442 @@
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#include <U8g2lib.h>
#include <Fonts/FreeSans9pt7b.h>
#define FONT u8g2_font_8x13_tr
#define LITTLE_FONT u8g2_font_5x8_tr
#define LINE_SPACING 16
// OLED дисплей 128x64, I2C адрес по умолчанию — 0x3C
#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
#define OLED_RESET -1
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
// Инициализация дисплея SSD1306 128x64 по I2C
// Выбери нужный конструктор в зависимости от контроллера
// Этот - для SSD1306, I2C, с аппаратным reset (если нет reset - поставить U8G2_R0 и -1)
U8G2_SSD1306_128X64_NONAME_F_HW_I2C u8g2(U8G2_R0, /* reset=*/ U8X8_PIN_NONE);
// Кнопки
#define BTN_UP_PIN 3
#define BTN_DOWN_PIN 2
#define BTN_OK_PIN 1 // #
#define BTN_BACK_PIN 0 // *
extern uint16_t startAddr;
extern uint16_t versionAddr;
extern void writeStringToEEPROM(const char* str, uint16_t addr);
extern void readModuleFromEEPROM();
extern void readVersionFromEEPROM();
extern char versionStr[32];
extern char moduleStr[32];
enum MenuState {
MENU_MAIN,
MENU_SELECT_MODEL,
MENU_SELECT_OPTION,
MENU_SELECT_VERSION,
MENU_SHOW_EEPROM
};
const char* modelList[] = { "MDO5", "MDO4", "MDO3", "MDO2", "MDO1", "DPO5", "DPO4", "DPO3", "DPO2", "DPO1" };
const uint8_t modelCount = sizeof(modelList) / sizeof(modelList[0]);
const char* optionList[] = {
"BND", // Bundle (all-in-one)
"AERO", // Aerospace serial buses
"AFG", // Arbitrary Function Generator
"AUDIO", // Audio serial buses
"AUTO", // Automotive serial buses
"AUTOMAX",// Automotive serial buses
"COMP", // Computer serial buses
"EMBD", // Embedded systems
"ENET", // Ethernet
"FLEX", // FlexRay
"LMT", // Limit testing and mask testing
"MSO", // Mixed Signal Option
"PWR", // Power analysis
"SA", // Spectrum Analyzer
"SA3", // Spectrum Analyzer
"SA6", // Spectrum Analyzer
"SEC", // Security extension
"TRIG", // RF Power Level Trigger
"USB", // USB analysis
"VID" // Video signal triggering
};
const char* optionDescriptions[] = {
"Include all available options in one",
"Aerospace buses: MIL-STD-1553, ARINC 429",
"Waveform generator for custom signals",
"Audio buses: I2S, TDM, LJ, RJ",
"Cars buses: CAN FD, CAN, LIN",
"Cars buses: CAN FD, CAN, LIN, FlexRay",
"Computer buses: SPI, I2C, RS-232, PS/2",
"Embedded protocols: I2C, SPI, UART, GPIO",
"Ethernet: 10/100/1000BASE-T",
"Cars bus FlexRay",
"Limit and mask testing: Go/No-Go",
"Mixed Signal Oscill: analog + digital",
"Power analysis: efficiency, ripple, Bode",
"Spectrum analysis: RF, high-frequency",
"Spectr analysis (3 MHz): RF, high-frequency",
"Spectr analysis (6 MHz): RF, high-frequency",
"Security extension: access control",
"RF power level triggering",
"USB decoding: USB 1.x/2.0/3.x",
"Video triggering: HDMI, VGA, analog"
};
const uint8_t optionCount = sizeof(optionList) / sizeof(optionList[0]);
uint8_t selectedModel = 0;
uint8_t selectedOption = 0;
MenuState currentMenu = MENU_MAIN;
uint8_t cursorPos = 0;
char editableVersion[16] = "v1.00";
uint8_t editIndex = 0;
bool editingVersion = false;
void setupUI() {
pinMode(BTN_UP_PIN, INPUT_PULLUP);
pinMode(BTN_DOWN_PIN, INPUT_PULLUP);
pinMode(BTN_OK_PIN, INPUT_PULLUP);
pinMode(BTN_BACK_PIN, INPUT_PULLUP);
if (!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) {
Serial.println(F("SSD1306 not found"));
while (true);
}
//display.clearDisplay();
//display.setFont(&FONT);
//display.setTextSize(1);
//display.setTextColor(SSD1306_WHITE);
//display.display();
u8g2.begin();
// Выбираем шрифт - очень маленький, около 6pt (пример: u8g2_font_6x10_tr)
u8g2.setFont(FONT);
showMainMenu();
}
void loopUI() {
static uint32_t lastPress = 0;
if (millis() - lastPress < 200) return;
if (currentMenu == MENU_SELECT_VERSION && editingVersion) {
if (!digitalRead(BTN_UP_PIN)) {
if (editableVersion[editIndex] >= '0' && editableVersion[editIndex] <= '9') {
if (editableVersion[editIndex] == '9') editableVersion[editIndex] = '0';
else editableVersion[editIndex]++;
}
updateMenuDisplay();
lastPress = millis();
return;
}
if (!digitalRead(BTN_DOWN_PIN)) {
if (editableVersion[editIndex] >= '0' && editableVersion[editIndex] <= '9') {
if (editableVersion[editIndex] == '0') editableVersion[editIndex] = '9';
else editableVersion[editIndex]--;
}
updateMenuDisplay();
lastPress = millis();
return;
}
if (!digitalRead(BTN_OK_PIN)) {
// Перейти к следующему редактируемому символу, пропуская точки и буквы
do {
editIndex++;
} while (editIndex < strlen(editableVersion) && (editableVersion[editIndex] < '0' || editableVersion[editIndex] > '9'));
if (editIndex >= strlen(editableVersion)) {
// Закончили редактировать
writeStringToEEPROM(editableVersion, versionAddr);
strncpy(versionStr, editableVersion, sizeof(versionStr));
editingVersion = false;
currentMenu = MENU_MAIN;
cursorPos = 0;
}
updateMenuDisplay();
lastPress = millis();
return;
}
if (!digitalRead(BTN_BACK_PIN)) {
// Назад по цифрам
do {
if (editIndex == 0) {
editingVersion = false;
currentMenu = MENU_MAIN;
cursorPos = 0;
break;
} else {
editIndex--;
}
} while (editableVersion[editIndex] < '0' || editableVersion[editIndex] > '9');
updateMenuDisplay();
lastPress = millis();
return;
}
return;
}
if (!digitalRead(BTN_UP_PIN)) {
if (cursorPos > 0) cursorPos--;
updateMenuDisplay();
lastPress = millis();
} else if (!digitalRead(BTN_DOWN_PIN)) {
cursorPos++;
updateMenuDisplay();
lastPress = millis();
} else if (!digitalRead(BTN_OK_PIN)) {
handleOk();
lastPress = millis();
} else if (!digitalRead(BTN_BACK_PIN)) {
handleBack();
lastPress = millis();
}
}
void showMainMenu() {
currentMenu = MENU_MAIN;
cursorPos = 0;
updateMenuDisplay();
}
void drawStringWrapped(int x, int y, int maxWidth, const char* text, int lineHeight) {
int lineStart = 0;
int textLen = strlen(text);
while (lineStart < textLen) {
int lineEnd = lineStart;
int lastSpace = -1;
int width = 0;
while (lineEnd < textLen) {
char c = text[lineEnd];
// Вычисляем ширину подстроки с lineStart до lineEnd + 1
char buffer[64]; // должен быть достаточного размера
int length = lineEnd - lineStart + 1;
if (length >= sizeof(buffer)) length = sizeof(buffer) - 1;
memcpy(buffer, text + lineStart, length);
buffer[length] = '\0';
int w = u8g2.getStrWidth(buffer);
if (w > maxWidth) {
break;
}
if (c == ' ' || c == '-' || c == '\t') {
lastSpace = lineEnd;
}
lineEnd++;
}
// Если мы вышли за предел maxWidth
if (lineEnd == lineStart) {
// Если один символ не помещается — выводим его все равно (чтобы не зацикливаться)
lineEnd = lineStart + 1;
} else if (lineEnd < textLen && lastSpace != -1) {
// Откатываемся до последнего пробела, чтобы не разрывать слово
lineEnd = lastSpace;
}
// Подстрока для вывода длиной (lineEnd - lineStart)
char buf[128];
int len = lineEnd - lineStart;
if (len >= sizeof(buf)) len = sizeof(buf) - 1;
strncpy(buf, text + lineStart, len);
buf[len] = 0;
u8g2.drawStr(x, y, buf);
y += lineHeight;
lineStart = (lineEnd == lastSpace) ? lineEnd + 1 : lineEnd;
}
}
void updateMenuDisplay() {
u8g2.clearBuffer();
//display.clearDisplay();
//display.setCursor(0, LINE_SPACING);
if (currentMenu == MENU_MAIN) {
// Выводим три строки меню с курсором >
if(cursorPos > 2)
{
cursorPos = 2;
}
u8g2.drawStr(0, LINE_SPACING * 1, cursorPos == 0 ? ">Set Options" : " Set Options");
u8g2.drawStr(0, LINE_SPACING * 2, cursorPos == 1 ? ">Set Version" : " Set Version");
u8g2.drawStr(0, LINE_SPACING * 3, cursorPos == 2 ? ">Read Module" : " Read Module");
/*display.print(cursorPos == 0 ? ">Set Options" : " Set Options");
display.setCursor(0, LINE_SPACING *2);
display.print(cursorPos == 1 ? ">Set Version" : " Set Version");
display.setCursor(0, LINE_SPACING *3);
display.print(cursorPos == 2 ? ">Read" : " Read");*/
} else if (currentMenu == MENU_SELECT_MODEL) {
u8g2.drawStr(0, LINE_SPACING * 1, "Model:");
// Формируем строку ">ModelName"
char line[20];
snprintf(line, sizeof(line), ">%s", modelList[cursorPos % modelCount]);
u8g2.drawStr(0, LINE_SPACING * 2, line);
/*display.print("Model:");
display.setCursor(0, LINE_SPACING *2);
display.print(">");
display.print(modelList[cursorPos % modelCount]);*/
} else if (currentMenu == MENU_SELECT_OPTION) {
u8g2.setFont(FONT); // основной шрифт
u8g2.drawStr(0, LINE_SPACING * 1, "Option:");
char line[20];
uint8_t optIndex = cursorPos % optionCount;
snprintf(line, sizeof(line), ">%s", optionList[optIndex]);
u8g2.drawStr(0, LINE_SPACING * 2, line);
// Мелкий шрифт — описание
u8g2.setFont(LITTLE_FONT);
drawStringWrapped(0, LINE_SPACING * 3 + 4, SCREEN_WIDTH, optionDescriptions[optIndex], 10);
u8g2.setFont(FONT);
/*display.print("Option:");
display.setCursor(0, LINE_SPACING *2);
display.print(">");
display.print(optionList[cursorPos % optionCount]);*/
} else if (currentMenu == MENU_SELECT_VERSION) {
u8g2.drawStr(0, LINE_SPACING * 1, "UART set ver:");
// Для версии выводим символы с квадратными скобками вокруг редактируемого
int x = 0;
for (uint8_t i = 0; i < strlen(editableVersion); i++) {
char buf[4];
if (i == editIndex && editingVersion) {
snprintf(buf, sizeof(buf), "[%c]", editableVersion[i]);
} else {
snprintf(buf, sizeof(buf), " %c ", editableVersion[i]);
}
u8g2.drawStr(x, LINE_SPACING * 2, buf);
x += u8g2.getStrWidth(buf); // смещение курсора вправо на ширину предыдущей части
}
/*display.print("UART set ver:");
display.setCursor(0, LINE_SPACING *2);
for (uint8_t i = 0; i < strlen(editableVersion); i++) {
if (i == editIndex && editingVersion) {
display.print("[");
display.print(editableVersion[i]);
display.print("]");
} else {
display.print(" ");
display.print(editableVersion[i]);
display.print(" ");
}
}*/
} else if (currentMenu == MENU_SHOW_EEPROM) {
char buf[40];
snprintf(buf, sizeof(buf), "Model Option:");
u8g2.drawStr(0, LINE_SPACING * 1, buf);
snprintf(buf, sizeof(buf), " %s", moduleStr);
u8g2.drawStr(0, LINE_SPACING * 2, buf);
snprintf(buf, sizeof(buf), "Version:");
u8g2.drawStr(0, LINE_SPACING * 3, buf);
snprintf(buf, sizeof(buf), " %s", versionStr);
u8g2.drawStr(0, LINE_SPACING * 4, buf);
/*display.print("Mod:");
display.println(moduleStr);
display.setCursor(0, LINE_SPACING *3);
display.print("Ver:");
display.println(versionStr);*/
}
//display.display();
u8g2.sendBuffer();
}
void handleOk() {
if (currentMenu == MENU_MAIN) {
if (cursorPos == 0) {
currentMenu = MENU_SELECT_MODEL;
cursorPos = 0;
} else if (cursorPos == 1) {
currentMenu = MENU_SELECT_VERSION;
} else if (cursorPos == 2) {
readVersionFromEEPROM();
readModuleFromEEPROM();
currentMenu = MENU_SHOW_EEPROM;
}
} else if (currentMenu == MENU_SELECT_MODEL) {
selectedModel = cursorPos % modelCount;
cursorPos = 0;
currentMenu = MENU_SELECT_OPTION;
} else if (currentMenu == MENU_SELECT_OPTION) {
selectedOption = cursorPos % optionCount;
char fullModule[32];
snprintf(fullModule, sizeof(fullModule), "%s%s", modelList[selectedModel], optionList[selectedOption]);
writeStringToEEPROM(fullModule, startAddr);
readAndDumpEEPROM();
strncpy(moduleStr, fullModule, sizeof(moduleStr) - 1);
moduleStr[sizeof(moduleStr) - 1] = 0;
Serial.print("[UI] Options written: ");
Serial.println(fullModule);
currentMenu = MENU_MAIN;
cursorPos = 0;
} else if (currentMenu == MENU_SELECT_VERSION) {
editingVersion = true;
editIndex = 1;
}
updateMenuDisplay();
}
void handleBack() {
if (currentMenu == MENU_SELECT_OPTION) {
currentMenu = MENU_SELECT_MODEL;
} else {
currentMenu = MENU_MAIN;
}
cursorPos = 0;
updateMenuDisplay();
}

View File

@ -1,180 +0,0 @@
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
// OLED дисплей 128x64, I2C адрес по умолчанию — 0x3C
#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
#define OLED_RESET -1
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
// Кнопки
#define BTN_UP_PIN 32
#define BTN_DOWN_PIN 33
#define BTN_OK_PIN 25 // #
#define BTN_BACK_PIN 26 // *
extern uint16_t startAddr;
extern void writeStringToEEPROM(const char* str, uint16_t addr);
extern void readVersionFromEEPROM();
extern char versionStr[32];
char moduleStr[32] = {0}; // буфер для считанного модуля
extern uint8_t eepromReadByte(uint8_t addr);
extern uint16_t startAddr;
enum MenuState {
MENU_MAIN,
MENU_SELECT_MODULE,
MENU_SELECT_VERSION,
MENU_SHOW_EEPROM
};
const char* moduleOptions[] = {
"DPO4COMP", "DPO2EMBD", "DPO4EMBD", "DPO4AUTO", "DPO4AUTOMAX", "DPO4PWR",
"DPO4USB", "DPO4ENET", "DPO4LMT", "DPO4AUDIO", "MSO5204B 5RL", "MDO4MSO", "MDO4EMBD",
"MDO4AERO", "MDO4AUTO", "MDO4COMP", "MDO4FLEX", "MDO4LMT", "MDO4SA", "MDO4SA3",
"MDO4SA6", "MDO4AFG", "MDO4PWR", "MDO4BND", "MDO4SEC", "MDO4AUDIO"
};
const uint8_t moduleCount = sizeof(moduleOptions) / sizeof(moduleOptions[0]);
MenuState currentMenu = MENU_MAIN;
uint8_t cursorPos = 0;
extern char versionStr[32]; // Используется из основного кода
void readModuleFromEEPROM() {
memset(moduleStr, 0, sizeof(moduleStr));
for (size_t i = 0; i < sizeof(moduleStr) - 1; i++) {
uint8_t b = eepromReadByte(startAddr + i);
if (b == 0 || b == 0xFF) {
moduleStr[i] = 0;
break;
}
moduleStr[i] = (char)b;
}
moduleStr[sizeof(moduleStr)-1] = 0;
}
void setupUI() {
pinMode(BTN_UP_PIN, INPUT_PULLUP);
pinMode(BTN_DOWN_PIN, INPUT_PULLUP);
pinMode(BTN_OK_PIN, INPUT_PULLUP);
pinMode(BTN_BACK_PIN, INPUT_PULLUP);
if (!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) {
Serial.println(F("SSD1306 not found"));
while (true);
}
display.clearDisplay();
display.setTextSize(1);
display.setTextColor(SSD1306_WHITE);
display.display();
showMainMenu();
}
void loopUI() {
static uint32_t lastPress = 0;
if (millis() - lastPress < 200) return;
if (!digitalRead(BTN_UP_PIN)) {
if (cursorPos > 0) cursorPos--;
updateMenuDisplay();
lastPress = millis();
} else if (!digitalRead(BTN_DOWN_PIN)) {
cursorPos++;
updateMenuDisplay();
lastPress = millis();
} else if (!digitalRead(BTN_OK_PIN)) {
handleOk();
lastPress = millis();
} else if (!digitalRead(BTN_BACK_PIN)) {
handleBack();
lastPress = millis();
}
}
void showMainMenu() {
currentMenu = MENU_MAIN;
cursorPos = 0;
updateMenuDisplay();
}
void updateMenuDisplay() {
display.clearDisplay();
display.setCursor(0, 0);
if (currentMenu == MENU_MAIN) {
display.setCursor(0, 0);
display.print(cursorPos == 0 ? "> Module" : " Module");
display.setCursor(0, 10);
display.print(cursorPos == 1 ? "> Version" : " Version");
display.setCursor(0, 20);
display.print(cursorPos == 2 ? "> Read" : " Read");
} else if (currentMenu == MENU_SELECT_MODULE) {
display.print("Module:");
display.setCursor(0, 10);
display.print(">");
display.print(moduleOptions[cursorPos % moduleCount]);
} else if (currentMenu == MENU_SELECT_VERSION) {
display.print("Set version via UART:");
display.setCursor(0, 10);
display.print("VER=1.23");
} else if (currentMenu == MENU_SHOW_EEPROM) {
display.setCursor(0, 0);
display.print("Module: ");
display.println(moduleStr);
display.setCursor(0, 20);
display.print("Version: ");
display.println(versionStr);
}
display.display();
}
void handleOk() {
if (currentMenu == MENU_MAIN) {
if (cursorPos == 0) {
currentMenu = MENU_SELECT_MODULE;
cursorPos = 0;
} else if (cursorPos == 1) {
currentMenu = MENU_SELECT_VERSION;
} else if (cursorPos == 2) {
// Считать из EEPROM
readVersionFromEEPROM(); // версия из 0x00
readModuleFromEEPROM(); // модуль из startAddr
currentMenu = MENU_SHOW_EEPROM;
}
}
else if (currentMenu == MENU_SELECT_MODULE) {
const char* sel = moduleOptions[cursorPos % moduleCount];
writeStringToEEPROM(sel, startAddr);
readAndDumpEEPROM();
strncpy(versionStr, sel, sizeof(versionStr) - 1);
versionStr[sizeof(versionStr) - 1] = 0;
Serial.print("[UI] Module written to EEPROM: ");
Serial.println(sel);
showMainMenu();
}
else if (currentMenu == MENU_SELECT_VERSION) {
writeStringToEEPROM("v1.23", 0);
readAndDumpEEPROM();
strncpy(versionStr, "v1.23", sizeof(versionStr) - 1);
versionStr[sizeof(versionStr) - 1] = 0;
Serial.print("[UI] Version written to EEPROM: ");
Serial.println(versionStr);
showMainMenu();
}
updateMenuDisplay();
}
void handleBack() {
showMainMenu();
}