1
0
This commit is contained in:
Aiden
2026-05-27 11:50:10 +10:00
parent 0d099235c5
commit c0304c575c
55 changed files with 26035 additions and 16 deletions

View File

@@ -77,6 +77,15 @@ class BenchConnectLcdTest(unittest.TestCase):
def test_label_frame_marks_visible_retry_ack_target(self):
self.assertEqual(label_frame(bytes.fromhex("07804020902D")), "visible_retry_0040_2090_candidate")
def test_label_frame_marks_active_selector0_keepalive_report(self):
self.assertEqual(label_frame(bytes.fromhex("00000080805A")), "active_selector0_keepalive_report")
def test_label_frame_marks_copy_completion_exit_selector_006c_candidate(self):
self.assertEqual(label_frame(bytes.fromhex("00006C000036")), "copy_completion_exit_selector_006c_candidate")
def test_label_frame_marks_copy_in_progress_selector_006d_candidate(self):
self.assertEqual(label_frame(bytes.fromhex("00006D000037")), "copy_in_progress_selector_006d_candidate")
if __name__ == "__main__":
unittest.main()

View File

@@ -0,0 +1,33 @@
import unittest
from ccu_emulator.frames import ACTIVE_SEED_COMMAND0, NEUTRAL_ACK_FRAME, build_frame, frame_checksum_ok
from ccu_emulator.policy import AckPolicy
from ccu_emulator.refresh import PeriodicRefresh
class CcuEmulatorFrameTests(unittest.TestCase):
def test_build_frame_adds_checksum(self):
self.assertEqual(build_frame(0x00, 0x0000, 0x8080), ACTIVE_SEED_COMMAND0)
self.assertTrue(frame_checksum_ok(build_frame(0x06, 0x0015, 0x0001)))
def test_ack_policy_acknowledges_reports_with_neutral_ack(self):
decision = AckPolicy().decide(bytes.fromhex("02000200005A"), "connect_ok_path_response_candidate")
self.assertTrue(decision.should_ack)
self.assertEqual(decision.frame, NEUTRAL_ACK_FRAME)
def test_ack_policy_skips_table_readback(self):
decision = AckPolicy().decide(bytes.fromhex("04000080805E"), "table_readback_candidate")
self.assertFalse(decision.should_ack)
class PeriodicRefreshTests(unittest.TestCase):
def test_periodic_refresh_returns_due_frames(self):
refresh = PeriodicRefresh(frames=[ACTIVE_SEED_COMMAND0], interval=0.5)
refresh.start(now=10.0)
self.assertEqual(refresh.due_frames(now=10.4), [])
self.assertEqual(refresh.due_frames(now=10.5), [ACTIVE_SEED_COMMAND0])
self.assertEqual(refresh.due_frames(now=10.6), [])
if __name__ == "__main__":
unittest.main()

View File

@@ -191,6 +191,28 @@ class EmulatorHarnessTest(unittest.TestCase):
self.assertEqual(writes[-1].value, 0x77)
self.assertEqual(writes[-1].pc, 0x1000)
def test_panel_input_injection_sets_source_shadow_previous_and_dirty_edge(self):
emulator = H8536Emulator(bytes(rom_with_reset()))
injection = emulator.inject_panel_input("cam-power", pressed=True)
self.assertEqual(injection.action.panel_input.selector, 0x0007)
self.assertEqual(emulator.memory.read8(0xF105) & 0x08, 0x08)
self.assertEqual(emulator.memory.read8(0xF6D4) & 0x08, 0x08)
self.assertEqual(emulator.memory.read8(0xF6E4) & 0x08, 0x00)
self.assertEqual(emulator.memory.read8(0xF6F2) & 0x10, 0x10)
def test_panel_input_release_forces_opposite_previous_sample(self):
emulator = H8536Emulator(bytes(rom_with_reset()))
injection = emulator.inject_panel_input("call", pressed=False)
self.assertEqual(injection.action.panel_input.selector, 0x0015)
self.assertEqual(emulator.memory.read8(0xF006) & 0x20, 0x00)
self.assertEqual(emulator.memory.read8(0xF6DB) & 0x20, 0x00)
self.assertEqual(emulator.memory.read8(0xF6EB) & 0x20, 0x20)
self.assertEqual(emulator.memory.read8(0xF6F3) & 0x08, 0x08)
if __name__ == "__main__":
unittest.main()

View File

@@ -2,7 +2,17 @@ import argparse
import unittest
from h8536.emulator import H8536Emulator, SCI1_RDR, SCI1_SSR, SCI_SSR_ORER, SCI_SSR_RDRF
from h8536.emulator.rx_probe import RunContext, UartTiming, _inject_frame_uart_timed, frame_checksum, frame_checksum_ok, parse_frame
from h8536.emulator.rx_probe import (
RunContext,
UartTiming,
_inject_frame_uart_timed,
frame_checksum,
frame_checksum_ok,
parse_frame,
parse_panel_action_arg,
parse_panel_press_arg,
parse_panel_release_arg,
)
def rom_with_reset(*, reset: int = 0x1000, size: int = 0x1020) -> bytearray:
@@ -30,6 +40,25 @@ class EmulatorRxProbeTest(unittest.TestCase):
with self.assertRaises(argparse.ArgumentTypeError):
parse_frame("04 00 00 40")
def test_parse_panel_action_accepts_alias_state_and_raw_shadow_bit(self):
action = parse_panel_action_arg("cam-power=release")
self.assertEqual(action.panel_input.shadow, 0xF6D4)
self.assertEqual(action.panel_input.bit, 3)
self.assertFalse(action.pressed)
raw = parse_panel_press_arg("F6D4.6")
self.assertEqual(raw.panel_input.source, 0xF105)
self.assertEqual(raw.panel_input.dirty, 0xF6F2)
self.assertEqual(raw.panel_input.dirty_bit, 4)
self.assertTrue(raw.pressed)
def test_parse_panel_release_accepts_source_address_lane(self):
action = parse_panel_release_arg("F006.5")
self.assertEqual(action.panel_input.shadow, 0xF6DB)
self.assertEqual(action.panel_input.previous, 0xF6EB)
self.assertFalse(action.pressed)
def test_uart_timed_injection_does_not_wait_for_rdrf_consumption(self):
emulator = H8536Emulator(bytes(rom_with_reset()), clock_hz=10_000_000)
context = RunContext()

View File

@@ -0,0 +1,37 @@
import unittest
from h8536.serial_scenario_compare import format_comparison
class SerialScenarioCompareTest(unittest.TestCase):
def test_comparison_reports_extra_selector_and_value(self):
baseline = {
"_path": "baseline.json",
"log": "baseline.txt",
"rx_frames": 10,
"ack_sent": 2,
"ack_targets": {
"01 00 02 00 00 59": 1,
},
}
candidate = {
"_path": "candidate.json",
"log": "candidate.txt",
"rx_frames": 12,
"ack_sent": 3,
"ack_targets": {
"01 00 02 00 00 59": 1,
"01 01 0F 80 00 D5": 1,
},
}
report = format_comparison(baseline, candidate)
self.assertIn("extra ACK-target frames in candidate", report)
self.assertIn("01 01 0F 80 00 D5", report)
self.assertIn("selector=0x008F", report)
self.assertIn("value=0x8000", report)
if __name__ == "__main__":
unittest.main()