#ifndef PCANBRIDGE_CAN_BRIDGE_H #define PCANBRIDGE_CAN_BRIDGE_H #define UNIX #include "MOOS/libMOOS/Thirdparty/AppCasting/AppCastingMOOSApp.h" #include "CanEndpoint.h" #include "CanDbStore.h" #include #include #include namespace canbridge { //============================================================================ // CanBridge:CAN <-> MOOSDB 多通道双向透传桥(MOOS 应用外壳)。 // // 通道配置(.moos 中可重复多行): // channel = <通道名>,<转换器IP>,<工作端口> // 如 channel = CAN0,192.168.0.222,4001(CANET: CAN0=4001..CAN7=4008) // 每通道一条独立 TCP 连接 + 独立接收线程。 // // 数据流(上行,每通道一条 TCP 连接): // CANET 工作端口 (TCP Server) // -> CanEndpoint(TCP Client,13 字节切帧) // -> handleFrame() 解析 // -> Notify 到 MOOSDB // // 数据流(下行,BCU 断路器/继电器控制等): // MOOS "CAN_TX_0x%08X"(二进制数据域,dlc<=8) // -> OnNewMail 解析 CAN ID 与数据 // -> 按消息 m_sSrcAux(目标通道名)路由到对应通道的 CanEndpoint // -> CanEndpoint::sendFrame(该通道 TCP 连接写出 13 字节帧) // -> CANET -> CAN 总线 // // MOOS 消息映射(上行/下行对称,通道一律走 m_sSrcAux): // 上行 m_sKey = "CAN_0x%08X" CAN ID(完整 4 字节,标准/扩展帧同格式) // 上行 m_sVal = 二进制 data(dlc 字节,MOOS_BINARY_STRING) // 上行 m_sSrcAux = 通道名(如 "CAN0") // 上行 m_dfVal2 = 原始帧信息字节 byte0(bit7 FF / bit6 RTR / bit3~0 DLC) // 下行 m_sKey = "CAN_TX_0x%08X",m_sVal = 二进制 data,m_sSrcAux = 目标通道名 // m_nID 不使用(MOOS 内部消息序号) // // 下行通道回退规则(m_sSrcAux 为空时): // 1) 配置了 default_channel 且命中 -> 用该通道 // 2) 仅配置了单通道 -> 用该通道 // 3) 多通道且无 default_channel -> 告警丢弃 // m_sSrcAux 非空但未命中任何通道 -> 告警丢弃 // // 每帧(上行)同时落库 SQLite(can_frame 表,配置项 dbpath); // 下行帧仅日志记录(can_frame 表无方向列,保持旧库兼容)。 //============================================================================ class CanBridge : public AppCastingMOOSApp { public: CanBridge(); ~CanBridge(); protected: bool OnNewMail(MOOSMSG_LIST &NewMail); bool Iterate(); bool OnConnectToServer(); bool OnStartUp(); bool buildReport(); void registerVariables(); private: // 通道配置(.moos 重复行 channel = name,host,port) struct ChannelCfg { std::string name; std::string host; long port = 0; }; // 运行中的通道(配置 + 独立 TCP 连接) struct Channel { ChannelCfg cfg; CanEndpoint* endpoint = nullptr; }; // 收帧回调(CanEndpoint 接收线程调用) void handleFrame(const std::string& channel, uint8_t frameInfo, uint32_t id, const uint8_t* data, int dlc); // 下行指令处理(OnNewMail 调用):CAN_TX_0x%08X -> 按通道路由发送 void handleTxMessage(CMOOSMsg& msg); // 按通道名查找运行通道;未命中返回 nullptr Channel* findChannel(const std::string& name); // 下行目标通道解析(含回退规则);返回通道指针,nullptr 表示丢弃 Channel* resolveTxChannel(const std::string& srcAux); // 配置 std::vector m_channels; std::string m_defaultChannel; // default_channel(可空) std::string m_dbPath = "pCanBridge_data.db"; // SQLite 路径(moos 配置项 dbpath) // 组件 CanDbStore* m_db = nullptr; std::atomic m_txCount{0}; // MOOS 下行接收总数 std::atomic m_txDropCount{0}; // 下行因通道解析失败丢弃数 }; } // namespace canbridge #endif // PCANBRIDGE_CAN_BRIDGE_H