Files
H100PowerManger/src/pPowerManger/PowerManger.cpp
T
zjk e0488d513b 协议:按0824协议更新复合管控通信解析 + 新增燃料电池监控网页
- pmSysvariable/ccuUdpMsg: 域起始符改为0x40 0x40,域标识符重编号0x0001~0x0004,
  ccuState/ccuColCmd/ccuSetParmCmd 按新协议字段布局与字节序重写(状态248B/操控45B/参数28B)
- systemData/httpserver: 新增FC单片电压、甲醇制氢装置、DC/DC、尾气装置、一体化罐、
  供氢供氧流量、应急上浮等字段解析与WebSocket JSON推送
- 新增 /fcs 燃料电池监控页(fuelcell.h):实时数据显示 + 操控指令交互按钮,
  过滤日志推送消息避免界面闪烁
- SQLite/LowerCommManager/测试:更新建表列、解析打印与单元/集成测试适配新协议
2026-08-26 20:56:39 +08:00

460 lines
14 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/************************************************************/
/* NAME: */
/* ORGN: MIT, Cambridge MA */
/* FILE: PowerManger.cpp */
/* DATE: December 29th, 1963 */
/************************************************************/
#include <iterator>
#include "MBUtils.h"
#include "ACTable.h"
#include "PowerManger.h"
#include "logc/loguru.hpp"
#include <memory>
using namespace std;
bool _FsmCB(void * pParam)
{
PowerManger* pMe = (PowerManger* )pParam;
return pMe->FsmLoop();
}
bool _CommCB(void * pParam)
{
PowerManger* pMe = (PowerManger* )pParam;
return pMe->commLoop();
}
//---------------------------------------------------------
// Constructor()
PowerManger::PowerManger()
{
workCondition = 0;
currentMod = 0;
powerState = 0;
faultLevel = 0;
soc = 0;
sustainableTime = 0;
m_faultNum = 0;
m_ticker = 0;
m_leakage = 0;
m_thrustRpm = 0;
m_thrustEnable = 0;
faultCode.clear();
m_skew = 10;
m_pmCurrentState = {};
m_currentDisBreakerState = {};
m_targetDisBreakerState = {};
m_currentDriverState = {};
m_MSDriverCmd = {};
m_subDisSysCmd = {};
m_subDisSysState = {};
m_subDisSysFault = {};
//初始化系统数据
m_systemData = new SystemData();
//初始化控制指令
initControlCmd();
//初始化下位机通信
m_lowerCommManager = new LowerCommManager(this,IPORT,CCUPORT,CCUHOST);
m_lowerCommManager->initUdpComm();
//初始化上位机通信
m_upperCommManager = new UpperCommManager(this);
//数据库在 OnStartUp 读取配置后初始化
m_db = nullptr;
//初始化http服务器
m_httpServer = new HttpServer(8090);
m_httpServer->setPowerManger(this);
m_httpServer->setLowerCommManager(m_lowerCommManager);
m_httpServer->setSystemData(m_systemData);
m_httpServer->start();
}
//---------------------------------------------------------
// Destructor
PowerManger::~PowerManger()
{
m_commThread.Stop();
// 必须先停 HTTP 线程(stop() 内部 pthread_join 阻塞等待线程退出),
// 否则 HTTP 线程每秒仍会读取 m_systemData / m_lowerCommManager / m_upperCommManager,
// 导致 use-after-free。
delete m_httpServer;
delete m_lowerCommManager; // 停止监听线程,确保其不再调用 DB
delete m_db;
delete m_upperCommManager;
delete m_systemData; // 最后删除,此时无任何线程引用
}
//---------------------------------------------------------
// Procedure: OnNewMail()
bool PowerManger::OnNewMail(MOOSMSG_LIST &NewMail)
{
AppCastingMOOSApp::OnNewMail(NewMail);
MOOSMSG_LIST::iterator p;
for(p=NewMail.begin(); p!=NewMail.end(); p++)
{
CMOOSMsg &msg = *p;
string key = msg.GetKey();
string strJson = msg.GetString();
double dfT;
msg.IsSkewed(m_curr_time, &dfT);
if(fabs(dfT) > m_skew)
{
LOG_F(INFO, "Message from %s at time %f is Skewed", msg.GetSource().c_str(), dfT);
return true;
}
//处理上位机发送的控制指令
if(!m_upperCommManager->processUpperMsg(key,strJson))
{
LOG_F(ERROR, "上位机消息处理错误: %s", key.c_str());
}
#if 0 // Keep these around just for template
string comm = msg.GetCommunity();
double dval = msg.GetDouble();
string sval = msg.GetString();
string msrc = msg.GetSource();
double mtime = msg.GetTime();
bool mdbl = msg.IsDouble();
bool mstr = msg.IsString();
#endif
if(key == "FOO")
LOG_F(INFO, "Received FOO message");
else if(key != "APPCAST_REQ") // handled by AppCastingMOOSApp
reportRunWarning("Unhandled Mail: " + key);
}
return(true);
}
//---------------------------------------------------------
// Procedure: OnConnectToServer()
bool PowerManger::OnConnectToServer()
{
registerVariables();
return(true);
}
//---------------------------------------------------------
// Procedure: Iterate()
// happens AppTick times per second
//固定为4Hz
bool PowerManger::Iterate()
{
AppCastingMOOSApp::Iterate();
// 触发定时任务
CycleTriggeredEvent cycleEvent;
PowerManagerFsm::dispatch(cycleEvent);
faultLevel = getFaultLevel();
m_systemData->updateCommonStatus();
// m_CcuColCmd.heartbeat
// if (m_ticker++ % 5 == 0)
// {
// m_CcuColCmd.heartbeat++;
// m_lowerCommManager->processPeriodicTasks();
// m_upperCommManager->processPeriodicTasks();
// }
return(true);
}
//---------------------------------------------------------
// Procedure: OnStartUp()
// happens before connection is open
bool PowerManger::OnStartUp()
{
AppCastingMOOSApp::OnStartUp();
STRING_LIST sParams;
m_MissionReader.EnableVerbatimQuoting(false);
if(!m_MissionReader.GetConfiguration(GetAppName(), sParams))
reportConfigWarning("No config block found for " + GetAppName());
std::string dbPath; // 数据库路径,不配置则默认当前目录 power_data.db
std::string logPath; // 日志文件路径,不配置则默认当前目录 pPowerManger.log
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 = false;
if(param == "foo") {
handled = true;
}
else if(param == "bar") {
handled = true;
}
else if(param == "dbpath") {
dbPath = value;
handled = true;
}
else if(param == "logpath") {
logPath = value;
handled = true;
}
if(!handled)
reportUnhandledConfigWarning(orig);
}
registerVariables();
// 初始化日志文件:logpath 未配置则默认当前目录
if (logPath.empty()) logPath = "pPowerManger.log";
loguru::add_file(logPath.c_str(), loguru::Append, loguru::Verbosity_MAX);
LOG_F(INFO, "日志文件路径: %s", logPath.c_str());
// 初始化数据库:dbpath 未配置则默认当前目录
if (dbPath.empty()) dbPath = "power_data.db";
LOG_F(INFO, "数据库存储路径: %s", dbPath.c_str());
m_db = new SQLite(dbPath);
m_db->createTable();
// 注入原始帧日志回调(RX/TX 双向落库)
m_lowerCommManager->setCommLogger(m_db);
// 数据库就绪后再启动下位机监听线程
m_lowerCommManager->startListenThread();
// 初始化状态机
PowerManagerFsm::init(this);
PowerManagerFsm::start();
InitEvent initEvent;
PowerManagerFsm::dispatch(initEvent);
//初始化通信线程
m_commThread.Initialise(_CommCB,this);
m_commThread.Start();
return(true);
}
//---------------------------------------------------------
// Procedure: registerVariables()
void PowerManger::registerVariables()
{
AppCastingMOOSApp::RegisterVariables();
// Register(DB_TO_PM_SUBDISSTATE, 0);
Register(DB_TO_PM_MSCMD, 0);
Register(DB_TO_PM_EQUIPMENTCMD, 0);
Register(m_upperCommManager->m_secdistStateMsg.key_fb,0);
Register(DB_TO_PM_MISSION,0);
Register(DB_TO_PM_DEEPTH,0);
Register(DB_TO_PM_SETOPCONDITION,0);
Register(DB_TO_PM_SETOPMODE,0);
Register(DB_TO_PM_SETPMSYS,0);
Register(DB_TO_PM_SETDEVSWITCH,0);
Register(DB_TO_PM_TASKSTOP,0);
Register(uDetect_xcVoltage_cmd::key,0);
Register(uDetect_zdpVoltage_cmd::key,0);
Register(uDevice_thruster_st::key,0);
// Register(uExternComm_setThrustSpeed_cmd::key,0);
}
//------------------------------------------------------------
// Procedure: buildReport()
bool PowerManger::buildReport()
{
m_msgs << "============================================" << endl;
m_msgs << "File: " << endl;
m_msgs << "============================================" << endl;
ACTable actab(4);
actab << "Alpha | Bravo | Charlie | Delta";
actab.addHeaderLines();
actab << "one" << "two" << "three" << "four";
m_msgs << actab.getFormattedString();
return(true);
}
bool PowerManger::FsmLoop()
{
return true;
}
int PowerManger::checkError()
{
//TODO:更新协议
//1.检查复合管控器状态
// if(m_pmCurrentState.ccustate.fcuGZ_1H != 0 ||
// m_pmCurrentState.ccustate.fcuGZ_1L != 0 ||
// m_pmCurrentState.ccustate.fcuGZ_2H != 0 ||
// m_pmCurrentState.ccustate.fcuGZ_2L != 0 ||
// m_pmCurrentState.ccustate.fcuGZ_3H != 0 ||
// m_pmCurrentState.ccustate.fcuGZ_3L != 0 ||
// m_pmCurrentState.ccustate.insEmergencyStatusWord != 0)
return 0;
}
void PowerManger::printState(const std::string& stateName, const std::string& desp){
if (desp.find("故障") != string::npos) {
LOG_F(ERROR, "STATE %s -> %s", stateName.c_str(), desp.c_str());
} else {
LOG_F(INFO, "STATE %s -> %s", stateName.c_str(), desp.c_str());
}
}
void PowerManger::initControlCmd()
{
//================初始化配电指令=============================
m_targetDisBreakerState.bus1Breaker.fuelCellCircuitBreaker = 0;
m_targetDisBreakerState.bus1Breaker.powerLithiumBatteryCircuitBreaker = 1; //动力锂电池默认接入
m_targetDisBreakerState.bus1Breaker.propulsionMotorCircuitBreaker = 0;
m_targetDisBreakerState.bus1Breaker.lithiumBatteryGroupInstrumentCircuitBreaker = 1; //仪表锂电池默认接入
m_targetDisBreakerState.bus1Breaker.dcDc5ModuleCircuitBreaker = 1; //DC-DC模块默认接入
m_targetDisBreakerState.bus1Breaker.bowHighVoltageDistributionBoxCircuitBreaker = 1; //艏部高压母线断路器默认接入
m_targetDisBreakerState.bus1Breaker.sternFTDevice45CircuitBreaker = 0; // sternFTDevice45CircuitBreaker默认接入
m_targetDisBreakerState.bus1Breaker.sternRudderSwitch1CircuitBreaker = 0;
m_targetDisBreakerState.bus1Breaker.sternRudderSwitch2CircuitBreaker = 0;
m_targetDisBreakerState.bus1Breaker.fbReservedCircuitBreaker = 0;
m_targetDisBreakerState.bus1Breaker.tyzReservedCircuitBreaker = 0;
m_targetDisBreakerState.bus1Breaker.reservedCircuitBreaker = 0;
m_targetDisBreakerState.bus2Breaker.bowFTDevice123CircuitBreaker = 0;
m_targetDisBreakerState.bus2Breaker.actuatorCircuitBreaker = 0;
m_targetDisBreakerState.bus2Breaker.mastSteeringGearControlBoxCircuitBreaker = 0;
m_targetDisBreakerState.bus2Breaker.xczCircuitBreaker = 0;
m_targetDisBreakerState.bus2Breaker.bowRudderControlBoxCircuitBreaker = 0;
m_targetDisBreakerState.bus2Breaker.openWaterCoverStartCylinderCircuitBreaker = 0;
//锂电池默认接入
m_targetDisBreakerState.bus3Breaker.lithiumBatteryGroupInstrumentCircuitBreaker = 1;
m_targetDisBreakerState.bus3Breaker.bowLowVoltageDistributionBoxCircuitBreaker = 1;
m_targetDisBreakerState.bus3Breaker.unit4InstrumentDC48VCircuitBreaker = 1;
m_targetDisBreakerState.bus3Breaker.dcC1DCDistributionPanelCircuitBreaker = 1;
m_targetDisBreakerState.bus3Breaker.reservedCircuitBreaker1 = 0;
m_targetDisBreakerState.bus3Breaker.reservedCircuitBreaker2 = 0;
m_targetDisBreakerState.bus3Breaker.emergencyLithiumBatteryGroup2CircuitBreaker = 1;
m_targetDisBreakerState.bus4Breaker.unit1CircuitBreaker = 1;
m_targetDisBreakerState.bus4Breaker.unit2CircuitBreaker = 1;
m_targetDisBreakerState.bus4Breaker.unit3CircuitBreaker = 1;
m_targetDisBreakerState.bus4Breaker.unit5CircuitBreaker = 1;
m_targetDisBreakerState.bus4Breaker.bowPZDeviceCircuitBreaker = 1;
m_targetDisBreakerState.bus4Breaker.reservedCircuitBreaker1 = 0;
m_targetDisBreakerState.bus4Breaker.reservedCircuitBreaker2 = 0;
m_targetDisBreakerState.bus4Breaker.emergencyLithiumBatteryGroup1CircuitBreaker = 1; //紧急锂电池默认接入
//================初始化复合管控=============================
m_CcuColCmd.fcmode = 0x00; //默认无效
m_CcuColCmd.fcuCmd = 0x00; //无效指令
m_CcuColCmd.fcuPowerEfficiency = 0; //输出功率指令,0~250,分辨率0.1kW
m_CcuColCmd.pitchData1 = 0; //纵倾姿态数据1
m_CcuColCmd.pitchData2 = 0; //纵倾姿态数据2
m_CcuColCmd.rollData1 = 0; //横倾姿态数据1
m_CcuColCmd.rollData2 = 0; //横倾姿态数据2
m_CcuColCmd.emergencyAllow = 0; //应急允许
m_CcuColCmd.depth = 0; //潜深深度
m_CcuColCmd.supplyExhaustCmd = 0x00; //补给/排放指令
m_CcuColCmd.reservedCmd5 = 0; //预留指令5
m_CcuColCmd.reservedCmd6 = 0; //预留指令6
m_CcuColCmd.insBatCmd = 0x00; //无效指令
m_CcuColCmd.powerBatCmd = 0x00; //无效指令
m_CcuColCmd.powerBatEfficiency = 0; //动力锂电池功率配置值
m_CcuColCmd.heartbeat = 0;
m_CcuColCmd.masterState = 0xAA;//主站状态,运行中
//================初始化上位机指令=========================
m_msCmd.modCMD = 99;
m_msCmd.powerCMD = 99;
m_msCmd.workCMD = 99;
//================初始化设备驱动指令========================
}
void PowerManger::addFaultCode(unsigned int code)
{
std::lock_guard<std::mutex> lock(m_stateMutex);
faultCode.push_back(code);
}
void PowerManger::clearFaultCodes()
{
std::lock_guard<std::mutex> lock(m_stateMutex);
faultCode.clear();
}
std::vector<unsigned int> PowerManger::getFaultCodes() const
{
std::lock_guard<std::mutex> lock(m_stateMutex);
return faultCode;
}
unsigned char PowerManger::getFaultLevel()
{
unsigned char maxLevel = 0;
for (auto code : getFaultCodes()) {
// 提取0xabcd中的b位 (右移8位后取低4位)
unsigned char level = (code >> 8) & 0xF;
if (level > maxLevel) {
maxLevel = level;
}
}
return maxLevel;
}
bool PowerManger::commLoop()
{
while(!m_commThread.IsQuitRequested())
{
{
std::lock_guard<std::mutex> lock(m_stateMutex);
m_CcuColCmd.heartbeat++;
}
m_lowerCommManager->processPeriodicTasks();
m_upperCommManager->processPeriodicTasks();
// 延时1秒
usleep(1000000);
}
return true;
}
void PowerManger::injectFault(unsigned type,unsigned int faultCode){
LOG_F(INFO, "注入故障: %d %d", type, faultCode);
TestEvent testEvent("故障注入测试",type,faultCode);
PowerManagerFsm::dispatch(testEvent);
}
void PowerManger::pushDeviceCommand(DeviceSwitchCmd cmd) {
std::lock_guard<std::mutex> lock(m_deviceCmdMutex);
m_deviceCmdQuenue.push(cmd);
}
bool PowerManger::popDeviceCommand(DeviceSwitchCmd &cmd) {
std::lock_guard<std::mutex> lock(m_deviceCmdMutex);
if(m_deviceCmdQuenue.empty()) {
return false;
}
cmd = m_deviceCmdQuenue.front();
m_deviceCmdQuenue.pop();
return true;
}
bool PowerManger::isDeviceCmdEmpty() const {
std::lock_guard<std::mutex> lock(m_deviceCmdMutex);
return m_deviceCmdQuenue.empty();
}