| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479 |
- /**
- ******************************************************************************
- * @file uart_protocol.c
- * @brief UART 通讯协议模块实现
- * 负责协议帧的组装/发送/接收/解析, 以及对 LED 显示的更新触发.
- ******************************************************************************
- */
- /* Includes ------------------------------------------------------------------*/
- #include "uart_protocol.h"
- #include "main.h" /* DebugUartHandle */
- #include "app_state.h"
- #include "led_driver.h"
- #include "battery_display.h"
- /* Private define ------------------------------------------------------------*/
- /* ========== 通讯协议常量 ========== */
- #define FRAME_HEADER1 0x55u
- #define FRAME_HEADER2 0xAAu
- #define CMD_READ 0x01u
- #define CMD_WRITE 0x02u
- #define CMD_REPORT 0x81u
- #define CMD_ACK 0xA0u /* 写操作成功回复 */
- /* 接收缓冲区大小 */
- #define RX_BUF_SIZE 32u
- /* UART 发送超时 (ms) */
- #define UART_TX_TIMEOUT 100u
- /* Private variables ---------------------------------------------------------*/
- extern UART_HandleTypeDef DebugUartHandle;
- /* ========== 接收缓冲 (双缓冲) ========== */
- #define RX_QUEUE_SIZE 2u
- static volatile uint8_t g_rxBuf[RX_QUEUE_SIZE][RX_BUF_SIZE];
- static volatile uint8_t g_frameLen[RX_QUEUE_SIZE];
- static volatile uint8_t g_rxLen = 0u;
- static volatile uint8_t g_rxWriteIdx = 0u;
- static volatile uint8_t g_rxReadIdx = 0u;
- static volatile uint8_t g_frameCount = 0u;
- uint8_t g_rxByte; /* 单字节接收缓冲 (extern 在 uart_protocol.h) */
- /* ========== 发送缓冲 ========== */
- static uint8_t g_txBuf[8];
- /* Private function prototypes -----------------------------------------------*/
- static void UART_SendFrame(uint8_t cmd, uint8_t item, uint8_t value);
- static void UART_SendWrite(uint8_t item, uint8_t value);
- static void HandleReportAll(uint8_t *data, uint8_t count);
- static void HandleReportSingle(uint8_t item, uint8_t value);
- /* ========== 帧状态查询 ========== */
- uint8_t UART_IsFrameReady(void)
- {
- return (g_frameCount > 0u) ? 1u : 0u;
- }
- void UART_ClearFrameReady(void)
- {
- /* 标志位管理移至 ProcessReceivedFrame 内完成 */
- }
- /* ========== UART 接收回调 ========== */
- /**
- * @brief USART2中断接收回调 - 每收到一个字节调用
- * 支持变长帧: 5字节标准帧及 AA 81 COUNT ... CRC 多字节上报
- */
- void UART_RxByteCallback(uint8_t data)
- {
- static uint8_t s_state = 0u; /* 0=Wait 55, 1=Wait AA(or A0), 2=Wait CMD, 3=Wait LEN, 4=Wait Body */
- static uint8_t s_expectedLen = 0u;
- static uint16_t s_timeout = 0u;
- uint8_t *curBuf = (uint8_t *)g_rxBuf[g_rxWriteIdx];
- if (s_state != 0u)
- {
- s_timeout++;
- if (s_timeout > 1000u)
- {
- s_state = 0u;
- s_timeout = 0u;
- }
- }
- else
- {
- s_timeout = 0u;
- }
- if (s_state == 0u)
- {
- if (data == FRAME_HEADER1)
- {
- curBuf[0] = data;
- g_rxLen = 1u;
- s_state = 1u;
- }
- else if (data == CMD_ACK)
- {
- curBuf[0] = CMD_ACK;
- if (g_frameCount < RX_QUEUE_SIZE)
- {
- g_frameLen[g_rxWriteIdx] = 1u;
- g_rxWriteIdx = (g_rxWriteIdx + 1u) % RX_QUEUE_SIZE;
- g_frameCount++;
- }
- g_rxLen = 0u;
- }
- return;
- }
- if (s_state == 1u)
- {
- if (data == FRAME_HEADER2)
- {
- curBuf[1] = data;
- g_rxLen = 2u;
- s_state = 2u;
- }
- else
- {
- s_state = 0u;
- }
- return;
- }
- if (s_state == 2u)
- {
- curBuf[g_rxLen++] = data;
- s_state = 3u;
- return;
- }
- if (s_state == 3u)
- {
- curBuf[g_rxLen++] = data;
- s_expectedLen = 5u + data;
- s_state = 4u;
-
- if (s_expectedLen > RX_BUF_SIZE)
- {
- s_state = 0u;
- g_rxLen = 0u;
- }
- return;
- }
- if (s_state == 4u)
- {
- curBuf[g_rxLen++] = data;
-
- if (g_rxLen >= s_expectedLen)
- {
- uint8_t cmd = curBuf[2];
- uint8_t len = curBuf[3];
- uint8_t crc = cmd ^ len;
- for (uint8_t i = 0; i < len; i++)
- {
- crc ^= curBuf[4 + i];
- }
-
- if (crc == data)
- {
- if (g_frameCount < RX_QUEUE_SIZE)
- {
- g_frameLen[g_rxWriteIdx] = g_rxLen;
- g_rxWriteIdx = (g_rxWriteIdx + 1u) % RX_QUEUE_SIZE;
- g_frameCount++;
- }
- }
- s_state = 0u;
- g_rxLen = 0u;
- }
- }
- }
- /* ========== 帧处理 ========== */
- /**
- * @brief 处理收到的完整协议帧
- */
- void ProcessReceivedFrame(void)
- {
- if (g_frameCount == 0u) return;
- uint8_t *frame = (uint8_t *)g_rxBuf[g_rxReadIdx];
- uint8_t rxLen = g_frameLen[g_rxReadIdx];
-
- if (rxLen >= 7u)
- {
- uint8_t cmd = frame[2];
- uint8_t len = frame[3];
- if (cmd == CMD_REPORT)
- {
- if (len == 2u)
- {
- /* 0x81 单条上报: 没有 COUNT 字节, frame[4]=ITEM, frame[5]=VALUE */
- HandleReportSingle(frame[4], frame[5]);
- }
- else if (len > 2u)
- {
- /* 0x81 多条上报: frame[4] 为键值对数量 COUNT */
- uint8_t count = frame[4];
- HandleReportAll(&frame[5], count);
- }
- }
- else if (cmd == CMD_READ || cmd == CMD_WRITE)
- {
- if (len == 2u)
- {
- HandleReportSingle(frame[4], frame[5]);
- }
- }
- }
- /* 释放缓冲区 */
- g_rxReadIdx = (g_rxReadIdx + 1u) % RX_QUEUE_SIZE;
- __disable_irq();
- g_frameCount--;
- __enable_irq();
- }
- /* ========== 发送函数 ========== */
- /**
- * @brief 直接寄存器操作发送单字节 (绕过 HAL, 避免 HAL 锁/超时关中断)
- * 在等待 TXE 时顺带清除接收端可能发生的 ORE 错误
- */
- static void UART_DirectSendByte(uint8_t byte)
- {
- uint32_t timeout = 0u;
- while (!(USART2->SR & USART_SR_TXE))
- {
- if (++timeout > 100000u) return; /* 安全超时, 不关中断直接返回 */
- /* 等待期间检查并清除 ORE (读 SR 再读 DR 清除) */
- if (USART2->SR & USART_SR_ORE)
- {
- (void)USART2->DR;
- }
- }
- USART2->DR = byte;
- }
- static void UART_SendFrame(uint8_t cmd, uint8_t item, uint8_t value)
- {
- uint8_t len = 0x02u;
- uint8_t crc = (uint8_t)(cmd ^ len ^ item ^ value);
- g_txBuf[0] = FRAME_HEADER1;
- g_txBuf[1] = FRAME_HEADER2;
- g_txBuf[2] = cmd;
- g_txBuf[3] = len;
- g_txBuf[4] = item;
- g_txBuf[5] = value;
- g_txBuf[6] = crc;
- for (uint8_t i = 0; i < 7u; i++)
- {
- UART_DirectSendByte(g_txBuf[i]);
- }
- /* 等待最后一个字节发送完毕 (TC) */
- uint32_t timeout = 0u;
- while (!(USART2->SR & USART_SR_TC))
- {
- if (++timeout > 100000u) break;
- }
- }
- static void UART_SendWrite(uint8_t item, uint8_t value)
- {
- UART_SendFrame(CMD_WRITE, item, value);
- }
- void SendSetInputSrc(uint8_t src)
- {
- UART_SendWrite(ITEM_INPUT_SRC, src);
- }
- void SendSetVolLR(uint8_t pct)
- {
- if (pct > 100u) pct = 100u;
- UART_SendWrite(ITEM_VOL_LR, pct);
- }
- void SendSetVolBass(uint8_t pct)
- {
- if (pct > 100u) pct = 100u;
- UART_SendWrite(ITEM_VOL_BASS, pct);
- }
- void SendSetDacMute(uint8_t unmute)
- {
- UART_SendWrite(ITEM_DAC_MUTE, unmute);
- }
- void SendBTDisconnect(void)
- {
- UART_SendWrite(ITEM_BT_CONN, 0x00u);
- }
- void SendSoftReset(void)
- {
- UART_SendWrite(ITEM_SOFT_RESET, 0x00u);
- }
- void SendBassMute(void)
- {
- UART_SendWrite(ITEM_BASS_MUTE, 0x00u);
- }
- void SendQueryAll(void)
- {
- UART_SendFrame(CMD_READ, ITEM_QUERY_ALL, 0x00u);
- }
- /* ========== 上报处理 (私有) ========== */
- /**
- * @brief 处理单条变化上报 (AA 81 ITEM VALUE CRC)
- */
- static void HandleReportSingle(uint8_t item, uint8_t value)
- {
- uint8_t firstTime = !g_dataReceived;
- if (firstTime)
- {
- g_dataReceived = 1u;
- }
- switch (item)
- {
- case ITEM_INPUT_SRC:
- g_inputSource = value;
- g_sourceReceived = 1u;
- UpdateSourceLED();
- break;
- case ITEM_BT_CONN:
- g_btConnState = value;
- g_sourceReceived = 1u;
- UpdateSourceLED();
- break;
- case ITEM_BT_AUDIO:
- g_audioPlaying = value;
- g_sourceReceived = 1u;
- UpdateSourceLED();
- break;
- case ITEM_BATTERY:
- g_batteryPct = value;
- g_batteryReceived = 1u;
- UpdateBatteryLEDs();
- break;
- case ITEM_CHG_FULL:
- g_chgFull = value;
- g_batteryReceived = 1u;
- UpdateBatteryLEDs();
- break;
- case ITEM_CHG_ING:
- g_chgIng = value;
- g_batteryReceived = 1u;
- UpdateBatteryLEDs();
- break;
- case ITEM_DAC_MUTE:
- g_dacMute = value;
- break;
- case ITEM_VOL_LR:
- if (!g_userActive)
- {
- g_volLRLevel = (int16_t)value;
- }
- g_volLRReceived = 1u;
- UpdateVolumeLEDs();
- break;
- case ITEM_VOL_BASS:
- if (!g_userActive)
- {
- g_volBassLevel = (int16_t)value;
- }
- g_volBassReceived = 1u;
- UpdateVolumeLEDs();
- break;
- default:
- break;
- }
- /* 第一次收到数据但不是完整的合并上报, 触发查询获取全部状态 */
- if (firstTime)
- {
- SendQueryAll();
- }
- }
- /**
- * @brief 处理多条上报 (AA 81 COUNT ITEM1 VAL1 ITEM2 VAL2 ... CRC)
- */
- static void HandleReportAll(uint8_t *data, uint8_t count)
- {
- if (!g_dataReceived)
- {
- g_dataReceived = 1u;
- }
- /* 解析每一对 ITEM+VALUE */
- for (uint8_t i = 0; i < count; i++)
- {
- uint8_t idx = (uint8_t)(i * 2u);
- uint8_t item = data[idx];
- uint8_t value = data[idx + 1u];
- switch (item)
- {
- case ITEM_INPUT_SRC:
- g_inputSource = value;
- g_sourceReceived = 1u;
- break;
- case ITEM_BT_CONN:
- g_btConnState = value;
- g_sourceReceived = 1u;
- break;
- case ITEM_BT_AUDIO:
- g_audioPlaying = value;
- g_sourceReceived = 1u;
- break;
- case ITEM_DAC_MUTE:
- g_dacMute = value;
- break;
- case ITEM_VOL_LR:
- if (!g_userActive)
- {
- g_volLRLevel = (int16_t)value;
- }
- g_volLRReceived = 1u;
- break;
- case ITEM_VOL_BASS:
- if (!g_userActive)
- {
- g_volBassLevel = (int16_t)value;
- }
- g_volBassReceived = 1u;
- break;
- case ITEM_BATTERY:
- g_batteryPct = value;
- g_batteryReceived = 1u;
- break;
- case ITEM_CHG_FULL:
- g_chgFull = value;
- g_batteryReceived = 1u;
- break;
- case ITEM_CHG_ING:
- g_chgIng = value;
- g_batteryReceived = 1u;
- break;
- default: break;
- }
- }
- /* 收到全量状态后,统一刷新所有 LED 显示,实现无缝切换 */
- UpdateVolumeLEDs();
- UpdateSourceLED();
- UpdateBatteryLEDs();
- }
|