Files
flyLink/protocol/protocol.h
flowerstonezl 056289625c init
2026-01-19 17:08:49 +08:00

145 lines
4.5 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
* @file protocol.h
* @brief SkyLink 多平台实时视频传输 - 公共协议定义
*
* 这个文件定义了机载端ROS 2、PC 端Qt和移动端Android之间的通信协议。
* 必须保持三端的字节对齐和字段顺序一致。
*
* @author SkyLink Team
* @date 2026-01-19
*/
#pragma once
#include <cstdint>
#include <cstring>
/**
* @brief 强制1字节对齐避免编译器补齐导致的大小差异
*/
#pragma pack(push, 1)
/**
* @struct PacketHeader
* @brief UDP 数据包头部结构
*
* 总大小: 50 字节
* - 报头识别: 2 字节 (Magic)
* - 帧标识: 4 字节 (FrameID)
* - 分片信息: 4 字节 (TotalChunks + ChunkIndex)
* - 数据长度: 2 字节 (DataLen)
* - 时间戳: 8 字节 (Timestamp)
* - GPS 位置: 24 字节 (Lat, Lon, Alt)
* - 预留: 6 字节 (Reserve 用于将来扩展)
*/
struct PacketHeader {
// ============ 包头识别 ============
uint16_t magic; ///< 魔数 0xAA55 用于识别合法数据包
// ============ 帧标识 ============
uint32_t frame_id; ///< 唯一的帧编号,从 0 开始递增,用于帧同步
// ============ 分片信息 ============
uint16_t total_chunks; ///< 该帧总共被分成多少个 UDP 包
uint16_t chunk_index; ///< 当前数据包是第几个分片 (0-based)
// ============ 载荷信息 ============
uint16_t data_len; ///< 当前包的有效载荷长度(单位:字节)
// ============ 时间戳 ============
double timestamp; ///< GPS 时间戳 (秒数Unix 时间 或 ROS 时间)
// ============ GPS 位置数据 ============
double lat; ///< 纬度 (WGS84 坐标系)
double lon; ///< 经度 (WGS84 坐标系)
double alt; ///< 海拔高度 (米)
// ============ 校验与预留 ============
uint16_t crc16; ///< CRC16 校验码 (可选,当前未使用)
uint32_t reserve; ///< 保留字段,用于将来的扩展
/**
* @brief 获取包头大小(字节数)
* @return 包头固定大小50 字节
*/
static constexpr uint16_t size() {
return sizeof(PacketHeader);
}
};
/**
* @brief 恢复默认的对齐方式
*/
#pragma pack(pop)
// ============================================================================
// 协议常量定义
// ============================================================================
/** @brief 数据包魔数,用于识别合法的 SkyLink 数据包 */
constexpr uint16_t SKYLINK_MAGIC = 0xAA55;
/** @brief 最大的单个 UDP 包大小 (包含报头) - MTU 1500 字节 */
constexpr uint16_t MAX_UDP_PACKET_SIZE = 1472; // 1500 - 20 (IP) - 8 (UDP)
/** @brief 最大的载荷大小 */
constexpr uint16_t MAX_PAYLOAD_SIZE = MAX_UDP_PACKET_SIZE - PacketHeader::size();
/** @brief UDP 接收缓冲区大小 */
constexpr uint32_t RX_BUFFER_SIZE = 65536;
/** @brief 最大支持的分片数 */
constexpr uint16_t MAX_CHUNKS = 1000;
/** @brief 帧超时时间(毫秒),超过此时间的分片将被丢弃 */
constexpr uint32_t FRAME_TIMEOUT_MS = 5000;
// ============================================================================
// 图像编码相关常量
// ============================================================================
/** @brief JPEG 图像格式 ID */
constexpr uint8_t IMAGE_FORMAT_JPEG = 0x01;
/** @brief JPEG 最大压缩质量 */
constexpr uint8_t JPEG_MAX_QUALITY = 100;
/** @brief JPEG 最小压缩质量 */
constexpr uint8_t JPEG_MIN_QUALITY = 10;
// ============================================================================
// 辅助函数
// ============================================================================
/**
* @brief 验证包头魔数是否合法
* @param header 待验证的包头结构
* @return 如果魔数为 0xAA55 返回 true否则返回 false
*/
inline bool isValidPacket(const PacketHeader& header) {
return header.magic == SKYLINK_MAGIC;
}
/**
* @brief 计算 CRC16 校验码 (可选)
* @param data 数据指针
* @param len 数据长度
* @return 16 位 CRC 校验结果
*/
inline uint16_t crc16_ccitt(const uint8_t* data, uint16_t len) {
uint16_t crc = 0xFFFF;
for (uint16_t i = 0; i < len; i++) {
crc ^= (uint16_t)data[i] << 8;
for (int j = 0; j < 8; j++) {
if (crc & 0x8000) {
crc = (crc << 1) ^ 0x1021;
} else {
crc = crc << 1;
}
crc &= 0xFFFF;
}
}
return crc;
}