HAL API
The public HAL interface is defined in
hal/hal.h — the
only header application code ever includes. It contains declarations, typedefs,
and macros, but no implementation. The prefix used throughout the source is
lpl_ / LPL_.
Common types
Section titled “Common types”typedef uint16_t lpl_pin_t;
typedef enum { LPL_OK = 0, LPL_ERR_TIMEOUT, LPL_ERR_BUSY, LPL_ERR_INVALID,} lpl_err_t;lpl_pin_t encodes (port << 8) | pin_number. On POSIX the high byte is always
0 (flat index). On STM32 it encodes the GPIO port (A=0, B=1, …) and the pin
(0–15).
Concrete pin constants (LPL_PIN_A0, LPL_PIN_0, …) live in pins.h — a
separate file per port, resolved by the build system through the include path.
System
Section titled “System”void lpl_system_init(void);void lpl_system_reset(void);lpl_system_init is the first function to call. On an MCU it configures the
clock and enables the base peripherals. On POSIX it captures the time reference,
clears GPIO state, opens the simulation-bus socket (gracefully if it fails), and
ignores SIGPIPE. It returns void: on POSIX it degrades silently, on an MCU
there is no recovery.
lpl_system_reset is a hardware reset (NVIC) on an MCU; on POSIX it closes the
sim bus and calls exit(0).
typedef enum { LPL_GPIO_INPUT, LPL_GPIO_OUTPUT,} lpl_gpio_dir_t;
typedef enum { LPL_GPIO_LOW = 0, LPL_GPIO_HIGH = 1,} lpl_gpio_level_t;
void lpl_gpio_init(lpl_pin_t pin, lpl_gpio_dir_t dir);void lpl_gpio_write(lpl_pin_t pin, lpl_gpio_level_t level);lpl_gpio_level_t lpl_gpio_read(lpl_pin_t pin);void lpl_gpio_toggle(lpl_pin_t pin);typedef struct { uint32_t baud_rate; uint8_t data_bits; uint8_t stop_bits;} lpl_uart_config_t;
lpl_err_t lpl_uart_init(uint8_t port, const lpl_uart_config_t *cfg);lpl_err_t lpl_uart_send(uint8_t port, uint8_t byte);lpl_err_t lpl_uart_recv(uint8_t port, uint8_t *out, uint32_t timeout_ms);lpl_uart_recv returns LPL_ERR_TIMEOUT if the timeout elapses before a byte
arrives; otherwise the received byte is written to *out.
uint32_t lpl_timer_tick_ms(void);void lpl_timer_delay_ms(uint32_t ms);uint64_t lpl_timer_timestamp_us(void);void lpl_adc_init(uint8_t channel);uint16_t lpl_adc_read(uint8_t channel);channel is 0–7. lpl_adc_read returns a 12-bit value (0–4095). On POSIX
the value is injectable through the sim bus (< ADC_SET). On a real MCU it
needs the hardware driver; the STM32L4 port currently has a return 0 stub.
typedef struct { uint32_t clock_hz; uint8_t mode; /* 0–3: CPOL/CPHA */ uint8_t bit_order; /* 0 = MSB first, 1 = LSB first */} lpl_spi_config_t;
lpl_err_t lpl_spi_init(uint8_t port, const lpl_spi_config_t *cfg);void lpl_spi_select(uint8_t port, lpl_pin_t cs_pin);void lpl_spi_deselect(uint8_t port, lpl_pin_t cs_pin);lpl_err_t lpl_spi_transfer(uint8_t port, const uint8_t *tx, uint8_t *rx, uint32_t len);lpl_spi_select / lpl_spi_deselect drive the CS pin (GPIO) and emit SPI_CS
on the sim bus. lpl_spi_transfer emits SPI_TX and waits for the < SPI_RX
reply from the bridge (50 ms timeout; on timeout it fills rx with 0xFF, the
realistic MISO-idle behavior). The STM32L4 port has a stub.
typedef struct { uint32_t clock_hz;} lpl_i2c_config_t;
lpl_err_t lpl_i2c_init(uint8_t port, const lpl_i2c_config_t *cfg);lpl_err_t lpl_i2c_write(uint8_t port, uint8_t addr, const uint8_t *buf, uint32_t len);lpl_err_t lpl_i2c_read(uint8_t port, uint8_t addr, uint8_t *buf, uint32_t len);lpl_i2c_write emits I2C_WRITE and waits for < I2C_WRITE_ACK (50 ms
timeout; NACK → LPL_ERR_BUSY). lpl_i2c_read emits I2C_READ and waits for
< I2C_READ with the data (50 ms timeout; timeout → LPL_ERR_TIMEOUT). The
STM32L4 port has a stub.
See the simulation bus reference for how the SPI and I2C request/response cycles work on the host.