/* Includes ----------------------------------------------------------------- */ #include "vt13.h" #include "bsp/uart.h" #include "bsp/time.h" #include "device.h" #include "crc16.h" #include #include /* -------------------------------------------------------- 串口参数 数值 波特率 921600 数据位 8 停止位 1 校验位 无 流控 无 -------------------------------------------------------- */ /* Private variables -------------------------------------------------------- */ static osThreadId_t thread_alert; static bool inited = false; /* Private macro ------------------------------------------------------------ */ /* Private function -------------------------------------------------------- */ static void VT13_RxCpltCallback(void) { osThreadFlagsSet(thread_alert, SIGNAL_VT13_RAW_REDY); } static bool VT13_DataCorrupted(const VT13_t *vt13) { /* 1. 帧头校验:必须为 0xA9 和 0x53 */ if (vt13->raw_data.header1 != 0xA9 || vt13->raw_data.header2 != 0x53) { return true; } /* 2. CRC16 校验:验证整个 21 字节的帧长度 */ if (!CRC16_Verify((const uint8_t *)&(vt13->raw_data), sizeof(VT13_RawData_t))) { return true; } /* 3. 挡位范围校验(作为双重保险,因为 CRC 只能保证通信无误,不能保证按键逻辑无误) */ if (vt13->raw_data.mode > 2) { return true; } return false; } /* Exported functions ------------------------------------------------------- */ int8_t VT13_Init(VT13_t *vt13) { if (vt13 == NULL) return DEVICE_ERR_NULL; if (inited) return DEVICE_ERR_INITED; if ((thread_alert = osThreadGetId()) == NULL) return DEVICE_ERR_NULL; /* 注意:图传模块波特率为 921600 ,请在 UART 初始化时核对 */ BSP_UART_RegisterCallback(BSP_UART_VT13, BSP_UART_RX_CPLT_CB, VT13_RxCpltCallback); inited = true; return DEVICE_OK; } int8_t VT13_Restart(void) { __HAL_UART_DISABLE(BSP_UART_GetHandle(BSP_UART_VT13)); __HAL_UART_ENABLE(BSP_UART_GetHandle(BSP_UART_VT13)); return DEVICE_OK; } int8_t VT13_StartDmaRecv(VT13_t *vt13) { if (HAL_UART_Receive_DMA(BSP_UART_GetHandle(BSP_UART_VT13), (uint8_t *)&(vt13->raw_data), sizeof(vt13->raw_data)) == HAL_OK) return DEVICE_OK; return DEVICE_ERR; } bool VT13_WaitDmaCplt(uint32_t timeout) { return (osThreadFlagsWait(SIGNAL_VT13_RAW_REDY, osFlagsWaitAll, timeout) == SIGNAL_VT13_RAW_REDY); } int8_t VT13_ParseData(VT13_t *vt13) { if (vt13 == NULL) return DEVICE_ERR_NULL; if (VT13_DataCorrupted(vt13)) { return DEVICE_ERR; } vt13->header.online = true; vt13->header.last_online_time = BSP_TIME_Get_us(); memset(&(vt13->data), 0, sizeof(vt13->data)); float full_range = (float)(VT13_CH_VALUE_MAX - VT13_CH_VALUE_MIN); /* 1. 解析摇杆与拨轮数据并归一化至 [-1.0, 1.0] */ vt13->data.ch_r_x = 2.0f * ((float)vt13->raw_data.ch_r_x - VT13_CH_VALUE_MID) / full_range; vt13->data.ch_r_y = 2.0f * ((float)vt13->raw_data.ch_r_y - VT13_CH_VALUE_MID) / full_range; vt13->data.ch_l_y = 2.0f * ((float)vt13->raw_data.ch_l_y - VT13_CH_VALUE_MID) / full_range; vt13->data.ch_l_x = 2.0f * ((float)vt13->raw_data.ch_l_x - VT13_CH_VALUE_MID) / full_range; vt13->data.dial = 2.0f * ((float)vt13->raw_data.dial - VT13_CH_VALUE_MID) / full_range; /* 2. 解析按钮和开关 [cite: 165] */ vt13->data.mode = (VT13_Mode_t)vt13->raw_data.mode; vt13->data.pause = vt13->raw_data.pause; vt13->data.custom_l = vt13->raw_data.custom_l; vt13->data.custom_r = vt13->raw_data.custom_r; vt13->data.trigger = vt13->raw_data.trigger; /* 3. 解析鼠标数据 */ vt13->data.mouse.x = vt13->raw_data.mouse_x; vt13->data.mouse.y = vt13->raw_data.mouse_y; vt13->data.mouse.z = vt13->raw_data.mouse_z; vt13->data.mouse.l_click = vt13->raw_data.mouse_l; vt13->data.mouse.r_click = vt13->raw_data.mouse_r; vt13->data.mouse.m_click = vt13->raw_data.mouse_m; /* 4. 解析键盘按键 */ uint16_t key_value = vt13->raw_data.keyboard; for (int i = 0; i < VT13_KEY_NUM; i++) { vt13->data.keyboard.key[i] = (key_value & (1 << i)) != 0; } return DEVICE_OK; } int8_t VT13_Offline(VT13_t *vt13) { if (vt13 == NULL) return DEVICE_ERR_NULL; vt13->header.online = false; memset(&(vt13->data), 0, sizeof(vt13->data)); return DEVICE_OK; }