Files
hpsg5-controller_v2-stm32g4/Core/Kline_Libs/kl_phy.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);
}