2026-08-27 调试完成版本
- FC 控制指令域修正:payload 14→18 字节,纵倾/横倾姿态拆分为数据1/数据2 - WebServer 广播改为待发队列模式,修复 mongoose 跨线程调用问题 - build-board.sh 增加板卡组网说明(/23 掩码方案)、pCCU 服务部署与 mission 同步 - 同步 0824 协议文档更新
This commit is contained in:
@@ -12,24 +12,45 @@ void registerFcMessages(MessageRegistry& reg) {
|
||||
|
||||
//============================================================================
|
||||
// 0x0001 控制指令域编解码
|
||||
// 数据域 14 字节,偏移 0~13(对应文档字节 7~20)
|
||||
// 数据域 18 字节(字节7~24),偏移 0~17;整包 24 字节
|
||||
//============================================================================
|
||||
|
||||
namespace {
|
||||
// 数据域内偏移(相对数据域起点,offset = 文档字节号 - 7)
|
||||
enum : size_t {
|
||||
CO_MODE = 0, // 模式设定 (字节7)
|
||||
CO_CMD = 1, // 操控指令 (字节8)
|
||||
CO_OUT_POWER = 2, // 输出功率指令 (字节9)
|
||||
CO_PITCH1 = 3, // 纵倾姿态数据1 int16 (字节10,11)
|
||||
CO_PITCH2 = 5, // 纵倾姿态数据2 int16 (字节12,13)
|
||||
CO_ROLL1 = 7, // 横倾姿态数据1 int16 (字节14,15)
|
||||
CO_ROLL2 = 9, // 横倾姿态数据2 int16 (字节16,17)
|
||||
CO_EMER_ALLOW = 11, // 应急允许 (字节18)
|
||||
CO_DEPTH = 12, // 潜深深度 u16 (字节19,20)
|
||||
CO_SUPPLY_CMD = 14, // 补给/排放指令 (字节21)
|
||||
CO_RESERVED5 = 15, // 预留指令5 (字节22)
|
||||
CO_RESERVED6 = 16, // 预留指令6 (字节23)
|
||||
CO_HEARTBEAT = 17, // 通信心跳 (字节24)
|
||||
};
|
||||
} // namespace
|
||||
|
||||
std::vector<uint8_t> FcControlMessage::encode(const void* obj) const {
|
||||
const FcControlValue* v = static_cast<const FcControlValue*>(obj);
|
||||
std::vector<uint8_t> payload(payloadLength(), 0);
|
||||
|
||||
FieldCodec::putU8(payload, 0, v->mode);
|
||||
FieldCodec::putU8(payload, 1, v->cmd);
|
||||
FieldCodec::putU8(payload, 2, v->outputPower);
|
||||
FieldCodec::putU16(payload, 3, static_cast<uint16_t>(v->pitch)); // 数据1=低位 / 数据2=高位
|
||||
FieldCodec::putU16(payload, 5, static_cast<uint16_t>(v->roll));
|
||||
FieldCodec::putU8(payload, 7, v->emergencyAllow);
|
||||
FieldCodec::putU16(payload, 8, v->depth);
|
||||
FieldCodec::putU8(payload, 10, v->supplyCmd);
|
||||
FieldCodec::putU8(payload, 11, v->reservedCmd5);
|
||||
FieldCodec::putU8(payload, 12, v->reservedCmd6);
|
||||
FieldCodec::putU8(payload, 13, v->heartbeat);
|
||||
FieldCodec::putU8(payload, CO_MODE, v->mode);
|
||||
FieldCodec::putU8(payload, CO_CMD, v->cmd);
|
||||
FieldCodec::putU8(payload, CO_OUT_POWER, v->outputPower);
|
||||
FieldCodec::putU16(payload, CO_PITCH1, static_cast<uint16_t>(v->pitch1));
|
||||
FieldCodec::putU16(payload, CO_PITCH2, static_cast<uint16_t>(v->pitch2));
|
||||
FieldCodec::putU16(payload, CO_ROLL1, static_cast<uint16_t>(v->roll1));
|
||||
FieldCodec::putU16(payload, CO_ROLL2, static_cast<uint16_t>(v->roll2));
|
||||
FieldCodec::putU8(payload, CO_EMER_ALLOW, v->emergencyAllow);
|
||||
FieldCodec::putU16(payload, CO_DEPTH, v->depth);
|
||||
FieldCodec::putU8(payload, CO_SUPPLY_CMD, v->supplyCmd);
|
||||
FieldCodec::putU8(payload, CO_RESERVED5, v->reservedCmd5);
|
||||
FieldCodec::putU8(payload, CO_RESERVED6, v->reservedCmd6);
|
||||
FieldCodec::putU8(payload, CO_HEARTBEAT, v->heartbeat);
|
||||
|
||||
return Frame::build(id(), payload, checksum());
|
||||
}
|
||||
@@ -39,17 +60,19 @@ bool FcControlMessage::decode(const std::vector<uint8_t>& frame, void* obj) cons
|
||||
FcControlValue* v = static_cast<FcControlValue*>(obj);
|
||||
|
||||
size_t o = FRAME_HEADER_LEN; // 数据域起点
|
||||
v->mode = FieldCodec::getU8(frame, o + 0);
|
||||
v->cmd = FieldCodec::getU8(frame, o + 1);
|
||||
v->outputPower = FieldCodec::getU8(frame, o + 2);
|
||||
v->pitch = static_cast<int16_t>(FieldCodec::getU16(frame, o + 3));
|
||||
v->roll = static_cast<int16_t>(FieldCodec::getU16(frame, o + 5));
|
||||
v->emergencyAllow = FieldCodec::getU8(frame, o + 7);
|
||||
v->depth = FieldCodec::getU16(frame, o + 8);
|
||||
v->supplyCmd = FieldCodec::getU8(frame, o + 10);
|
||||
v->reservedCmd5 = FieldCodec::getU8(frame, o + 11);
|
||||
v->reservedCmd6 = FieldCodec::getU8(frame, o + 12);
|
||||
v->heartbeat = FieldCodec::getU8(frame, o + 13);
|
||||
v->mode = FieldCodec::getU8(frame, o + CO_MODE);
|
||||
v->cmd = FieldCodec::getU8(frame, o + CO_CMD);
|
||||
v->outputPower = FieldCodec::getU8(frame, o + CO_OUT_POWER);
|
||||
v->pitch1 = static_cast<int16_t>(FieldCodec::getU16(frame, o + CO_PITCH1));
|
||||
v->pitch2 = static_cast<int16_t>(FieldCodec::getU16(frame, o + CO_PITCH2));
|
||||
v->roll1 = static_cast<int16_t>(FieldCodec::getU16(frame, o + CO_ROLL1));
|
||||
v->roll2 = static_cast<int16_t>(FieldCodec::getU16(frame, o + CO_ROLL2));
|
||||
v->emergencyAllow = FieldCodec::getU8(frame, o + CO_EMER_ALLOW);
|
||||
v->depth = FieldCodec::getU16(frame, o + CO_DEPTH);
|
||||
v->supplyCmd = FieldCodec::getU8(frame, o + CO_SUPPLY_CMD);
|
||||
v->reservedCmd5 = FieldCodec::getU8(frame, o + CO_RESERVED5);
|
||||
v->reservedCmd6 = FieldCodec::getU8(frame, o + CO_RESERVED6);
|
||||
v->heartbeat = FieldCodec::getU8(frame, o + CO_HEARTBEAT);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -28,14 +28,16 @@ struct FcControlValue {
|
||||
uint8_t mode = 0; // 模式设定 00~03
|
||||
uint8_t cmd = 0; // 操控指令 00~0B
|
||||
uint8_t outputPower = 0; // 输出功率指令 0~250,分辨率0.1kW
|
||||
int16_t pitch = 0; // 纵倾姿态(数据1=低8位 / 数据2=高8位,int16),分辨率0.1°
|
||||
int16_t roll = 0; // 横倾姿态(数据1=低8位 / 数据2=高8位,int16),分辨率0.1°
|
||||
uint8_t emergencyAllow = 0; // 应急允许:Bit0 允许降载 / Bit1 允许排气
|
||||
uint16_t depth = 0; // 潜深深度,单位 m
|
||||
uint8_t supplyCmd = 0; // 补给/排放指令 00~0B
|
||||
uint8_t reservedCmd5 = 0; // 预留指令5
|
||||
uint8_t reservedCmd6 = 0; // 预留指令6
|
||||
uint8_t heartbeat = 0; // 通信心跳,每次+1
|
||||
int16_t pitch1 = 0; // 纵倾姿态数据1 int16,分辨率0.1°(字节10,11)
|
||||
int16_t pitch2 = 0; // 纵倾姿态数据2 int16,分辨率0.1°(字节12,13)
|
||||
int16_t roll1 = 0; // 横倾姿态数据1 int16,分辨率0.1°(字节14,15)
|
||||
int16_t roll2 = 0; // 横倾姿态数据2 int16,分辨率0.1°(字节16,17)
|
||||
uint8_t emergencyAllow = 0; // 应急允许:Bit0 允许降载 / Bit1 允许排气(字节18)
|
||||
uint16_t depth = 0; // 潜深深度,单位 m(字节19,20)
|
||||
uint8_t supplyCmd = 0; // 补给/排放指令 00~0B(字节21)
|
||||
uint8_t reservedCmd5 = 0; // 预留指令5(字节22)
|
||||
uint8_t reservedCmd6 = 0; // 预留指令6(字节23)
|
||||
uint8_t heartbeat = 0; // 通信心跳,每次+1(字节24)
|
||||
};
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
@@ -132,7 +134,8 @@ public:
|
||||
uint16_t id() const override { return 0x0001; }
|
||||
const char* name() const override { return "fc_control"; }
|
||||
const ChecksumPolicy& checksum() const override { return m_checksum; }
|
||||
size_t payloadLength() const override { return 14; }
|
||||
// 1.1.1 控制指令域:数据域 18 字节(字节7~24),整包 24 字节(域字节数 0x0018)
|
||||
size_t payloadLength() const override { return 18; }
|
||||
|
||||
std::vector<uint8_t> encode(const void* obj) const override;
|
||||
bool decode(const std::vector<uint8_t>& frame, void* obj) const override;
|
||||
|
||||
@@ -12,7 +12,9 @@ bool Message::validateFrame(const std::vector<uint8_t>& frame,
|
||||
FrameHeader h;
|
||||
if (!Frame::parseHeader(frame, h)) return false;
|
||||
if (h.id != expectId) return false;
|
||||
if (h.length != expectTotalLen) return false;
|
||||
// 协议规定域字节数=整个包长度;联调发现 FC 设备该字段填 120 而非 150,
|
||||
// 与文档不符但不影响数据域布局,若实际包体足够容纳数据域则放行
|
||||
if (h.length != expectTotalLen && frame.size() < expectTotalLen) return false;
|
||||
|
||||
// 校验和(长度不足由 verify 内部判断)
|
||||
if (!policy.verify(frame)) return false;
|
||||
|
||||
Reference in New Issue
Block a user