新增复合管控器(pCCU) + 惯导数据解析 + 设备控制页增强 + 0824协议文档归档

- 新增 pCCU 复合管控器程序(src/pCCU):FC/PM 双链路(UDP)、协议编解码器
  (FcProtocol/PmProtocol/Frame/Message/MessageRegistry)、快照与落库(DbStore)、
  内置 WebServer;挂入 src/CMakeLists.txt 与板卡 mission(h100.moos)
- 惯导/深度数据:新增 uDevice_insData 消息解析,接入 UpperCommManager,
  pPowerMangerHost 注册监视,UpmsgTest 覆盖
- pPowerMangerHost 设备控制页增强(web/index.html)
- 部署/运维脚本改为 4 个 systemd 服务(moosdb/pPowerManger/pPowerMangerHost/pCCU):
  deploy/clean-data/fetch-data 同步适配
- 协议文档:归档 0824 控制主机与复合管控器通信协议 xlsx 及关联 docx,移除旧 md
- 测试:新增 pccu 单元/集成测试与 disSysTest Python 配电仿真
- 清理:移除未使用的 CCU 状态调试打印 coutMsg;.gitignore 补充编译产物/临时文件忽略
This commit is contained in:
zjk
2026-08-26 22:43:10 +08:00
parent e0488d513b
commit 54c32a180a
79 changed files with 8731 additions and 1398 deletions
+318
View File
@@ -0,0 +1,318 @@
#include "FcProtocol.h"
#include "FieldCodec.h"
#include "Frame.h"
#include "MessageRegistry.h"
namespace ccu {
void registerFcMessages(MessageRegistry& reg) {
reg.registerMessage(std::unique_ptr<Message>(new FcControlMessage()));
reg.registerMessage(std::unique_ptr<Message>(new FcStatusMessage()));
}
//============================================================================
// 0x0001 控制指令域编解码
// 数据域 14 字节,偏移 0~13(对应文档字节 7~20)
//============================================================================
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);
return Frame::build(id(), payload, checksum());
}
bool FcControlMessage::decode(const std::vector<uint8_t>& frame, void* obj) const {
if (!validateFrame(frame, id(), checksum(), totalLength())) return false;
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);
return true;
}
//============================================================================
// 0x0002 状态反馈域编解码
// 数据域 144 字节
//============================================================================
namespace {
// 数据域内各字段偏移(相对数据域起点,offset = 文档字节号 - 7)
// 注意:文档中"系统故障等级"为字节19(1字节),字节20为隐式保留位,
// "系统发电功率"从字节21(offset 14)开始,其后的字段均按此定位。
enum : size_t {
OFF_MODE = 0, // 运行模式 (字节7)
OFF_STATUS = 1, // 运行状态 (字节8)
OFF_FL1 = 2, // 一级故障码 u16 (字节9-10)
OFF_FL2 = 4, // 二级故障码 (字节11-12)
OFF_FL3 = 6, // 三级故障码 (字节13-14)
OFF_FL4 = 8, // 四级故障码 (字节15-16)
OFF_GEN_TIME = 10, // 累积发电时间 u16 (字节17-18)
OFF_FAULT_LEVEL = 12, // 系统故障等级 (字节19)
// 字节20 隐式保留(offset 13)
OFF_GEN_POWER = 14, // 系统发电功率 u16 (字节21-22)
OFF_H2_CAP = 16, // 储氢剩余容量 (字节23)
OFF_LO2_CAP = 17, // 液氧剩余容量 (字节24)
OFF_FC1_MIN_V = 18, // I#FC最低单片电压 (字节25)
OFF_FC1_MIN_POS = 19, // I#FC最低单片电压位置 (字节26)
OFF_FC1_AVG_V = 20, // I#FC平均单片电压 (字节27)
OFF_FC2_MIN_V = 21, // 2#FC最低单片电压 (字节28)
OFF_FC2_MIN_POS = 22, // 2#FC最低单片电压位置 (字节29)
OFF_FC2_AVG_V = 23, // 2#FC平均单片电压 (字节30)
OFF_PALLADIUM_TEMP = 24, // 钯膜最高温度 u16 (字节31-32)
OFF_BUFFER_PRES = 26, // 缓冲罐压力 (字节33-34)
OFF_FLUE_TOTAL = 28, // 烟气累计排放量 (字节35-36)
OFF_FLUE_PRES = 30, // 烟气压力 (字节37-38)
OFF_REACTOR_PRES = 32, // 反应器压力 (字节39-40)
OFF_EVALVE_OPEN = 34, // 电动阀开度 (字节41-42)
OFF_DCDC1_IN_V = 36, // DC/DC通道1输入电压 (字节43-44)
OFF_DCDC1_IN_I = 38, // DC/DC通道1输入电流 (字节45-46)
OFF_DCDC2_IN_V = 40, // DC/DC通道2输入电压 (字节47-48)
OFF_DCDC2_IN_I = 42, // DC/DC通道2输入电流 (字节49-50)
OFF_DCDC_OUT_V = 44, // DC/DC输出电压 (字节51-52)
OFF_DCDC_OUT_I = 46, // DC/DC输出电流 (字节53-54)
OFF_DCDC_CTRL_V = 48, // DC/DC控制电源电压 (字节55)
OFF_DCDC_AUX_V = 49, // DC/DC辅电输出电压 (字节56)
OFF_METHANOL_TOTAL = 50, // 甲醇累计使用量 u16 (字节57-58)
OFF_METHANOL_FEED = 52, // 甲醇溶液进料量 (字节59-60)
OFF_O2_WATER = 54, // 氧侧生成水箱液位 (字节61-62)
OFF_H2_WATER = 56, // 氢侧生成水箱液位 (字节63-64)
OFF_BALLAST_WATER = 58, // 配重水箱液位 (字节65-66)
OFF_EXH_IN_PRES = 60, // 尾气装置进气压力 (字节67-68)
OFF_EXH_OUT_PRES = 62, // 尾气装置排气压力 (字节69-70)
OFF_CABIN_P1 = 64, // 舱室压力1 (字节71-72)
OFF_CABIN_P2 = 66, // 舱室压力2 (字节73-74)
OFF_CABIN_T1 = 68, // 舱室温度1 (字节75-76)
OFF_CABIN_T2 = 70, // 舱室温度2 (字节77-78)
OFF_CABIN_H1 = 72, // 舱室湿度1 (字节79-80)
OFF_CABIN_H2 = 74, // 舱室湿度2 (字节81-82)
OFF_H2_C1 = 76, // 舱室H2浓度1 (字节83-84)
OFF_H2_C2 = 78, // 舱室H2浓度2 (字节85-86)
OFF_H2_C3 = 80, // 舱室H2浓度3 (字节87-88)
OFF_O2_C1 = 82, // 舱室O2浓度1 (字节89-90)
OFF_O2_C2 = 84, // 舱室O2浓度2 (字节91-92)
OFF_CH3OH_C1 = 86, // 舱室甲醇浓度1 (字节93-94)
OFF_CH3OH_C2 = 88, // 舱室甲醇浓度2 (字节95-96)
OFF_FLAME1 = 90, // 火焰探测器1 (字节97)
OFF_FLAME2 = 91, // 火焰探测器2 (字节98)
OFF_EMER_DEPTH = 92, // 应急上浮深度 u16 (字节99-100)
OFF_EMER_TIME = 94, // 应急上浮时间 (字节101-102)
OFF_EXH_FREQ = 96, // 尾气运行频率 (字节103-104)
OFF_EXH_IN_TEMP = 98, // 尾气进气温度 (字节105-106)
OFF_EXH_OUT_TEMP = 100, // 尾气排气温度 (字节107-108)
OFF_EXH_WIN_PRES = 102, // 尾气进水压力 (字节109-110)
OFF_EXH_WOUT_PRES = 104, // 尾气排水压力 (字节111-112)
OFF_TANK_LO2_PRES = 106, // 液氧罐压力 (字节113-114)
OFF_TANK_CO2_PRES = 108, // 二氧化碳压力 (字节115-116)
OFF_TANK_LO2_LEVEL = 110, // 液氧罐液位 (字节117-118)
OFF_ALLOY_H2_FLOW = 112, // 合金供氢流量 (字节119-120)
OFF_FC_H2_FLOW = 114, // FC供氢流量 (字节121-122)
OFF_FC_O2_FLOW = 116, // FC供氧流量 (字节123-124)
OFF_RESERVED = 118, // 预留1~12 u16*12 -> 118..141 (字节125-148)
OFF_HEARTBEAT = 142, // 通信心跳 (字节149)
OFF_EMERGENCY_CMD = 143, // 应急指令 (字节150)
};
inline void getU16Arr(const std::vector<uint8_t>& frame, size_t off, uint16_t* dst, size_t n) {
for (size_t i = 0; i < n; ++i) dst[i] = FieldCodec::getU16(frame, off + i * 2);
}
inline void putU16Arr(std::vector<uint8_t>& p, size_t off, const uint16_t* src, size_t n) {
for (size_t i = 0; i < n; ++i) FieldCodec::putU16(p, off + i * 2, src[i]);
}
} // namespace
std::vector<uint8_t> FcStatusMessage::encode(const void* obj) const {
const FcStatusValue* v = static_cast<const FcStatusValue*>(obj);
std::vector<uint8_t> p(payloadLength(), 0);
FieldCodec::putU8(p, OFF_MODE, v->fc_mode);
FieldCodec::putU8(p, OFF_STATUS, v->fc_status);
FieldCodec::putU16(p, OFF_FL1, v->fault_level_1);
FieldCodec::putU16(p, OFF_FL2, v->fault_level_2);
FieldCodec::putU16(p, OFF_FL3, v->fault_level_3);
FieldCodec::putU16(p, OFF_FL4, v->fault_level_4);
FieldCodec::putU16(p, OFF_GEN_TIME, v->total_generation_time);
FieldCodec::putU8(p, OFF_FAULT_LEVEL, v->fc_fault_level);
FieldCodec::putU16(p, OFF_GEN_POWER, v->generation_power);
FieldCodec::putU8(p, OFF_H2_CAP, v->hydrogen_capacity);
FieldCodec::putU8(p, OFF_LO2_CAP, v->liquid_oxygen_capacity);
FieldCodec::putU8(p, OFF_FC1_MIN_V, v->fc1_min_cell_voltage);
FieldCodec::putU8(p, OFF_FC1_MIN_POS, v->fc1_min_cell_pos);
FieldCodec::putU8(p, OFF_FC1_AVG_V, v->fc1_avg_cell_voltage);
FieldCodec::putU8(p, OFF_FC2_MIN_V, v->fc2_min_cell_voltage);
FieldCodec::putU8(p, OFF_FC2_MIN_POS, v->fc2_min_cell_pos);
FieldCodec::putU8(p, OFF_FC2_AVG_V, v->fc2_avg_cell_voltage);
FieldCodec::putU16(p, OFF_PALLADIUM_TEMP, v->palladium_temp);
FieldCodec::putU16(p, OFF_BUFFER_PRES, v->buffer_tank_pressure);
FieldCodec::putU16(p, OFF_FLUE_TOTAL, v->flue_total_emission);
FieldCodec::putU16(p, OFF_FLUE_PRES, v->flue_pressure);
FieldCodec::putU16(p, OFF_REACTOR_PRES, v->reactor_pressure);
FieldCodec::putU16(p, OFF_EVALVE_OPEN, v->electric_valve_open);
FieldCodec::putU16(p, OFF_DCDC1_IN_V, v->dcdc1_in_voltage);
FieldCodec::putU16(p, OFF_DCDC1_IN_I, v->dcdc1_in_current);
FieldCodec::putU16(p, OFF_DCDC2_IN_V, v->dcdc2_in_voltage);
FieldCodec::putU16(p, OFF_DCDC2_IN_I, v->dcdc2_in_current);
FieldCodec::putU16(p, OFF_DCDC_OUT_V, v->dcdc_out_voltage);
FieldCodec::putU16(p, OFF_DCDC_OUT_I, v->dcdc_out_current);
FieldCodec::putU8(p, OFF_DCDC_CTRL_V, v->dcdc_ctrl_voltage);
FieldCodec::putU8(p, OFF_DCDC_AUX_V, v->dcdc_aux_voltage);
FieldCodec::putU16(p, OFF_METHANOL_TOTAL, v->methanol_total_use);
FieldCodec::putU16(p, OFF_METHANOL_FEED, v->methanol_feed);
FieldCodec::putU16(p, OFF_O2_WATER, v->oxygen_side_water_level);
FieldCodec::putU16(p, OFF_H2_WATER, v->hydrogen_side_water_level);
FieldCodec::putU16(p, OFF_BALLAST_WATER, v->ballast_water_level);
FieldCodec::putU16(p, OFF_EXH_IN_PRES, v->exhaust_inlet_pressure);
FieldCodec::putU16(p, OFF_EXH_OUT_PRES, v->exhaust_outlet_pressure);
FieldCodec::putU16(p, OFF_CABIN_P1, v->cabin_pressure1);
FieldCodec::putU16(p, OFF_CABIN_P2, v->cabin_pressure2);
FieldCodec::putU16(p, OFF_CABIN_T1, v->cabin_temp1);
FieldCodec::putU16(p, OFF_CABIN_T2, v->cabin_temp2);
FieldCodec::putU16(p, OFF_CABIN_H1, v->cabin_humidity1);
FieldCodec::putU16(p, OFF_CABIN_H2, v->cabin_humidity2);
FieldCodec::putU16(p, OFF_H2_C1, v->h2_concentration1);
FieldCodec::putU16(p, OFF_H2_C2, v->h2_concentration2);
FieldCodec::putU16(p, OFF_H2_C3, v->h2_concentration3);
FieldCodec::putU16(p, OFF_O2_C1, v->o2_concentration1);
FieldCodec::putU16(p, OFF_O2_C2, v->o2_concentration2);
FieldCodec::putU16(p, OFF_CH3OH_C1, v->ch3oh_concentration1);
FieldCodec::putU16(p, OFF_CH3OH_C2, v->ch3oh_concentration2);
FieldCodec::putU8(p, OFF_FLAME1, v->flame_detector1);
FieldCodec::putU8(p, OFF_FLAME2, v->flame_detector2);
FieldCodec::putU16(p, OFF_EMER_DEPTH, v->emergency_float_depth);
FieldCodec::putU16(p, OFF_EMER_TIME, v->emergency_float_time);
FieldCodec::putU16(p, OFF_EXH_FREQ, v->exhaust_run_freq);
FieldCodec::putU16(p, OFF_EXH_IN_TEMP, v->exhaust_inlet_temp);
FieldCodec::putU16(p, OFF_EXH_OUT_TEMP, v->exhaust_outlet_temp);
FieldCodec::putU16(p, OFF_EXH_WIN_PRES, v->exhaust_water_in_pressure);
FieldCodec::putU16(p, OFF_EXH_WOUT_PRES, v->exhaust_water_out_pressure);
FieldCodec::putU16(p, OFF_TANK_LO2_PRES, v->tank_lo2_pressure);
FieldCodec::putU16(p, OFF_TANK_CO2_PRES, v->tank_co2_pressure);
FieldCodec::putU16(p, OFF_TANK_LO2_LEVEL, v->tank_lo2_level);
FieldCodec::putU16(p, OFF_ALLOY_H2_FLOW, v->alloy_h2_flow);
FieldCodec::putU16(p, OFF_FC_H2_FLOW, v->fc_h2_flow);
FieldCodec::putU16(p, OFF_FC_O2_FLOW, v->fc_o2_flow);
putU16Arr(p, OFF_RESERVED, v->reserved, 12);
FieldCodec::putU8(p, OFF_HEARTBEAT, v->heartbeat);
FieldCodec::putU8(p, OFF_EMERGENCY_CMD, v->emergency_cmd);
return Frame::build(id(), p, checksum());
}
bool FcStatusMessage::decode(const std::vector<uint8_t>& frame, void* obj) const {
if (!validateFrame(frame, id(), checksum(), totalLength())) return false;
FcStatusValue* v = static_cast<FcStatusValue*>(obj);
size_t o = FRAME_HEADER_LEN;
v->fc_mode = FieldCodec::getU8(frame, o + OFF_MODE);
v->fc_status = FieldCodec::getU8(frame, o + OFF_STATUS);
v->fault_level_1 = FieldCodec::getU16(frame, o + OFF_FL1);
v->fault_level_2 = FieldCodec::getU16(frame, o + OFF_FL2);
v->fault_level_3 = FieldCodec::getU16(frame, o + OFF_FL3);
v->fault_level_4 = FieldCodec::getU16(frame, o + OFF_FL4);
v->total_generation_time = FieldCodec::getU16(frame, o + OFF_GEN_TIME);
v->fc_fault_level = FieldCodec::getU8(frame, o + OFF_FAULT_LEVEL);
v->generation_power = FieldCodec::getU16(frame, o + OFF_GEN_POWER);
v->hydrogen_capacity = FieldCodec::getU8(frame, o + OFF_H2_CAP);
v->liquid_oxygen_capacity = FieldCodec::getU8(frame, o + OFF_LO2_CAP);
v->fc1_min_cell_voltage = FieldCodec::getU8(frame, o + OFF_FC1_MIN_V);
v->fc1_min_cell_pos = FieldCodec::getU8(frame, o + OFF_FC1_MIN_POS);
v->fc1_avg_cell_voltage = FieldCodec::getU8(frame, o + OFF_FC1_AVG_V);
v->fc2_min_cell_voltage = FieldCodec::getU8(frame, o + OFF_FC2_MIN_V);
v->fc2_min_cell_pos = FieldCodec::getU8(frame, o + OFF_FC2_MIN_POS);
v->fc2_avg_cell_voltage = FieldCodec::getU8(frame, o + OFF_FC2_AVG_V);
v->palladium_temp = FieldCodec::getU16(frame, o + OFF_PALLADIUM_TEMP);
v->buffer_tank_pressure = FieldCodec::getU16(frame, o + OFF_BUFFER_PRES);
v->flue_total_emission = FieldCodec::getU16(frame, o + OFF_FLUE_TOTAL);
v->flue_pressure = FieldCodec::getU16(frame, o + OFF_FLUE_PRES);
v->reactor_pressure = FieldCodec::getU16(frame, o + OFF_REACTOR_PRES);
v->electric_valve_open = FieldCodec::getU16(frame, o + OFF_EVALVE_OPEN);
v->dcdc1_in_voltage = FieldCodec::getU16(frame, o + OFF_DCDC1_IN_V);
v->dcdc1_in_current = FieldCodec::getU16(frame, o + OFF_DCDC1_IN_I);
v->dcdc2_in_voltage = FieldCodec::getU16(frame, o + OFF_DCDC2_IN_V);
v->dcdc2_in_current = FieldCodec::getU16(frame, o + OFF_DCDC2_IN_I);
v->dcdc_out_voltage = FieldCodec::getU16(frame, o + OFF_DCDC_OUT_V);
v->dcdc_out_current = FieldCodec::getU16(frame, o + OFF_DCDC_OUT_I);
v->dcdc_ctrl_voltage = FieldCodec::getU8(frame, o + OFF_DCDC_CTRL_V);
v->dcdc_aux_voltage = FieldCodec::getU8(frame, o + OFF_DCDC_AUX_V);
v->methanol_total_use = FieldCodec::getU16(frame, o + OFF_METHANOL_TOTAL);
v->methanol_feed = FieldCodec::getU16(frame, o + OFF_METHANOL_FEED);
v->oxygen_side_water_level= FieldCodec::getU16(frame, o + OFF_O2_WATER);
v->hydrogen_side_water_level = FieldCodec::getU16(frame, o + OFF_H2_WATER);
v->ballast_water_level = FieldCodec::getU16(frame, o + OFF_BALLAST_WATER);
v->exhaust_inlet_pressure = FieldCodec::getU16(frame, o + OFF_EXH_IN_PRES);
v->exhaust_outlet_pressure= FieldCodec::getU16(frame, o + OFF_EXH_OUT_PRES);
v->cabin_pressure1 = FieldCodec::getU16(frame, o + OFF_CABIN_P1);
v->cabin_pressure2 = FieldCodec::getU16(frame, o + OFF_CABIN_P2);
v->cabin_temp1 = FieldCodec::getU16(frame, o + OFF_CABIN_T1);
v->cabin_temp2 = FieldCodec::getU16(frame, o + OFF_CABIN_T2);
v->cabin_humidity1 = FieldCodec::getU16(frame, o + OFF_CABIN_H1);
v->cabin_humidity2 = FieldCodec::getU16(frame, o + OFF_CABIN_H2);
v->h2_concentration1 = FieldCodec::getU16(frame, o + OFF_H2_C1);
v->h2_concentration2 = FieldCodec::getU16(frame, o + OFF_H2_C2);
v->h2_concentration3 = FieldCodec::getU16(frame, o + OFF_H2_C3);
v->o2_concentration1 = FieldCodec::getU16(frame, o + OFF_O2_C1);
v->o2_concentration2 = FieldCodec::getU16(frame, o + OFF_O2_C2);
v->ch3oh_concentration1 = FieldCodec::getU16(frame, o + OFF_CH3OH_C1);
v->ch3oh_concentration2 = FieldCodec::getU16(frame, o + OFF_CH3OH_C2);
v->flame_detector1 = FieldCodec::getU8(frame, o + OFF_FLAME1);
v->flame_detector2 = FieldCodec::getU8(frame, o + OFF_FLAME2);
v->emergency_float_depth = FieldCodec::getU16(frame, o + OFF_EMER_DEPTH);
v->emergency_float_time = FieldCodec::getU16(frame, o + OFF_EMER_TIME);
v->exhaust_run_freq = FieldCodec::getU16(frame, o + OFF_EXH_FREQ);
v->exhaust_inlet_temp = FieldCodec::getU16(frame, o + OFF_EXH_IN_TEMP);
v->exhaust_outlet_temp = FieldCodec::getU16(frame, o + OFF_EXH_OUT_TEMP);
v->exhaust_water_in_pressure = FieldCodec::getU16(frame, o + OFF_EXH_WIN_PRES);
v->exhaust_water_out_pressure= FieldCodec::getU16(frame, o + OFF_EXH_WOUT_PRES);
v->tank_lo2_pressure = FieldCodec::getU16(frame, o + OFF_TANK_LO2_PRES);
v->tank_co2_pressure = FieldCodec::getU16(frame, o + OFF_TANK_CO2_PRES);
v->tank_lo2_level = FieldCodec::getU16(frame, o + OFF_TANK_LO2_LEVEL);
v->alloy_h2_flow = FieldCodec::getU16(frame, o + OFF_ALLOY_H2_FLOW);
v->fc_h2_flow = FieldCodec::getU16(frame, o + OFF_FC_H2_FLOW);
v->fc_o2_flow = FieldCodec::getU16(frame, o + OFF_FC_O2_FLOW);
getU16Arr(frame, o + OFF_RESERVED, v->reserved, 12);
v->heartbeat = FieldCodec::getU8(frame, o + OFF_HEARTBEAT);
v->emergency_cmd = FieldCodec::getU8(frame, o + OFF_EMERGENCY_CMD);
return true;
}
} // namespace ccu