#include "CanBridge.h" #include "CanBridge_Info.h" #include "MBUtils.h" #include "MOOS/libMOOS/Comms/MOOSMsg.h" #include using namespace std; namespace canbridge { //--------------------------------------------------------- // Constructor / Destructor CanBridge::CanBridge() {} CanBridge::~CanBridge() { if (m_endpoint) { m_endpoint->stop(); delete m_endpoint; m_endpoint = nullptr; } if (m_db) { m_db->close(); delete m_db; m_db = nullptr; } } //--------------------------------------------------------- // OnStartUp:读取配置并启动 CAN 链路 bool CanBridge::OnStartUp() { AppCastingMOOSApp::OnStartUp(); STRING_LIST sParams; m_MissionReader.EnableVerbatimQuoting(false); if (!m_MissionReader.GetConfiguration(GetAppName(), sParams)) reportConfigWarning("No config block found for " + GetAppName()); STRING_LIST::iterator p; for (p = sParams.begin(); p != sParams.end(); p++) { string orig = *p; string line = *p; string param = stripBlankEnds(tolower(biteStringX(line, '='))); string value = stripBlankEnds(line); bool handled = true; if (param == "can_host") m_canHost = value; else if (param == "can_port") m_canPort = atol(value.c_str()); else if (param == "can_channel_name") m_channelName = value; else if (param == "dbpath") m_dbPath = value; else handled = false; if (!handled) reportUnhandledConfigWarning(orig); } registerVariables(); // 数据库(CAN 帧落库) m_db = new CanDbStore(m_dbPath); if (!m_db->open()) { reportRunWarning("CAN db open failed: " + m_dbPath + " (" + m_db->lastError() + ")"); delete m_db; m_db = nullptr; } // CAN 链路(TCP Client,收帧回调在接收线程中触发) m_endpoint = new CanEndpoint(); m_endpoint->configure(m_canHost, m_canPort); m_endpoint->setFrameCallback( [this](uint8_t fi, uint32_t id, const uint8_t* data, int dlc) { handleFrame(fi, id, data, dlc); }); if (!m_endpoint->start()) { reportRunWarning("CAN endpoint start failed: " + m_canHost); } cout << "pCanBridge started: " << m_canHost << ":" << m_canPort << " (" << m_channelName << "), db: " << m_dbPath << endl; return true; } //--------------------------------------------------------- // OnConnectToServer bool CanBridge::OnConnectToServer() { registerVariables(); return true; } //--------------------------------------------------------- // registerVariables:纯发布应用,无需注册订阅变量 void CanBridge::registerVariables() { AppCastingMOOSApp::RegisterVariables(); } //--------------------------------------------------------- // OnNewMail:当前无订阅指令,预留 bool CanBridge::OnNewMail(MOOSMSG_LIST &NewMail) { AppCastingMOOSApp::OnNewMail(NewMail); MOOSMSG_LIST::iterator p; for (p = NewMail.begin(); p != NewMail.end(); p++) { CMOOSMsg &msg = *p; (void)msg; } return true; } //--------------------------------------------------------- // Iterate:周期任务 bool CanBridge::Iterate() { AppCastingMOOSApp::Iterate(); AppCastingMOOSApp::PostReport(); return true; } //--------------------------------------------------------- // handleFrame:CAN 帧 -> CMOOSMsg(二进制) -> MOOSDB // // 在 CanEndpoint 接收线程中调用;m_Comms::Post 线程安全。 void CanBridge::handleFrame(uint8_t frameInfo, uint32_t id, const uint8_t* data, int dlc) { // 落库(WAL + 预处理语句,~60帧/秒无压力) if (m_db) m_db->onFrame(m_channelName, frameInfo, id, data, dlc); char key[32]; std::snprintf(key, sizeof(key), "CAN_0x%08X", id); // 二进制构造:m_cDataType = MOOS_BINARY_STRING CMOOSMsg msg(MOOS_NOTIFY, key, static_cast(dlc), const_cast(data)); msg.SetSourceAux(m_channelName); // 通道 -> m_sSrcAux msg.SetDoubleAux(static_cast(frameInfo)); // FF/RTR/DLC -> m_dfVal2 m_Comms.Post(msg); ++m_notifyCount; } //--------------------------------------------------------- // buildReport:AppCasting 报告 bool CanBridge::buildReport() { m_msgs << "============================================" << "\n"; m_msgs << "pCanBridge CAN->MOOSDB 透传" << "\n"; m_msgs << "============================================" << "\n"; if (m_endpoint) { m_msgs << "目标: " << m_endpoint->host() << ":" << m_endpoint->port() << " (" << m_channelName << ")" << "\n"; m_msgs << "连接状态: " << (m_endpoint->isConnected() ? "已连接" : "断开") << "\n"; m_msgs << "收帧数: " << m_endpoint->frameCount() << "\n"; m_msgs << "发布数: " << m_notifyCount << "\n"; m_msgs << "错误数: " << m_endpoint->errorCount() << "\n"; m_msgs << "重连次数: " << m_endpoint->reconnectCount() << "\n"; m_msgs << "最近收帧: " << m_endpoint->lastFrameTime() << "\n"; } if (m_db) { m_msgs << "数据库: " << m_dbPath << (m_db->isOpen() ? " (已打开)" : " (未打开)") << "\n"; m_msgs << "落库记录数: " << m_db->count() << "\n"; } return true; } } // namespace canbridge