#include <stdint.h>

#define USART0_STAT  (*(volatile uint32_t*)0x4001381C)
#define USART0_RDATA (*(volatile uint32_t*)0x40013824)
#define USART0_CTL2  (*(volatile uint32_t*)0x40013808)
#define RXNE_BIT    (1u << 5)
#define DENR_BIT    (1u << 6)
#define CHANNEL_BUF ((volatile uint8_t*)0x2000006e)
/* schedule gate: 0/2/3 -> schedule recomputes+overwrites target buffer;
 * any other value -> schedule skipped entirely, manual value left alone */
#define SCHEDULE_MODE (*(volatile uint8_t*)0x20000110)
#define MANUAL_MODE_VALUE 1

/* These live outside the firmware's own .bss layout, so they are NOT
 * zero-initialized on reset -- every access must be written to be
 * correct regardless of starting garbage, never assume a 0 start. */
static volatile uint8_t awaiting_value = 0;
static volatile uint8_t pending_channel = 0;

void uart_cmd_poll(void) {
    /* idempotent: safe to repeat every call, no init-order dependency */
    USART0_CTL2 &= ~DENR_BIT;

    if (!(USART0_STAT & RXNE_BIT))
        return;

    uint8_t b = (uint8_t)USART0_RDATA;

    if (b >= 0xA0 && b <= 0xA5) {
        /* channel-select byte always resets the state machine,
         * self-healing regardless of prior garbage state */
        pending_channel = b - 0xA0;
        awaiting_value = 1;
    } else if (awaiting_value == 1) {
        CHANNEL_BUF[pending_channel] = b;
        awaiting_value = 0;
        SCHEDULE_MODE = MANUAL_MODE_VALUE;
    }
}
