chore: 导入 Simba-OmniInfantry 基线(云台/底盘双工程)
- 云台(ROBOT_TYPE_GIMBAL)与底盘(ROBOT_TYPE_CHASSIS)完整固件源码 - 新增根级 .gitignore,排除 Keil MDK-ARM 构建产物(.o/.d/.crf/.axf/.lnp/.map/.htm/.sct/.dep/.iex/.lst 等) 与 *.uvguix.* / DebugConfig/(与机器绑定的 UI 布局) - core.autocrlf=false,避免固件源码在检出时被改动换行符
This commit is contained in:
@@ -0,0 +1,218 @@
|
||||
/* =============================================================================
|
||||
* referee.c - 裁判系统协议解析(0x0201 机器人状态 / 0x0202 实时功率 /
|
||||
* 0x0304 自定义控制器键鼠)
|
||||
* 输入: referee_parse_byte() 流式喂字节(USART6 整帧回调里循环调用)
|
||||
* 校验: CRC8(多项式0x31,初值0xFF) / CRC16(0x1021,0xFFFF),位运算实现,
|
||||
* 与 legacy 查表算法等价
|
||||
* 字段偏移与 legacy 逐一对应:
|
||||
* 0x0201: data[0]=robot_id, data[10..11]=功率上限, data[12]&0x04=发射机构上电
|
||||
* 0x0202: data[4..7]=实时功率(float), data[8..9]=缓冲能量(J)
|
||||
* 0x0304: 12 字节键鼠数据 -> keyboard 钩子(仅云台板注册)
|
||||
* 解析在接收中断内完成,任务层只读 referee_data_t 全局量
|
||||
* ========================================================================== */
|
||||
#include "referee.h"
|
||||
#include "main.h"
|
||||
|
||||
/* 帧结构: SOF(1) data_len(2) seq(1) CRC8(1) | cmd_id(2) data(n) CRC16(2)
|
||||
* 校验算法与 DJI 裁判系统协议一致:
|
||||
* CRC8 多项式 0x31,初值 0xFF,输入输出不反转
|
||||
* CRC16 多项式 0x1021,初值 0xFFFF,输入输出不反转 */
|
||||
|
||||
#define REF_FRAME_MAX_LEN 160
|
||||
|
||||
static uint8_t crc8_update(uint8_t crc, uint8_t data)
|
||||
{
|
||||
crc ^= data;
|
||||
for (uint8_t i = 0; i < 8; i++)
|
||||
crc = (crc & 0x80) ? (uint8_t)((crc << 1) ^ 0x31) : (uint8_t)(crc << 1);
|
||||
return crc;
|
||||
}
|
||||
|
||||
static uint16_t crc16_update(uint16_t crc, uint8_t data)
|
||||
{
|
||||
crc ^= (uint16_t)data << 8;
|
||||
for (uint8_t i = 0; i < 8; i++)
|
||||
crc = (crc & 0x8000) ? (uint16_t)((crc << 1) ^ 0x1021) : (uint16_t)(crc << 1);
|
||||
return crc;
|
||||
}
|
||||
|
||||
static uint8_t verify_crc8(const uint8_t * data, uint16_t len)
|
||||
{
|
||||
uint8_t crc = 0xFF;
|
||||
for (uint16_t i = 0; i < len - 1; i++)
|
||||
crc = crc8_update(crc, data[i]);
|
||||
return crc == data[len - 1];
|
||||
}
|
||||
|
||||
static uint8_t verify_crc16(const uint8_t * data, uint16_t len)
|
||||
{
|
||||
uint16_t crc = 0xFFFF;
|
||||
for (uint16_t i = 0; i < len - 2; i++)
|
||||
crc = crc16_update(crc, data[i]);
|
||||
return (uint8_t)(crc & 0xFF) == data[len - 2] && (uint8_t)(crc >> 8) == data[len - 1];
|
||||
}
|
||||
|
||||
referee_data_t referee = {
|
||||
.robot_id = 0,
|
||||
.shooter_power_on = 1,
|
||||
.chassis_power_limit = 60,
|
||||
.chassis_power = 0,
|
||||
.buffer_energy = 60.0f,
|
||||
.link_status = 0,
|
||||
.last_update_tick = 0,
|
||||
};
|
||||
|
||||
static referee_keyboard_hook_f keyboard_hook = NULL;
|
||||
|
||||
void referee_set_keyboard_hook(referee_keyboard_hook_f hook)
|
||||
{
|
||||
keyboard_hook = hook;
|
||||
}
|
||||
|
||||
/* 解析状态机 */
|
||||
typedef enum
|
||||
{
|
||||
REF_STATE_SOF = 0,
|
||||
REF_STATE_LEN_LOW,
|
||||
REF_STATE_LEN_HIGH,
|
||||
REF_STATE_SEQ,
|
||||
REF_STATE_HEADER_CRC8,
|
||||
REF_STATE_CMD_LOW,
|
||||
REF_STATE_CMD_HIGH,
|
||||
REF_STATE_DATA,
|
||||
REF_STATE_CRC16_LOW,
|
||||
REF_STATE_CRC16_HIGH,
|
||||
} ref_state_e;
|
||||
|
||||
static ref_state_e ref_state = REF_STATE_SOF;
|
||||
static uint16_t ref_data_len = 0;
|
||||
static uint16_t ref_cmd_id = 0;
|
||||
static uint16_t ref_data_index = 0;
|
||||
static uint8_t ref_frame_buf[REF_FRAME_MAX_LEN];
|
||||
static uint16_t ref_frame_index = 0;
|
||||
|
||||
static void referee_dispatch(uint16_t cmd_id, const uint8_t * data, uint16_t len)
|
||||
{
|
||||
switch (cmd_id)
|
||||
{
|
||||
case 0x0201: // 机器人状态(与 legacy 偏移一致)
|
||||
if (len >= 13)
|
||||
{
|
||||
referee.robot_id = data[0];
|
||||
referee.chassis_power_limit = (uint16_t)(data[10] | (data[11] << 8));
|
||||
referee.shooter_power_on = (data[12] & 0x04) >> 2;
|
||||
referee.last_update_tick = HAL_GetTick();
|
||||
referee.link_status = 1;
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x0202: // 实时功率(与 legacy 偏移一致)
|
||||
if (len >= 10)
|
||||
{
|
||||
float power;
|
||||
memcpy(&power, &data[4], 4);
|
||||
referee.chassis_power = power;
|
||||
referee.buffer_energy = (float)((uint16_t)(data[8] | (data[9] << 8)));
|
||||
referee.last_update_tick = HAL_GetTick();
|
||||
referee.link_status = 1;
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x0304: // 自定义控制器(经图传链路转发)
|
||||
if (len >= 12 && keyboard_hook != NULL)
|
||||
keyboard_hook(data);
|
||||
referee.last_update_tick = HAL_GetTick();
|
||||
referee.link_status = 1;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void referee_parse_byte(uint8_t byte)
|
||||
{
|
||||
switch (ref_state)
|
||||
{
|
||||
case REF_STATE_SOF:
|
||||
if (byte == 0xA5)
|
||||
{
|
||||
ref_frame_index = 0;
|
||||
ref_frame_buf[ref_frame_index++] = byte;
|
||||
ref_state = REF_STATE_LEN_LOW;
|
||||
}
|
||||
break;
|
||||
|
||||
case REF_STATE_LEN_LOW:
|
||||
ref_data_len = byte;
|
||||
ref_frame_buf[ref_frame_index++] = byte;
|
||||
ref_state = REF_STATE_LEN_HIGH;
|
||||
break;
|
||||
|
||||
case REF_STATE_LEN_HIGH:
|
||||
ref_data_len |= (uint16_t)byte << 8;
|
||||
ref_frame_buf[ref_frame_index++] = byte;
|
||||
if (ref_data_len > REF_FRAME_MAX_LEN - 9) // 帧过长,重新找帧头
|
||||
ref_state = REF_STATE_SOF;
|
||||
else
|
||||
ref_state = REF_STATE_SEQ;
|
||||
break;
|
||||
|
||||
case REF_STATE_SEQ:
|
||||
ref_frame_buf[ref_frame_index++] = byte;
|
||||
ref_state = REF_STATE_HEADER_CRC8;
|
||||
break;
|
||||
|
||||
case REF_STATE_HEADER_CRC8:
|
||||
ref_frame_buf[ref_frame_index++] = byte;
|
||||
if (verify_crc8(ref_frame_buf, 5))
|
||||
ref_state = REF_STATE_CMD_LOW;
|
||||
else
|
||||
ref_state = REF_STATE_SOF;
|
||||
break;
|
||||
|
||||
case REF_STATE_CMD_LOW:
|
||||
ref_cmd_id = byte;
|
||||
ref_frame_buf[ref_frame_index++] = byte;
|
||||
ref_state = REF_STATE_CMD_HIGH;
|
||||
break;
|
||||
|
||||
case REF_STATE_CMD_HIGH:
|
||||
ref_cmd_id |= (uint16_t)byte << 8;
|
||||
ref_frame_buf[ref_frame_index++] = byte;
|
||||
ref_data_index = 0;
|
||||
if (ref_data_len == 0)
|
||||
ref_state = REF_STATE_CRC16_LOW;
|
||||
else
|
||||
ref_state = REF_STATE_DATA;
|
||||
break;
|
||||
|
||||
case REF_STATE_DATA:
|
||||
ref_frame_buf[ref_frame_index++] = byte;
|
||||
if (++ref_data_index >= ref_data_len)
|
||||
ref_state = REF_STATE_CRC16_LOW;
|
||||
break;
|
||||
|
||||
case REF_STATE_CRC16_LOW:
|
||||
ref_frame_buf[ref_frame_index++] = byte;
|
||||
ref_state = REF_STATE_CRC16_HIGH;
|
||||
break;
|
||||
|
||||
case REF_STATE_CRC16_HIGH:
|
||||
ref_frame_buf[ref_frame_index++] = byte;
|
||||
if (verify_crc16(ref_frame_buf, ref_frame_index))
|
||||
referee_dispatch(ref_cmd_id, &ref_frame_buf[7], ref_data_len);
|
||||
ref_state = REF_STATE_SOF;
|
||||
break;
|
||||
|
||||
default:
|
||||
ref_state = REF_STATE_SOF;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void referee_parse_bytes(const uint8_t * data, uint16_t len)
|
||||
{
|
||||
while (len--)
|
||||
referee_parse_byte(*data++);
|
||||
}
|
||||
Reference in New Issue
Block a user