import json import tempfile import unittest from pathlib import Path from h8536.serial_pseudocode import ( SerialPseudocodeOptions, generate_serial_pseudocode, write_serial_pseudocode, ) def candidate_payload() -> dict: return { "instructions": [], "sci_protocol": { "manual_references": [ "Manual/0900766b802125d0.md:15794 RDR receive data register", "Manual/0900766b802125d0.md:15823 TDR transmit data register", ], }, "board_profile": { "summary": "Board trace ties the H8/536 SCI1 pins to a MAX202 RS232 transceiver.", "manual_references": [ "Manual/0900766b802125d0.md:2417 FP-80 H8/536 pin 66 is P95/TXD", ], "traces": [ { "signal": "TXD", "h8_pin": 66, "h8_pin_name": "P95/TXD", "max202_pin": 11, "evidence": "MAX202 pin 11 traces to H8 pin 66", }, { "signal": "RXD", "h8_pin": 67, "h8_pin_name": "P96/RXD", "max202_pin": 12, "evidence": "MAX202 pin 12 traces to H8 pin 67", }, ], }, "serial_reconstruction": { "candidates": [ { "kind": "candidate_sci1_tx_frame", "channel": "SCI1", "frame_length": 6, "buffer_start": 0xF858, "buffer_start_hex": "H'F858", "buffer_end": 0xF85D, "buffer_end_hex": "H'F85D", "checksum_address": 0xF85D, "tx_index_address": 0xF9C2, "tdr_address": 0xFEDB, "checksum_seed": 0x5A, "checksum_formula": "checksum = 0x5A ^ byte0 ^ byte1 ^ byte2 ^ byte3 ^ byte4", "confidence": "high", "confidence_score": 0.95, "confidence_reason": "all required independent evidence groups were observed", "comment": "candidate/evidence-supported SCI1 6-byte TX frame hypothesis", "evidence_addresses_hex": { "tx_checksum_seed": ["H'BA4E"], "xor_checksum_chain": ["H'BA50", "H'BA54"], }, }, { "kind": "candidate_sci1_rx_frame", "channel": "SCI1", "frame_length": 6, "capture_buffer_start": 0xF868, "capture_buffer_start_hex": "H'F868", "capture_buffer_end": 0xF86D, "capture_buffer_end_hex": "H'F86D", "validation_buffer_start": 0xF860, "validation_buffer_end": 0xF865, "checksum_address": 0xF865, "rx_index_address": 0xF9C3, "rdr_address": 0xFEDD, "interbyte_timeout_address": 0xF9C1, "complete_timer_address": 0xF9C5, "checksum_seed": 0x5A, "checksum_formula": "checksum = 0x5A ^ byte0 ^ byte1 ^ byte2 ^ byte3 ^ byte4", "confidence": "high", "confidence_score": 0.9, "confidence_reason": "RX count, copy, and checksum-validation evidence were observed", "caveat": "candidate frame means six consecutive bytes, not a proven delimited packet", "comment": "candidate/evidence-supported SCI1 6-byte RX frame hypothesis", "evidence_addresses_hex": { "rx_rdr_read": ["H'BB6D"], "rx_xor_checksum_validation": ["H'BBD6", "H'BBEC"], }, }, ], }, } class SerialPseudocodeTest(unittest.TestCase): def test_generates_focused_tx_and_rx_candidate_paths(self): text = generate_serial_pseudocode(candidate_payload(), source_name="rom.json") self.assertIn("focused SCI RX/TX pseudocode from rom.json", text) self.assertIn("SCI1 TX 6-byte frame at H'F858-H'F85D", text) self.assertIn("SCI1 RX 6-byte frame captured at H'F868-H'F86D", text) self.assertIn("MAX202 pin 11 traces to H8 pin 66", text) self.assertIn("Manual/0900766b802125d0.md:15823 TDR transmit data register", text) self.assertIn("#define TX_FRAME(n) MEM8[(u16)(0xF858u + (n))]", text) self.assertIn("#define RX_CAPTURE(n) MEM8[(u16)(0xF868u + (n))]", text) self.assertIn("checksum ^= TX_FRAME(4);", text) self.assertIn("TX_FRAME(5) = sci1_tx_candidate_checksum();", text) self.assertIn("SCI1_TDR = TX_FRAME(0);", text) self.assertIn("void sci1_txi_candidate_isr(void)", text) self.assertIn("SCI1_SSR &= (u8)~SCI_SSR_RDRF;\n byte = SCI1_RDR;", text) self.assertIn("RX_CAPTURE(RX_INDEX) = byte;", text) self.assertIn("return sci1_process_rx_candidate_frame();", text) self.assertIn("rx_xor_checksum_validation: H'BBD6, H'BBEC", text) def test_tx_only_option_omits_rx_functions(self): text = generate_serial_pseudocode( candidate_payload(), options=SerialPseudocodeOptions(include_rx=False), ) self.assertIn("void sci1_tx_start_candidate_frame(void)", text) self.assertNotIn("sci1_rx_byte_received_candidate_isr", text) def test_write_serial_pseudocode_writes_output_file(self): with tempfile.TemporaryDirectory() as tmp: input_path = Path(tmp) / "rom.json" output_path = Path(tmp) / "serial.c" input_path.write_text( json.dumps(candidate_payload()), encoding="utf-8", ) write_serial_pseudocode(input_path, output_path, SerialPseudocodeOptions()) self.assertIn("sci1_process_rx_candidate_frame", output_path.read_text(encoding="utf-8")) if __name__ == "__main__": unittest.main()