163 lines
4.2 KiB
C
163 lines
4.2 KiB
C
/*
|
|
* kl_phy.c
|
|
* Physical layer: UART driver, state-based echo suppression, RX FIFO.
|
|
*/
|
|
|
|
#include "kl_phy.h"
|
|
#include "main.h"
|
|
#include <string.h>
|
|
|
|
extern UART_HandleTypeDef huart1;
|
|
|
|
static KL_Phy phy;
|
|
|
|
/* ================================================================
|
|
* RX FIFO (single-producer ISR, single-consumer main loop)
|
|
* ================================================================ */
|
|
static void rx_fifo_push(uint8_t b)
|
|
{
|
|
uint16_t next = (uint16_t)((phy.rx_head + 1U) % KL_RX_FIFO_SIZE);
|
|
if (next == phy.rx_tail) {
|
|
/* Overflow: drop oldest */
|
|
phy.rx_tail = (uint16_t)((phy.rx_tail + 1U) % KL_RX_FIFO_SIZE);
|
|
}
|
|
phy.rx_fifo[phy.rx_head] = b;
|
|
phy.rx_head = next;
|
|
}
|
|
|
|
int KL_Phy_RxPop(uint8_t *out)
|
|
{
|
|
if (phy.rx_head == phy.rx_tail) return 0;
|
|
if (out) *out = phy.rx_fifo[phy.rx_tail];
|
|
phy.rx_tail = (uint16_t)((phy.rx_tail + 1U) % KL_RX_FIFO_SIZE);
|
|
return 1;
|
|
}
|
|
|
|
int KL_Phy_RxAvailable(void)
|
|
{
|
|
return (phy.rx_head != phy.rx_tail) ? 1 : 0;
|
|
}
|
|
|
|
void KL_Phy_RxFlush(void)
|
|
{
|
|
phy.rx_tail = phy.rx_head;
|
|
}
|
|
|
|
/* ================================================================
|
|
* GPIO pin configuration helpers
|
|
* ================================================================ */
|
|
static void phy_set_pins_uart_af(void)
|
|
{
|
|
GPIO_InitTypeDef gi = {0};
|
|
__HAL_RCC_GPIOA_CLK_ENABLE();
|
|
|
|
gi.Pin = KL_TX_PIN | KL_RX_PIN;
|
|
gi.Mode = GPIO_MODE_AF_PP;
|
|
gi.Pull = GPIO_PULLUP;
|
|
gi.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
|
|
gi.Alternate = GPIO_AF7_USART1;
|
|
HAL_GPIO_Init(KL_GPIO_PORT, &gi);
|
|
}
|
|
|
|
/* ================================================================
|
|
* Init / Mode switching
|
|
* ================================================================ */
|
|
void KL_Phy_Init(void)
|
|
{
|
|
memset(&phy, 0, sizeof(phy));
|
|
phy.tx_state = KL_PHY_TX_IDLE;
|
|
HAL_UART_DeInit(&huart1);
|
|
}
|
|
|
|
void KL_Phy_EnableUart9600(void)
|
|
{
|
|
HAL_UART_DeInit(&huart1);
|
|
phy_set_pins_uart_af();
|
|
|
|
huart1.Instance = USART1;
|
|
huart1.Init.BaudRate = 9600;
|
|
huart1.Init.WordLength = UART_WORDLENGTH_8B;
|
|
huart1.Init.StopBits = UART_STOPBITS_1;
|
|
huart1.Init.Parity = UART_PARITY_NONE;
|
|
huart1.Init.Mode = UART_MODE_TX_RX;
|
|
huart1.Init.HwFlowCtl = UART_HWCONTROL_NONE;
|
|
huart1.Init.OverSampling = UART_OVERSAMPLING_16;
|
|
if (HAL_UART_Init(&huart1) != HAL_OK) {
|
|
Error_Handler();
|
|
}
|
|
|
|
KL_Phy_RxFlush();
|
|
phy.tx_state = KL_PHY_TX_IDLE;
|
|
phy.echo_pending = 0;
|
|
|
|
HAL_UART_Receive_IT(&huart1, phy.rx_it_buf, 1);
|
|
}
|
|
|
|
void KL_Phy_DisableUart(void)
|
|
{
|
|
HAL_UART_DeInit(&huart1);
|
|
phy.tx_state = KL_PHY_TX_IDLE;
|
|
phy.echo_pending = 0;
|
|
}
|
|
|
|
/* ================================================================
|
|
* Non-blocking single-byte TX
|
|
* ================================================================ */
|
|
int KL_Phy_TxByte(uint8_t byte)
|
|
{
|
|
if (phy.tx_state != KL_PHY_TX_IDLE) return 0;
|
|
|
|
phy.tx_byte = byte;
|
|
phy.last_tx_byte = byte;
|
|
phy.echo_pending = 1;
|
|
phy.tx_state = KL_PHY_TX_SENDING;
|
|
|
|
if (HAL_UART_Transmit_IT(&huart1, &phy.tx_byte, 1) != HAL_OK) {
|
|
phy.tx_state = KL_PHY_TX_IDLE;
|
|
phy.echo_pending = 0;
|
|
return 0;
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
int KL_Phy_TxBusy(void)
|
|
{
|
|
return (phy.tx_state != KL_PHY_TX_IDLE) ? 1 : 0;
|
|
}
|
|
|
|
/* ================================================================
|
|
* Service: echo-timeout recovery
|
|
* ================================================================ */
|
|
void KL_Phy_Service(void)
|
|
{
|
|
if (phy.tx_state == KL_PHY_TX_ECHO_WAIT) {
|
|
if (kl_tick_diff(HAL_GetTick(), phy.tx_done_tick) >= (int32_t)KL_ECHO_TMO_MS) {
|
|
phy.tx_state = KL_PHY_TX_IDLE;
|
|
phy.echo_pending = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* ================================================================
|
|
* ISR callbacks
|
|
* ================================================================ */
|
|
void KL_Phy_TxCpltCB(void)
|
|
{
|
|
phy.tx_done_tick = HAL_GetTick();
|
|
phy.tx_state = KL_PHY_TX_ECHO_WAIT;
|
|
}
|
|
|
|
void KL_Phy_RxCpltCB(void)
|
|
{
|
|
uint8_t byte = phy.rx_it_buf[0];
|
|
|
|
if (phy.echo_pending && byte == phy.last_tx_byte) {
|
|
phy.echo_pending = 0;
|
|
phy.tx_state = KL_PHY_TX_IDLE;
|
|
} else {
|
|
rx_fifo_push(byte);
|
|
}
|
|
|
|
HAL_UART_Receive_IT(&huart1, phy.rx_it_buf, 1);
|
|
}
|