225 lines
5.0 KiB
C
225 lines
5.0 KiB
C
|
|
/**
|
|||
|
|
******************************************************************************
|
|||
|
|
* @file uart2_print.c
|
|||
|
|
* @brief UART2调试打印模块实现
|
|||
|
|
* @author Application Layer
|
|||
|
|
* @version 1.1
|
|||
|
|
******************************************************************************
|
|||
|
|
* @attention
|
|||
|
|
* 本模块实现基于环形缓冲区的非阻塞调试信息输出
|
|||
|
|
* 关键特性:
|
|||
|
|
* 1. 环形缓冲区避免数据丢失
|
|||
|
|
* 2. 中断安全,支持ISR中调用
|
|||
|
|
* 3. 非阻塞发送,不影响实时性
|
|||
|
|
*
|
|||
|
|
* 修订历史:
|
|||
|
|
* v1.1 - 修复审查报告高危-1/2/3,中危-4
|
|||
|
|
******************************************************************************
|
|||
|
|
*/
|
|||
|
|
|
|||
|
|
#include "uart2_print.h"
|
|||
|
|
#include "usart.h"
|
|||
|
|
#include <string.h>
|
|||
|
|
#include <stdio.h>
|
|||
|
|
|
|||
|
|
#define DEBUG_PRINT_ENABLED 1
|
|||
|
|
|
|||
|
|
#if DEBUG_PRINT_ENABLED
|
|||
|
|
#define DEBUG_LOG(fmt, ...) UART2_Print_Printf("[UART2] " fmt "\r\n", ##__VA_ARGS__)
|
|||
|
|
#else
|
|||
|
|
#define DEBUG_LOG(fmt, ...)
|
|||
|
|
#endif
|
|||
|
|
|
|||
|
|
typedef struct {
|
|||
|
|
uint8_t buffer[UART2_TX_BUFFER_SIZE];
|
|||
|
|
volatile uint16_t head;
|
|||
|
|
volatile uint16_t tail;
|
|||
|
|
volatile uint16_t count;
|
|||
|
|
volatile bool is_sending;
|
|||
|
|
volatile uint16_t overflow_count;
|
|||
|
|
} ring_buffer_t;
|
|||
|
|
|
|||
|
|
static ring_buffer_t tx_ring = {0};
|
|||
|
|
|
|||
|
|
void UART2_Print_Init(void)
|
|||
|
|
{
|
|||
|
|
tx_ring.head = 0;
|
|||
|
|
tx_ring.tail = 0;
|
|||
|
|
tx_ring.count = 0;
|
|||
|
|
tx_ring.is_sending = false;
|
|||
|
|
tx_ring.overflow_count = 0;
|
|||
|
|
|
|||
|
|
DEBUG_LOG("Init OK, buffer size: %d", UART2_TX_BUFFER_SIZE);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
void UART2_Print_Send(const uint8_t *data, uint16_t len)
|
|||
|
|
{
|
|||
|
|
if (len == 0 || data == NULL) {
|
|||
|
|
return;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
uint16_t written = 0;
|
|||
|
|
bool needs_kickoff = false;
|
|||
|
|
|
|||
|
|
__disable_irq();
|
|||
|
|
for (uint16_t i = 0; i < len; i++) {
|
|||
|
|
if (tx_ring.count >= UART2_TX_BUFFER_SIZE) {
|
|||
|
|
tx_ring.overflow_count++;
|
|||
|
|
break;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
tx_ring.buffer[tx_ring.head] = data[i];
|
|||
|
|
tx_ring.head = (tx_ring.head + 1) % UART2_TX_BUFFER_SIZE;
|
|||
|
|
tx_ring.count++;
|
|||
|
|
written++;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if (written > 0 && !tx_ring.is_sending) {
|
|||
|
|
tx_ring.is_sending = true;
|
|||
|
|
needs_kickoff = true;
|
|||
|
|
}
|
|||
|
|
__enable_irq();
|
|||
|
|
|
|||
|
|
if (needs_kickoff) {
|
|||
|
|
uint8_t byte;
|
|||
|
|
__disable_irq();
|
|||
|
|
byte = tx_ring.buffer[tx_ring.tail];
|
|||
|
|
__enable_irq();
|
|||
|
|
HAL_UART_Transmit_IT(&huart2, &byte, 1);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
void UART2_Print_String(const char *str)
|
|||
|
|
{
|
|||
|
|
if (str == NULL) {
|
|||
|
|
return;
|
|||
|
|
}
|
|||
|
|
UART2_Print_Send((const uint8_t *)str, strlen(str));
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
void UART2_Print_Printf(const char *fmt, ...)
|
|||
|
|
{
|
|||
|
|
if (fmt == NULL) {
|
|||
|
|
return;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
char buffer[128];
|
|||
|
|
va_list args;
|
|||
|
|
|
|||
|
|
va_start(args, fmt);
|
|||
|
|
int len = vsnprintf(buffer, sizeof(buffer), fmt, args);
|
|||
|
|
va_end(args);
|
|||
|
|
|
|||
|
|
if (len >= 0) {
|
|||
|
|
if (len >= (int)sizeof(buffer)) {
|
|||
|
|
len = sizeof(buffer) - 1;
|
|||
|
|
}
|
|||
|
|
UART2_Print_Send((const uint8_t *)buffer, len);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
void UART2_Print_Task(void)
|
|||
|
|
{
|
|||
|
|
uint8_t byte;
|
|||
|
|
uint16_t current_tail;
|
|||
|
|
|
|||
|
|
__disable_irq();
|
|||
|
|
if (tx_ring.is_sending || tx_ring.count == 0) {
|
|||
|
|
__enable_irq();
|
|||
|
|
return;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
current_tail = tx_ring.tail;
|
|||
|
|
tx_ring.tail = (tx_ring.tail + 1) % UART2_TX_BUFFER_SIZE;
|
|||
|
|
tx_ring.count--;
|
|||
|
|
tx_ring.is_sending = true;
|
|||
|
|
byte = tx_ring.buffer[current_tail];
|
|||
|
|
__enable_irq();
|
|||
|
|
|
|||
|
|
HAL_UART_Transmit_IT(&huart2, &byte, 1);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
void UART2_Print_TxCpltCallback(void)
|
|||
|
|
{
|
|||
|
|
uint8_t byte;
|
|||
|
|
uint16_t current_tail;
|
|||
|
|
bool has_more = false;
|
|||
|
|
|
|||
|
|
__disable_irq();
|
|||
|
|
tx_ring.is_sending = false;
|
|||
|
|
|
|||
|
|
if (tx_ring.count > 0) {
|
|||
|
|
current_tail = tx_ring.tail;
|
|||
|
|
tx_ring.tail = (tx_ring.tail + 1) % UART2_TX_BUFFER_SIZE;
|
|||
|
|
tx_ring.count--;
|
|||
|
|
tx_ring.is_sending = true;
|
|||
|
|
byte = tx_ring.buffer[current_tail];
|
|||
|
|
has_more = true;
|
|||
|
|
}
|
|||
|
|
__enable_irq();
|
|||
|
|
|
|||
|
|
if (has_more) {
|
|||
|
|
HAL_UART_Transmit_IT(&huart2, &byte, 1);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
bool UART2_Print_IsBusy(void)
|
|||
|
|
{
|
|||
|
|
bool busy;
|
|||
|
|
__disable_irq();
|
|||
|
|
busy = tx_ring.is_sending || (tx_ring.count > 0);
|
|||
|
|
__enable_irq();
|
|||
|
|
return busy;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
uint16_t UART2_Print_Available(void)
|
|||
|
|
{
|
|||
|
|
uint16_t available;
|
|||
|
|
__disable_irq();
|
|||
|
|
available = UART2_TX_BUFFER_SIZE - tx_ring.count;
|
|||
|
|
__enable_irq();
|
|||
|
|
return available;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
uint16_t UART2_Print_GetOverflowCount(void)
|
|||
|
|
{
|
|||
|
|
return tx_ring.overflow_count;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* @brief printf重定向函数 (Keil MDK)
|
|||
|
|
* @note 重定向标准库printf到UART2
|
|||
|
|
* @param ch: 待发送字符
|
|||
|
|
* @param f: 文件指针(未使用)
|
|||
|
|
* @retval 发送的字符
|
|||
|
|
*/
|
|||
|
|
#if defined(__CC_ARM) || defined(__ARMCC_VERSION)
|
|||
|
|
int fputc(int ch, FILE *f)
|
|||
|
|
{
|
|||
|
|
(void)f;
|
|||
|
|
UART2_Print_Send((uint8_t *)&ch, 1);
|
|||
|
|
return ch;
|
|||
|
|
}
|
|||
|
|
#endif
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* @brief printf重定向函数 (GCC)
|
|||
|
|
* @note 重定向标准库printf到UART2
|
|||
|
|
* @param ch: 待发送字符
|
|||
|
|
* @retval 发送的字符
|
|||
|
|
*/
|
|||
|
|
#if defined(__GNUC__)
|
|||
|
|
int __io_putchar(int ch)
|
|||
|
|
{
|
|||
|
|
UART2_Print_Send((uint8_t *)&ch, 1);
|
|||
|
|
return ch;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
int _write(int file, char *ptr, int len)
|
|||
|
|
{
|
|||
|
|
(void)file;
|
|||
|
|
UART2_Print_Send((uint8_t *)ptr, len);
|
|||
|
|
return len;
|
|||
|
|
}
|
|||
|
|
#endif
|