- 新增 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 补充编译产物/临时文件忽略
108 lines
3.2 KiB
C++
108 lines
3.2 KiB
C++
#include "LinkManager.h"
|
|
#include "../protocol/Frame.h"
|
|
#include "MOOS/libMOOS/Utils/MOOSUtilityFunctions.h"
|
|
#include "loguru.hpp"
|
|
|
|
namespace ccu {
|
|
|
|
LinkManager::LinkManager(const std::string& linkName, long localPort)
|
|
: m_linkName(linkName), m_localPort(localPort) {}
|
|
|
|
LinkManager::~LinkManager() {
|
|
stop();
|
|
}
|
|
|
|
bool LinkManager::start() {
|
|
if (m_running) return true;
|
|
if (!m_endpoint.init(m_localPort)) {
|
|
LOG_F(ERROR, "[%s] bind failed on port %ld", m_linkName.c_str(), m_localPort);
|
|
return false;
|
|
}
|
|
m_running = true;
|
|
m_rxThread = std::thread([this]() { rxThreadFunc(); });
|
|
LOG_F(INFO, "[%s] listening on local port %ld", m_linkName.c_str(), m_localPort);
|
|
return true;
|
|
}
|
|
|
|
void LinkManager::stop() {
|
|
if (!m_running) return;
|
|
m_running = false;
|
|
if (m_rxThread.joinable()) m_rxThread.join();
|
|
}
|
|
|
|
bool LinkManager::sendMessage(uint16_t id, const void* value) {
|
|
return sendMessageTo(id, value, defaultRemoteHost(), defaultRemotePort());
|
|
}
|
|
|
|
bool LinkManager::sendMessageTo(uint16_t id, const void* value,
|
|
const std::string& host, long port) {
|
|
if (host.empty() || port <= 0) return false;
|
|
Message* msg = m_registry.find(id);
|
|
if (!msg) {
|
|
LOG_F(ERROR, "[%s] unknown message id 0x%04X", m_linkName.c_str(), id);
|
|
return false;
|
|
}
|
|
std::vector<uint8_t> frame = msg->encode(value);
|
|
if (!m_endpoint.sendTo(host, port, frame)) {
|
|
LOG_F(ERROR, "[%s] send msg 0x%04X to %s:%ld failed",
|
|
m_linkName.c_str(), id, host.c_str(), port);
|
|
return false;
|
|
}
|
|
++m_txCount;
|
|
if (m_logSink) m_logSink->onRawFrame(1, id, m_linkName, frame, true);
|
|
if (m_onRawFrame) m_onRawFrame(1, frame, true);
|
|
return true;
|
|
}
|
|
|
|
bool LinkManager::handleIncoming(const std::vector<uint8_t>& frame) {
|
|
if (frame.size() < FRAME_HEADER_LEN) return false;
|
|
|
|
uint16_t id = 0;
|
|
if (!Frame::parseId(frame, id)) {
|
|
LOG_F(WARNING, "[%s] bad frame header", m_linkName.c_str());
|
|
++m_errorCount;
|
|
return false;
|
|
}
|
|
|
|
Message* msg = m_registry.find(id);
|
|
if (!msg) {
|
|
LOG_F(WARNING, "[%s] unknown msg id 0x%04X, len=%zu",
|
|
m_linkName.c_str(), id, frame.size());
|
|
++m_errorCount;
|
|
return false;
|
|
}
|
|
|
|
bool checksumOk = msg->checksum().verify(frame);
|
|
++m_rxCount;
|
|
m_lastRxTime = MOOSTime(false);
|
|
|
|
// 原始帧落库 + 回调
|
|
if (m_logSink) m_logSink->onRawFrame(0, id, m_linkName, frame, checksumOk);
|
|
if (m_onRawFrame) m_onRawFrame(0, frame, checksumOk);
|
|
|
|
if (!checksumOk) {
|
|
LOG_F(WARNING, "[%s] checksum error msg 0x%04X", m_linkName.c_str(), id);
|
|
++m_errorCount;
|
|
return false;
|
|
}
|
|
|
|
// 解码交给上层(CCU 层知道具体消息类型)
|
|
if (m_onMessage) m_onMessage(msg, frame);
|
|
return true;
|
|
}
|
|
|
|
void LinkManager::rxThreadFunc() {
|
|
uint8_t buf[2048];
|
|
while (m_running) {
|
|
int n = m_endpoint.receive(buf, sizeof(buf));
|
|
if (n > 0) {
|
|
std::vector<uint8_t> frame(buf, buf + n);
|
|
handleIncoming(frame);
|
|
} else {
|
|
// 无数据,短暂休眠避免忙等
|
|
std::this_thread::sleep_for(std::chrono::milliseconds(10));
|
|
}
|
|
}
|
|
}
|
|
|
|
} // namespace ccu
|