Files
HaloKeymind/test/test_t096_button_wake_profile.py
T

140 lines
6.2 KiB
Python

#!/usr/bin/env python3
from pathlib import Path
import unittest
ROOT = Path(__file__).resolve().parents[1]
TARGET = ROOT / "variants" / "heltec_t096" / "target.cpp"
PROFILE = ROOT / "variants" / "heltec_t096" / "platformio.ini"
UI = ROOT / "examples" / "companion_radio" / "ui-new" / "UITask.cpp"
DISPLAY = ROOT / "src" / "helpers" / "ui" / "ST7735Display.cpp"
BUTTON = ROOT / "src" / "helpers" / "ui" / "MomentaryButton.cpp"
BUTTON_HEADER = ROOT / "src" / "helpers" / "ui" / "MomentaryButton.h"
MAIN = ROOT / "examples" / "companion_radio" / "main.cpp"
REPEATER_MAIN = ROOT / "examples" / "simple_repeater" / "main.cpp"
ROOM_UI = ROOT / "examples" / "simple_room_server" / "UITask.cpp"
ROOM_MAIN = ROOT / "examples" / "simple_room_server" / "main.cpp"
SENSOR_UI = ROOT / "examples" / "simple_sensor" / "UITask.cpp"
SENSOR_MAIN = ROOT / "examples" / "simple_sensor" / "main.cpp"
NRF52_BOARD = ROOT / "src" / "helpers" / "NRF52Board.cpp"
class T096ButtonWakeProfileTest(unittest.TestCase):
def test_active_low_user_button_enables_internal_pullup(self):
target = TARGET.read_text(encoding="utf-8")
self.assertIn(
"MomentaryButton user_btn(PIN_USER_BTN, 1000, true, true, true);",
target,
)
def test_multiclick_remains_enabled_for_previous_page_gesture(self):
target = TARGET.read_text(encoding="utf-8")
self.assertIn(
"MomentaryButton user_btn(PIN_USER_BTN, 1000, true, true, true);",
target,
)
def test_nrf52_button_wakes_poller_on_press_and_release(self):
button = BUTTON.read_text(encoding="utf-8")
profile = PROFILE.read_text(encoding="utf-8")
t096_base = profile.split("[Heltec_t096]", 1)[1].split("[env:", 1)[0]
begin_start = button.index("void MomentaryButton::begin()")
begin_end = button.index("\n}\n", begin_start)
begin = button[begin_start:begin_end]
self.assertIn("-D MOMENTARY_BUTTON_WAKE_FROM_SLEEP=1", t096_base)
self.assertIn("defined(MOMENTARY_BUTTON_WAKE_FROM_SLEEP)", button)
self.assertIn("wakeMomentaryButtonPoller", button)
self.assertIn(
"attachInterrupt((uint32_t)_pin, wakeMomentaryButtonPoller, CHANGE)",
begin,
)
def test_pending_gesture_deadlines_prevent_event_sleep(self):
header = BUTTON_HEADER.read_text(encoding="utf-8")
main = MAIN.read_text(encoding="utf-8")
repeater_main = REPEATER_MAIN.read_text(encoding="utf-8")
room_main = ROOM_MAIN.read_text(encoding="utf-8")
sensor_main = SENSOR_MAIN.read_text(encoding="utf-8")
self.assertIn(
"return _debouncing || _press_active || _pending_click || isWakeHoldActive();",
header,
)
self.assertIn("defined(MOMENTARY_BUTTON_WAKE_FROM_SLEEP)", main)
self.assertIn("!user_btn.needsPolling()", main)
self.assertIn("defined(MOMENTARY_BUTTON_WAKE_FROM_SLEEP)", repeater_main)
self.assertIn("!user_btn.needsPolling()", repeater_main)
self.assertIn("defined(MOMENTARY_BUTTON_WAKE_FROM_SLEEP)", room_main)
self.assertIn("!user_btn.needsPolling()", room_main)
self.assertIn("defined(MOMENTARY_BUTTON_WAKE_FROM_SLEEP)", sensor_main)
self.assertIn("!user_btn.needsPolling()", sensor_main)
def test_room_and_sensor_use_event_driven_button_on_t096(self):
room_ui = ROOM_UI.read_text(encoding="utf-8")
sensor_ui = SENSOR_UI.read_text(encoding="utf-8")
for source in (room_ui, sensor_ui):
self.assertIn('#include "target.h"', source)
self.assertIn("defined(MOMENTARY_BUTTON_WAKE_FROM_SLEEP)", source)
self.assertIn("defined(DISPLAY_CLASS)", source)
self.assertIn("user_btn.begin();", source)
self.assertIn("user_btn.check();", source)
self.assertIn("ev != BUTTON_EVENT_NONE", source)
self.assertIn("digitalRead(PIN_USER_BTN)", source)
def test_raw_nrf52_event_wait_preserves_pending_gpio_edge(self):
board = NRF52_BOARD.read_text(encoding="utf-8")
sleep = board[board.index("void NRF52Board::sleep"):]
raw_wait = sleep.split("} else {", 1)[1]
self.assertLess(raw_wait.index("__WFE();"), raw_wait.index("__SEV();"))
self.assertIn("__WFE();\n __SEV();\n __WFE();", raw_wait)
def test_switch_bounce_is_stabilized_before_counting_clicks(self):
button = BUTTON.read_text(encoding="utf-8")
header = BUTTON_HEADER.read_text(encoding="utf-8")
self.assertIn("#define BUTTON_DEBOUNCE_MS", button)
self.assertIn("raw_btn == prev", button)
self.assertIn("now - _candidate_since", button)
self.assertIn("press_candidate_in_window", button)
self.assertIn("bool _debouncing;", header)
self.assertIn("bool _press_active;", header)
def test_release_only_polling_preserves_long_press(self):
button = BUTTON.read_text(encoding="utf-8")
release_start = button.index("// button UP")
release_end = button.index("down_at = 0;", release_start)
release = button[release_start:release_end]
self.assertIn(">= (uint32_t)_long_millis", release)
self.assertIn("event = BUTTON_EVENT_LONG_PRESS", release)
def test_last_message_navigation_returns_home_instead_of_noop(self):
ui = UI.read_text(encoding="utf-8")
msg_input_start = ui.index("bool handleInput(char c) override", ui.index("class MsgPreviewScreen"))
msg_input_end = ui.index("\n }\n};", msg_input_start)
msg_input = ui[msg_input_start:msg_input_end]
self.assertIn("if (view_offset + 1 < filteredCount())", msg_input)
self.assertIn("_task->gotoHomeScreen();", msg_input)
def test_temporary_wake_diagnostics_are_not_shipped(self):
ui = UI.read_text(encoding="utf-8")
display = DISPLAY.read_text(encoding="utf-8")
button = BUTTON.read_text(encoding="utf-8")
self.assertNotIn("T096_BUTTON_WAKE_DIAGNOSTICS", ui)
self.assertNotIn("T096_BUTTON_WAKE_DIAGNOSTICS", display)
self.assertNotIn("T096_BUTTON_WAKE_DIAGNOSTICS", button)
self.assertNotIn("T096_WAKE", ui)
self.assertNotIn("T096_WAKE", display)
self.assertNotIn("wake-bright", display)
if __name__ == "__main__":
unittest.main()