From 98200fcac946045b3a12a960febaff966d4c0752 Mon Sep 17 00:00:00 2001 From: Yukti Date: Fri, 27 Feb 2026 07:56:15 +0530 Subject: [PATCH 01/12] add global 'exit' command to abort any prompt or test --- Firmware/factoryTest/FactoryTest_wMenu/FactoryTest_wMenu.ino | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Firmware/factoryTest/FactoryTest_wMenu/FactoryTest_wMenu.ino b/Firmware/factoryTest/FactoryTest_wMenu/FactoryTest_wMenu.ino index 4075cb7..0b2770a 100644 --- a/Firmware/factoryTest/FactoryTest_wMenu/FactoryTest_wMenu.ino +++ b/Firmware/factoryTest/FactoryTest_wMenu/FactoryTest_wMenu.ino @@ -99,8 +99,7 @@ const int SPI_CS_PIN = 5; // ===== TEST PARAMETERS ===== static const uint32_t SPI_SPEED = 1000000; // 1 MHz (safe for factory) static const uint8_t TEST_PATTERN[] = { - 0x55, 0xAA, 0x00, 0xFF, 0x12, 0x34, 0xA5 -}; + 0x55, 0xAA, 0x00, 0xFF, 0x12, 0x34, 0xA5}; // RS-232 (UART1) – IMPORTANT: set these to YOUR PCB pins (via MAX3232) const int UART1_TXD1 = 2; // placeholder safe GPIO From 39329f1e0d9aae97495b409dc6905f087ffa2eb3 Mon Sep 17 00:00:00 2001 From: Yukti Date: Fri, 27 Feb 2026 07:57:13 +0530 Subject: [PATCH 02/12] Added global exit command to abort tests --- .../FactoryTest_wMenu/FactoryTest_wMenu.ino | 144 +++++++++++++----- 1 file changed, 105 insertions(+), 39 deletions(-) diff --git a/Firmware/factoryTest/FactoryTest_wMenu/FactoryTest_wMenu.ino b/Firmware/factoryTest/FactoryTest_wMenu/FactoryTest_wMenu.ino index 0b2770a..ab02e92 100644 --- a/Firmware/factoryTest/FactoryTest_wMenu/FactoryTest_wMenu.ino +++ b/Firmware/factoryTest/FactoryTest_wMenu/FactoryTest_wMenu.ino @@ -1,4 +1,4 @@ -#define FIRMWARE_VERSION "v0.4.2.7" +#define FIRMWARE_VERSION "v0.4.2.8" /* ------------------------------------------------------------------------------ File: FactoryTest_wMenu.ino @@ -140,18 +140,18 @@ enum TestIndex { }; const char* TEST_NAMES[T_COUNT] = { - "0 Power / ID", - "1 Inputs (Encoder / Button)", - "2 LCD (I2C)", - "3 LEDs / Lamps", - "4 DFPlayer ", - "5 SD (DFPlayer card)", - "6 Speaker", - "7 Wi-Fi AP", - "8 Wi-Fi STA (manual SSID/PASS)", - "A LittleFS R/W", - "B UART0 (USB Serial)", - "C SPI loopback", + "0 Power / ID", + "1 Inputs (Encoder / Button)", + "2 LCD (I2C)", + "3 LEDs / Lamps", + "4 DFPlayer ", + "5 SD (DFPlayer card)", + "6 Speaker", + "7 Wi-Fi AP", + "8 Wi-Fi STA (manual SSID/PASS)", + "A LittleFS R/W", + "B UART0 (USB Serial)", + "C SPI loopback", "D RS-232 loopback" }; @@ -163,7 +163,26 @@ bool testResults[T_COUNT] = { false }; static char g_pendingCmd = 0; -static char up(char c) { +// ----------------------------------------------------------------------------- +// GLOBAL EXIT SUPPORT +// If user types "exit" (any case), abort current operation and return to menu. +// ----------------------------------------------------------------------------- +static volatile bool g_globalExitRequested = false; + +// Case-insensitive check for exact string "exit" +static bool isExitCommand(const String &s) +{ + if (s.length() != 4) + return false; + + return (tolower(s[0]) == 'e' && + tolower(s[1]) == 'x' && + tolower(s[2]) == 'i' && + tolower(s[3]) == 't'); +} + +static char up(char c) +{ return (char)toupper((unsigned char)c); } @@ -187,6 +206,14 @@ static bool readLineOrMenuAbort(String& out, uint32_t timeoutMs = 15000) { if (c == '\n' || c == '\r') { out.trim(); + // --- GLOBAL EXIT CHECK --- + // If user typed "exit", trigger global abort + if (isExitCommand(out)) + { + g_globalExitRequested = true; + out = ""; + return false; // abort current prompt + } if (out.length() == 1 && isMenuKey(out[0])) { g_pendingCmd = up(out[0]); @@ -224,7 +251,16 @@ static bool promptYesNo(const __FlashStringHelper* question, if (c == '\n' || c == '\r') { buf.trim(); - if (buf.length() == 0) continue; + // --- GLOBAL EXIT CHECK --- + // If user typed "exit", abort test and return to menu + if (isExitCommand(buf)) + { + g_globalExitRequested = true; + Serial.println(F("\nGlobal EXIT requested.")); + return false; + } + if (buf.length() == 0) + continue; char k = up(buf[0]); if (k == 'Y') return true; @@ -292,16 +328,16 @@ static void printSummary() { // Left column Serial.printf( - "%-33s : %-4s", - TEST_NAMES[i], - testResults[i] ? "PASS" : "FAIL"); + "%-33s : %-4s", + TEST_NAMES[i], + testResults[i] ? "PASS" : "FAIL"); // Right column (if present) if (i + 1 < T_COUNT) { Serial.printf( - " %-33s : %-4s", - TEST_NAMES[i + 1], - testResults[i + 1] ? "PASS" : "FAIL"); + " %-33s : %-4s", + TEST_NAMES[i + 1], + testResults[i + 1] ? "PASS" : "FAIL"); } Serial.println(); @@ -503,9 +539,9 @@ static bool runTest_LCD() { // STEP 3: Deterministic pattern test const char* patterns[4] = { - "####################", - "ABCDEFGHIJKLMNOPQRST", - "abcdefghijklmnopqrst", + "####################", + "ABCDEFGHIJKLMNOPQRST", + "abcdefghijklmnopqrst", "12345678901234567890" }; @@ -516,8 +552,8 @@ static bool runTest_LCD() { // STEP 4: Operator optical confirmation bool visible = promptYesNo( - F("Do you see 4 FULL lines, aligned, no garbage characters?"), - PROMPT_TIMEOUT_MS, + F("Do you see 4 FULL lines, aligned, no garbage characters?"), + PROMPT_TIMEOUT_MS, false ); @@ -540,11 +576,11 @@ static bool runTest_LEDs() { const int pins[] = { LAMP1, LAMP2, LAMP3, LAMP4, LAMP5, LED_Status }; const char* names[] = { - "LAMP1", - "LAMP2 (LAMP2)", - "LAMP3 (LAMP3)", - "LAMP4 (LAMP4)", - "LAMP5 (LAMP5)", + "LAMP1", + "LAMP2 (LAMP2)", + "LAMP3 (LAMP3)", + "LAMP4 (LAMP4)", + "LAMP5 (LAMP5)", "LED_Status (LED_Status)" }; @@ -639,7 +675,7 @@ static bool initDFPlayer() { Serial.println(F("DFPlayer detected and responding.")); return true; } - + // Put this OUTSIDE of runTest_DFPlayer() (global scope). // Call it when dfPlayer.available() is true. void printDetail(uint8_t type, int value) { @@ -960,12 +996,12 @@ static bool runTest_RS232() { Serial.printf("Using UART1 TXD=%d, RXD=%d, BAUD=%ld\n", UART1_TXD1, UART1_RXD1, UART1_BAUD); //Set up UART1 - + pinMode(UART1_RTS1, OUTPUT); pinMode(UART1_CTS1, INPUT); // NO pull up required because MAX3232 drives. //digitalWrite(UART1_RTS1, HIGH); // will make CTS at DB9 negative voltage through loop back digitalWrite(UART1_RTS1, LOW); // will make CTS at DB9 positive voltage through loop back - + HardwareSerial rs232(1); rs232.begin(UART1_BAUD, SERIAL_8N1, UART1_RXD1, UART1_TXD1); delay(150); @@ -998,7 +1034,7 @@ static bool runTest_RS232() { // Validate if (HIGH == digitalRead(UART1_CTS1)){ - Serial.print("[rs232] FAIL: FLOW CONTROL. Expected DB9 pin 7 between 3-18V. "); + Serial.print("[rs232] FAIL: FLOW CONTROL. Expected DB9 pin 7 between 3-18V. "); Serial.println("Tip: ensure rs232 RTS<->CTS loopback plug is installed."); return false; } @@ -1125,6 +1161,19 @@ void setup() { } void loop() { + + // --------------------------------------------------------------------------- + // GLOBAL EXIT HANDLER + // If "exit" was detected inside any prompt/test, + // abort and return to main menu safely. + // --------------------------------------------------------------------------- + if (g_globalExitRequested) { + g_globalExitRequested = false; + Serial.println(F("\n[GLOBAL EXIT] Aborting current operation.")); + printMenu(); + return; + } + // If a menu key was pressed during a prompt, execute it now. if (g_pendingCmd) { char c = g_pendingCmd; @@ -1137,10 +1186,27 @@ void loop() { } if (Serial.available()) { + + static String lineBuf; char c = Serial.read(); - if (c == '\r' || c == '\n') return; - Serial.println(up(c)); // echo - handleCommand(c); + if (c == '\r' || c == '\n') { + lineBuf.trim(); + + // --- GLOBAL EXIT CHECK (main menu level) --- + if (isExitCommand(lineBuf)) { + Serial.println(F("\n[GLOBAL EXIT]")); + printMenu(); + } + else if (lineBuf.length() == 1) { + Serial.println(up(lineBuf[0])); + handleCommand(lineBuf[0]); + } + + lineBuf = ""; + return; + } + + lineBuf += c; } -} +} \ No newline at end of file From 0ef503e27ea82ba3ea114d2af68cefe0e0b9e1eb Mon Sep 17 00:00:00 2001 From: Yukti Date: Sat, 28 Feb 2026 12:20:43 +0530 Subject: [PATCH 03/12] Added global exit to runAllTests() based on codex review --- .../factoryTest/FactoryTest_wMenu/FactoryTest_wMenu.ino | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/Firmware/factoryTest/FactoryTest_wMenu/FactoryTest_wMenu.ino b/Firmware/factoryTest/FactoryTest_wMenu/FactoryTest_wMenu.ino index ab02e92..4044ec7 100644 --- a/Firmware/factoryTest/FactoryTest_wMenu/FactoryTest_wMenu.ino +++ b/Firmware/factoryTest/FactoryTest_wMenu/FactoryTest_wMenu.ino @@ -29,7 +29,8 @@ Revision History: |v0.4.2.5 | 2026-1-7 | L. Erickson | Use myDFPlayer.getVersion() | |v0.4.2.6 | 2026-1-8 | Yukti | Fix DFPlayer test to fail cleanly when hardware | | | | | is missing; improve error handling | -|v0.4.2.7 | 2026-2-7 | L. Erickson | bugfix/356-firmware-factory-test-bring-up-add-flow-control-test-for-com-port| | +|v0.4.2.7 | 2026-2-7 | L. Erickson | bugfix/356-firmware-factory-test-bring-up-add-flow-control-test-for-com-port| +|v0.4.2.8 | 2026-1-8 | Yukti | add global 'exit' command to abort any test | ----------------------------------------------------------------------------------------| Overview: - Repeatable factory test sequence for ESP32-WROOM-32D Krake/GPAD v2 boards. @@ -1095,6 +1096,12 @@ static void runAllTests() { Serial.println(F("\n[P] Running ALL tests (1 -> D) in order...")); for (int i = 0; i < T_COUNT; ++i) { + + if (g_globalExitRequested) { + Serial.println(F("[Run-All aborted by GLOBAL EXIT]")); + return; + } + if (g_pendingCmd) break; testResults[i] = runSingleTestFromIndex(static_cast(i)); From 6836156cae31c74dbcd8f8236f3c773bdb48a096 Mon Sep 17 00:00:00 2001 From: Yukti Date: Sat, 28 Feb 2026 12:24:06 +0530 Subject: [PATCH 04/12] Changed Exit command() based on Review --- .../factoryTest/FactoryTest_wMenu/FactoryTest_wMenu.ino | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/Firmware/factoryTest/FactoryTest_wMenu/FactoryTest_wMenu.ino b/Firmware/factoryTest/FactoryTest_wMenu/FactoryTest_wMenu.ino index 4044ec7..6600459 100644 --- a/Firmware/factoryTest/FactoryTest_wMenu/FactoryTest_wMenu.ino +++ b/Firmware/factoryTest/FactoryTest_wMenu/FactoryTest_wMenu.ino @@ -173,13 +173,7 @@ static volatile bool g_globalExitRequested = false; // Case-insensitive check for exact string "exit" static bool isExitCommand(const String &s) { - if (s.length() != 4) - return false; - - return (tolower(s[0]) == 'e' && - tolower(s[1]) == 'x' && - tolower(s[2]) == 'i' && - tolower(s[3]) == 't'); + return s.equalsIgnoreCase("exit"); } static char up(char c) From 045ae682c5e1396342afd7ccd927fd584b4f1d00 Mon Sep 17 00:00:00 2001 From: Yukti Date: Sat, 28 Feb 2026 12:40:43 +0530 Subject: [PATCH 05/12] updated firmware version --- Firmware/factoryTest/FactoryTest_wMenu/FactoryTest_wMenu.ino | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Firmware/factoryTest/FactoryTest_wMenu/FactoryTest_wMenu.ino b/Firmware/factoryTest/FactoryTest_wMenu/FactoryTest_wMenu.ino index 6600459..f3ecf93 100644 --- a/Firmware/factoryTest/FactoryTest_wMenu/FactoryTest_wMenu.ino +++ b/Firmware/factoryTest/FactoryTest_wMenu/FactoryTest_wMenu.ino @@ -1,4 +1,4 @@ -#define FIRMWARE_VERSION "v0.4.2.8" +#define FIRMWARE_VERSION "v0.4.2.9" /* ------------------------------------------------------------------------------ File: FactoryTest_wMenu.ino @@ -31,6 +31,8 @@ Revision History: | | | | is missing; improve error handling | |v0.4.2.7 | 2026-2-7 | L. Erickson | bugfix/356-firmware-factory-test-bring-up-add-flow-control-test-for-com-port| |v0.4.2.8 | 2026-1-8 | Yukti | add global 'exit' command to abort any test | +| | | | and return to menu. | +|v0.4.2.9 | 2026-1-9 | Yukti | updated code and firmware ver. based on review | ----------------------------------------------------------------------------------------| Overview: - Repeatable factory test sequence for ESP32-WROOM-32D Krake/GPAD v2 boards. From 957fab933f2541f294a7fdc7a6c46f3000a26237 Mon Sep 17 00:00:00 2001 From: Yukti Date: Sat, 28 Feb 2026 18:49:49 +0530 Subject: [PATCH 06/12] changed exit to break for consistency --- .../FactoryTest_wMenu/FactoryTest_wMenu.ino | 60 ++++++++++--------- 1 file changed, 31 insertions(+), 29 deletions(-) diff --git a/Firmware/factoryTest/FactoryTest_wMenu/FactoryTest_wMenu.ino b/Firmware/factoryTest/FactoryTest_wMenu/FactoryTest_wMenu.ino index f3ecf93..4b2a7fb 100644 --- a/Firmware/factoryTest/FactoryTest_wMenu/FactoryTest_wMenu.ino +++ b/Firmware/factoryTest/FactoryTest_wMenu/FactoryTest_wMenu.ino @@ -1,4 +1,4 @@ -#define FIRMWARE_VERSION "v0.4.2.9" +#define FIRMWARE_VERSION "v0.4.3.2" /* ------------------------------------------------------------------------------ File: FactoryTest_wMenu.ino @@ -29,10 +29,12 @@ Revision History: |v0.4.2.5 | 2026-1-7 | L. Erickson | Use myDFPlayer.getVersion() | |v0.4.2.6 | 2026-1-8 | Yukti | Fix DFPlayer test to fail cleanly when hardware | | | | | is missing; improve error handling | -|v0.4.2.7 | 2026-2-7 | L. Erickson | bugfix/356-firmware-factory-test-bring-up-add-flow-control-test-for-com-port| -|v0.4.2.8 | 2026-1-8 | Yukti | add global 'exit' command to abort any test | +|v0.4.2.7 | 2026-2-7 | L. Erickson | bugfix/356-firmware-factory-test-bring-up-add- | +| flow-control-test-for-com-port | +|v0.4.3.0 | 2026-2-27 | Yukti | add global 'exit' command to abort any test | | | | | and return to menu. | -|v0.4.2.9 | 2026-1-9 | Yukti | updated code and firmware ver. based on review | +|v0.4.3.1 | 2026-2-28 | Yukti | updated code and firmware ver. based on review | +|v0.4.3.2 | 2026-2-28 | Yukti | changed 'exit' to 'break' | ----------------------------------------------------------------------------------------| Overview: - Repeatable factory test sequence for ESP32-WROOM-32D Krake/GPAD v2 boards. @@ -167,15 +169,15 @@ bool testResults[T_COUNT] = { false }; static char g_pendingCmd = 0; // ----------------------------------------------------------------------------- -// GLOBAL EXIT SUPPORT -// If user types "exit" (any case), abort current operation and return to menu. +// GLOBAL BREAK SUPPORT +// If user types "break" (any case), abort current operation and return to menu. // ----------------------------------------------------------------------------- -static volatile bool g_globalExitRequested = false; +static volatile bool g_globalBreakRequested = false; -// Case-insensitive check for exact string "exit" -static bool isExitCommand(const String &s) +// Case-insensitive check for exact string "break" +static bool isBreakCommand(const String &s) { - return s.equalsIgnoreCase("exit"); + return s.equalsIgnoreCase("break"); } static char up(char c) @@ -203,11 +205,11 @@ static bool readLineOrMenuAbort(String& out, uint32_t timeoutMs = 15000) { if (c == '\n' || c == '\r') { out.trim(); - // --- GLOBAL EXIT CHECK --- - // If user typed "exit", trigger global abort - if (isExitCommand(out)) + // --- GLOBAL BREAK CHECK --- + // If user typed "break", trigger global abort + if (isBreakCommand(out)) { - g_globalExitRequested = true; + g_globalBreakRequested = true; out = ""; return false; // abort current prompt } @@ -248,12 +250,12 @@ static bool promptYesNo(const __FlashStringHelper* question, if (c == '\n' || c == '\r') { buf.trim(); - // --- GLOBAL EXIT CHECK --- - // If user typed "exit", abort test and return to menu - if (isExitCommand(buf)) + // --- GLOBAL BREAK CHECK --- + // If user typed "break", abort test and return to menu + if (isBreakCommand(buf)) { - g_globalExitRequested = true; - Serial.println(F("\nGlobal EXIT requested.")); + g_globalBreakRequested = true; + Serial.println(F("\nGlobal BREAK requested.")); return false; } if (buf.length() == 0) @@ -1093,8 +1095,8 @@ static void runAllTests() { for (int i = 0; i < T_COUNT; ++i) { - if (g_globalExitRequested) { - Serial.println(F("[Run-All aborted by GLOBAL EXIT]")); + if (g_globalBreakRequested) { + Serial.println(F("[Run-All aborted by GLOBAL BREAK]")); return; } @@ -1166,13 +1168,13 @@ void setup() { void loop() { // --------------------------------------------------------------------------- - // GLOBAL EXIT HANDLER - // If "exit" was detected inside any prompt/test, + // GLOBAL BREAK HANDLER + // If "break" was detected inside any prompt/test, // abort and return to main menu safely. // --------------------------------------------------------------------------- - if (g_globalExitRequested) { - g_globalExitRequested = false; - Serial.println(F("\n[GLOBAL EXIT] Aborting current operation.")); + if (g_globalBreakRequested) { + g_globalBreakRequested = false; + Serial.println(F("\n[GLOBAL BREAK] Aborting current operation.")); printMenu(); return; } @@ -1196,9 +1198,9 @@ void loop() { if (c == '\r' || c == '\n') { lineBuf.trim(); - // --- GLOBAL EXIT CHECK (main menu level) --- - if (isExitCommand(lineBuf)) { - Serial.println(F("\n[GLOBAL EXIT]")); + // --- GLOBAL BREAK CHECK (main menu level) --- + if (isBreakCommand(lineBuf)) { + Serial.println(F("\n[GLOBAL BREAK]")); printMenu(); } else if (lineBuf.length() == 1) { From 4b90e0fc58e505c226fd14d9d0636db2a047ee3c Mon Sep 17 00:00:00 2001 From: Yukti Date: Sat, 28 Feb 2026 19:10:36 +0530 Subject: [PATCH 07/12] Add cooperative GLOBAL BREAK checks in long loops --- .../FactoryTest_wMenu/FactoryTest_wMenu.ino | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/Firmware/factoryTest/FactoryTest_wMenu/FactoryTest_wMenu.ino b/Firmware/factoryTest/FactoryTest_wMenu/FactoryTest_wMenu.ino index 4b2a7fb..a4af8be 100644 --- a/Firmware/factoryTest/FactoryTest_wMenu/FactoryTest_wMenu.ino +++ b/Firmware/factoryTest/FactoryTest_wMenu/FactoryTest_wMenu.ino @@ -389,6 +389,7 @@ static bool runTest_Inputs() { unsigned long start = millis(); while (millis() - start < 10000UL) { + if (g_globalBreakRequested) return false; int clk = digitalRead(ENC_CLK); if (clk != lastCLK) { if (digitalRead(ENC_DT) != clk) { @@ -810,6 +811,10 @@ static bool runTest_Speaker() { uint32_t start = millis(); while (millis() - start < 3000) { + if (g_globalBreakRequested) { + dfPlayer.stop(); + return false; + } delay(10); } @@ -883,6 +888,10 @@ static bool runTest_WifiSTA() { uint32_t start = millis(); while (WiFi.status() != WL_CONNECTED && millis() - start < WIFI_CONNECT_MS) { + if (g_globalBreakRequested) { + WiFi.disconnect(true, true); + return false; + } delay(500); Serial.print('.'); } @@ -1023,6 +1032,10 @@ static bool runTest_RS232() { String rx; uint32_t t0 = millis(); while (millis() - t0 < TIMEOUT_MS && rx.length() < n) { + if (g_globalBreakRequested) { + rs232.end(); + return false; + } while (rs232.available()) { char c = (char)rs232.read(); rx += c; @@ -1061,10 +1074,7 @@ static bool runTest_RS232() { Serial.print(rx); Serial.println("[rs232] PASS: UART1 loopback OK"); return true; - - bool ok = (rx == payload); - Serial.printf("RS-232 loopback test: %s\n", ok ? "PASS" : "FAIL (wiring/MAX3232/pins)"); - return ok; +//removed dead code }//end runTest_RS232() // ============================================================================ @@ -1096,6 +1106,7 @@ static void runAllTests() { for (int i = 0; i < T_COUNT; ++i) { if (g_globalBreakRequested) { + g_pendingCmd = 0; Serial.println(F("[Run-All aborted by GLOBAL BREAK]")); return; } From fce74c599024908ee09f433a658af962d111df5b Mon Sep 17 00:00:00 2001 From: Yukti Date: Sat, 28 Feb 2026 19:13:33 +0530 Subject: [PATCH 08/12] updated firmware version for exit/break changes --- Firmware/factoryTest/FactoryTest_wMenu/FactoryTest_wMenu.ino | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Firmware/factoryTest/FactoryTest_wMenu/FactoryTest_wMenu.ino b/Firmware/factoryTest/FactoryTest_wMenu/FactoryTest_wMenu.ino index a4af8be..41823f7 100644 --- a/Firmware/factoryTest/FactoryTest_wMenu/FactoryTest_wMenu.ino +++ b/Firmware/factoryTest/FactoryTest_wMenu/FactoryTest_wMenu.ino @@ -1,4 +1,4 @@ -#define FIRMWARE_VERSION "v0.4.3.2" +#define FIRMWARE_VERSION "v0.4.3.3" /* ------------------------------------------------------------------------------ File: FactoryTest_wMenu.ino @@ -35,6 +35,7 @@ Revision History: | | | | and return to menu. | |v0.4.3.1 | 2026-2-28 | Yukti | updated code and firmware ver. based on review | |v0.4.3.2 | 2026-2-28 | Yukti | changed 'exit' to 'break' | +|v0.4.3.3 | 2026-2-29 | Yukti | added global break support to all tests | ----------------------------------------------------------------------------------------| Overview: - Repeatable factory test sequence for ESP32-WROOM-32D Krake/GPAD v2 boards. From b2dc36cba75dbeeb167d814d83ec16efd69efc4e Mon Sep 17 00:00:00 2001 From: Yukti Date: Mon, 2 Mar 2026 10:26:52 +0530 Subject: [PATCH 09/12] removed dynamic parsing in loop and tried fixing the 'break' causing reboot --- .../FactoryTest_wMenu/FactoryTest_wMenu.ino | 46 +++++++++++++------ 1 file changed, 33 insertions(+), 13 deletions(-) diff --git a/Firmware/factoryTest/FactoryTest_wMenu/FactoryTest_wMenu.ino b/Firmware/factoryTest/FactoryTest_wMenu/FactoryTest_wMenu.ino index 41823f7..43d0d39 100644 --- a/Firmware/factoryTest/FactoryTest_wMenu/FactoryTest_wMenu.ino +++ b/Firmware/factoryTest/FactoryTest_wMenu/FactoryTest_wMenu.ino @@ -176,9 +176,17 @@ static char g_pendingCmd = 0; static volatile bool g_globalBreakRequested = false; // Case-insensitive check for exact string "break" -static bool isBreakCommand(const String &s) +static bool isBreakCommand(const char* s) { - return s.equalsIgnoreCase("break"); + if (!s) return false; + + return + (tolower(s[0]) == 'b') && + (tolower(s[1]) == 'r') && + (tolower(s[2]) == 'e') && + (tolower(s[3]) == 'a') && + (tolower(s[4]) == 'k') && + (s[5] == '\0'); } static char up(char c) @@ -1181,8 +1189,6 @@ void loop() { // --------------------------------------------------------------------------- // GLOBAL BREAK HANDLER - // If "break" was detected inside any prompt/test, - // abort and return to main menu safely. // --------------------------------------------------------------------------- if (g_globalBreakRequested) { g_globalBreakRequested = false; @@ -1191,7 +1197,9 @@ void loop() { return; } - // If a menu key was pressed during a prompt, execute it now. + // --------------------------------------------------------------------------- + // Pending menu command from aborted prompt + // --------------------------------------------------------------------------- if (g_pendingCmd) { char c = g_pendingCmd; g_pendingCmd = 0; @@ -1202,28 +1210,40 @@ void loop() { return; } + // --------------------------------------------------------------------------- + // Main menu serial input (fixed buffer, no String) + // --------------------------------------------------------------------------- if (Serial.available()) { - static String lineBuf; + static char lineBuf[32]; // fixed-size buffer + static uint8_t idx = 0; // current write index + char c = Serial.read(); + // If newline -> process full line if (c == '\r' || c == '\n') { - lineBuf.trim(); - // --- GLOBAL BREAK CHECK (main menu level) --- + lineBuf[idx] = '\0'; // null-terminate + + // GLOBAL BREAK CHECK if (isBreakCommand(lineBuf)) { Serial.println(F("\n[GLOBAL BREAK]")); printMenu(); } - else if (lineBuf.length() == 1) { - Serial.println(up(lineBuf[0])); - handleCommand(lineBuf[0]); + // Single-character command + else if (idx == 1) { + char cmd = up(lineBuf[0]); + Serial.println(cmd); + handleCommand(cmd); } - lineBuf = ""; + idx = 0; // reset buffer return; } - lineBuf += c; + // Append character safely + if (idx < sizeof(lineBuf) - 1) { + lineBuf[idx++] = c; + } } } \ No newline at end of file From 8cb22bd67e3ad3ecec05ca223a18023bd7ec3fbe Mon Sep 17 00:00:00 2001 From: Yukti Date: Mon, 2 Mar 2026 10:29:44 +0530 Subject: [PATCH 10/12] Use strcasecmp() for safe case-insensitive GLOBAL BREAK detection --- .../FactoryTest_wMenu/FactoryTest_wMenu.ino | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/Firmware/factoryTest/FactoryTest_wMenu/FactoryTest_wMenu.ino b/Firmware/factoryTest/FactoryTest_wMenu/FactoryTest_wMenu.ino index 43d0d39..420406a 100644 --- a/Firmware/factoryTest/FactoryTest_wMenu/FactoryTest_wMenu.ino +++ b/Firmware/factoryTest/FactoryTest_wMenu/FactoryTest_wMenu.ino @@ -62,6 +62,7 @@ Build notes: #include #include #include +#include // ============================================================================ // Configuration @@ -178,15 +179,7 @@ static volatile bool g_globalBreakRequested = false; // Case-insensitive check for exact string "break" static bool isBreakCommand(const char* s) { - if (!s) return false; - - return - (tolower(s[0]) == 'b') && - (tolower(s[1]) == 'r') && - (tolower(s[2]) == 'e') && - (tolower(s[3]) == 'a') && - (tolower(s[4]) == 'k') && - (s[5] == '\0'); + return (s != nullptr) && (strcasecmp(s, "break") == 0); } static char up(char c) From 03684e50d92f60ce67e6db9748d290580741e741 Mon Sep 17 00:00:00 2001 From: Yukti Date: Mon, 2 Mar 2026 10:32:01 +0530 Subject: [PATCH 11/12] Remove String usage from promptYesNo() for deterministic GLOBAL BREAK handling --- .../FactoryTest_wMenu/FactoryTest_wMenu.ino | 42 +++++++++++++------ 1 file changed, 30 insertions(+), 12 deletions(-) diff --git a/Firmware/factoryTest/FactoryTest_wMenu/FactoryTest_wMenu.ino b/Firmware/factoryTest/FactoryTest_wMenu/FactoryTest_wMenu.ino index 420406a..ce1f19a 100644 --- a/Firmware/factoryTest/FactoryTest_wMenu/FactoryTest_wMenu.ino +++ b/Firmware/factoryTest/FactoryTest_wMenu/FactoryTest_wMenu.ino @@ -237,35 +237,45 @@ static bool readLineOrMenuAbort(String& out, uint32_t timeoutMs = 15000) { static bool promptYesNo(const __FlashStringHelper* question, uint32_t timeoutMs = PROMPT_TIMEOUT_MS, - bool defaultNo = true) { + bool defaultNo = true) +{ Serial.println(question); Serial.println(F("Press Y to PASS or N to FAIL (Enter optional).")); Serial.println(F("(Menu keys abort this step and run next.)")); Serial.print(F("> ")); uint32_t start = millis(); - String buf; + + char buf[16]; // fixed buffer + uint8_t idx = 0; while (millis() - start < timeoutMs) { + while (Serial.available()) { + char c = Serial.read(); + // --- ENTER pressed --- if (c == '\n' || c == '\r') { - buf.trim(); - // --- GLOBAL BREAK CHECK --- - // If user typed "break", abort test and return to menu - if (isBreakCommand(buf)) - { + + buf[idx] = '\0'; // null terminate + + // GLOBAL BREAK CHECK + if (isBreakCommand(buf)) { g_globalBreakRequested = true; Serial.println(F("\nGlobal BREAK requested.")); return false; } - if (buf.length() == 0) - continue; + + if (idx == 0) { + continue; // ignore empty line + } char k = up(buf[0]); + if (k == 'Y') return true; if (k == 'N') return false; + if (isMenuKey(k)) { g_pendingCmd = k; Serial.println(F("\nAborted -> FAIL.")); @@ -276,12 +286,14 @@ static bool promptYesNo(const __FlashStringHelper* question, return false; } - if (buf.length() == 0 && isMenuKey(c)) { + // Immediate single-key abort (first char only) + if (idx == 0 && isMenuKey(c)) { g_pendingCmd = up(c); Serial.println(F("\nAborted -> FAIL.")); return false; } + // Immediate Y/N without Enter char u = up(c); if (u == 'Y') { Serial.println(F("Y")); @@ -292,12 +304,18 @@ static bool promptYesNo(const __FlashStringHelper* question, return false; } - buf += c; + // Append safely + if (idx < sizeof(buf) - 1) { + buf[idx++] = c; + } } + delay(5); } - Serial.println(defaultNo ? F("\nNo response -> FAIL") : F("\nNo response -> PASS")); + Serial.println(defaultNo ? F("\nNo response -> FAIL") + : F("\nNo response -> PASS")); + return !defaultNo; } From 30dfc8ff286eb60df57fc4008037d31bc857ab2c Mon Sep 17 00:00:00 2001 From: Yukti Date: Mon, 2 Mar 2026 10:43:36 +0530 Subject: [PATCH 12/12] updated firmware version --- .../factoryTest/FactoryTest_wMenu/FactoryTest_wMenu.ino | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/Firmware/factoryTest/FactoryTest_wMenu/FactoryTest_wMenu.ino b/Firmware/factoryTest/FactoryTest_wMenu/FactoryTest_wMenu.ino index ce1f19a..b65f95d 100644 --- a/Firmware/factoryTest/FactoryTest_wMenu/FactoryTest_wMenu.ino +++ b/Firmware/factoryTest/FactoryTest_wMenu/FactoryTest_wMenu.ino @@ -1,4 +1,4 @@ -#define FIRMWARE_VERSION "v0.4.3.3" +#define FIRMWARE_VERSION "v0.4.3.4" /* ------------------------------------------------------------------------------ File: FactoryTest_wMenu.ino @@ -35,7 +35,10 @@ Revision History: | | | | and return to menu. | |v0.4.3.1 | 2026-2-28 | Yukti | updated code and firmware ver. based on review | |v0.4.3.2 | 2026-2-28 | Yukti | changed 'exit' to 'break' | -|v0.4.3.3 | 2026-2-29 | Yukti | added global break support to all tests | +|v0.4.3.3 | 2026-2-29 | Yukti | added global break support to all tests | +|v0.4.3.4 | 2026-03-01| Yukti | Refactor GLOBAL BREAK handling; remove dynamic | +| | | String usage from interactive paths; add | +| | | cooperative break checks in long-running loops | ----------------------------------------------------------------------------------------| Overview: - Repeatable factory test sequence for ESP32-WROOM-32D Krake/GPAD v2 boards.