Files
flyLink/protocol/protocol.h

175 lines
5.6 KiB
C
Raw Normal View History

2026-01-19 17:08:49 +08:00
/**
* @file protocol.h
* @brief SkyLink -
*
* ROS 2PC QtAndroid
*
*
2026-01-20 10:41:22 +08:00
* @author flowzl
2026-01-19 17:08:49 +08:00
* @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);
}
};
2026-01-21 13:44:29 +08:00
/**
* @brief UDP 10000
*
*
*/
struct DeviceInfoPacket {
uint16_t magic; ///< 魔数 0xAA56
uint32_t sequence; ///< 序列号
uint16_t width; ///< 图像宽度
uint16_t height; ///< 图像高度
float framerate; ///< 帧率
uint32_t pixel_format; ///< 像素格式V4L2 FourCC
char device_path[32]; ///< 设备路径(/dev/videoX
char device_name[64]; ///< 设备名称
float current_fps; ///< 当前实际 FPS
uint32_t total_frames; ///< 总帧数
uint64_t timestamp; ///< 时间戳(毫秒)
uint16_t crc16; ///< CRC 校验(可选)
static constexpr uint16_t size() {
return sizeof(DeviceInfoPacket);
}
};
2026-01-19 17:08:49 +08:00
/**
* @brief
*/
#pragma pack(pop)
// ============================================================================
// 协议常量定义
// ============================================================================
/** @brief 数据包魔数,用于识别合法的 SkyLink 数据包 */
constexpr uint16_t SKYLINK_MAGIC = 0xAA55;
2026-01-21 13:44:29 +08:00
/** @brief 设备信息魔数,用于识别设备信息数据包 */
constexpr uint16_t DEVICE_INFO_MAGIC = 0xAA56;
/** @brief 设备信息请求魔数,用于请求立即发送设备信息 */
constexpr uint16_t DEVICE_INFO_REQUEST = 0xAA57;
2026-01-19 17:08:49 +08:00
/** @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;
}