/* * Binary IPC between pog422_uartd (C, owns UART fd) and Python bridge/listen. * * All multi-byte integers little-endian. Stream framing: * uint32 magic (POG422_IPC_MAGIC) * uint32 type * uint32 payload_len * payload[payload_len] */ #ifndef POG422_IPC_H #define POG422_IPC_H #include #define POG422_IPC_MAGIC 0x50342200u /* Matched EtherGold BOM — MajorFeature.MinorFeature.MajorFix.MinorFix */ #define POG422_EG_VERSION "4.1.0.11" #define POG422_UARTD_VERSION POG422_EG_VERSION #define POG422_INJECT_VERSION POG422_EG_VERSION /* daemon → Python */ #define POG422_IPC_HS_ACTIVE 1u #define POG422_IPC_HS_INACTIVE 2u #define POG422_IPC_WINDOW 3u #define POG422_IPC_DISCARD 4u #define POG422_IPC_INJECT_DONE 5u #define POG422_IPC_SLV_IN 6u #define POG422_IPC_GPIO7_ACK 7u #define POG422_IPC_HAT_REGS 8u #define POG422_IPC_INJECT_FORENSICS 10u #define POG422_IPC_UART_SUSPEND_ACK 11u #define POG422_IPC_UART_RESUME_ACK 12u /* Bytes read back during eth→UART inject software window (TX echo on multi-drop). */ #define POG422_IPC_INJECT_ECHO 13u /* GPIO_STAT + FIFO phase timeline during inject (on-board copper proxy). */ #define POG422_IPC_INJECT_COPPER 14u /* Daemon + inject-shim version strings (reply to GET_VERSION). */ #define POG422_IPC_VERSION 15u /* Bytes pulled after GPIO7 DE off (XR may mute RX while DE high). */ #define POG422_IPC_POST_DE_RX 16u /* Compile-out HW debug timeline samples (only emitted when POG422_HW_DEBUG=1). */ #define POG422_IPC_HWDBG 17u /* UART device lost (USB disconnect / deleted inode); reopen in progress. */ #define POG422_IPC_UART_PORT_LOST 18u /* UART re-attached after channel resolve (old_path + new_path). */ #define POG422_IPC_UART_PORT_REOPEN 19u /* EG 3.0.1.1: uartd auto-synth 0D after local x9+x1 (hard-RT close). */ #define POG422_IPC_AUTO_CLOSE_DONE 20u /* EG 3.0.1.20: full local x1 SOH..EOP before synth 0D (Master eth forward). */ #define POG422_IPC_X1_ACK_FRAME 21u typedef struct __attribute__((packed)) { char old_path[128]; char new_path[128]; /* empty on LOST */ } pog422_ipc_uart_port_event_t; #ifndef POG422_INJECT_FORENSICS_WIDE_MAX #define POG422_INJECT_FORENSICS_WIDE_MAX 512u #endif #ifndef POG422_COPPER_PHASE_MAX #define POG422_COPPER_PHASE_MAX 16u #endif typedef struct __attribute__((packed)) { char uartd[32]; char inject[32]; char eg[32]; /* product BOM; same as uartd/inject on matched builds */ uint8_t hw_debug; /* 1 if daemon compiled with POG422_HW_DEBUG */ uint8_t _pad_hw[3]; } pog422_ipc_version_t; typedef struct __attribute__((packed)) { uint8_t inject_method; uint8_t wide_is_wire; int16_t driver_errno; uint32_t frame_len; uint32_t wide_len; uint32_t rx_fifo_before; uint32_t rx_fifo_after; uint32_t drain_wait_ns; /* 1.0.56+ / driver 1S — TX path samples (appended; older clients ignore trailing) */ uint32_t tx_fifo_before; uint32_t tx_fifo_after_bulk; uint32_t tx_fifo_after_drain; uint32_t usb_actual; /* EG 2.2 — DE release (appended; older clients ignore trailing before wide) */ uint32_t de_hold_us; uint8_t tx_empty_reason; /* POG422_TX_EMPTY_REASON_* (was mislabeled lsr) */ uint8_t de_release_reason; /* 1=temt, 2=timeout, 3=error, 4=air deadline */ uint8_t _pad_de[2]; /* uint8_t wide[wide_len] follows when wide_len > 0 */ } pog422_ipc_inject_forensics_hdr_t; typedef struct __attribute__((packed)) { uint32_t gpio_mode; uint32_t uart_flow; uint8_t n; uint8_t _pad[3]; /* n × pog422_ipc_copper_sample_t follows */ } pog422_ipc_inject_copper_hdr_t; typedef struct __attribute__((packed)) { uint32_t t_us; uint16_t gpio_stat; uint16_t tx_fifo; uint16_t rx_fifo; uint8_t phase; uint8_t gpio7; uint8_t gpio1; uint8_t _pad; } pog422_ipc_copper_sample_t; /* Python → daemon */ #define POG422_IPC_INJECT 0x80u #define POG422_IPC_GET_SLV_IN 0x81u #define POG422_IPC_SHUTDOWN 0x82u #define POG422_IPC_GPIO7_ASSERT 0x83u #define POG422_IPC_GPIO7_RELEASE 0x84u #define POG422_IPC_GET_HAT_REGS 0x85u #define POG422_IPC_UART_SUSPEND 0x86u #define POG422_IPC_UART_RESUME 0x87u #define POG422_IPC_GET_VERSION 0x88u typedef struct { uint64_t mono_ns; } pog422_ipc_hs_t; typedef struct __attribute__((packed)) { uint64_t window_start_mono_ns; uint64_t first_byte_mono_ns; uint64_t last_byte_mono_ns; uint32_t window_len; /* uint8_t data[window_len] follows in payload — wire header is exactly 28 bytes */ } pog422_ipc_window_hdr_t; typedef struct { uint32_t count; uint8_t first_byte; uint8_t _pad[3]; } pog422_ipc_discard_t; typedef struct __attribute__((packed)) { int32_t err; } pog422_ipc_uart_gate_ack_t; typedef struct { uint32_t pre_tx_us; uint32_t post_hold_us; uint8_t flush_rx; uint8_t require_idle; /* 1 = wait for SLV-IN inactive before DE (EG 2.1+) */ uint16_t idle_wait_ms; /* max wait when require_idle; 0 = instant EBUSY if busy */ uint32_t frame_len; /* uint8_t frame[frame_len] follows */ /* optional pog422_ipc_auto_close_t when payload longer than hdr+frame */ } pog422_ipc_inject_req_hdr_t; /* * Optional trailer after inject frame (EG 3.0.1.1). * When enable=1 and inject is local gameplay x9, uartd harvests peer x1 then * (EG 3.0.1.52) sends INJECT_DONE before synth 0x0D so Python eth path is not * held for the full auto-close window. AUTO_CLOSE_DONE follows 0D TX. */ typedef struct __attribute__((packed)) { uint8_t enable; /* 1 = arm hard-RT auto-close */ uint8_t tid_tail0; /* 0D bytes 9-10 (bank / progressive master) */ uint8_t tid_tail1; uint8_t local_tid0; /* x1 TID filter (wire bytes 3-4) */ uint8_t local_tid1; uint8_t _pad[3]; } pog422_ipc_auto_close_t; /* AUTO_CLOSE_DONE err codes (non-errno) */ #define POG422_AUTO_CLOSE_OK 0 #define POG422_AUTO_CLOSE_NO_X1 1 #define POG422_AUTO_CLOSE_BUILD_FAIL 2 #define POG422_AUTO_CLOSE_INJECT_FAIL 3 typedef struct __attribute__((packed)) { int32_t err; /* 0=ok; 1=no_x1; 2=build; 3=0D inject errno (positive) or fail */ uint8_t x1_msg; uint8_t counter; uint8_t harvest; /* 1=echo, 2=post_de, 3=hs_window/FIFO (EG 3.0.1.4), * 4=immediate_post_x9 peel (EG 3.0.1.17), * 5=pending_expire miss (EG 4.0.0.63 listen-until-x1) */ uint8_t _pad; uint64_t od_tx_ns; uint64_t od_total_ns; } pog422_ipc_auto_close_done_t; typedef struct __attribute__((packed)) { int32_t err; uint64_t tx_ns; uint64_t total_ns; uint32_t air_us; uint8_t slv_in_before; uint8_t slv_in_after_on; uint8_t slv_in_after_body; uint8_t slv_in_after_drain; uint8_t slv_in_after_off; uint8_t gpio1_edges; uint8_t _pad; uint32_t gpio1_first_edge_us; uint32_t gpio1_last_edge_us; /* EG 3.0.1.57 — inject stage forensics (optional if older uartd plen short) */ uint32_t idle_wait_elapsed_us; /* require_idle spin; 0 if never waited */ uint32_t pre_bulk_us; /* t0 → INJECT_TX ioctl enter (flush + idle + setup) */ uint32_t bulk_wall_us; /* ioctl wall time (bulk + driver) */ uint16_t idle_wait_budget_ms; /* require_idle deadline */ uint8_t require_idle; /* opts flag */ uint8_t idle_saw_busy; /* 1 = SLV-IN active at start of require_idle */ /* EG 3.0.1.58 — uartd worker wall vs inject_burst (µs; optional trailer) */ uint32_t uartd_pre_burst_us; /* handle_inject enter → inject_burst call */ uint32_t uartd_burst_wall_us; /* inject_burst call → return */ uint32_t uartd_post_burst_us; /* inject_burst return → INJECT_DONE send */ uint32_t uartd_job_to_done_us; /* handle_inject enter → DONE send */ /* EG 3.0.2.4 — x1 peel event marks (µs from DE-off peel t0; optional) */ uint16_t peel_first_byte_us; /* first RX byte in imm peel; 0 if quiet / N/A */ uint16_t peel_hit_us; /* local x1 SOH..EOP complete; 0 if miss */ uint8_t peel_src; /* 0=none, 1=echo, 2=post_de, 3=hs, 4=imm */ uint8_t peel_x1_msg; /* gameplay ack msg nibble (wire byte 1) */ uint16_t _pad_peel; } pog422_ipc_inject_done_t; typedef struct __attribute__((packed)) { uint8_t active; } pog422_ipc_slv_in_t; typedef struct __attribute__((packed)) { int32_t err; uint8_t slv_in; uint8_t gpio7_tx; } pog422_ipc_gpio7_ack_t; typedef struct __attribute__((packed)) { int32_t err; uint32_t gpio_mode; /* channel 2 / machine (SLV block) */ uint32_t uart_flow; uint32_t gpio_mode_ch0; /* channel 0 / OIS (MST block) */ uint32_t uart_flow_ch0; } pog422_ipc_hat_regs_t; #endif /* POG422_IPC_H */