pCCU 锂电池页新增 BCU 断路器控制(0x10XX81FF 经 pCanBridge 下行 CAN 总线)
- CanBms: bcuCtrlCanId(0x10XX81FF) + buildBcuRelayCtrlData(02 00 总正 总负 FF*4) - SystemData: BcuCtrlCmd 下行队列(Web线程入队->Iterate/MOOS线程出队Notify) + 下发统计 - CCU: /api/bcu_ctrl(addr/action 或 pos/neg, 校验地址01h~36h) + Iterate 经 MOOS CAN_TX_0x* 下发 - pCanBridge 变双向透传: 订阅 CAN_TX_0x*,CanEndpoint::sendFrame(13字节CANET帧,TCP写,互斥保护) - 网页: 每BCU节点断路器闭合/断开按钮(confirm确认) + 下发统计卡片 - 测试: pccuTest 控制帧编码用例(183项);集成测试新增假CANET服务器验证完整下行链路(闭合/断开/非法地址)
This commit is contained in:
+89
-1
@@ -5,6 +5,7 @@
|
||||
#include "protocol/CanBms.h"
|
||||
#include <chrono>
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
|
||||
using namespace ccu;
|
||||
using namespace std;
|
||||
@@ -277,6 +278,9 @@ bool CCU::Iterate() {
|
||||
m_lastStatusTx = now;
|
||||
}
|
||||
|
||||
// BCU 断路器控制指令下发(网页 -> 队列 -> MOOS CAN_TX_*)
|
||||
sendPendingBcuCtrl();
|
||||
|
||||
// 电源协调器:协调算法占位
|
||||
if (m_coord)
|
||||
m_coord->tick(now);
|
||||
@@ -503,16 +507,95 @@ std::string CCU::buildSnapshot() {
|
||||
}
|
||||
|
||||
//---------------------------------------------------------
|
||||
// handleApi:/api/logs
|
||||
// handleApi:/api/logs、/api/bcu_ctrl
|
||||
|
||||
std::string CCU::handleApi(const std::string& uri, const std::string& query) {
|
||||
if (uri == "/api/logs") {
|
||||
if (m_snap) return m_snap->buildLogs(50);
|
||||
return "[]";
|
||||
}
|
||||
if (uri == "/api/bcu_ctrl") {
|
||||
return handleBcuCtrlApi(query);
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
//---------------------------------------------------------
|
||||
// handleBcuCtrlApi:BCU 断路器控制指令下发
|
||||
//
|
||||
// GET /api/bcu_ctrl?addr=5&action=1 action: 1 闭合 / 0 断开(总正+总负)
|
||||
// GET /api/bcu_ctrl?addr=5&pos=1&neg=0 也可单独指定总正/总负
|
||||
// Web 线程不可直接 Notify,指令入队后由 Iterate(MOOS 线程)下发。
|
||||
|
||||
std::string CCU::handleBcuCtrlApi(const std::string& query) {
|
||||
if (!m_sysData) return "{\"ok\":false,\"error\":\"not ready\"}";
|
||||
|
||||
// 简易 query 解析(k=v&k=v)
|
||||
auto getParam = [&query](const char* key, int& out) -> bool {
|
||||
std::string k = std::string(key) + "=";
|
||||
size_t p = query.find(k);
|
||||
if (p == std::string::npos) return false;
|
||||
size_t e = query.find('&', p);
|
||||
std::string v = query.substr(p + k.size(),
|
||||
(e == std::string::npos) ? std::string::npos
|
||||
: e - p - k.size());
|
||||
out = atoi(v.c_str());
|
||||
return true;
|
||||
};
|
||||
|
||||
int addr = 0, action = -1, pos = -1, neg = -1;
|
||||
getParam("addr", addr);
|
||||
getParam("action", action);
|
||||
getParam("pos", pos);
|
||||
getParam("neg", neg);
|
||||
|
||||
if (addr < kBcuAddrMin || addr > kBcuAddrMax)
|
||||
return "{\"ok\":false,\"error\":\"bad addr\"}";
|
||||
if (pos < 0) pos = action; // 未单独指定时跟随 action
|
||||
if (neg < 0) neg = action;
|
||||
if (action < 0 && (pos < 0 || neg < 0))
|
||||
return "{\"ok\":false,\"error\":\"missing action\"}";
|
||||
if (action > 1 || pos > 1 || neg > 1)
|
||||
return "{\"ok\":false,\"error\":\"bad value\"}";
|
||||
|
||||
BcuCtrlCmd c;
|
||||
c.addr = static_cast<uint8_t>(addr);
|
||||
c.pos = static_cast<uint8_t>(pos);
|
||||
c.neg = static_cast<uint8_t>(neg);
|
||||
if (!m_sysData->pushBcuCtrlCmd(c))
|
||||
return "{\"ok\":false,\"error\":\"queue full\"}";
|
||||
|
||||
LOG_F(INFO, "[BCU/CAN] 断路器指令入队: 节点%d 总正=%d 总负=%d", addr, pos, neg);
|
||||
char buf[96];
|
||||
std::snprintf(buf, sizeof(buf),
|
||||
"{\"ok\":true,\"addr\":%d,\"pos\":%d,\"neg\":%d}", addr, pos, neg);
|
||||
return buf;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------
|
||||
// sendPendingBcuCtrl:出队控制指令,编码 0x10XX81FF 经 MOOS 下发
|
||||
// 链路:MOOS CAN_TX_0x* -> pCanBridge 订阅 -> CanEndpoint(TCP) -> USBCAN
|
||||
|
||||
void CCU::sendPendingBcuCtrl() {
|
||||
if (!m_sysData) return;
|
||||
BcuCtrlCmd c;
|
||||
while (m_sysData->popBcuCtrlCmd(c)) {
|
||||
uint8_t data[8];
|
||||
buildBcuRelayCtrlData(c.pos, c.neg, data);
|
||||
uint32_t canId = bcuCtrlCanId(c.addr);
|
||||
|
||||
char key[32];
|
||||
std::snprintf(key, sizeof(key), "CAN_TX_0x%08X", canId);
|
||||
// 二进制构造同 pCanBridge 上行发布(MOOS_BINARY_STRING)
|
||||
CMOOSMsg msg(MOOS_NOTIFY, key,
|
||||
static_cast<unsigned int>(sizeof(data)), data);
|
||||
bool ok = m_Comms.Post(msg);
|
||||
m_sysData->noteBcuCtrlSent(c, ok);
|
||||
LOG_F(INFO, "[BCU/CAN] 断路器指令 0x%08X 节点%d 总正=%d 总负=%d %s",
|
||||
canId, c.addr, c.pos, c.neg, ok ? "已投递MOOS" : "投递失败");
|
||||
}
|
||||
}
|
||||
|
||||
//---------------------------------------------------------
|
||||
// buildReport
|
||||
|
||||
@@ -551,6 +634,11 @@ bool CCU::buildReport() {
|
||||
m_msgs << "BMS 报文接收计数:" << m_sysData->bmsStatusCount() << "\n";
|
||||
m_msgs << "FC 状态接收次数:" << m_sysData->fcStatusCount() << "\n";
|
||||
m_msgs << "PM 指令接收次数:" << m_sysData->pmControlCount() << "\n";
|
||||
const BcuCtrlStat& bc = m_sysData->bcuCtrlStat();
|
||||
m_msgs << "断路器指令下发:" << bc.sentCount << " 成功 / " << bc.errCount
|
||||
<< " 失败 (最近: 节点" << static_cast<int>(bc.last.addr)
|
||||
<< " 总正=" << static_cast<int>(bc.last.pos)
|
||||
<< " 总负=" << static_cast<int>(bc.last.neg) << ")\n";
|
||||
}
|
||||
if (m_db) {
|
||||
m_msgs << "数据库记录数:" << m_db->count() << "\n";
|
||||
|
||||
Reference in New Issue
Block a user