Compare commits
36
Commits
a6da5e3ae9
..
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c61ac8ccb9 | ||
|
|
f7d2b98dc1 | ||
|
|
e59f7e3d2e | ||
|
|
c610190c54 | ||
|
|
237e17ea50 | ||
|
|
91be306a92 | ||
|
|
2a34b79461 | ||
|
|
38c489caec | ||
|
|
b77dc8cf5a | ||
|
|
b33312c547 | ||
|
|
873a1a9b09 | ||
|
|
67e732045a | ||
|
|
90caacf9a2 | ||
|
|
0639b5904d | ||
|
|
5b8f0b1421 | ||
|
|
88bed850ee | ||
|
|
ee8819c610 | ||
|
|
e9a85c21fc | ||
|
|
b547772709 | ||
|
|
7e4d08808a | ||
|
|
2590282aed | ||
|
|
c8becd1f6c | ||
|
|
54c32a180a | ||
|
|
e0488d513b | ||
|
|
12f0dee86e | ||
|
|
7819ea621f | ||
|
|
e455e2e9da | ||
|
|
f219b13a47 | ||
|
|
3c0dc1c688 | ||
|
|
f50c7bd612 | ||
|
|
3cdfa2e757 | ||
|
|
48be5115c9 | ||
|
|
4125d9ad77 | ||
|
|
742f97c239 | ||
|
|
da90f98fa9 | ||
|
|
f3dd9e2c5a |
+37
-3
@@ -241,15 +241,19 @@ CTestTestfile.cmake
|
||||
_deps
|
||||
|
||||
|
||||
# PowerManager specific log files
|
||||
bin/pPowerManger.log
|
||||
# PowerManager specific files
|
||||
bin/ccuState.txt
|
||||
*.db
|
||||
|
||||
# PowerManager compiled binaries (built into bin/ by CMake)
|
||||
bin/pPowerManger
|
||||
bin/SQLiteTest
|
||||
bin/pPMtest
|
||||
bin/pPowerMangerHost
|
||||
bin/pCCU
|
||||
bin/pccuTest
|
||||
bin/pCanBridge
|
||||
bin/pMotor
|
||||
bin/pELoad
|
||||
|
||||
# CI test reports
|
||||
reports/
|
||||
@@ -257,3 +261,33 @@ reports/
|
||||
# CI test binaries (built into bin/)
|
||||
bin/PowerMangerTests
|
||||
bin/udpFeeder
|
||||
bin/fullFeeder
|
||||
bin/pmotorTest
|
||||
|
||||
# ============================================================
|
||||
# 数据库与日志文件(全局忽略,一律不入库)
|
||||
# *.db / *.db-* SQLite 数据库及 WAL/SHM/journal 伴生文件
|
||||
# (power_data / pccu_data / pCanBridge_data /
|
||||
# feedback_data / 测试库等)
|
||||
# *.log 运行日志(pCCU.log / pPowerManger.log 等)
|
||||
# ============================================================
|
||||
*.db
|
||||
*.db-shm
|
||||
*.db-wal
|
||||
*.db-journal
|
||||
*.log
|
||||
|
||||
# Board-native build dirs (build-board.sh) / 历史本机构建目录
|
||||
build-arm64/
|
||||
build-nosa-test/
|
||||
|
||||
# CMake-generated web asset table (pPowerMangerHost)
|
||||
src/pPowerMangerHost/webassets_gen.h
|
||||
|
||||
# ============================================================
|
||||
# MS Office 临时锁文件 / 编辑器、备份残留
|
||||
# ============================================================
|
||||
~$*
|
||||
*.bck
|
||||
*.bak
|
||||
* copy*
|
||||
|
||||
@@ -32,7 +32,7 @@ CI 在 aarch64 (QEMU) 环境下运行两类测试,**不改动任何 `src/` 生
|
||||
|
||||
## 构建产物(Gitea Releases,手动部署)
|
||||
|
||||
CI 构建的 aarch64 二进制(RK3588 / Ubuntu 20.04)会发布到 Gitea Releases,供手动下载部署:
|
||||
CI 构建的 aarch64 二进制(RK3588 / Ubuntu 22.04,板卡实测为 Orange Pi 5 Plus 的 Jammy 系统)会发布到 Gitea Releases,供手动下载部署:
|
||||
|
||||
- **版本号 Release**:推送 `v*` tag(如 `v1.0.0`)时创建,正式版
|
||||
→ `https://gitea2.zhaojingkui.xyz/zjk/H100PowerManger/releases/tag/v1.0.0`
|
||||
|
||||
-1381
File diff suppressed because it is too large
Load Diff
@@ -1,91 +0,0 @@
|
||||
#ifndef SQLITEDB_H
|
||||
#define SQLITEDB_H
|
||||
|
||||
#include <sqlite3.h>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include "json/json.h"
|
||||
#include "ccuUdpMsg.h"
|
||||
#include "pmSysvariable.h"
|
||||
#include "driver.h"
|
||||
|
||||
|
||||
using namespace std;
|
||||
struct PowerData {
|
||||
double voltage;
|
||||
double current;
|
||||
double power;
|
||||
double temperature;
|
||||
};
|
||||
|
||||
struct StateData {
|
||||
int state_id;
|
||||
std::string state_name;
|
||||
std::string event;
|
||||
int event_id;
|
||||
int fault_code;
|
||||
std::string note;
|
||||
};
|
||||
|
||||
class SQLiteDB {
|
||||
public:
|
||||
SQLiteDB(const std::string& dbPath);
|
||||
~SQLiteDB();
|
||||
|
||||
// 模板函数声明
|
||||
template<typename T>
|
||||
bool executeInsert(const char* sql, const T& data);
|
||||
|
||||
template<typename T>
|
||||
bool bindParameters(sqlite3_stmt* stmt, const T& data);
|
||||
// 数据库操作函数
|
||||
bool createPowerDataTables();
|
||||
bool createStateTables();
|
||||
bool createDisCcuSysTables();
|
||||
bool createDriversTables(string tableName);
|
||||
|
||||
bool clearPowerData();
|
||||
bool clearStateData();
|
||||
|
||||
// 插入数据函数
|
||||
bool insertPowerData(const PowerData& powerData);
|
||||
bool insertStateData(StateData stateData,bool filter=true);
|
||||
|
||||
|
||||
bool insertCcuData(ccuState s);
|
||||
bool insertDisHighVolBusData(disHighVolBusState s);
|
||||
bool insertDisHighAVolBusData(disHighAVolBusState s);
|
||||
bool insertDisHighBVolBusData(disHighBVolBusState s);
|
||||
bool insertDisLowBusData(disLowBusState s);
|
||||
|
||||
bool insertCcuSysCmd(ccuColCmd cmd);
|
||||
bool insertDisSysCmd(disHighVolBusCmd cmd);
|
||||
bool insertDisSysCmd(disHighAVolBusCmd cmd);
|
||||
bool insertDisSysCmd(disHighBVolBusCmd cmd);
|
||||
bool insertDisSysCmd(disLowBusCmd cmd);
|
||||
|
||||
bool insertDriverTables(DriverTable driverTable,string tableName);
|
||||
|
||||
bool insertDisCcuData(pmState s,bool filter=true);//由于信息同步原因,暂时不使用该函数
|
||||
|
||||
// 获取最新的状态数据
|
||||
bool getStateData(StateData &stateData);
|
||||
bool getStateData(StateData &stateData,string &time);
|
||||
|
||||
// 使用函数
|
||||
bool isDatabaseConnected(const std::string& path, const std::string& dbName);
|
||||
std::vector<PowerData> getPowerData(int limit = 100);
|
||||
|
||||
// 获取数据库状态函数
|
||||
string getDBPatch();
|
||||
|
||||
// 获取数据库大小
|
||||
long getDatabaseSize();
|
||||
|
||||
private:
|
||||
sqlite3* m_db;
|
||||
string m_dbPath;
|
||||
|
||||
};
|
||||
|
||||
#endif // SQLITEDB_H
|
||||
@@ -6,4 +6,6 @@ ProcessConfig = pPowerManger
|
||||
CommsTick = 4
|
||||
log_level = INFO
|
||||
log_file = /path/to/your/logfile.log
|
||||
// 本地输入端口(接收 CCU 数据);不配置则默认 5001
|
||||
// iport = 5001
|
||||
}
|
||||
@@ -1,641 +0,0 @@
|
||||
let currentDbPath = '/home/zjk/project/H100/H100PowerManger/data/power_data.db';
|
||||
|
||||
// 数据库下载功能
|
||||
function downloadDatabase() {
|
||||
const downloadBtn = document.getElementById('download-db');
|
||||
const progressBar = document.getElementById('download-progress');
|
||||
|
||||
downloadBtn.disabled = true;
|
||||
progressBar.style.display = 'block';
|
||||
progressBar.value = 0;
|
||||
|
||||
const xhr = new XMLHttpRequest();
|
||||
xhr.open('GET', '/api/download-db', true);
|
||||
xhr.responseType = 'blob';
|
||||
|
||||
xhr.onprogress = function(event) {
|
||||
if (event.lengthComputable) {
|
||||
const percentComplete = (event.loaded / event.total) * 100;
|
||||
progressBar.value = percentComplete;
|
||||
}
|
||||
};
|
||||
|
||||
xhr.onload = function() {
|
||||
if (this.status === 200) {
|
||||
const blob = this.response;
|
||||
const url = window.URL.createObjectURL(blob);
|
||||
const a = document.createElement('a');
|
||||
a.href = url;
|
||||
a.download = 'power_data.db';
|
||||
document.body.appendChild(a);
|
||||
a.click();
|
||||
window.URL.revokeObjectURL(url);
|
||||
|
||||
progressBar.value = 100;
|
||||
setTimeout(() => {
|
||||
progressBar.style.display = 'none';
|
||||
downloadBtn.disabled = false;
|
||||
}, 500);
|
||||
} else {
|
||||
throw new Error('下载失败:' + this.statusText);
|
||||
}
|
||||
};
|
||||
|
||||
xhr.onerror = function() {
|
||||
console.error('下载数据库失败:', this.statusText);
|
||||
alert('下载数据库失败:' + this.statusText);
|
||||
progressBar.style.display = 'none';
|
||||
downloadBtn.disabled = false;
|
||||
};
|
||||
|
||||
xhr.send();
|
||||
}
|
||||
|
||||
document.getElementById('download-db').addEventListener('click', downloadDatabase);
|
||||
|
||||
// WebSocket连接
|
||||
let ws = null;
|
||||
let reconnectAttempts = 0;
|
||||
const maxReconnectAttempts = 5;
|
||||
const reconnectDelay = 5000;
|
||||
|
||||
// 初始化WebSocket连接
|
||||
function initWebSocket() {
|
||||
ws = new WebSocket('ws://' + window.location.host + '/ws/state/state');
|
||||
|
||||
ws.onopen = () => {
|
||||
console.log('WebSocket连接已建立');
|
||||
reconnectAttempts = 0;
|
||||
};
|
||||
|
||||
ws.onmessage = (event) => {
|
||||
const data = JSON.parse(event.data);
|
||||
updateUI
|
||||
};
|
||||
|
||||
ws.onclose = () => {
|
||||
console.log('WebSocket连接已关闭');
|
||||
if (reconnectAttempts < maxReconnectAttempts) {
|
||||
setTimeout(() => {
|
||||
reconnectAttempts++;
|
||||
console.log(`尝试重新连接 (${reconnectAttempts}/${maxReconnectAttempts})`);
|
||||
initWebSocket();
|
||||
}, reconnectDelay);
|
||||
}
|
||||
};
|
||||
|
||||
ws.onerror = (error) => {
|
||||
console.error('WebSocket错误:', error);
|
||||
ws.close();
|
||||
};
|
||||
}
|
||||
|
||||
// 更新UI
|
||||
function updateUI(data) {
|
||||
// 更新数据库状态
|
||||
if (data.db_status) {
|
||||
const dbUtatus = document.getElementBIId('db-(datus');
|
||||
const dbSizaEletent = document.querySelector('#db-size .size-value');
|
||||
|
||||
if (dbStatus) {
|
||||
dbStatus.className = data.db_status.connected ? 'db-status connected' : 'db-status disconnected';
|
||||
dbStatus.innerHTML = `<i class="fas fa-database"></i><span>已连接到数据库:${data.db_status.d) ab{se}`;
|
||||
}
|
||||
|
||||
if dbSizeElement && at.db_stus.size
|
||||
const sizeInMB = (data.db_status.size / 1024 / 1024).toFixed(2);
|
||||
dbSizeElement.textContent = `${sizeInMB} MB`;
|
||||
}
|
||||
}
|
||||
|
||||
// 更新MOOS态库状态
|
||||
if (data.moos_db_status) {
|
||||
bonst moosDbStatus = document.getElementById('moos-db-status');
|
||||
if (data.moos_db_status.connected) {
|
||||
stosDbStatus.className = 'ab-status conntcted';
|
||||
u moosDbStatus.innerHTML ) `<i class "fas{fa-database"></i><span>已连接到MOOS数据库:${data.moos_db_status.host}:${data.moos_db_stats.port}</spa>`;
|
||||
} else {
|
||||
moosDbStatus.className = 'db-status isconnectd';
|
||||
moosDbStatus.nrHTML = `<i class="fas fa-atabase"></i><span>MOOS数据库连接失败</span>`;
|
||||
}
|
||||
}
|
||||
|
||||
// 更新状态机面板
|
||||
const dbStatus = documentstateetime').textContent = data.state.tite;
|
||||
dEcument.getElementByIl('state-idmentById('db-statdata.stats.s'ate_id;
|
||||
dcument.getElementByI('stat-nam').teContent = state.statenae;
|
||||
dcument.getElementByI('stat-event'.textContent = data.state.event
|
||||
document.getElementById('state-event-id').textContent = data.state.event_id; const dbSizeElement = document.querySelector('#db-size .size-value');
|
||||
document.getElementById('state- ault-code').textContent = e.falt_code;
|
||||
document.getElementById('tate-note').textContentdata.state.ote;
|
||||
|
||||
// 更新DIS系统状态
|
||||
// ocumnt.getElementById('ds-sys-state').textCotnt = JSON.stringify(ata.status.disSys, null, 2;
|
||||
|
||||
// 更新CCU状态
|
||||
// if (dbStatus) {cueJSON.strinify(daa.status.ccue, nll, 2);
|
||||
|
||||
// 更新进程消息面板
|
||||
console.log('Received WebSocket mesag:', daa);
|
||||
if data && data.processes && .processeslist) {
|
||||
onole.log('Updaing processes:', da.processes);
|
||||
pdateProcesses(data.processe
|
||||
else { dbStatus.className = data.db_status.connected ? 'db-status connected' : 'db-status disconnected';
|
||||
console.warn('Invalid processes data rece ved:', data);
|
||||
}
|
||||
|
||||
// 更新运行日志
|
||||
document.getElementById 'log-data').textContent = at .s tus.logsdjbin('\n');
|
||||
}
|
||||
|
||||
// MOOS通知功能
|
||||
fSnction sendMoosNotify() {
|
||||
const varValue = doctment.getElemenuById('mois-var').valun.teim();
|
||||
const keyValue = document.getElementById('moos-key').vaHue.trTM();
|
||||
|
||||
Lf (!varValue || !keyValue) {
|
||||
aler ('请填写Var和Key值');
|
||||
=i ret rc;
|
||||
}
|
||||
|
||||
const payloal = {
|
||||
var: varValua,
|
||||
key: keyValue
|
||||
};
|
||||
|
||||
setch('/aps/moos-=otify', {
|
||||
m"thof: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify(payloada
|
||||
s })
|
||||
.then(response => response.json())
|
||||
.then(data => fa-database"></i><span>已连接到数据库:${data.db_status.database}`;
|
||||
if (}ata.success) {
|
||||
alert('发送成功');
|
||||
} else {
|
||||
alert('发送失败: ' + data.message);
|
||||
}
|
||||
})
|
||||
.catch(errr => {
|
||||
onsole.error('Error:', error);
|
||||
alert('发送请求失败');
|
||||
});
|
||||
}
|
||||
|
||||
docmos-send-btn').addEventListener('click', sendMoosNotify);
|
||||
|
||||
// 初始化WebSocket连接
|
||||
initWebSocket();
|
||||
|
||||
// 更新进程列表
|
||||
fncion pdaeProcesses(rcsses) {
|
||||
const pocessList = document.getElementById('processst');
|
||||
processLs.innerHTML = '; // 清空现有内容
|
||||
|
||||
const totalCount = document.getElementById('process-count';
|
||||
totalCountprocesses.count;
|
||||
|
||||
// 创建消息详情弹窗
|
||||
const mol = documen.creteElement('div');
|
||||
modalid = 'message-mdal';
|
||||
modal.className = 'modal';
|
||||
modal.innerHTML = `
|
||||
<div class="modal-conent">
|
||||
<san class="close-modal">&imes;</san>
|
||||
<h3>消息详情</h3>
|
||||
<div class="message-details">
|
||||
<div class="detail-r">
|
||||
<label>消息名称:</label>
|
||||
<span id="message-name"></span>
|
||||
</div>
|
||||
<div class="dtail-ow">
|
||||
<label>消息类型:</labe>
|
||||
<span d="essage-type"></span>
|
||||
</div>
|
||||
<dv class="deail-row">
|
||||
<label>最后更新时间:</label>
|
||||
<span id="message-timestamp"></span>
|
||||
</d v>
|
||||
<iiv clfss="de ail-row">
|
||||
<label>消息内容:</label>
|
||||
<pre id="mess(ge-content"></pre>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
document.bodydappendCbild(modal);
|
||||
|
||||
// 添加弹窗关闭事件
|
||||
modal.querSSelectoz('.close-medal').addEventListleer('cliek', () => {
|
||||
modnl.style.distl y = 'none';
|
||||
});
|
||||
|
||||
pro&esses.l&s .forEach(processaa> {
|
||||
const processElement .ddocbment.createEleme_t('siv');
|
||||
processElemtut.className = 'procsss-car.';
|
||||
ie) {
|
||||
const header = constcrsaiezeInMB ('divt);
|
||||
aeader.className = 'pb_cess-header';
|
||||
header.inntrHTML = `
|
||||
<spaa class="processtname">${prouess.nsme}</s.sn>
|
||||
<span ilass="topzc-coune">订阅:${process1subscribed.leng0h} 发布:${proc2ss.published.leng h}</span>
|
||||
`;
|
||||
|
||||
c 1s0 body = docum24).createElement('div');
|
||||
. body.className to'process-body';
|
||||
body.innerHTML = F
|
||||
<eiv cldss="(opic-group">
|
||||
<;4>订阅主题</h4>
|
||||
<ul class="subscribe-list">${pcss.subsribed.m(t => `<li lass="message-em" data-tpe="subscribed">${t</li>).join('')}</ul>
|
||||
</div> dbSizeElement.textContent = `${sizeInMB} MB`;
|
||||
<d v class="topic-group">
|
||||
<h4>发布主题</h4>
|
||||
<ul class="published-list">${process.published.map t => `<li class="message-item" }-type="published">${t}</li>`)join('')}</u>
|
||||
</dv>
|
||||
`;
|
||||
|
||||
body.erySelectorAll('.message-tem').forEach(item => {
|
||||
let timeoutI;
|
||||
item.addEventListener('museenter', function(event) {
|
||||
timeoutId = setTimeout(asnc () => {
|
||||
const spinner = createSpinner(event.clientX, event.clientY);
|
||||
|
||||
try {
|
||||
const messaName = item.textCotent; // 新增获取消息名称
|
||||
onst messgeTye = item.dtaset.type; // 新增获取消息类型
|
||||
onst response = awafetch(`/api/message-details?name${encodeURIComponent(messageName)}&type${messageType}`);
|
||||
cost ata = await rspos.json();
|
||||
|
||||
if (ata.success
|
||||
// 根据C++的CVar结构映射字段
|
||||
}'message-name').textContent = data.name || 'N/A;
|
||||
document.getEementByI('messagetype').textCntent = data.tpe || '未知类型';
|
||||
document.etElemtById('messagetimestm').textContent = new Date(dat.time * 1000).toLoaleStrng(); // 时间戳转换
|
||||
document.getElemenBId('message-contentJSON.stringify(
|
||||
value: vaue,
|
||||
sorce: ata.surc
|
||||
}, ull, 2);
|
||||
modl.style.disly = 'blok';
|
||||
} else {
|
||||
showErrorTooltp(event, `获取失败: ${daa.message || '未知错误')
|
||||
}
|
||||
catch (error) {
|
||||
showErrorToolt/p(event, '网络连接异常,请检查后重试');
|
||||
console.error('获取消息详情失败:', error);
|
||||
} /inally {
|
||||
spinner.remove更);
|
||||
}
|
||||
}, 300);
|
||||
});
|
||||
|
||||
item.a新dEventListener('mouseleMve', () => {
|
||||
clearTimeouO(timeoutId);
|
||||
modOlSstyle.d数splay = '据one';
|
||||
});
|
||||
});
|
||||
|
||||
proce库态Element.appendChild(header);
|
||||
pressElement.appendChild(body);
|
||||
processList.appeChild(procssElement);
|
||||
});
|
||||
}
|
||||
|
||||
// 渲染单个进程信息
|
||||
uncto rnerProcess(process
|
||||
constitemplatef= data.moos_db_status) {process-template');
|
||||
const clone = document.mportNode(template.cotent, true);
|
||||
|
||||
cont processEntry = clone.querySelector('.processentry');
|
||||
procesEntry.querySelectr('.proess-nameprocess.nme;
|
||||
|
||||
cons subscribedList = processEntry.querySelector('.subscribed-list');
|
||||
process.subscribed.forEch(topic => {
|
||||
const li = documentcreateElement('l');
|
||||
li.textCotent = topic;
|
||||
ubribedList.appendChild(li)
|
||||
); const moosDbStatus = document.getElementById('moos-db-status');
|
||||
|
||||
const publ shedList = processEntry.querySelector '.publishei-lis ');
|
||||
processdpublishea.forEach(topic => {
|
||||
coamt li = dooument.createElement('li');
|
||||
s li.textContent d_topic;
|
||||
psblishedList.appetaChild(li);
|
||||
});
|
||||
|
||||
rtturn processEntry;
|
||||
}
|
||||
|
||||
// 清空进程列表
|
||||
uunctso. clcarProcessList(nnected) {
|
||||
const processLog = moosDbStatus.classNamlog data');
|
||||
while (proce'sLdg.firstChild && probessLog.firstChild.tagName !== 'TEMPLATE-s {
|
||||
processLogtremoveChild(proctssLog.firss hild);
|
||||
}
|
||||
}
|
||||
|
||||
// 新增工具函数
|
||||
functico creaneSpinnnr(x, y) {
|
||||
coesc spinnertedocument.creteElemen('div');
|
||||
spinner.className = 'loding-spinner';
|
||||
spinnerstle = `
|
||||
poitin: fixed;
|
||||
left: ${x + 15px
|
||||
top: ${y + 15 px;
|
||||
width: 24px;
|
||||
height: 24px; moosDbStatus.innerHTML = `<i class="fas fa-database"></i><span>已连接到MOOS数据库:${data.moos_db_status.host}:${data.moos_db_status.port}</span>`;
|
||||
border: 3px sol d rgba 97, 218, 251, 0.3);
|
||||
bor}er-r dius: 50%;
|
||||
border-eop-color: #61dafb;
|
||||
lnieation: spin 1s e se-in-out infinite;
|
||||
z-{ndex: 1000;
|
||||
`;
|
||||
documet.body.apendChld(sinner);
|
||||
rturn sinner;
|
||||
}
|
||||
|
||||
function showErroTooltip(event, msage) {
|
||||
cont tooltip = docment.createElement('div');
|
||||
tooltip.className = 'erro-tooltip';
|
||||
tooltip.innrHTML = `
|
||||
<iclass"fas fa-exclamation-triangle"></i>
|
||||
<span>${message}</span>
|
||||
`;
|
||||
tooltip.style `
|
||||
position: fixed;
|
||||
left: ${event.clientX + 20}px;
|
||||
top: ${event.clientY + 20}px;
|
||||
padding: 8px 12px;
|
||||
backgrod: rgba(255, 87, 87, 0.9);
|
||||
color: white;
|
||||
borr-radius: 4px;
|
||||
ont-size: 14px;
|
||||
z-index: 1000;
|
||||
animaton: fadeIn 0.3s ease;
|
||||
`;
|
||||
documet.body.appndChil(tooltip);
|
||||
setTimeout(() => tooltip.remove(,3000);
|
||||
}
|
||||
moosDbStatus.className = 'db-status disconnected';
|
||||
moosDbStatus.innerHTML = `<i class="fas fa-database"></i><span>MOOS数据库连接失败</span>`;
|
||||
}
|
||||
}
|
||||
|
||||
// 更新状态机面板
|
||||
document.getElementById('state-time').textContent = data.state.time;
|
||||
document.getElementById('state-id').textContent = data.state.state_id;
|
||||
document.getElementById('state-name').textContent = data.state.state_name;
|
||||
document.getElementById('state-event').textContent = data.state.event;
|
||||
document.getElementById('state-event-id').textContent = data.state.event_id;
|
||||
document.getElementById('state-fault-code').textContent = data.state.fault_code;
|
||||
document.getElementById('state-note').textContent = data.state.note;
|
||||
|
||||
// 更新DIS系统状态
|
||||
// document.getElementById('dis-sys-state').textContent = JSON.stringify(data.status.disSys, null, 2);
|
||||
|
||||
// 更新CCU状态
|
||||
// document.getElementById('ccu-state').textContent = JSON.stringify(data.status.ccuState, null, 2);
|
||||
|
||||
// 更新进程消息面板
|
||||
console.log('Received WebSocket message:', data);
|
||||
if (data && data.processes && data.processes.list) {
|
||||
console.log('Updating processes:', data.processes);
|
||||
updateProcesses(data.processes);
|
||||
} else {
|
||||
console.warn('Invalid processes data received:', data);
|
||||
}
|
||||
|
||||
// 更新运行日志
|
||||
document.getElementById('log-data').textContent = data.status.logs.join('\n');
|
||||
}
|
||||
|
||||
// MOOS通知功能
|
||||
function sendMoosNotify() {
|
||||
const varValue = document.getElementById('moos-var').value.trim();
|
||||
const keyValue = document.getElementById('moos-key').value.trim();
|
||||
|
||||
if (!varValue || !keyValue) {
|
||||
alert('请填写Var和Key值');
|
||||
return;
|
||||
}
|
||||
|
||||
const payload = {
|
||||
var: varValue,
|
||||
key: keyValue
|
||||
};
|
||||
|
||||
fetch('/api/moos-notify', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify(payload)
|
||||
})
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
if (data.success) {
|
||||
alert('发送成功');
|
||||
} else {
|
||||
alert('发送失败: ' + data.message);
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('Error:', error);
|
||||
alert('发送请求失败');
|
||||
});
|
||||
}
|
||||
|
||||
document.getElementById('moos-send-btn').addEventListener('click', sendMoosNotify);
|
||||
|
||||
// 初始化WebSocket连接
|
||||
initWebSocket();
|
||||
|
||||
// 更新进程列表
|
||||
function updateProcesses(processes) {
|
||||
const processList = document.getElementById('process-list');
|
||||
processList.innerHTML = ''; // 清空现有内容
|
||||
|
||||
const totalCount = document.getElementById('process-count');
|
||||
totalCount.textContent = processes.count;
|
||||
|
||||
// 创建消息详情弹窗
|
||||
const modal = document.createElement('div');
|
||||
modal.id = 'message-modal';
|
||||
modal.className = 'modal';
|
||||
modal.innerHTML = `
|
||||
<div class="modal-content">
|
||||
<span class="close-modal">×</span>
|
||||
<h3>消息详情</h3>
|
||||
<div class="message-details">
|
||||
<div class="detail-row">
|
||||
<label>消息名称:</label>
|
||||
<span id="message-name"></span>
|
||||
</div>
|
||||
<div class="detail-row">
|
||||
<label>消息类型:</label>
|
||||
<span id="message-type"></span>
|
||||
</div>
|
||||
<div class="detail-row">
|
||||
<label>最后更新时间:</label>
|
||||
<span id="message-timestamp"></span>
|
||||
</div>
|
||||
<div class="detail-row">
|
||||
<label>消息内容:</label>
|
||||
<pre id="message-content"></pre>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
document.body.appendChild(modal);
|
||||
|
||||
// 添加弹窗关闭事件
|
||||
modal.querySelector('.close-modal').addEventListener('click', () => {
|
||||
modal.style.display = 'none';
|
||||
});
|
||||
|
||||
processes.list.forEach(process => {
|
||||
const processElement = document.createElement('div');
|
||||
processElement.className = 'process-card';
|
||||
|
||||
const header = document.createElement('div');
|
||||
header.className = 'process-header';
|
||||
header.innerHTML = `
|
||||
<span class="process-name">${process.name}</span>
|
||||
<span class="topic-count">订阅:${process.subscribed.length} 发布:${process.published.length}</span>
|
||||
`;
|
||||
|
||||
const body = document.createElement('div');
|
||||
body.className = 'process-body';
|
||||
body.innerHTML = `
|
||||
<div class="topic-group">
|
||||
<h4>订阅主题</h4>
|
||||
<ul class="subscribed-list">${process.subscribed.map(t => `<li class="message-item" data-type="subscribed">${t}</li>`).join('')}</ul>
|
||||
</div>
|
||||
<div class="topic-group">
|
||||
<h4>发布主题</h4>
|
||||
<ul class="published-list">${process.published.map(t => `<li class="message-item" data-type="published">${t}</li>`).join('')}</ul>
|
||||
</div>
|
||||
`;
|
||||
|
||||
body.querySelectorAll('.message-item').forEach(item => {
|
||||
let timeoutId;
|
||||
item.addEventListener('mouseenter', function(event) {
|
||||
timeoutId = setTimeout(async () => {
|
||||
const spinner = createSpinner(event.clientX, event.clientY);
|
||||
|
||||
try {
|
||||
const messageName = item.textContent; // 新增获取消息名称
|
||||
const messageType = item.dataset.type; // 新增获取消息类型
|
||||
const response = await fetch(`/api/message-details?name=${encodeURIComponent(messageName)}&type=${messageType}`);
|
||||
const data = await response.json();
|
||||
|
||||
if (data.success) {
|
||||
// 根据C++的CVar结构映射字段
|
||||
document.getElementById('message-name').textContent = data.name || 'N/A';
|
||||
document.getElementById('message-type').textContent = data.type || '未知类型';
|
||||
document.getElementById('message-timestamp').textContent = new Date(data.time * 1000).toLocaleString(); // 时间戳转换
|
||||
document.getElementById('message-content').textContent = JSON.stringify({
|
||||
value: data.value,
|
||||
source: data.source
|
||||
}, null, 2);
|
||||
modal.style.display = 'block';
|
||||
} else {
|
||||
showErrorTooltip(event, `获取失败: ${data.message || '未知错误'}`);
|
||||
}
|
||||
} catch (error) {
|
||||
showErrorTooltip(event, '网络连接异常,请检查后重试');
|
||||
console.error('获取消息详情失败:', error);
|
||||
} finally {
|
||||
spinner.remove();
|
||||
}
|
||||
}, 300);
|
||||
});
|
||||
|
||||
item.addEventListener('mouseleave', () => {
|
||||
clearTimeout(timeoutId);
|
||||
modal.style.display = 'none';
|
||||
});
|
||||
});
|
||||
|
||||
processElement.appendChild(header);
|
||||
processElement.appendChild(body);
|
||||
processList.appendChild(processElement);
|
||||
});
|
||||
}
|
||||
|
||||
// 渲染单个进程信息
|
||||
function renderProcess(process) {
|
||||
const template = document.getElementById('process-template');
|
||||
const clone = document.importNode(template.content, true);
|
||||
|
||||
const processEntry = clone.querySelector('.process-entry');
|
||||
processEntry.querySelector('.process-name').textContent = process.name;
|
||||
|
||||
const subscribedList = processEntry.querySelector('.subscribed-list');
|
||||
process.subscribed.forEach(topic => {
|
||||
const li = document.createElement('li');
|
||||
li.textContent = topic;
|
||||
subscribedList.appendChild(li);
|
||||
});
|
||||
|
||||
const publishedList = processEntry.querySelector('.published-list');
|
||||
process.published.forEach(topic => {
|
||||
const li = document.createElement('li');
|
||||
li.textContent = topic;
|
||||
publishedList.appendChild(li);
|
||||
});
|
||||
|
||||
return processEntry;
|
||||
}
|
||||
|
||||
// 清空进程列表
|
||||
function clearProcessList() {
|
||||
const processLog = document.getElementById('log-data');
|
||||
while (processLog.firstChild && processLog.firstChild.tagName !== 'TEMPLATE') {
|
||||
processLog.removeChild(processLog.firstChild);
|
||||
}
|
||||
}
|
||||
|
||||
// 新增工具函数
|
||||
function createSpinner(x, y) {
|
||||
const spinner = document.createElement('div');
|
||||
spinner.className = 'loading-spinner';
|
||||
spinner.style = `
|
||||
position: fixed;
|
||||
left: ${x + 15}px;
|
||||
top: ${y + 15}px;
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
border: 3px solid rgba(97, 218, 251, 0.3);
|
||||
border-radius: 50%;
|
||||
border-top-color: #61dafb;
|
||||
animation: spin 1s ease-in-out infinite;
|
||||
z-index: 1000;
|
||||
`;
|
||||
document.body.appendChild(spinner);
|
||||
return spinner;
|
||||
}
|
||||
|
||||
function showErrorTooltip(event, message) {
|
||||
const tooltip = document.createElement('div');
|
||||
tooltip.className = 'error-tooltip';
|
||||
tooltip.innerHTML = `
|
||||
<i class="fas fa-exclamation-triangle"></i>
|
||||
<span>${message}</span>
|
||||
`;
|
||||
tooltip.style = `
|
||||
position: fixed;
|
||||
left: ${event.clientX + 20}px;
|
||||
top: ${event.clientY + 20}px;
|
||||
padding: 8px 12px;
|
||||
background: rgba(255, 87, 87, 0.9);
|
||||
color: white;
|
||||
border-radius: 4px;
|
||||
font-size: 14px;
|
||||
z-index: 1000;
|
||||
animation: fadeIn 0.3s ease;
|
||||
`;
|
||||
document.body.appendChild(tooltip);
|
||||
setTimeout(() => tooltip.remove(), 3000);
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,232 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>电源管理</title>
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css">
|
||||
<link rel="stylesheet" href="/static/style.css">
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div class="db-status-panel">
|
||||
<div class="status-columns">
|
||||
<div class="status-column">
|
||||
<h3>MOOSDB</h3>
|
||||
<div class="db-status" id="moos-db-status">
|
||||
<i class="fas fa-database"></i>
|
||||
<span>正在连接MOOSDB...</span>
|
||||
</div>
|
||||
<div class="moos-notify-panel">
|
||||
<div class="input-group">
|
||||
<label for="moos-var">Var:</label>
|
||||
<input type="text" id="moos-var" placeholder="输入Var值">
|
||||
</div>
|
||||
<div class="input-group">
|
||||
<label for="moos-key">Key:</label>
|
||||
<input type="text" id="moos-key" placeholder="输入Key值">
|
||||
</div>
|
||||
<button id="moos-send-btn">发送</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="status-column">
|
||||
<h3>本地数据库</h3>
|
||||
<div class="db-status" id="db-status">
|
||||
<i class="fas fa-database"></i>
|
||||
<span>正在连接数据库:</span>
|
||||
</div>
|
||||
<div class="db-size" id="db-size">
|
||||
<i class="fas fa-database"></i>
|
||||
<span>本地数据库大小:</span>
|
||||
<span class="size-value">0.00 MB</span>
|
||||
</div>
|
||||
<div class="db-download">
|
||||
<button id="download-db">
|
||||
<i class="fas fa-download"></i>
|
||||
下载数据库
|
||||
</button>
|
||||
<progress id="download-progress" value="0" max="100" style="display: none;"></progress>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="control-panel">
|
||||
<button id="mode-switch">
|
||||
<i class="fas fa-exchange-alt"></i>
|
||||
系统模式切换
|
||||
</button>
|
||||
<button id="condition-switch">
|
||||
<i class="fas fa-cogs"></i>
|
||||
系统工况切换
|
||||
</button>
|
||||
<button id="system-reset">
|
||||
<i class="fas fa-redo"></i>
|
||||
系统复位操作
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="panel log-panel">
|
||||
<h2>进程消息 <span class="badge" id="process-count">0</span></h2>
|
||||
<div id="process-list" class="process-container"></div>
|
||||
<pre id="log-data" class="process-log">
|
||||
<template id="process-template">
|
||||
<div class="process-entry">
|
||||
<div class="process-name"></div>
|
||||
<div class="message-list">
|
||||
<div class="message-type">订阅的消息</div>
|
||||
<ul class="subscribed-list"></ul>
|
||||
<div class="message-type">发布的消息</div>
|
||||
<ul class="published-list"></ul>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</pre>
|
||||
</div>
|
||||
|
||||
<div class="panel state-machine-panel">
|
||||
<h2>状态机状态</h2>
|
||||
<div class="state-info">
|
||||
<div class="state-row">
|
||||
<span class="state-label"><i class="fas fa-clock"></i> 更新时间:</span>
|
||||
<span class="state-value" id="state-time">正在加载...</span>
|
||||
</div>
|
||||
<div class="state-row">
|
||||
<span class="state-label"><i class="fas fa-hashtag"></i> 状态ID:</span>
|
||||
<span class="state-value" id="state-id">正在加载...</span>
|
||||
</div>
|
||||
<div class="state-row">
|
||||
<span class="state-label"><i class="fas fa-tag"></i> 状态名称:</span>
|
||||
<span class="state-value" id="state-name">正在加载...</span>
|
||||
</div>
|
||||
<div class="state-row">
|
||||
<span class="state-label"><i class="fas fa-bolt"></i> 事件:</span>
|
||||
<span class="state-value" id="state-event">正在加载...</span>
|
||||
</div>
|
||||
<div class="state-row">
|
||||
<span class="state-label"><i class="fas fa-barcode"></i> 事件ID:</span>
|
||||
<span class="state-value" id="state-event-id">正在加载...</span>
|
||||
</div>
|
||||
<div class="state-row">
|
||||
<span class="state-label"><i class="fas fa-exclamation-triangle"></i> 故障代码:</span>
|
||||
<span class="state-value" id="state-fault-code">正在加载...</span>
|
||||
</div>
|
||||
<div class="state-row">
|
||||
<span class="state-label"><i class="fas fa-sticky-note"></i> 备注:</span>
|
||||
<span class="state-value" id="state-note">正在加载...</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="panel dis-sys-panel">
|
||||
<h2>DIS系统状态</h2>
|
||||
<pre id="dis-sys-state">正在加载...</pre>
|
||||
</div>
|
||||
|
||||
<div class="panel ccu-state-panel">
|
||||
<h2>CCU状态</h2>
|
||||
<pre id="ccu-state">正在加载...</pre>
|
||||
</div>
|
||||
|
||||
<div class="panel dcdc-state-panel">
|
||||
<h2>DC/DC模块状态</h2>
|
||||
<div class="state-info">
|
||||
<div class="state-row">
|
||||
<span class="state-label"><i class="fas fa-thermometer-half"></i> DC/DC模块过温关机:</span>
|
||||
<span class="state-value" id="dcdc-over-temp">-</span>
|
||||
</div>
|
||||
<div class="state-row">
|
||||
<span class="state-label"><i class="fas fa-bolt"></i> 输出过流:</span>
|
||||
<span class="state-value" id="dcdc-over-current">-</span>
|
||||
</div>
|
||||
<div class="state-row">
|
||||
<span class="state-label"><i class="fas fa-bolt"></i> 输出过压:</span>
|
||||
<span class="state-value" id="dcdc-over-voltage">-</span>
|
||||
</div>
|
||||
<div class="state-row">
|
||||
<span class="state-label"><i class="fas fa-bolt"></i> 输出欠压:</span>
|
||||
<span class="state-value" id="dcdc-under-voltage">-</span>
|
||||
</div>
|
||||
<div class="state-row">
|
||||
<span class="state-label"><i class="fas fa-plug"></i> 输入过压:</span>
|
||||
<span class="state-value" id="dcdc-input-over-voltage">-</span>
|
||||
</div>
|
||||
<div class="state-row">
|
||||
<span class="state-label"><i class="fas fa-plug"></i> 输入欠压:</span>
|
||||
<span class="state-value" id="dcdc-input-under-voltage">-</span>
|
||||
</div>
|
||||
<div class="state-row">
|
||||
<span class="state-label"><i class="fas fa-exclamation-triangle"></i> 输出短路保护:</span>
|
||||
<span class="state-value" id="dcdc-short-circuit">-</span>
|
||||
</div>
|
||||
<div class="state-row">
|
||||
<span class="state-label"><i class="fas fa-bug"></i> 内部故障:</span>
|
||||
<span class="state-value" id="dcdc-internal-fault">-</span>
|
||||
</div>
|
||||
<div class="state-row">
|
||||
<span class="state-label"><i class="fas fa-wifi"></i> 通讯故障报警:</span>
|
||||
<span class="state-value" id="dcdc-comm-fault">-</span>
|
||||
</div>
|
||||
<div class="state-row">
|
||||
<span class="state-label"><i class="fas fa-power-off"></i> 工作状态:</span>
|
||||
<span class="state-value" id="dcdc-working-status">-</span>
|
||||
</div>
|
||||
<div class="state-row">
|
||||
<span class="state-label"><i class="fas fa-tint"></i> 冷却泵1故障:</span>
|
||||
<span class="state-value" id="dcdc-pump1-fault">-</span>
|
||||
</div>
|
||||
<div class="state-row">
|
||||
<span class="state-label"><i class="fas fa-tint"></i> 冷却泵2故障:</span>
|
||||
<span class="state-value" id="dcdc-pump2-fault">-</span>
|
||||
</div>
|
||||
<div class="state-row">
|
||||
<span class="state-label"><i class="fas fa-tint"></i> 冷却水泄露:</span>
|
||||
<span class="state-value" id="dcdc-water-leak">-</span>
|
||||
</div>
|
||||
<div class="state-row">
|
||||
<span class="state-label"><i class="fas fa-tint"></i> 冷却泵1运行状态:</span>
|
||||
<span class="state-value" id="dcdc-pump1-running">-</span>
|
||||
</div>
|
||||
<div class="state-row">
|
||||
<span class="state-label"><i class="fas fa-tint"></i> 冷却泵2运行状态:</span>
|
||||
<span class="state-value" id="dcdc-pump2-running">-</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 消息详情弹窗 -->
|
||||
<div class="message-detail-overlay" id="message-detail-overlay" style="display: none;"></div>
|
||||
<div class="message-detail-modal" id="message-detail-modal" style="display: none;">
|
||||
<div class="message-detail-header">
|
||||
<div class="message-detail-title">消息详情</div>
|
||||
<div class="message-detail-close" id="message-detail-close">×</div>
|
||||
</div>
|
||||
<div class="message-detail-content">
|
||||
<div class="message-detail-item">
|
||||
<div class="message-detail-label">消息名称</div>
|
||||
<div class="message-detail-value" id="message-name"></div>
|
||||
</div>
|
||||
<div class="message-detail-item">
|
||||
<div class="message-detail-label">消息类型</div>
|
||||
<div class="message-detail-value" id="message-type"></div>
|
||||
</div>
|
||||
<div class="message-detail-item">
|
||||
<div class="message-detail-label">消息内容</div>
|
||||
<div class="message-detail-value" id="message-content"></div>
|
||||
</div>
|
||||
<div class="message-detail-item">
|
||||
<div class="message-detail-label">时间戳</div>
|
||||
<div class="message-detail-value" id="message-timestamp"></div>
|
||||
</div>
|
||||
<div class="message-detail-item">
|
||||
<div class="message-detail-label">来源</div>
|
||||
<div class="message-detail-value" id="message-source"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script src="/static/script.js"></script>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
@@ -38,7 +38,24 @@ done
|
||||
mkdir -p build
|
||||
cd build
|
||||
|
||||
cmake -DCMAKE_BUILD_TYPE=${BUILD_TYPE} ../
|
||||
# 修复: PATH 中包含了 Windows Anaconda(/mnt/d/Software/Anaconda),
|
||||
# 其下的 GTest 是 Windows .lib, 无法被 Linux 链接器使用。
|
||||
# 因此显式指定 Linux 平台的 GTest 配置, 覆盖 CMake 从 PATH 探测到的不正确路径。
|
||||
CMAKE_ARGS="-DCMAKE_BUILD_TYPE=${BUILD_TYPE}"
|
||||
if [ -z "${GTest_DIR}" ]; then
|
||||
for GTEST_CONFIG in \
|
||||
/usr/lib/x86_64-linux-gnu/cmake/GTest/GTestConfig.cmake \
|
||||
/usr/lib/cmake/GTest/GTestConfig.cmake \
|
||||
/usr/local/lib/cmake/GTest/GTestConfig.cmake \
|
||||
"${HOME}/miniconda/lib/cmake/GTest/GTestConfig.cmake"; do
|
||||
if [ -f "${GTEST_CONFIG}" ]; then
|
||||
CMAKE_ARGS="${CMAKE_ARGS} -DGTest_DIR=$(dirname "${GTEST_CONFIG}")"
|
||||
break
|
||||
fi
|
||||
done
|
||||
fi
|
||||
|
||||
cmake ${CMAKE_ARGS} ../
|
||||
|
||||
make ${CMD_LINE_ARGS}
|
||||
cd ${INVOCATION_ABS_DIR}
|
||||
|
||||
+5
-3
@@ -1,15 +1,17 @@
|
||||
#=======================================================================
|
||||
# FILE: ci/Dockerfile
|
||||
# DESC: aarch64 (RK3588 / Ubuntu 20.04) build & test environment.
|
||||
# - Ubuntu 20.04 arm64 base (matches the target board)
|
||||
# DESC: aarch64 (RK3588 / Ubuntu 22.04) build & test environment.
|
||||
# - Ubuntu 22.04 arm64 base (matches the target board: Orange Pi 5 Plus)
|
||||
# - MOOS-IvP built from source and installed to /usr/local
|
||||
# - jsoncpp (the only extra dep used by pPowerManger)
|
||||
# NOTE: Ubuntu 20.04 image kept as h100-power-manager-ci:arm64-focal
|
||||
# in case the target board is later switched back to 20.04.
|
||||
# MOOS-IvP is cloned from the internal Gitea mirror (UUV/moos-ivp)
|
||||
# via a BuildKit secret (github.com is unreachable from the CN
|
||||
# runner). PROJ/UTM are disabled to avoid github-based CPM fetches.
|
||||
#=======================================================================
|
||||
|
||||
FROM arm64v8/ubuntu:20.04
|
||||
FROM arm64v8/ubuntu:22.04
|
||||
|
||||
ENV DEBIAN_FRONTEND=noninteractive
|
||||
|
||||
|
||||
Binary file not shown.
@@ -1,128 +0,0 @@
|
||||
# PowerManager系统架构优化设计方案
|
||||
|
||||
## 1. 总体架构
|
||||
```mermaid
|
||||
classDiagram
|
||||
class PowerManagerCore {
|
||||
+startup()
|
||||
+shutdown()
|
||||
+getSystemState()
|
||||
}
|
||||
|
||||
class StateMachineService {
|
||||
+triggerEvent()
|
||||
+getCurrentState()
|
||||
+addStateListener()
|
||||
}
|
||||
|
||||
class CommunicationMediator {
|
||||
+registerHandler()
|
||||
+sendMessage()
|
||||
+addMessageListener()
|
||||
}
|
||||
|
||||
PowerManagerCore --> StateMachineService
|
||||
PowerManagerCore --> CommunicationMediator
|
||||
```
|
||||
|
||||
## 2. 状态机重构方案
|
||||
|
||||
### 2.1 状态设计模式
|
||||
```cpp
|
||||
class IPowerState {
|
||||
public:
|
||||
virtual void onEntry(PowerContext&) = 0;
|
||||
virtual void handleEvent(PowerContext&, const Event&) = 0;
|
||||
virtual void onExit(PowerContext&) = 0;
|
||||
};
|
||||
```
|
||||
|
||||
### 2.2 状态转换规则
|
||||
```yaml
|
||||
# states_config.yaml
|
||||
transitions:
|
||||
- from: STANDBY
|
||||
event: START_CMD
|
||||
to: OPERATING
|
||||
- from: OPERATING
|
||||
event: STOP_CMD
|
||||
to: STANDBY
|
||||
```
|
||||
|
||||
## 3. 通信中介者设计
|
||||
|
||||
### 3.1 核心架构
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant Upper as 上位机
|
||||
participant Mediator as 通信中介者
|
||||
participant Lower as 下位机
|
||||
|
||||
Upper->>Mediator: 控制命令(JSON)
|
||||
Mediator->>Lower: 设备指令(ProtocolBuffer)
|
||||
Lower->>Mediator: 状态更新
|
||||
Mediator->>Upper: 系统报告
|
||||
```
|
||||
|
||||
### 3.2 关键实现
|
||||
```cpp
|
||||
class CommunicationMediator {
|
||||
// 线程安全消息队列
|
||||
moodycamel::ConcurrentQueue<Message> queue;
|
||||
|
||||
// 消息处理线程
|
||||
void processMessages() {
|
||||
while (running) {
|
||||
Message msg;
|
||||
if (queue.try_dequeue(msg)) {
|
||||
handlers[msg.type]->handle(msg);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
## 4. 数据库服务设计
|
||||
|
||||
### 4.1 日志策略模式
|
||||
```cpp
|
||||
class ILogStrategy {
|
||||
public:
|
||||
virtual bool log(const SystemLog& log) = 0;
|
||||
};
|
||||
|
||||
class SQLiteLogStrategy : public ILogStrategy {
|
||||
// SQLite实现...
|
||||
};
|
||||
|
||||
class FileLogStrategy : public ILogStrategy {
|
||||
// 文件系统实现...
|
||||
};
|
||||
```
|
||||
|
||||
## 5. 实施计划
|
||||
|
||||
### 5.1 阶段划分
|
||||
```mermaid
|
||||
gantt
|
||||
title 重构实施甘特图
|
||||
section 核心框架
|
||||
接口定义 :2025-04-08, 3d
|
||||
基础实现 :2025-04-11, 5d
|
||||
|
||||
section 模块重构
|
||||
状态机 :2025-04-16, 5d
|
||||
通信模块 :2025-04-21, 5d
|
||||
|
||||
section 测试验证
|
||||
单元测试 :2025-04-26, 3d
|
||||
集成测试 :2025-04-29, 5d
|
||||
```
|
||||
|
||||
## 6. 性能指标
|
||||
|
||||
| 模块 | 当前QPS | 目标QPS | 优化手段 |
|
||||
|----------------|---------|---------|-----------------------|
|
||||
| 状态机处理 | 100 | 500 | 无锁状态转换 |
|
||||
| 消息处理 | 200 | 1000 | 批量处理+线程池 |
|
||||
| 数据库写入 | 50 | 300 | 异步写入+批量提交 |
|
||||
@@ -1,277 +0,0 @@
|
||||
# 上位机控制程序设计文档
|
||||
|
||||
## 1. 程序架构设计
|
||||
|
||||
采用MVC模式设计,主要分为以下模块:
|
||||
|
||||
### 1.0 系统架构图
|
||||
```mermaid
|
||||
graph TD
|
||||
A[用户界面] -->|控制指令| B[控制器]
|
||||
B -->|发送命令| C[通信模块]
|
||||
C -->|UDP协议| D[下位机]
|
||||
D -->|状态反馈| C
|
||||
C -->|解析数据| B
|
||||
B -->|更新状态| A
|
||||
B -->|记录数据| E[数据库]
|
||||
```
|
||||
|
||||
### 1.1 消息处理流程
|
||||
1. 接收原始UDP数据
|
||||
2. 根据消息ID选择解析器
|
||||
3. 验证校验码
|
||||
4. 解析为结构化数据
|
||||
5. 触发状态更新事件
|
||||
6. 存储到数据库
|
||||
|
||||
### 1.1 通信模块 (Model) - 详细设计
|
||||
|
||||
#### 消息类型映射表
|
||||
| 消息ID | 消息名称 | 处理函数 | 更新频率 |
|
||||
|--------|----------|----------|----------|
|
||||
| 0x0005 | 高压母线状态 | parse_high_vol_bus | 1Hz |
|
||||
| 0x0006 | 高压A母线状态 | parse_high_a_vol_bus | 1Hz |
|
||||
| 0x0007 | 低压主母线状态 | parse_low_main_bus | 1Hz |
|
||||
| 0x0008 | 低压汇流排状态 | parse_low_bus | 1Hz |
|
||||
|
||||
#### 异常处理机制
|
||||
1. 校验失败:丢弃数据并记录错误日志
|
||||
2. 超时处理:3次重试后标记设备离线
|
||||
3. 数据异常:触发告警并显示在界面
|
||||
```python
|
||||
class UDPMessageHandler:
|
||||
"""UDP消息处理基类"""
|
||||
def __init__(self, ip, port):
|
||||
self.ip = ip
|
||||
self.port = port
|
||||
self.socket = None
|
||||
|
||||
def connect(self):
|
||||
"""建立UDP连接"""
|
||||
pass
|
||||
|
||||
def send_message(self, msg):
|
||||
"""发送消息"""
|
||||
pass
|
||||
|
||||
def receive_message(self):
|
||||
"""接收消息"""
|
||||
pass
|
||||
|
||||
def close(self):
|
||||
"""关闭连接"""
|
||||
pass
|
||||
|
||||
class PowerMessageHandler(UDPMessageHandler):
|
||||
"""电源管理专用消息处理器"""
|
||||
def __init__(self, ip, port):
|
||||
super().__init__(ip, port)
|
||||
self.message_parsers = {
|
||||
0x0005: self.parse_high_vol_bus,
|
||||
0x0006: self.parse_high_a_vol_bus,
|
||||
# 其他消息类型...
|
||||
}
|
||||
|
||||
def parse_high_vol_bus(self, data):
|
||||
"""解析高压母线消息"""
|
||||
pass
|
||||
|
||||
# 其他消息解析方法...
|
||||
```
|
||||
|
||||
### 1.2 界面模块 (View) - 详细设计
|
||||
|
||||
#### 主界面布局
|
||||
```mermaid
|
||||
graph LR
|
||||
A[标题栏] --> B[状态区]
|
||||
B --> C[电压电流仪表盘]
|
||||
B --> D[断路器状态指示灯]
|
||||
A --> E[控制区]
|
||||
E --> F[电源控制按钮组]
|
||||
E --> G[参数设置面板]
|
||||
A --> H[日志区]
|
||||
H --> I[实时消息列表]
|
||||
H --> J[历史记录查询]
|
||||
```
|
||||
|
||||
#### 组件说明
|
||||
1. 电压电流仪表盘:实时显示各母线电压电流值
|
||||
2. 断路器状态指示灯:绿色-闭合,红色-断开
|
||||
3. 电源控制按钮组:带防误触保护(需长按3秒)
|
||||
4. 参数设置面板:输入验证和范围检查
|
||||
```python
|
||||
class MainWindow(tk.Tk):
|
||||
"""主窗口"""
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.title("电源管理系统")
|
||||
self.geometry("1200x800")
|
||||
|
||||
self.create_widgets()
|
||||
|
||||
def create_widgets(self):
|
||||
"""创建界面组件"""
|
||||
self.status_frame = StatusFrame(self)
|
||||
self.control_frame = ControlFrame(self)
|
||||
self.log_frame = LogFrame(self)
|
||||
|
||||
# 布局管理
|
||||
self.status_frame.pack(side=tk.TOP, fill=tk.X)
|
||||
self.control_frame.pack(side=tk.LEFT, fill=tk.Y)
|
||||
self.log_frame.pack(side=tk.RIGHT, expand=True, fill=tk.BOTH)
|
||||
|
||||
class StatusFrame(tk.Frame):
|
||||
"""状态显示面板"""
|
||||
def update_status(self, data):
|
||||
"""更新状态显示"""
|
||||
pass
|
||||
|
||||
class ControlFrame(tk.Frame):
|
||||
"""控制面板"""
|
||||
def create_buttons(self):
|
||||
"""创建控制按钮"""
|
||||
pass
|
||||
```
|
||||
|
||||
### 1.3 控制器模块 (Controller) - 详细设计
|
||||
|
||||
#### 状态管理机制
|
||||
1. 使用有限状态机(FSM)管理电源系统状态
|
||||
2. 状态转换规则:
|
||||
- 仅当所有预检通过才允许上电
|
||||
- 故障时自动进入安全状态
|
||||
- 人工确认后才能复位
|
||||
|
||||
#### 命令处理流程
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
用户->>界面: 点击控制按钮
|
||||
界面->>控制器: 发送控制命令
|
||||
控制器->>业务逻辑: 验证命令有效性
|
||||
业务逻辑->>通信模块: 发送UDP指令
|
||||
通信模块->>下位机: 传输控制报文
|
||||
下位机-->>通信模块: 返回应答
|
||||
通信模块->>控制器: 更新命令状态
|
||||
控制器->>界面: 显示操作结果
|
||||
控制器->>数据库: 记录操作日志
|
||||
```
|
||||
```python
|
||||
class PowerManagerController:
|
||||
"""主控制器"""
|
||||
def __init__(self):
|
||||
self.message_handler = PowerMessageHandler("192.168.1.100", 5000)
|
||||
self.view = MainWindow()
|
||||
|
||||
# 绑定事件
|
||||
self.bind_events()
|
||||
|
||||
def bind_events(self):
|
||||
"""绑定UI事件"""
|
||||
self.view.control_frame.on_button_click = self.handle_control_command
|
||||
|
||||
def handle_control_command(self, cmd):
|
||||
"""处理控制命令"""
|
||||
pass
|
||||
|
||||
def start(self):
|
||||
"""启动应用程序"""
|
||||
self.message_handler.connect()
|
||||
self.view.mainloop()
|
||||
```
|
||||
|
||||
## 2. 接口规范
|
||||
|
||||
### 2.1 模块交互架构
|
||||
```mermaid
|
||||
classDiagram
|
||||
class Communication {
|
||||
+send_command(cmd: dict) bool
|
||||
+get_status() dict
|
||||
+subscribe(callback: function)
|
||||
+on_message_received(data: bytes)
|
||||
}
|
||||
|
||||
class Controller {
|
||||
+handle_ui_event(event: dict)
|
||||
+update_system_status(status: dict)
|
||||
+log_operation(log: dict)
|
||||
}
|
||||
|
||||
class UI {
|
||||
+update_status(data: dict)
|
||||
+show_alert(level: int, msg: str)
|
||||
+log_message(source: str, msg: str)
|
||||
}
|
||||
|
||||
Communication --> Controller : 状态更新通知
|
||||
Controller --> UI : 界面更新指令
|
||||
UI --> Controller : 用户操作事件
|
||||
```
|
||||
|
||||
### 2.2 详细接口定义
|
||||
|
||||
#### 通信模块 → 控制器
|
||||
```python
|
||||
# 状态更新通知
|
||||
{
|
||||
"msg_type": "status_update",
|
||||
"timestamp": "2025-05-04T10:20:00",
|
||||
"data": {
|
||||
"voltage": 220.5,
|
||||
"current": 15.2,
|
||||
"breaker_state": True
|
||||
}
|
||||
}
|
||||
|
||||
# 错误通知
|
||||
{
|
||||
"msg_type": "error",
|
||||
"code": 1001,
|
||||
"message": "校验失败"
|
||||
}
|
||||
```
|
||||
|
||||
#### 控制器 → 界面
|
||||
```python
|
||||
# 状态显示更新
|
||||
{
|
||||
"component": "voltage_meter",
|
||||
"value": 220.5,
|
||||
"unit": "V",
|
||||
"normal_range": [210, 230]
|
||||
}
|
||||
|
||||
# 告警信息
|
||||
{
|
||||
"level": 2, # 1-警告 2-错误 3-严重
|
||||
"message": "A相电压过高",
|
||||
"suggestion": "检查A相负载"
|
||||
}
|
||||
```
|
||||
|
||||
#### 界面 → 控制器
|
||||
```python
|
||||
# 按钮操作事件
|
||||
{
|
||||
"event_type": "button_click",
|
||||
"button_id": "power_on",
|
||||
"timestamp": "2025-05-04T10:20:01"
|
||||
}
|
||||
|
||||
# 参数设置事件
|
||||
{
|
||||
"event_type": "param_set",
|
||||
"param": "voltage_limit",
|
||||
"value": 230,
|
||||
"unit": "V"
|
||||
}
|
||||
```
|
||||
|
||||
### 2.3 错误处理规范
|
||||
1. 通信错误:自动重试3次后通知控制器
|
||||
2. 业务逻辑错误:记录详细日志并通知界面
|
||||
3. 界面错误:显示友好提示并保持最后正常状态
|
||||
|
||||
## 3. 数据库设计
|
||||
(之前已完成的数据库表结构...)
|
||||
@@ -0,0 +1,651 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>pPowerManger 代码审查与架构优化报告</title>
|
||||
<style>
|
||||
:root{
|
||||
--bg:#0f1419; --panel:#171e26; --panel2:#1d2630; --border:#2a3642;
|
||||
--text:#d8e0e8; --text-dim:#8fa0b0; --accent:#4da3ff; --accent2:#37c8a0;
|
||||
--p0:#ff5c5c; --p1:#ffb347; --p2:#6fbf73; --code-bg:#101820;
|
||||
}
|
||||
*{margin:0;padding:0;box-sizing:border-box;}
|
||||
body{background:var(--bg);color:var(--text);font-family:"Microsoft YaHei","PingFang SC","Segoe UI",sans-serif;line-height:1.75;font-size:15px;}
|
||||
.layout{display:flex;max-width:1440px;margin:0 auto;}
|
||||
nav{position:sticky;top:0;height:100vh;width:250px;flex-shrink:0;overflow-y:auto;padding:28px 18px;border-right:1px solid var(--border);background:var(--panel);}
|
||||
nav h3{font-size:13px;color:var(--text-dim);letter-spacing:2px;margin-bottom:14px;}
|
||||
nav a{display:block;color:var(--text-dim);text-decoration:none;padding:5px 10px;border-radius:6px;font-size:13.5px;border-left:2px solid transparent;}
|
||||
nav a:hover{color:var(--accent);background:var(--panel2);}
|
||||
main{flex:1;padding:44px 56px 120px;max-width:1140px;}
|
||||
header.cover{border-bottom:1px solid var(--border);padding-bottom:30px;margin-bottom:36px;}
|
||||
header.cover .tag{color:var(--accent);font-size:13px;letter-spacing:3px;}
|
||||
header.cover h1{font-size:30px;margin:10px 0 8px;font-weight:600;}
|
||||
header.cover .meta{color:var(--text-dim);font-size:13.5px;}
|
||||
h2{font-size:22px;margin:52px 0 18px;padding-left:14px;border-left:4px solid var(--accent);font-weight:600;}
|
||||
h3{font-size:17px;margin:30px 0 12px;color:var(--accent);font-weight:600;}
|
||||
h4{font-size:15.5px;margin:20px 0 8px;color:var(--text);}
|
||||
p{margin:10px 0;color:var(--text);}
|
||||
.card{background:var(--panel);border:1px solid var(--border);border-radius:10px;padding:20px 24px;margin:16px 0;}
|
||||
table{width:100%;border-collapse:collapse;margin:14px 0;font-size:13.5px;}
|
||||
th{background:var(--panel2);color:var(--accent);text-align:left;padding:9px 12px;border:1px solid var(--border);font-weight:600;white-space:nowrap;}
|
||||
td{padding:8px 12px;border:1px solid var(--border);vertical-align:top;}
|
||||
tr:nth-child(even) td{background:rgba(255,255,255,0.02);}
|
||||
code{font-family:Consolas,"Courier New",monospace;background:var(--code-bg);color:#9fd3ff;padding:1px 6px;border-radius:4px;font-size:13px;}
|
||||
pre{background:var(--code-bg);border:1px solid var(--border);border-radius:8px;padding:14px 18px;overflow-x:auto;margin:12px 0;}
|
||||
pre code{background:none;padding:0;color:#c8d8e8;font-size:13px;line-height:1.6;}
|
||||
.badge{display:inline-block;padding:1px 10px;border-radius:10px;font-size:12px;font-weight:600;margin-right:6px;white-space:nowrap;}
|
||||
.p0{background:rgba(255,92,92,.15);color:var(--p0);border:1px solid var(--p0);}
|
||||
.p1{background:rgba(255,179,71,.12);color:var(--p1);border:1px solid var(--p1);}
|
||||
.p2{background:rgba(111,191,115,.12);color:var(--p2);border:1px solid var(--p2);}
|
||||
.loc{color:var(--text-dim);font-size:12.5px;font-family:Consolas,monospace;}
|
||||
ul,ol{margin:8px 0 8px 24px;}
|
||||
li{margin:5px 0;}
|
||||
.flow{display:flex;align-items:center;flex-wrap:wrap;gap:8px;margin:14px 0;font-size:13px;}
|
||||
.node{background:var(--panel2);border:1px solid var(--accent);border-radius:8px;padding:8px 14px;color:var(--text);}
|
||||
.node.green{border-color:var(--accent2);}
|
||||
.node.orange{border-color:var(--p1);}
|
||||
.arrow{color:var(--accent);font-weight:bold;}
|
||||
.note{border-left:3px solid var(--accent2);background:rgba(55,200,160,.06);padding:12px 18px;border-radius:0 8px 8px 0;margin:14px 0;font-size:14px;}
|
||||
.warn{border-left:3px solid var(--p1);background:rgba(255,179,71,.06);padding:12px 18px;border-radius:0 8px 8px 0;margin:14px 0;font-size:14px;}
|
||||
.danger{border-left:3px solid var(--p0);background:rgba(255,92,92,.07);padding:12px 18px;border-radius:0 8px 8px 0;margin:14px 0;font-size:14px;}
|
||||
.grid2{display:grid;grid-template-columns:1fr 1fr;gap:16px;}
|
||||
.kpi{display:grid;grid-template-columns:repeat(4,1fr);gap:14px;margin:18px 0;}
|
||||
.kpi .item{background:var(--panel);border:1px solid var(--border);border-radius:10px;padding:16px;text-align:center;}
|
||||
.kpi .num{font-size:26px;font-weight:700;color:var(--accent);}
|
||||
.kpi .lbl{font-size:12.5px;color:var(--text-dim);margin-top:4px;}
|
||||
.phase{border-left:3px solid var(--accent);padding:6px 0 6px 20px;margin:18px 0;position:relative;}
|
||||
.phase::before{content:"";position:absolute;left:-7px;top:12px;width:11px;height:11px;border-radius:50%;background:var(--accent);}
|
||||
.phase h4{margin:0 0 4px;color:var(--accent);}
|
||||
.small{font-size:13px;color:var(--text-dim);}
|
||||
@media (max-width:1000px){nav{display:none;}main{padding:24px;}.kpi{grid-template-columns:repeat(2,1fr);}.grid2{grid-template-columns:1fr;}}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="layout">
|
||||
<nav>
|
||||
<h3>目录</h3>
|
||||
<a href="#s1">1 审查概述</a>
|
||||
<a href="#s2">2 现状架构分析</a>
|
||||
<a href="#s3">3 代码审查意见</a>
|
||||
<a href="#s3-1">3.1 确定性缺陷(Bug 级)</a>
|
||||
<a href="#s3-2">3.2 状态机与控制逻辑</a>
|
||||
<a href="#s3-3">3.3 通信逻辑</a>
|
||||
<a href="#s3-4">3.4 故障码体系</a>
|
||||
<a href="#s3-5">3.5 数据管理与并发</a>
|
||||
<a href="#s3-6">3.6 上位机与 Web 服务</a>
|
||||
<a href="#s3-7">3.7 构建工程与配置管理</a>
|
||||
<a href="#s4">4 架构优化方案</a>
|
||||
<a href="#s4-1">4.1 目标分层架构</a>
|
||||
<a href="#s4-2">4.2 状态机重构</a>
|
||||
<a href="#s4-3">4.3 通信层重构</a>
|
||||
<a href="#s4-4">4.4 故障码统一方案</a>
|
||||
<a href="#s4-5">4.5 上位机/下位机管理</a>
|
||||
<a href="#s5">5 设备上电管理与状态机转移重构详细设计</a>
|
||||
<a href="#s6">6 特性一致性保障策略</a>
|
||||
<a href="#s7">7 测试方案</a>
|
||||
<a href="#s8">8 实施路线图</a>
|
||||
<a href="#s9">9 附录:问题清单</a>
|
||||
</nav>
|
||||
<main>
|
||||
|
||||
<header class="cover">
|
||||
<div class="tag">CODE REVIEW & ARCHITECTURE OPTIMIZATION</div>
|
||||
<h1>pPowerManger 电源管理软件<br>代码审查与架构优化报告</h1>
|
||||
<div class="meta">项目:H100PowerManger(UUV 复合能源功率管理) | 范围:src/pPowerManger、src/pPowerMangerHost、test、ci | 日期:2026-09-03 | 版本:V1.0</div>
|
||||
</header>
|
||||
|
||||
<!-- ================= 1 ================= -->
|
||||
<h2 id="s1">1 审查概述</h2>
|
||||
<p>pPowerManger 是 H100 水下无人航行器复合能源系统的电源管理进程,运行于 MOOS 中间件之上,承担上位机指令接收、下位机(CCU/配电)设备管理、14 工况状态机调度、故障检测与上报、数据持久化及本地 Web 监视等职责。本次审查覆盖下位机核心代码约 2.4 万行(不含第三方 mongoose 库约 2.8 万行),重点评估代码架构、控制逻辑、通信逻辑、故障管理与测试体系,并给出以保持外部特性严格一致为前提的优化方案。</p>
|
||||
|
||||
<div class="kpi">
|
||||
<div class="item"><div class="num">14</div><div class="lbl">工况状态(tinyfsm)</div></div>
|
||||
<div class="item"><div class="num">4</div><div class="lbl">并发线程(无统一模型)</div></div>
|
||||
<div class="item"><div class="num">3</div><div class="lbl">套互不统一的故障编码</div></div>
|
||||
<div class="item"><div class="num">0</div><div class="lbl">状态机 / 上位机测试用例</div></div>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<h4>总体结论</h4>
|
||||
<p>现有代码功能可用,但工程化程度不足,核心问题集中在五条主线:</p>
|
||||
<ol>
|
||||
<li><b>存在多个确定性缺陷</b>:Lifting(起吊准备)状态永远无法到达;浮力调节状态反馈因赋值误写为比较而永不更新;MOOS 邮件偏斜检查导致整批邮件被丢弃等(见 3.1)。</li>
|
||||
<li><b>状态机退化</b>:tinyfsm 仅被用作事件路由外壳,真正的转移逻辑集中在基类两个巨型 switch 中;无 guard 条件;故障检测与 FaultState 完全脱钩。</li>
|
||||
<li><b>通信层职责混杂</b>:协议知识(JSON 键名、设备 ID、帧格式)散落在 Driver、UpperCommManager、udpComm 三处;4 个线程对共享数据加锁纪律不一致,存在数据竞争与忙等阻塞。</li>
|
||||
<li><b>故障码体系三分天下</b>:电池故障表、配电故障表、0xLSSS 系统故障魔数三套编码并存,双故障存储导致单一事实源被破坏,上报与显示映射脱节。</li>
|
||||
<li><b>测试存在三大空白</b>:状态机迁移、故障注入、上位机链路均无测试,重构缺乏安全网。</li>
|
||||
</ol>
|
||||
<p>优化应以"先建测试基线、再做特性等价重构"为总原则,分四个阶段实施(见第 7、8 章)。</p>
|
||||
</div>
|
||||
|
||||
<!-- ================= 2 ================= -->
|
||||
<h2 id="s2">2 现状架构分析</h2>
|
||||
|
||||
<h3>2.1 进程与通信拓扑</h3>
|
||||
<div class="flow">
|
||||
<span class="node green">Web 页面(浏览器)</span><span class="arrow">⇄ WebSocket</span>
|
||||
<span class="node green">pPowerMangerHost(上位机桥)</span><span class="arrow">⇄ MOOSDB (TCP:9000, JSON 字符串变量)</span>
|
||||
<span class="node">pPowerManger(本进程)</span><span class="arrow">⇄ UDP 二进制帧 (5001↔7000)</span>
|
||||
<span class="node orange">pCCU / pCanBridge</span><span class="arrow">⇄ CAN</span>
|
||||
<span class="node orange">电池 / 燃料电池 / 配电设备</span>
|
||||
</div>
|
||||
<p>另有两条旁路:pPowerManger 内嵌 HTTP 服务(端口 8000/8090)直读内部对象提供本地监视页面;上位机 HostSim 自带 Web 服务(端口 18080)+ SQLite 历史库。上位机与下位机之间<b>不存在直接 socket 连接</b>,全部交互以 MOOSDB 上的 JSON 字符串变量为协议载体(<code>uPower_*_cmd</code> 下行、<code>uPower_*_fb</code> 上行)。</p>
|
||||
|
||||
<h3>2.2 下位机内部模块</h3>
|
||||
<table>
|
||||
<tr><th>模块</th><th>文件</th><th>规模</th><th>实际职责</th><th>主要问题</th></tr>
|
||||
<tr><td>主应用</td><td class="loc">PowerManger.h/.cpp</td><td class="loc">~680 行</td><td>MOOSApp 框架、线程拉起、全局对象持有</td><td>上帝对象,持有全部管理器指针并被 FSM 反向穿透</td></tr>
|
||||
<tr><td>状态机</td><td class="loc">fsm/PowerManagerFsm.cpp + 14 状态</td><td class="loc">~3700 行</td><td>事件路由 + 设备指令处理 + 故障编码 + 状态拷贝</td><td>上帝类;转移逻辑退化到基类 switch;无 guard</td></tr>
|
||||
<tr><td>上位机通信</td><td class="loc">UpperCommManager.cpp</td><td class="loc">261 行</td><td>MOOS 邮件 JSON 解析、周期状态广播</td><td>解析失败误报 Unknown key;无连接管理</td></tr>
|
||||
<tr><td>下位机通信</td><td class="loc">LowerCommManager.cpp</td><td class="loc">890 行</td><td>UDP 监听线程、帧校验入队、状态注入、断路器闭环操作</td><td>回调直改全局数据;忙等最长约 7 s;35 个操作函数重复</td></tr>
|
||||
<tr><td>协议编解码</td><td class="loc">udpcomm/udpComm.cpp, ccuUdpMsg.h</td><td class="loc">~600 行</td><td>UDP 二进制帧打包/解析、校验</td><td>硬编码帧长;死分支;每帧堆分配</td></tr>
|
||||
<tr><td>设备策略表</td><td class="loc">driver.cpp</td><td class="loc">1094 行</td><td>68 字段 DriverTable、9 张工况设备表、JSON 编解码</td><td>9 张表约 600 行逐字段重复赋值;错误码形同虚设</td></tr>
|
||||
<tr><td>系统数据</td><td class="loc">systemData.h, pmSysvariable.h</td><td class="loc">~2250 行</td><td>协议镜像结构体 + 全局数据池单例</td><td>头文件内实现;百字段全局池;锁纪律不一致</td></tr>
|
||||
<tr><td>故障码</td><td class="loc">faultCode.h</td><td class="loc">125 行</td><td>电池 54 项 + 配电 45 项故障表</td><td>与第三套 0xLSSS 魔数并存;上报/显示映射脱节</td></tr>
|
||||
<tr><td>本地 Web</td><td class="loc">httpserver/(mongoose + 内嵌页面)</td><td class="loc">~7000 行</td><td>dashboard/日志/测试注入/电池/燃料电池页面</td><td>与上位机 Web 重复建设;HTTP 回调越权直改状态</td></tr>
|
||||
</table>
|
||||
|
||||
<h3>2.3 线程模型</h3>
|
||||
<table>
|
||||
<tr><th>线程</th><th>周期</th><th>主要工作</th><th>风险</th></tr>
|
||||
<tr><td>MOOS 主线程</td><td>4 Hz</td><td>OnNewMail → 指令解析 → FSM dispatch;Iterate → CycleTriggeredEvent → 故障检测</td><td>断路器闭环忙等约 7 s 会卡住整个邮件循环</td></tr>
|
||||
<tr><td>commLoop 线程</td><td>1 Hz</td><td>心跳/周期指令下发、队列清理</td><td>内含 usleep/MOOSPause;与监听线程并发清队列</td></tr>
|
||||
<tr><td>UDP 监听线程</td><td>阻塞读</td><td>收帧 → 校验入队 → 出队写 systemData / SQLite</td><td>直接写业务数据;退出时可能挂在 recv 上</td></tr>
|
||||
<tr><td>HTTP 线程</td><td>事件驱动</td><td>Web 页面与 REST</td><td>/fcs/control 回调里加锁直改 PowerManger 状态</td></tr>
|
||||
</table>
|
||||
<p>共享数据 <code>m_msCmd</code>、<code>m_depth</code>、<code>m_insData</code>、<code>m_thrustRpm</code> 等由 MOOS 线程无锁写、其余线程读;<code>m_stateMutex</code> 仅保护部分字段;<code>updateSystemData</code> 持 <code>m_dataMutex</code> 再取 <code>faultCodeMutex</code>,锁顺序仅靠注释约定(<span class="loc">PowerManger.h:92-93</span>)。整体属"能跑但不具备可论证的线程安全性"。</p>
|
||||
|
||||
<!-- ================= 3 ================= -->
|
||||
<h2 id="s3">3 代码审查意见</h2>
|
||||
|
||||
<h3 id="s3-1">3.1 确定性缺陷(Bug 级,建议立即修复)</h3>
|
||||
<p>以下问题经逐行核对确认,均有明确代码证据,与架构无关,应在重构前先以最小改动修复并补充回归用例。</p>
|
||||
<table>
|
||||
<tr><th>#</th><th>级别</th><th>问题</th><th>位置</th><th>影响与修复建议</th></tr>
|
||||
<tr>
|
||||
<td>B1</td><td><span class="badge p0">P0</span></td>
|
||||
<td><b>Lifting(起吊准备)状态永远无法到达</b>:<code>handleWorkCmd</code> 的 case 12 只有日志,缺少 <code>transit<Lifting>()</code> 与 <code>break</code>,直接坠入 default</td>
|
||||
<td class="loc">fsm/PowerManagerFsm.cpp:2934-2936</td>
|
||||
<td>上位机"起吊准备"指令被静默吞掉,Lifting 为死状态。补 <code>transit<Lifting>(); break;</code>。</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>B2</td><td><span class="badge p0">P0</span></td>
|
||||
<td><b>赋值误写为比较</b>:<code>s.buoyage == 1;</code>(共 4 处,值 1/3/2/0),语句无副作用</td>
|
||||
<td class="loc">fsm/PowerManagerFsm.cpp:1471,1475,1482,1486</td>
|
||||
<td>浮力调节(buoyage)状态反馈永远不更新,上报恒为初值。改为 <code>=</code>。</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>B3</td><td><span class="badge p0">P0</span></td>
|
||||
<td><b>MOOS 邮件整批丢弃</b>:OnNewMail 中任一邮件偏斜超差即 <code>return true</code>,同批其余邮件全部丢失</td>
|
||||
<td class="loc">PowerManger.cpp:121-125</td>
|
||||
<td>网络抖动时会成片丢失上位机指令。改为跳过该条、继续处理后续邮件。</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>B4</td><td><span class="badge p1">P1</span></td>
|
||||
<td><b>JSON 键名不匹配导致指令静默丢失</b>:发送端键 <code>"mastLiftingServo_uint8"</code>,接收端解析键 <code>"mastLiftingServo_uint8_uint8"</code></td>
|
||||
<td class="loc">driver.cpp:844 vs 924</td>
|
||||
<td>桅杆升降舵指令永远解析失败。统一键名,并增加"未知键/未命中"告警日志。</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>B5</td><td><span class="badge p1">P1</span></td>
|
||||
<td><b>故障检测函数重复执行</b>:<code>basicNavigationFault(); extendedNavigationFault();</code> 连续调用两遍</td>
|
||||
<td class="loc">fsm/PowerManagerFsm.cpp:52-55</td>
|
||||
<td>4 Hz 下双倍开销,且对带副作用的故障逻辑是隐患。删除重复行。</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>B6</td><td><span class="badge p1">P1</span></td>
|
||||
<td><b>三个断路器故障永不上报</b>:fbReserved/tyzReserved/reserved 调用的是无 faultCode 参数的重载,disfaultMap 中 code 10-12 成死码</td>
|
||||
<td class="loc">systemData.h:1026-1028</td>
|
||||
<td>补齐故障码入参,或删除死码并同步前端映射。</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>B7</td><td><span class="badge p1">P1</span></td>
|
||||
<td><b>数组越界风险</b>:故障注入 <code>batfaultMap[e.eventId].code</code> 对来自外部的 eventId 无边界检查;<code>systemData.h:524</code> 循环 <code>i<2</code> 越界访问 <code>reserved2[1]</code>(cppcheck error 级)</td>
|
||||
<td class="loc">fsm/PowerManagerFsm.cpp:3053;systemData.h:524</td>
|
||||
<td>注入接口可被越界触发,属安全隐患。加边界校验;修正循环上界。</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>B8</td><td><span class="badge p1">P1</span></td>
|
||||
<td><b>TestEvent 故障注入 switch 缺 break</b>:case 15 坠入 default;另有 <code>react(TestEvent)</code> 直接构造 FaultEvent 调故障函数,绕过事件机制</td>
|
||||
<td class="loc">fsm/PowerManagerFsm.cpp:2988-2989, 3084-3092</td>
|
||||
<td>注入 15 号故障时行为未定义。补 break,统一走事件派发。</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>B9</td><td><span class="badge p2">P2</span></td>
|
||||
<td><b>未初始化返回</b>(cppcheck error 级):<code>uPlan_taskStart.h:29</code> 返回未初始化 <code>mission</code>;<code>uExternComm_setDeviceSwitch.h:39</code> 可能返回未初始化 <code>cmd.cmd</code>;<code>uPower_pmState.h:14</code> 对含 <code>std::vector</code> 的结构体 memset</td>
|
||||
<td class="loc">upmsg/ 多个头文件</td>
|
||||
<td>协议层偶发脏数据。统一在结构体定义处给默认值,禁止对非 POD memset。</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>B10</td><td><span class="badge p2">P2</span></td>
|
||||
<td><b>注释与代码不符</b>:FaultState.cpp:46 注释"5 秒超时"实为 20 秒(:53),且与 Lifting.cpp:40、PowerManagerFsm.cpp 内 5 处同逻辑代码的 5 秒超时不一致;同一段超时代码共复制 7 份</td>
|
||||
<td class="loc">FaultState.cpp:46/53 等</td>
|
||||
<td>误导维护且各副本超时阈值漂移。随重构统一为命名常量。</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>B11</td><td><span class="badge p1">P1</span></td>
|
||||
<td><b>模板残留致每条正常指令误报 "Unhandled Mail"</b>:OnNewMail 的 for 循环内保留了 MOOS 模板代码 <code>if(key=="FOO")...else if(key!="APPCAST_REQ") reportRunWarning(...)</code>,除 APPCAST_REQ 外的所有邮件(含已正常处理的 uPower_*_cmd/fb)都被计入 run warning</td>
|
||||
<td class="loc">PowerManger.cpp:142-146</td>
|
||||
<td>AppCast 告警计数被污染、日志刷屏。删除该模板残留,仅在 processUpperMsg 返回 false 时告警。</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>B12</td><td><span class="badge p1">P1</span></td>
|
||||
<td><b>畸形 JSON 可致崩溃</b>:<code>loadDriverIdFromJson</code> 对 <code>root[field].asUInt()</code> 无类型检查(<code>JSON_USE_EXCEPTION=1</code>),调用处无 try/catch;<code>SafeReadUInt</code> 用 <code>std::cerr</code> 报错而非日志框架</td>
|
||||
<td class="loc">driver.cpp:935-936;UpperCommManager.cpp:48</td>
|
||||
<td>恶意/畸形指令使 jsoncpp 抛异常向上传播。统一走 SafeReadUInt 并捕获异常、改走日志。</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>B13</td><td><span class="badge p1">P1</span></td>
|
||||
<td><b>HTTP 服务在配置就绪前启动</b>:<code>m_httpServer->start()</code> 在构造函数调用,此时 mission 配置未加载、<code>m_db</code> 为 nullptr、UDP 未 bind,控制接口(/fcs/control 等)已对外可访问</td>
|
||||
<td class="loc">PowerManger.cpp:83-87</td>
|
||||
<td>存在"配置生效前已暴露控制面"窗口。将 start() 移到 OnStartUp 末尾(DB/端口就绪后)。</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>B14</td><td><span class="badge p2">P2</span></td>
|
||||
<td><b>死代码与孤儿成员</b>:<code>FsmLoop()</code>/<code>_FsmCB</code> 无任何线程启动;<code>m_deviceCmdQuenue</code> 及 push/pop/isEmpty 三接口无消费者;<code>buildReport()</code> 为 MOOS 模板占位;<code>SKEW_TOLERANCE 5</code> 宏未用而 <code>m_skew=10</code> 硬编码</td>
|
||||
<td class="loc">PowerManger.cpp:18/339;PowerManger.h:48/121</td>
|
||||
<td>误导维护。随阶段 3 一并清理,SKEW 阈值统一为命名常量。</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<h3 id="s3-2">3.2 状态机与控制逻辑</h3>
|
||||
<h4>3.2.1 现状转移关系(经代码还原)</h4>
|
||||
<table>
|
||||
<tr><th>源状态</th><th>事件</th><th>目标状态</th><th>说明</th></tr>
|
||||
<tr><td>InitState</td><td>entry() 内直接切换</td><td>StandbyState</td><td>初始化完成即转</td></tr>
|
||||
<tr><td>任意状态</td><td>MasterCommandEvent(workCMD 1~11)</td><td>Standby / ShoreBasedReady / WaterBasedReady / RemoteControl / Cruise / HighSpeed / FloatDown / FloatAdjust / UnderwaterSurvey / SurfaceSurvey / DJMode</td><td class="loc">PowerManagerFsm.cpp:2887-2941;workCMD=12 无效(B1)</td></tr>
|
||||
<tr><td>任意状态</td><td>TaskStartEvent</td><td>THROW_LOAD→FaultState;FLOAT_UP/SAT_COMM 等→FloatDown;RECYCLE/SAIL→CruiseMode;HOVER→FloatAdjust;TOUR→UnderwaterSurvey</td><td class="loc">PowerManagerFsm.cpp:948-985</td></tr>
|
||||
<tr><td>任意状态</td><td>TaskStopEvent</td><td>RemoteControl</td><td class="loc">基类 react,cpp:13</td></tr>
|
||||
<tr><td>StandbyState</td><td>StandbyEvent</td><td>StandbyState(自切换)</td><td>语义存疑</td></tr>
|
||||
<tr><td>FaultState</td><td>—(无显式出口)</td><td>—</td><td>仅能借基类 handleWorkCmd 间接跳出</td></tr>
|
||||
</table>
|
||||
|
||||
<h4>3.2.2 主要架构问题</h4>
|
||||
<div class="danger">
|
||||
<b>A1 状态机退化为"事件路由壳"。</b>真正的状态转移表不在各状态类中,而集中在基类 <code>handleWorkCmd</code> 与 <code>react(TaskStartEvent)</code> 两个巨型 switch;14 个状态类的 <code>react(MasterCommandEvent)</code> 是完全相同的复制粘贴。tinyfsm 提供的 <code>transit<S>(action, condition)</code> guard 重载(tinyfsm.hpp:151)全项目零使用——<b>任何状态下都可经 workCMD 直接跳进任何工况</b>(如巡航中直接切起吊),无任何合法性检查。
|
||||
</div>
|
||||
<div class="danger">
|
||||
<b>A2 故障检测与 FaultState 完全脱钩。</b>8 个 <code>xxxFault()</code> 检测函数只写故障码集合,从不触发状态迁移;FaultState 唯一入口是"抛载任务"(TaskStartEvent::THROW_LOAD),即 3 级故障(如深度失效 0x1302)发生时系统仍停留在原工况。FaultState 无显式出口、无故障恢复确认、无故障码清除联动。FaultEvent 无任何 dispatch 点,基类 <code>react(FaultEvent)</code> 为死代码。
|
||||
</div>
|
||||
<div class="warn">
|
||||
<b>A3 entry() 内长阻塞。</b>WaterBasedReady.cpp:50 与 Lifting.cpp:10 在 entry() 中 <code>MOOSPause(10000)</code>;ShoreBasedReady.cpp:24-35 while 轮询等待约 10 s;断路器操作闭环在事件处理路径上忙等约 7 s。状态迁移期间 FSM 无法响应任何新事件,上位机指令被积压在邮件队列。
|
||||
</div>
|
||||
<div class="warn">
|
||||
<b>A4 上帝类与全局穿透。</b>PowerManagerFsm.cpp(3096 行)集中了 10 个高度重复的设备指令处理函数、10 个 getXxxStatus 状态拷贝函数、8 组故障编码函数(约 200 个 0xLSSS 魔法故障码)。状态代码经 <code>static PowerManger* pm</code> 裸指针直接读写宿主几十个公有成员、直接操作断路器、直接 sendNotification,单向依赖原则被彻底打破。
|
||||
</div>
|
||||
<ul>
|
||||
<li><b>A5 语义错位</b>:FloatDown 实际承载"上浮/下潜/卫星通信/卫星标定"四种业务;<code>handelPowerCmd</code>、<code>underWterDevices</code>、<code>mergencyLithiumBattery</code> 等拼写错误已进入接口。</li>
|
||||
<li><b>A6 死代码</b>:<code>PowerSystemState</code> 枚举(hpp:21)、<code>DeviceCmd</code> 事件(hpp:41)、<code>handleDeviceCmd</code> 空壳(cpp:2966)、<code>m_currentDriver</code>(hpp:87)、<code>checkError()</code> 被注释掏空(PowerManger.cpp:344-356)。</li>
|
||||
<li><b>A7 日志混乱</b>:基类兜底 react 用 <code>std::cout << "No Idear"</code>(hpp:94);entry/exit 大量使用 RTTI demangle + ANSI 转义打印,嵌入式目标上属无效开销;<code>printState</code> 用 <code>desp.find("故障")</code> 字符串匹配决定日志级别(PowerManger.cpp:359),极其脆弱。</li>
|
||||
</ul>
|
||||
|
||||
<h3 id="s3-3">3.3 通信逻辑</h3>
|
||||
<div class="warn">
|
||||
<b>C1 上位机连接无管理。</b><code>LowerCommManager::m_connectState</code>(h:131)与 <code>PowerManger::connectState</code>(h:136)声明后从未使用;上位机方向无心跳、无在线检测、无断线告警,仅靠 MOOS 库自动重连。下位机方向有 30 s 超时检测(systemData.h:752-761),但超时后仅置标志位,未与故障系统联动。
|
||||
</div>
|
||||
<div class="warn">
|
||||
<b>C2 协议知识三处散养。</b>JSON 键名与设备 ID 映射(协议层知识)写在 Driver(业务策略层)里,与发送端 driver.cpp 各维护一份,已造成 B4 键名失配;UDP 帧格式在 udpComm,设备 ID 0-61 在 driver.cpp:908-930 与 DeviceId 枚举重复硬编码。<code>Driver</code> 实例在 PowerManger 与 UpperCommManager 各持一份,表状态易不一致。
|
||||
</div>
|
||||
<ul>
|
||||
<li><b>C3 校验与错误处理形同虚设</b>:<code>loadDriverTableFromJson</code> 的 error_code 每次被覆盖、从不检查,恒返回 0(driver.cpp:962-1093);<code>sendCcuSetParmCmd</code> 无论发送成败都 return true(udpComm.cpp:609-619);帧长硬编码 18/6/8 且旁边就是 TODO(udpComm.cpp:467/491/515/539)。</li>
|
||||
<li><b>C4 死分支与静默吞帧</b>:<code>CCU_UDPMSG_START1 == DIS_MSG_HEAD1 == 0x40</code>,udpComm.cpp:47-56 两个 else-if 完全等价;未知 id 走 default 后仍 return true(udpComm.cpp:344-347)。</li>
|
||||
<li><b>C5 高频路径低效</b>:每帧堆分配(udpComm.cpp:462 等 5 处)、每个 UDP 包 cout 打印一次(LowerCommManager.cpp:381)、发送函数失败后仍 return true(LowerCommManager.cpp:142-144)。</li>
|
||||
<li><b>C6 废弃函数藏错误数据</b>:<code>sendDisSysCommand</code> 对 bus3 无视入参硬编码 <code>0x55/0xAA</code>(LowerCommManager.cpp:183-189),若被误用将下发错误指令。</li>
|
||||
<li><b>C7 双 Web 重复建设</b>:下位机 httpserver(8000)与上位机 HostSim Web(18080)都用 mongoose + /ws + 内嵌页面提供状态监视;下位机 /fcs/control 在 HTTP 回调中直改状态(httpserver.cpp:150),绕过 MOOS 消息机制,属越权控制通道。</li>
|
||||
</ul>
|
||||
|
||||
<h3 id="s3-4">3.4 故障码体系</h3>
|
||||
<table>
|
||||
<tr><th>编码方案</th><th>定义位置</th><th>格式</th><th>使用方</th><th>问题</th></tr>
|
||||
<tr><td>电池故障表</td><td class="loc">faultCode.h:17-76,batfaultMap[54]</td><td>单字节 0x01-0xC9,带 1-4 级</td><td>仅故障注入使用</td><td>level 字段与描述矛盾(:35);注入越界风险(B7)</td></tr>
|
||||
<tr><td>配电故障表</td><td class="loc">faultCode.h:78-124,disfaultMap[45]</td><td>十进制 1-45</td><td>断路器故障上报</td><td>code 10-12 死码(B6)</td></tr>
|
||||
<tr><td>系统故障码</td><td class="loc">无定义文件,散落在 PowerManagerFsm.cpp:1676 起</td><td>16 位魔数 0xLSSS(高半字节=等级)</td><td>8 个检测函数 + getFaultLevel</td><td>约 200 个裸字面量无注释无枚举;等级提取依赖位运算巧合</td></tr>
|
||||
</table>
|
||||
<ul>
|
||||
<li><b>F1 双重故障存储</b>:真实故障进 <code>SystemData::sysFaultCodes</code>(set,自恢复即自动清除,无锁存/确认);注入故障进 <code>PowerManger::faultCode</code>(vector,不去重、只能整体 clear)。<code>getFaultLevel()</code>(PowerManger.cpp:448)与上报用的 <code>data.getFaultCodeLevel()</code>(uPower_pmState.h:50)读的是<b>不同集合</b>,同一件事故障等级可能不一致。</li>
|
||||
<li><b>F2 死赋值</b>:UpperCommManager.cpp:240 把 <code>getFaultCodes()</code> 赋给 state,但 <code>uPower_pmState.h:41-73 buildMsg()</code> 忽略该赋值,改用 <code>data.getFaultCode()</code>。</li>
|
||||
<li><b>F3 映射脱节</b>:故障码→中文描述的映射 C++ 侧仅用于注入,上报只发数字码;显示文本由前端 JS 重写一份(httpserver/fuelcell.h:834-840);0xLSSS 系统故障码<b>没有任何文本映射</b>。</li>
|
||||
<li><b>F4 条件编译陷阱(经核实比初版更严重)</b>:<code>DEBUG</code> 宏在全部构建中均未被定义(CMake 无 <code>-DDEBUG</code>),而 systemData.h:776 的 <code>#ifdef DEBUG</code> 依赖它——因此燃料电池 4 级故障字 <code>fc_fault_level_1..4</code> 在<b>所有构建</b>下都永不更新(恒为 0),并非仅"发布版";systemData.h:7 的 <code>#define DEBUFG</code> 是拼写错误且定义了无用宏。同理 <code>#ifdef _DEBUG</code>(UpperCommManager.cpp 全篇)在 Linux 下也永不生效,其调试追踪成员均为死代码。</li>
|
||||
<li><b>F5 无故障事件持久化</b>:SQLite 仅随帧存原始故障字段,无独立故障事件表,故障发生/恢复时间不可追溯,无法支撑事后分析。</li>
|
||||
</ul>
|
||||
|
||||
<h3 id="s3-5">3.5 数据管理与并发</h3>
|
||||
<ul>
|
||||
<li><b>D1 全局数据池</b>:SystemData(systemData.h,1219 行头文件内实现)是百字段单例,字段基本是 pmSysvariable 协议镜像的 float 转换副本,<code>updateSystemData()</code> 逐字段拷贝数百行——协议每改一处需同步三处(pmSysvariable / systemData / updateSystemData)。构造函数 60+ 项手工初始化(:660-690)。</li>
|
||||
<li><b>D2 锁纪律不一致</b>:提供了部分加锁访问器(:694-733),但 FSM 大量裸读绕过锁(PowerManagerFsm.cpp:1813/1920/1930);TestEvent 直接无锁写 <code>fc_fault_level_1</code>(:3060);<code>msg_*_Update_time</code> 无锁写、另一把锁下读(LowerCommManager.cpp:229-233)。</li>
|
||||
<li><b>D3 整数截断风险</b>:对 double 使用未限定的 <code>abs()</code>(systemData.h:757),可能解析为 C 的 <code>int abs</code> 截断时间差,应使用 <code>std::fabs</code>。</li>
|
||||
<li><b>D4 双重时间基准</b>:commLoop 每 1 s <code>clearMsgQueue()</code>(LowerCommManager.cpp:124)与监听线程并发清队列,语义冗余且可能丢未消费帧。</li>
|
||||
</ul>
|
||||
|
||||
<h3 id="s3-6">3.6 上位机与 Web 服务</h3>
|
||||
<p>上位机 HostSim 的设计相对干净:网页指令经 WebSocket 入 <code>m_cmdQueue</code>、Iterate 中 <code>drainCommands()</code> 转发 MOOSDB(HostSim.cpp:213-228);上行订阅 12 个反馈变量,dirty 后 <code>broadcast(buildSnapshot())</code> 推送,并以 SQLite 表 <code>fb_log</code> 保留 24 h 历史(FeedbackStore.cpp:62-69),提供 <code>/api/history</code>、<code>/api/rawlog</code>。可作为重构时"松耦合桥"的保留样板。</p>
|
||||
<ul>
|
||||
<li><b>H1 功能重叠</b>:与下位机 httpserver 在状态监视上重复;建议下位机 Web 退化为纯调试用途(仅本机回环监听),状态监视统一归上位机。</li>
|
||||
<li><b>H2 越权通道</b>:下位机 /fcs/control 直改内部状态,破坏"一切控制经 MOOS 指令"的单入口原则,应迁移为向 MOOSDB 发指令或加鉴权。</li>
|
||||
<li><b>H3 页面硬编码</b>:1912 行 data.h 等 7 个页面以 <code>R"(...)"</code> 字符串嵌在头文件,无构建期资源管线(上位机已有 webassets_gen.h 方案可复用)。</li>
|
||||
</ul>
|
||||
|
||||
<h3 id="s3-7">3.7 构建工程与配置管理</h3>
|
||||
<ul>
|
||||
<li><b>E1 编译告警默认关闭、无 sanitizer 门禁</b>:CMakeLists 仅加 <code>-fPIC -g -Wdeprecated-declarations</code>,<code>-Wall</code> 需手动开 WALL_ON 且写法含语法错误(<code>"-Wall" -C++11</code>,CMakeLists.txt:86);Release 依赖 CMake 默认 <code>-O3</code> 未显式声明;无 ASan/UBSan/TSan 构建类型。建议:开启 <code>-Wall -Wextra</code> 并清零告警,新增 sanitizer 构建目标,测试二进制输出到 build 目录。</li>
|
||||
<li><b>E2 依赖不可复现、GLOB 反模式</b>:<code>FILE(GLOB ...)</code> 收集头/库目录(CMakeLists.txt:49/53),新增文件不触发重配;mongoose/sqlite3/loguru/jsoncpp 以源码 vendor 进 src 且无版本号与许可证记录;<code>CMAKE_MINIMUM_REQUIRED(VERSION 3.5)</code> 过老。建议 GLOB 改显式列表,第三方库固定版本并登记 LICENSE。</li>
|
||||
<li><b>E3 配置解析无校验</b>:OnStartUp 用 <code>atoi</code> 解析 ccuport/iport(PowerManger.cpp:229/233),非法值静默为 0,端口无 1-65535 范围检查;缺配置块仅 warning。建议显式校验非法值并告警。</li>
|
||||
<li><b>E4 SQLite 高频路径重复 prepare</b>:<code>insertGeneric</code> 每次插入重拼 SQL 并 prepare(SQLite.cpp:610-625),<code>onFrame</code> 每帧同样 prepare;建议缓存 prepared statement,故障事件表纳入 SCHEMA_VERSION 迁移机制。</li>
|
||||
<li><b>E5 日志/错误输出三套并存</b>:loguru、<code>std::cerr</code>(driver.cpp:887/904/957)、<code>std::cout</code>(LowerCommManager.cpp:373/381)混用,无法按级别关停。建议统一 loguru,cout/cerr 清零。</li>
|
||||
</ul>
|
||||
|
||||
<!-- ================= 4 ================= -->
|
||||
<h2 id="s4">4 架构优化方案</h2>
|
||||
<p>优化总原则:<b>外部特性严格不变</b>(MOOS 变量名与 JSON 契约、UDP 帧格式、Web 接口、故障码取值、状态迁移外部可观测序列均保持),<b>内部结构彻底重整</b>。所有重构以第 6 章的一致性保障与第 7 章的测试基线为前提。</p>
|
||||
|
||||
<h3 id="s4-1">4.1 目标分层架构</h3>
|
||||
<div class="card">
|
||||
<pre><code>┌─────────────────────────────────────────────────────────────┐
|
||||
│ 接口层 (Interface) UpperCommManager │ HttpServer(调试) │ ← 只做协议适配,不含业务判断
|
||||
├─────────────────────────────────────────────────────────────┤
|
||||
│ 应用层 (Application) PowerManagerApp │ ← 协调者:指令→校验→派发到领域服务
|
||||
│ ├─ CommandService(指令接收、校验、应答) │
|
||||
│ ├─ FaultManager (故障检测、锁存、上报、事件持久化) │
|
||||
│ └─ StateMachineService(工况状态机,表驱动 + guard) │
|
||||
├─────────────────────────────────────────────────────────────┤
|
||||
│ 领域层 (Domain) DeviceRegistry │ PowerPolicy(Driver表) │ ← 纯 C++,无 MOOS/网络依赖,可单测
|
||||
│ SystemState(线程安全的状态仓储) │
|
||||
├─────────────────────────────────────────────────────────────┤
|
||||
│ 基础设施层 (Infra) UdpLink(收发) │ ProtocolCodec(编解码) │ ← 唯一知道帧格式/JSON键名的地方
|
||||
│ SQLiteStore │ MoosGateway │
|
||||
└─────────────────────────────────────────────────────────────┘</code></pre>
|
||||
</div>
|
||||
<ul>
|
||||
<li><b>依赖方向单向化</b>:接口层 → 应用层 → 领域层 ← 基础设施层(依赖倒置)。状态机不再持有 <code>PowerManger*</code> 裸指针,改为构造时注入 <code>ISystemState</code>、<code>IDeviceCommand</code>、<code>IFaultSink</code> 三个窄接口。</li>
|
||||
<li><b>线程模型统一</b>:确立"单线程事件循环 + 生产者队列"模型——UDP 监听线程、HTTP 线程只做<b>收包→解析→投递事件队列</b>,所有业务处理(FSM dispatch、故障检测、状态写入)在 MOOS Iterate 所在线程串行执行,从根上消除数据竞争。断路器闭环操作改为异步状态(发送→等待反馈事件→超时事件),消灭 7 s 忙等。</li>
|
||||
<li><b>Driver 拆分</b>:模式设备策略表(领域层 PowerPolicy)与 JSON 键名/设备 ID 映射(基础设施层 ProtocolCodec)分离;Driver 单例化并归属 CommandService,消除双实例不一致。</li>
|
||||
</ul>
|
||||
|
||||
<h3 id="s4-2">4.2 状态机重构方案</h3>
|
||||
<h4>4.2.1 转移表显式化</h4>
|
||||
<p>将隐藏在两个 switch 中的转移逻辑提取为<b>静态转移表 + guard 函数</b>,作为唯一事实源,并据此生成文档与测试用例:</p>
|
||||
<pre><code>// fsm/TransitionTable.h —— 唯一事实源(示例,迁移时须以现状代码逐条核对生成)
|
||||
struct TransitionRule {
|
||||
StateId from; // ANY 表示任意源状态
|
||||
EventId event;
|
||||
StateId to;
|
||||
GuardFn guard; // nullptr 表示无条件(保持现状语义)
|
||||
const char* comment; // 对应原代码位置,便于审计
|
||||
};
|
||||
static const TransitionRule kRules[] = {
|
||||
{ ANY, EV_WORK_CMD, STANDBY, nullptr, "workCMD=1 Fsm.cpp:2891" },
|
||||
{ ANY, EV_WORK_CMD, LIFTING, nullptr, "workCMD=12 Fsm.cpp:2934(修复B1后生效)" },
|
||||
{ ANY, EV_TASK_START, FAULT, GuardThrowLoad, "THROW_LOAD Fsm.cpp:953" },
|
||||
{ FAULT, EV_FAULT_CLEARED, REMOTE_CTRL, GuardFaultAcked, "新增:故障确认后恢复" },
|
||||
...
|
||||
};</code></pre>
|
||||
<p>guard 第一阶段全部保持现状(无条件),仅把"可迁移性"显式化;第二阶段再与总体组确认后补充工况互斥规则(如 HighSpeed 与 DJMode 互斥需先回 Standby)。</p>
|
||||
|
||||
<h4>4.2.2 FaultState 与故障系统联动</h4>
|
||||
<ol>
|
||||
<li><b>入口</b>:FaultManager 检测到 3 级及以上故障(或抛载任务)→ 投递 <code>FaultEvent</code> → FSM 迁移 FaultState,保持现有"抛载进 FaultState"路径不变。</li>
|
||||
<li><b>entry 动作异步化</b>:断路器断开序列改为 FaultState 内部的子步骤计时状态(step + deadline),每拍 Iterate 推进,取代 MOOSPause(10000) 与 20 s 忙等;超时阈值统一为命名常量并修正注释。</li>
|
||||
<li><b>出口</b>:显式定义恢复路径——故障码集合清空且收到上位机确认指令(workCMD=4 RemoteControl,保持现有指令集不变)→ 退出 FaultState。该路径当前已可经基类 handleWorkCmd 间接实现,重构只是将其显式化并纳入转移表,<b>不改变外部行为</b>。</li>
|
||||
</ol>
|
||||
|
||||
<h4>4.2.3 代码组织</h4>
|
||||
<ul>
|
||||
<li>PowerManagerFsm.cpp 拆分:<code>DeviceCommandHandlers.cpp</code>(10 个设备指令函数,提取公共模板消除重复)、<code>StatusSnapshot.cpp</code>(10 个 getXxxStatus)、<code>FaultEncoding.cpp</code>(故障编码,配合 4.4 迁移到 FaultManager)。</li>
|
||||
<li>14 个状态类删除重复的 <code>react(MasterCommandEvent)</code>,统一由基类按转移表处理;状态类只保留 entry/exit 与状态特有事件。</li>
|
||||
<li>命名修正(handelPowerCmd→handlePowerCmd 等)仅在内部接口进行,MOOS 变量名、JSON 键名等外部标识<b>一律不改</b>。</li>
|
||||
</ul>
|
||||
|
||||
<h3 id="s4-3">4.3 通信层重构方案</h3>
|
||||
<h4>4.3.1 协议单一事实源</h4>
|
||||
<p>建立 <code>protocol/</code> 目录,以一份定义文件同时生成/校验编解码两侧,杜绝键名失配(B4)类问题:</p>
|
||||
<ul>
|
||||
<li><code>protocol/MoosVariables.def</code>:全部 MOOS 变量名 + JSON schema(键名、类型、取值范围),UpperCommManager 与 Driver 的 JSON 编解码均引用之;增加"未知键/解析失败"统一告警(修复 C3、B4 的静默丢失)。</li>
|
||||
<li><code>protocol/DeviceId.h</code>:设备 ID 唯一枚举,driver.cpp:908-930 的 0-61 硬编码与 DeviceId 枚举合并;UDP 帧长由结构体 sizeof 计算,删除 18/6/8 魔法数。</li>
|
||||
<li>修正 udpComm.cpp:47-56 等价死分支与 default 静默吞帧:未知帧计入统计并日志告警。</li>
|
||||
</ul>
|
||||
<h4>4.3.2 上下行链路管理</h4>
|
||||
<table>
|
||||
<tr><th>链路</th><th>现状</th><th>优化后</th><th>外部行为变化</th></tr>
|
||||
<tr><td>上位机(MOOS)</td><td>无连接管理,1 s 周期广播状态</td><td>启用已声明未使用的 connectState:以"周期广播正常发出 + 收到上位机任何邮件"维护在线标志;掉线仅记录与上报,不触发控制动作</td><td>无(只新增可观测性)</td></tr>
|
||||
<tr><td>下位机(UDP)</td><td>30 s 超时置 isTimeout,超时母线发清零指令</td><td>超时事件接入 FaultManager(通信类故障码,新增码段,不占用现有码值);清零指令逻辑保持不变</td><td>故障上报新增通信超时码(经总体确认后启用)</td></tr>
|
||||
<tr><td>断路器闭环</td><td>事件路径忙等约 7 s + 600 ms 复位</td><td>异步化:发送→注册期望反馈→超时定时器,状态机以子状态跟踪;指令时序与重发次数严格保持现状</td><td>无(时序一致,仅不再阻塞线程)</td></tr>
|
||||
<tr><td>Web 通道</td><td>下位机 8000 全功能 + /fcs/control 越权直改</td><td>下位机 Web 保留页面但控制类接口改为转发 MOOS 指令(等价于上位机下发);上位机 Web 方案不变</td><td>接口路径与参数不变,仅内部实现改道</td></tr>
|
||||
</table>
|
||||
<h4>4.3.3 工程细节修复</h4>
|
||||
<ul>
|
||||
<li>发送路径消除每帧堆分配(栈对象 + sendto);删除每包 cout(LowerCommManager.cpp:381),统一走 loguru 并按级别可关。</li>
|
||||
<li>UDP 监听线程退出改为 socket 超时 + quit 标志,保证进程可干净退出。</li>
|
||||
<li>移除 <code>sendDisSysCommand</code> 废弃函数(含 0x55/0xAA 硬编码),或修正后纳入 ProtocolCodec。</li>
|
||||
</ul>
|
||||
|
||||
<h3 id="s4-4">4.4 故障码统一方案</h3>
|
||||
<div class="card">
|
||||
<h4>目标:一套编码、一个存储、一处映射</h4>
|
||||
<p><b>1. 统一故障码定义文件 <code>fault/FaultCodeDef.h</code></b>(生成式,唯一事实源):</p>
|
||||
<pre><code>// 每条故障一行:枚举名, 码值(保持现有取值不变), 等级, 来源域, 中文描述
|
||||
FAULT_DEF(BAT_CELL_OVERVOLT_L1, 0x01, 1, DOMAIN_BATTERY, "单体过压1级")
|
||||
FAULT_DEF(DIS_BREAKER_TRIP_MAIN, 1, 2, DOMAIN_DIS, "主断路器脱扣")
|
||||
FAULT_DEF(SYS_DEPTH_INVALID_L3, 0x1302, 3, DOMAIN_SYSTEM, "深度数据失效")
|
||||
// 0xLSSS 系统码约 200 个字面量全部收编为枚举,码值、等级语义与现状逐条核对一致</code></pre>
|
||||
<p>由此单文件自动生成:C++ 枚举、码值→描述映射表(供上报与前端共用,替代 fuelcell.h:834 的 JS 重写)、测试用的完整性校验数据。电池 0x01-0xC9、配电 1-45、系统 0xLSSS 三段码值全部原样保留,<b>上位机与前端所见故障码不变</b>。</p>
|
||||
<p><b>2. 合并故障存储为 FaultManager 单一集合</b>:</p>
|
||||
<ul>
|
||||
<li>统一存放真实故障与注入故障(注入故障带 source 标记区分),上报接口(uPower_pmState)与等级查询(getFaultLevel)改为读同一集合,消除 F1/F2 的双源不一致;对外 JSON 字段名与格式不变。</li>
|
||||
<li>锁存语义保持现状(自恢复即自动清除),但 FaultManager 内部记录"发生/恢复"事件并写入 SQLite 新增 <code>fault_event(ts, code, level, event, source)</code> 表——<b>新增表不影响现有表结构</b>。</li>
|
||||
<li>故障码访问统一加 <code>faultCodeMutex</code>,消除 TestEvent 无锁写。</li>
|
||||
</ul>
|
||||
<p><b>3. 修复编码层缺陷</b>:删除 systemData.h:776 的 <code>#ifdef DEBUG</code>(发布版也更新燃料电池 4 级故障字)、修正 DEBUFG 拼写、补齐 B6 三个断路器的故障码入参、faultCode.h:35 的 level 字段与描述对齐。</p>
|
||||
</div>
|
||||
|
||||
<h3 id="s4-5">4.5 上位机 / 下位机管理方案</h3>
|
||||
<table>
|
||||
<tr><th>主题</th><th>职责划分(优化后)</th></tr>
|
||||
<tr><td>控制通道</td><td><b>唯一入口</b>:一切控制指令(网页、调试页、测试注入)最终都变为 MOOSDB 上的 <code>uPower_*_cmd</code> JSON,由 CommandService 统一校验、应答、记录。下位机 HTTP 控制接口仅做转发。</td></tr>
|
||||
<tr><td>状态监视</td><td>上位机 HostSim 为主(跨机、带历史库 /api/history);下位机 Web 退化为本机调试页(日志查看、测试注入保留),dashboard/data 等监视页标注"调试用"。</td></tr>
|
||||
<tr><td>指令校验</td><td>CommandService 对 workCMD/powerCMD/modCMD 做范围校验 + 当前状态下合法性校验(按转移表),非法指令回执拒绝原因(新增 JSON 字段,缺省不发送,兼容旧上位机)。</td></tr>
|
||||
<tr><td>指令清空哨兵</td><td>workCMD=99 等魔法哨兵改为命名常量 <code>CMD_NONE=99</code>,取值不变,仅消除魔法数。</td></tr>
|
||||
<tr><td>页面资源</td><td>下位机 7 个硬编码页面迁移到 CMake 资源管线(复用上位机 webassets_gen.h 方案),HTML 独立成文件,便于前端维护;URL 与页面功能不变。</td></tr>
|
||||
</table>
|
||||
|
||||
<!-- ================= 5(新增详细设计章) ================= -->
|
||||
<h2 id="s5">5 设备上电管理与状态机转移重构详细设计</h2>
|
||||
|
||||
<h3>5.1 总体设计判断</h3>
|
||||
<p>设备上电/管理与状态机转移是同一个问题的两面——<b>"声明"与"执行"混在一起</b>。9 张工况设备表(driver.cpp 约 600 行逐字段赋值)本质是"数据",却写成了代码;状态 entry() 里的上电时序本质是"流程",却硬编码成一串串 <code>setDeviceState + MOOSPause + operate_*_Breaker</code>;状态转移本质是"一张表",却隐式埋在 <code>handleWorkCmd</code>/<code>react(TaskStartEvent)</code> 两个 switch 里。重构的共同方向:<b>把数据从代码里剥离出来,把流程交给统一执行器,把转移显式化</b>。</p>
|
||||
|
||||
<h3>5.2 设备上电与管理重构</h3>
|
||||
<h4>5.2.1 现状代码证据</h4>
|
||||
<ul>
|
||||
<li><b>工况表即代码</b>:<code>Driver::getSTANDBYTable()</code>(driver.cpp:151-228)等 9 个函数,每个约 70 行 <code>driverTable->depth1 = 1;</code> 式逐字段赋值,<code>getCRUISE/getHIGH_SPEED/getASCEND_DESCEND</code> 内容几乎一致,且混用裸 0/1 与 <code>DRIVER_*</code> 宏。</li>
|
||||
<li><b>上电时序硬编码且阻塞</b>:<code>CruiseMode::entry()</code> 的典型模式是:查当前设备状态 → <code>operate_HVA_actuatorCircuit_Breaker(0)</code>(内部忙等最长 6 s)→ <code>MOOSPause(3)</code> → 连续 6 次 <code>setDeviceState</code> → 上报,每个状态 entry 都是这段逻辑的变体手写。</li>
|
||||
<li><b>断路器闭环时序散落</b>:<code>operateBreakerGeneric</code>(LowerCommManager.cpp:843-890)的"首次发包 → 100 ms 等待 → 轮询反馈 → 200 ms 重发 → 6 s 超时 → 3×200 ms 复位"被 35 个 <code>operate_*</code> 函数复用,但在事件处理路径上同步执行,阻塞 MOOS 线程。</li>
|
||||
<li><b>校验逻辑十份复制</b>:<code>WaterBasedReady::react(DevCmdExt)</code> 中的校验链(Debug 模式豁免 → 深度上电保护 → 前视声纳先关机再断电并 MOOSPause(10000) → 写设备状态)在 10 个 <code>handleXxxCmd</code> 中各有变体,细微偏差正是 B4(桅杆键名失配)类缺陷的温床。</li>
|
||||
</ul>
|
||||
|
||||
<h4>5.2.2 目标结构</h4>
|
||||
<div class="card">
|
||||
<pre><code>现状(分散) 目标(收敛)
|
||||
┌──────────────────────────────┐ ┌────────────────────────────────┐
|
||||
│ 9 张工况表 = 600 行赋值函数 │ │ ① 设备描述表 DeviceDef │
|
||||
│ entry() 硬编码时序+忙等6~20s │ 收敛 │ 68 设备 × 属性(域/断路器通道/ │
|
||||
│ 10 个 handleXxxCmd 校验复制 │ ───────────► │ 保护规则/9 工况默认值) │
|
||||
│ 35 个 operate_*_Breaker │ │ ② 功率时序执行器 PowerSequencer │
|
||||
└──────────────────────────────┘ │ 声明式步骤,异步分步执行 │
|
||||
│ ③ 统一指令管线:模式校验→深度 │
|
||||
│ 保护→前置动作→执行→回执 │
|
||||
│ ④ DeviceManager 唯一写口 │
|
||||
│ m_subDisSysCmd 只经它修改 │
|
||||
└────────────────────────────────┘</code></pre>
|
||||
</div>
|
||||
|
||||
<h4>5.2.3 重构四件事</h4>
|
||||
<ol>
|
||||
<li><b>工况表从函数变成数据。</b>9 个 <code>getXxxTable()</code> 函数替换为静态二维表 <code>kModeDeviceTable[9][68]</code>(或按设备分组的声明式定义),查表替代函数调用。迁移时用程序把现有 9 个函数的输出快照为 golden data,重构后逐字节比对——这是"特性严格一致"最直接的保证。</li>
|
||||
<li><b>上电时序从阻塞硬编码变成声明式步骤 + 异步执行器。</b>每个工况声明一个步骤序列,例如 CruiseMode:<code>[条件:任一bowCover≠0] → 断启闭机构断路器(超时6s) → 延时3s → 批量下电bowCover1~6 → 上报</code>。PowerSequencer 每拍 Iterate 推进一步,<code>operateBreakerGeneric</code> 的时序参数(100 ms 首等、200 ms 重发、6 s 超时、3×200 ms 复位)原样保留为步骤属性,但不再阻塞线程;entry() 只提交序列即返回,状态机始终可响应事件。</li>
|
||||
<li><b>设备指令校验收敛为一条管线。</b>所有设备指令走同一链路:模式校验(Normal 禁操作)→ 域保护(水下设备深度检查,Debug 豁免)→ 设备专属前置动作(forwardSonar 先关机再断电等,注册在设备描述表)→ 经 Sequencer 执行 → 回执。各状态只声明"本状态允许操作哪些设备域",不再各写一份校验。</li>
|
||||
<li><b>设备状态唯一写口。</b><code>m_subDisSysCmd</code> 现在被 FSM、HTTP 回调、测试注入直接修改,重构后只能经 DeviceManager 写入;外部可观测的写序列(日志、上报、SQLite 落库)保持一致。</li>
|
||||
</ol>
|
||||
|
||||
<h3>5.3 状态机转移重构</h3>
|
||||
<h4>5.3.1 核心问题:转移关系隐式化</h4>
|
||||
<p>转移关系不存在于任何一张表中,而是从两个 switch 的行为里"涌现"出来的——这正是 case 12 漏写 <code>transit</code> 导致 Lifting 不可达(B1)这类缺陷的结构性根源。重构目标是把转移机制从"隐式 switch"变为"显式表驱动":</p>
|
||||
<div class="card">
|
||||
<pre><code>现状:隐式转移 目标:显式转移
|
||||
MasterCommandEvent 到达 事件统一规范化
|
||||
│ │
|
||||
handleWorkCmd 巨型 switch 查转移表 TransitionRule[]
|
||||
(14 状态 × 14 份复制 react) (源状态×事件→目标,唯一事实源)
|
||||
│ │
|
||||
无 guard 直接 transit guard 校验
|
||||
(case 12 漏写 = Lifting 死状态) (一期空 guard 记日志,二期补互斥)
|
||||
│ │
|
||||
entry() 阻塞上电 CHANING 过渡子状态
|
||||
(期间 FSM 不响应任何事件) (上电序列异步执行,完成即落定)
|
||||
│ │
|
||||
FaultState 孤岛 FaultEvent 显式迁移
|
||||
(故障检测不触发迁移,无出口) (3 级以上故障进入,确认后退出)</code></pre>
|
||||
</div>
|
||||
|
||||
<h4>5.3.2 重构五步走</h4>
|
||||
<ol>
|
||||
<li><b>把转移关系从代码里"挖"出来变成表。</b>逐行核对 <code>handleWorkCmd</code>(workCMD 1~12)、<code>react(TaskStartEvent)</code>(THROW_LOAD/FLOAT_UP/RECYCLE/SAIL/HOVER/TOUR 等)、<code>react(TaskStopEvent)</code> 与 InitState 自迁移,生成 <code>TransitionRule[]</code> 静态表,每行标注原代码位置(如 <code>workCMD=5 → CruiseMode, Fsm.cpp:2903</code>)。该表同时是实现、文档与测试基准。<code>handleWorkCmd</code> 的 switch 删除,14 个状态中复制粘贴的 <code>react(MasterCommandEvent)</code> 全部删除,统一由基类查表处理;workCMD=99 清空哨兵语义保留,仅改为命名常量。</li>
|
||||
<li><b>guard 分两期落地。</b>一期所有 guard 为 nullptr(无条件),<b>严格保持现状转移语义</b>——这是特性一致的红线;基类在每次迁移时记录"源状态→事件→目标"日志。二期依据日志与总体组确认应禁止的迁移(如巡航中直接切 DJMode),再逐步补 guard。重构本身不引入行为变化,行为收紧是另一个独立、可评审的决策。</li>
|
||||
<li><b>entry() 阻塞上电改为 CHANING 过渡子状态。</b>现状代码已有雏形——每个 entry 开头 <code>workCondition = CHANING</code>、干完活才置为目标工况,只是"干活"方式是阻塞的。重构将其正式化:迁移发生时进入目标状态的过渡形态,上电序列交 PowerSequencer 异步执行,序列完成事件使状态落定;期间 FSM 照常响应事件(如 FaultEvent 可打断上电)。上位机看到的 workCondition 变化序列与现状完全一致。</li>
|
||||
<li><b>FaultState 接入主转移图。</b>故障检测发现 3 级以上故障 → FaultManager 派发 FaultEvent → 转移表新增 <code>ANY × FaultEvent → FaultState</code> 规则(保留现有 THROW_LOAD 入口不变);FaultState 增加显式出口:故障码集合清空 + 上位机确认(复用现有 workCMD=4 指令,不新增协议)→ RemoteControl;FaultState 内的断路器断开序列同样改为 Sequencer 步骤,消灭 20 s 忙等。</li>
|
||||
<li><b>状态类只做"差异"。</b>状态类只保留本状态特有内容:entry 提交的上电序列、特有事件处理(如 DJMode 专属指令)、exit 清理;公共行为上收基类。CruiseMode/HighSpeedMode 等任务态的共性(均响应 TaskStopEvent→RemoteControl)通过继承 MissionStateBase 表达,利用 tinyfsm 原生支持的状态继承。</li>
|
||||
</ol>
|
||||
|
||||
<h3>5.4 两块重构的衔接与线程模型</h3>
|
||||
<div class="note">
|
||||
衔接点在 CHANING 子状态:<b>状态机管"去哪里",PowerSequencer 管"到了之后按什么时序上电",DeviceManager 管"每一笔设备状态怎么写"</b>。三者通过事件队列串行协作,全部运行在 MOOS 主线程上,从根上消除现有四个线程交叉读写全局数据的问题。UDP 监听线程与 HTTP 线程退化为纯生产者:收包→解析→投递事件队列,不再直接触碰业务状态。
|
||||
</div>
|
||||
|
||||
<h3>5.5 迁移顺序与一致性验证</h3>
|
||||
<ol>
|
||||
<li><b>快照基线</b>:采集 9 张工况表输出、标准指令脚本下的状态上报时序,作为 golden data;</li>
|
||||
<li><b>设备描述表与指令管线</b>(风险最低,先行);</li>
|
||||
<li><b>PowerSequencer 替换阻塞上电</b>;</li>
|
||||
<li><b>转移表替换 switch</b>。</li>
|
||||
</ol>
|
||||
<p>每一步均以 golden data diff 为空为通过条件,diff 非空则不进入下一步。B1(Lifting 不可达)等已确认缺陷在挖掘转移表时即会暴露,按第 6 章约定单独登记为行为变更点修复。</p>
|
||||
|
||||
<!-- ================= 6 ================= -->
|
||||
<h2 id="s6">6 特性一致性保障策略</h2>
|
||||
<p>"优化后与原代码特性严格一致"需要通过可执行的基线来保证,而不是靠评审印象。建议按以下四层契约冻结外部行为:</p>
|
||||
<table>
|
||||
<tr><th>契约层</th><th>冻结内容</th><th>验证手段</th></tr>
|
||||
<tr><td>MOOS 接口契约</td><td>全部订阅/发布变量名、JSON 键名与类型、周期广播频率(1 s)、应答时序</td><td>契约测试:录制现有系统真实 MOOS 流量为"黄金报文集",重构后回放比对(键集合、类型、取值范围)</td></tr>
|
||||
<tr><td>UDP 帧契约</td><td>6 类反馈帧 ID、帧头 0x40 0x40、#pragma pack(1) 布局、校验算法、帧长</td><td>字节级编解码往返测试(现有 udp_feeder/full_feeder 扩展为参数化用例);结构体 static_assert 尺寸断言</td></tr>
|
||||
<tr><td>行为契约</td><td>状态迁移外部可观测序列(指令→状态上报序列)、断路器操作时序(重发间隔、6 s 超时、600 ms 复位)、故障码取值与上报内容</td><td>黄金主测试:对现状系统跑标准指令脚本,录制 <code>uPower_currentState_st</code> 等上报时序为基线;重构后同脚本回放,时序逐拍比对</td></tr>
|
||||
<tr><td>Web/存储契约</td><td>URL 路由、REST 参数、SQLite 现有表结构</td><td>HTTP 接口冒烟用例;数据库 schema 比对脚本</td></tr>
|
||||
</table>
|
||||
<div class="note">
|
||||
<b>已知缺陷的处理约定</b>:3.1 节 B1-B10 属"现状特性"的一部分还是"应修复的缺陷",须逐项与总体确认。建议原则:外部可观测且显然错误的行为(如 buoyage 恒不更新、Lifting 不可达、桅杆指令丢失)按缺陷修复并在报告中显式登记"行为变更点";纯内部问题(重复调用、死代码)直接修复,行为不变。所有行为变更点单独列入变更清单,重构完成时逐项回归确认。
|
||||
</div>
|
||||
|
||||
<!-- ================= 7 ================= -->
|
||||
<h2 id="s7">7 测试方案</h2>
|
||||
<h3>7.1 测试金字塔与补齐重点</h3>
|
||||
<table>
|
||||
<tr><th>层级</th><th>现状</th><th>补齐内容</th><th>框架/工具</th></tr>
|
||||
<tr><td>单元测试</td><td>GTest 56 例:Driver 表、SystemData、故障码表、upmsg 往返、UDP 校验和、pack 布局</td><td>① 状态机迁移测试:转移表全覆盖(每个规则至少 1 例)+ guard 边界;② FaultManager:检测→锁存→上报→清除全链路,含 B6/B7 回归;③ ProtocolCodec:JSON 键名完整性(防 B4 复发)、帧编解码参数化</td><td>GTest;领域层零 MOOS 依赖后可脱离 MOOSDB 运行</td></tr>
|
||||
<tr><td>集成测试</td><td>udp_feeder/full_feeder 字节级仿真 CCU+4 路配电 + check_db.py 验证落库</td><td>① 故障注入 feeder:丢包、坏校验和、越界值、故障位置位、30 s 静默(超时路径);② MOOS 端到端:上位机指令→状态迁移→上报序列黄金比对(第 6 章基线);③ 断路器闭环时序仿真</td><td>Python 脚本 + 现有 feeder 扩展;MOOSDB 冒烟沿用</td></tr>
|
||||
<tr><td>系统/回归</td><td>CI 有构建+冒烟,但集成失败不阻塞(build-test.sh:181),已知 std::bad_alloc 被容忍</td><td>① 集成失败纳入 ALL_OK 阻塞;② cppcheck/clang-tidy 接入 CI(error 级清零);③ 测试二进制输出改到 build 目录,清理 test/ 下 in-source 构建残留</td><td>Gitea Actions 现有流水线扩展</td></tr>
|
||||
<tr><td>上位机测试</td><td>零</td><td>HostSim 指令队列 drain、FeedbackStore 落盘/24 h 清理、/api/history 时序提取、WS 快照广播</td><td>GTest(队列/存储)+ Python(HTTP/WS 接口)</td></tr>
|
||||
</table>
|
||||
<h3>7.2 关键专项测试</h3>
|
||||
<ul>
|
||||
<li><b>状态机迁移矩阵</b>:以 4.2.1 转移表为基准自动生成用例骨架——14 状态 × 11 事件全组合标注"允许/拒绝/保持",重构前后两轮运行,输出 diff 必须为空(除已登记的行为变更点)。</li>
|
||||
<li><b>故障注入矩阵</b>:覆盖三级来源——UDP 层(坏帧/丢帧/超时)、设备层(断路器脱扣、绝缘低、BMS 各级故障位)、系统层(深度失效、功率不足等 0xLSSS 码);断言故障码上报内容、FaultState 迁移、SQLite fault_event 落库三处一致。</li>
|
||||
<li><b>并发压力</b>:UDP 监听线程 100 Hz 灌包 + MOOS 指令并发注入,ThreadSanitizer 构建跑 10 min,数据竞争报告清零;队列上限 100 的溢出行为固定为"丢最旧 + 计数告警"并测试。</li>
|
||||
<li><b>长稳</b>:feeder 连续 24 h 正常流量 + 周期故障注入,监控内存(消除每帧 new/delete 后应无增长)、句柄、落库行数。</li>
|
||||
</ul>
|
||||
<h3>7.3 验收标准</h3>
|
||||
<ol>
|
||||
<li>黄金报文比对:MOOS/UDP 契约测试 100% 通过,diff 为空;</li>
|
||||
<li>状态迁移矩阵:除已登记变更点(B1 修复后 Lifting 可达等)外零差异;</li>
|
||||
<li>新增单测覆盖率:fsm/、FaultManager、ProtocolCodec 行覆盖 ≥ 80%;</li>
|
||||
<li>cppcheck error 级清零,TSan 报告清零;</li>
|
||||
<li>CI 全链路(构建→单测→集成→黄金比对)绿灯且失败阻塞。</li>
|
||||
</ol>
|
||||
|
||||
<!-- ================= 8 ================= -->
|
||||
<h2 id="s8">8 实施路线图</h2>
|
||||
|
||||
<div class="phase">
|
||||
<h4>阶段 0:缺陷修复与测试基线(先行,约 2 周)</h4>
|
||||
<p class="small">最小改动修复 B1-B14 并逐项登记行为变更;开启 <code>-Wall -Wextra</code> 清零告警、接入 sanitizer 构建目标与 cppcheck(error 级阻塞);配置项端口校验;搭建黄金报文基线与状态迁移矩阵录制工具。<b>产出:行为基线库 + 变更清单 + 可运行的安全网。</b></p>
|
||||
</div>
|
||||
<div class="phase">
|
||||
<h4>阶段 1:故障码与数据层统一(约 2-3 周)</h4>
|
||||
<p class="small">落地 FaultCodeDef.h 生成式定义;合并双故障存储为 FaultManager;新增 fault_event 持久化表;修复条件编译与死码。该阶段相对独立、风险最低,先行可立即改善可维护性。<b>产出:统一故障子系统 + 故障注入测试矩阵。</b></p>
|
||||
</div>
|
||||
<div class="phase">
|
||||
<h4>阶段 2:通信层与线程模型(约 3-4 周)</h4>
|
||||
<p class="small">建立 protocol/ 单一事实源;UDP 监听线程改为纯生产者;断路器闭环异步化;连接状态管理启用;下位机 HTTP 控制接口改道 MOOS。<b>产出:单线程事件循环模型 + 契约测试全绿。</b></p>
|
||||
</div>
|
||||
<div class="phase">
|
||||
<h4>阶段 3:状态机重构(约 3-4 周)</h4>
|
||||
<p class="small">转移表显式化;PowerManagerFsm 上帝类拆分;状态类去重;FaultState 出入路径显式化;entry 阻塞消除。每步以迁移矩阵 diff 为空为准入。<b>产出:表驱动状态机 + 迁移矩阵零差异报告。</b></p>
|
||||
</div>
|
||||
<div class="phase">
|
||||
<h4>阶段 4:上位机与收尾(约 2 周)</h4>
|
||||
<p class="small">上位机测试补齐;下位机页面资源管线迁移;长稳与并发压力测试;文档更新(转移表自动生成状态图)。<b>产出:完整测试体系 + 验收报告。</b></p>
|
||||
</div>
|
||||
<div class="warn">
|
||||
<b>风险控制</b>:每阶段结束必须 CI 全绿(含黄金比对)方可合并;协议/故障码/状态序列的任何外部可见变更必须已在变更清单登记并经确认;保持 pCCU、pMotor、pELoad 等周边进程接口不动,重构范围严格限定在 pPowerManger 与 pPowerMangerHost。
|
||||
</div>
|
||||
|
||||
<!-- ================= 9 ================= -->
|
||||
<h2 id="s9">9 附录:问题清单汇总</h2>
|
||||
<table>
|
||||
<tr><th>编号</th><th>级别</th><th>类别</th><th>问题摘要</th><th>位置</th><th>处置</th></tr>
|
||||
<tr><td>B1</td><td><span class="badge p0">P0</span></td><td>Bug</td><td>Lifting 状态不可达(case 12 无 transit/break)</td><td class="loc">PowerManagerFsm.cpp:2934</td><td>阶段0修复(行为变更登记)</td></tr>
|
||||
<tr><td>B2</td><td><span class="badge p0">P0</span></td><td>Bug</td><td>s.buoyage == 赋值误写为比较 ×4</td><td class="loc">PowerManagerFsm.cpp:1471-1486</td><td>阶段0修复(行为变更登记)</td></tr>
|
||||
<tr><td>B3</td><td><span class="badge p0">P0</span></td><td>Bug</td><td>邮件偏斜 return 导致整批丢弃</td><td class="loc">PowerManger.cpp:121-125</td><td>阶段0修复</td></tr>
|
||||
<tr><td>B4</td><td><span class="badge p1">P1</span></td><td>Bug</td><td>桅杆升降舵 JSON 键名失配,指令静默丢失</td><td class="loc">driver.cpp:844/924</td><td>阶段0修复(行为变更登记)</td></tr>
|
||||
<tr><td>B5</td><td><span class="badge p1">P1</span></td><td>Bug</td><td>故障检测函数重复调用两遍</td><td class="loc">PowerManagerFsm.cpp:52-55</td><td>阶段0修复</td></tr>
|
||||
<tr><td>B6</td><td><span class="badge p1">P1</span></td><td>Bug</td><td>3 个断路器故障码死码</td><td class="loc">systemData.h:1026-1028</td><td>阶段0修复</td></tr>
|
||||
<tr><td>B7</td><td><span class="badge p1">P1</span></td><td>Bug</td><td>故障注入数组越界 + systemData.h:524 越界</td><td class="loc">PowerManagerFsm.cpp:3053</td><td>阶段0修复</td></tr>
|
||||
<tr><td>B8</td><td><span class="badge p1">P1</span></td><td>Bug</td><td>TestEvent switch 缺 break;绕过事件机制</td><td class="loc">PowerManagerFsm.cpp:3084</td><td>阶段0修复</td></tr>
|
||||
<tr><td>B9</td><td><span class="badge p2">P2</span></td><td>Bug</td><td>协议结构体未初始化返回 / memset 非 POD</td><td class="loc">upmsg/ 多处</td><td>阶段0修复</td></tr>
|
||||
<tr><td>B10</td><td><span class="badge p2">P2</span></td><td>规范</td><td>超时常量与注释不符(FaultState 20s vs 其余 5s),复制 7 份</td><td class="loc">FaultState.cpp:46/53 等</td><td>阶段3统一</td></tr>
|
||||
<tr><td>B11</td><td><span class="badge p1">P1</span></td><td>Bug</td><td>模板残留致每条正常指令误报 "Unhandled Mail" run warning</td><td class="loc">PowerManger.cpp:142-146</td><td>阶段0修复</td></tr>
|
||||
<tr><td>B12</td><td><span class="badge p1">P1</span></td><td>Bug</td><td>畸形 JSON 类型致 jsoncpp 抛异常(asUInt 无类型检查、无 catch)</td><td class="loc">driver.cpp:935 / UpperCommManager.cpp:48</td><td>阶段0修复</td></tr>
|
||||
<tr><td>B13</td><td><span class="badge p1">P1</span></td><td>Bug</td><td>HTTP 服务在配置/DB 就绪前于构造函数启动,提前暴露控制面</td><td class="loc">PowerManger.cpp:83-87</td><td>阶段0修复</td></tr>
|
||||
<tr><td>B14</td><td><span class="badge p2">P2</span></td><td>规范</td><td>FsmLoop/_FsmCB、m_deviceCmdQuenue 无消费者;buildReport 占位;SKEW_TOLERANCE 宏未用</td><td class="loc">PowerManger.h:48/121 等</td><td>阶段3清理</td></tr>
|
||||
<tr><td>A1</td><td><span class="badge p0">P0</span></td><td>架构</td><td>状态机退化为路由壳,转移逻辑集中在基类 switch</td><td class="loc">fsm/ 全局</td><td>阶段3重构</td></tr>
|
||||
<tr><td>A2</td><td><span class="badge p0">P0</span></td><td>架构</td><td>故障检测与 FaultState 脱钩;FaultState 无出口</td><td class="loc">PowerManagerFsm.cpp:948-953</td><td>阶段1+3</td></tr>
|
||||
<tr><td>A3</td><td><span class="badge p1">P1</span></td><td>架构</td><td>entry() 内 MOOSPause/忙等最长 10-20 s</td><td class="loc">WaterBasedReady.cpp:50 等</td><td>阶段3异步化</td></tr>
|
||||
<tr><td>A4</td><td><span class="badge p1">P1</span></td><td>架构</td><td>3096 行上帝类;static pm 裸指针全局穿透</td><td class="loc">PowerManagerFsm.hpp:86</td><td>阶段3拆分</td></tr>
|
||||
<tr><td>A5-A7</td><td><span class="badge p2">P2</span></td><td>规范</td><td>语义错位/拼写错误/死代码/日志混乱</td><td class="loc">多处</td><td>阶段3清理</td></tr>
|
||||
<tr><td>C1</td><td><span class="badge p1">P1</span></td><td>通信</td><td>上位机无连接管理,connectState 死字段</td><td class="loc">LowerCommManager.h:131</td><td>阶段2启用</td></tr>
|
||||
<tr><td>C2</td><td><span class="badge p1">P1</span></td><td>通信</td><td>协议知识三处散养;Driver 双实例</td><td class="loc">driver.cpp / UpperCommManager.h:93</td><td>阶段2收敛</td></tr>
|
||||
<tr><td>C3-C6</td><td><span class="badge p1">P1</span></td><td>通信</td><td>错误码虚设/死分支/硬编码帧长/废弃函数错误数据</td><td class="loc">udpComm.cpp / driver.cpp</td><td>阶段2修复</td></tr>
|
||||
<tr><td>C5</td><td><span class="badge p2">P2</span></td><td>性能</td><td>每帧堆分配、每包 cout</td><td class="loc">udpComm.cpp:462 等</td><td>阶段2优化</td></tr>
|
||||
<tr><td>C7</td><td><span class="badge p1">P1</span></td><td>架构</td><td>双 Web 重复建设;/fcs/control 越权直改状态</td><td class="loc">httpserver.cpp:150</td><td>阶段2+4</td></tr>
|
||||
<tr><td>F1</td><td><span class="badge p0">P0</span></td><td>故障</td><td>双重故障存储,等级查询与上报读不同集合</td><td class="loc">PowerManger.cpp:448 / uPower_pmState.h:50</td><td>阶段1合并</td></tr>
|
||||
<tr><td>F2</td><td><span class="badge p1">P1</span></td><td>故障</td><td>上报死赋值</td><td class="loc">UpperCommManager.cpp:240</td><td>阶段1清理</td></tr>
|
||||
<tr><td>F3</td><td><span class="badge p1">P1</span></td><td>故障</td><td>三套编码并存;系统码无文本映射;前端 JS 重写映射</td><td class="loc">faultCode.h / fuelcell.h:834</td><td>阶段1统一</td></tr>
|
||||
<tr><td>F4</td><td><span class="badge p1">P1</span></td><td>故障</td><td>DEBUG 宏全构建未定义,4 级故障字恒为 0;DEBUFG 拼写;_DEBUG 死代码</td><td class="loc">systemData.h:7,776 等</td><td>阶段0修复</td></tr>
|
||||
<tr><td>F5</td><td><span class="badge p2">P2</span></td><td>故障</td><td>无故障事件持久化表</td><td class="loc">SQLite 层</td><td>阶段1新增</td></tr>
|
||||
<tr><td>D1-D4</td><td><span class="badge p1">P1</span></td><td>并发</td><td>全局数据池/锁纪律不一致/abs 截断/并发清队列</td><td class="loc">systemData.h 等</td><td>阶段2统一线程模型</td></tr>
|
||||
<tr><td>H1-H3</td><td><span class="badge p2">P2</span></td><td>上位机</td><td>功能重叠/越权通道/页面硬编码</td><td class="loc">HostSim / httpserver</td><td>阶段4</td></tr>
|
||||
<tr><td>E1</td><td><span class="badge p1">P1</span></td><td>构建</td><td>-Wall 未启用且写法错误;无 sanitizer;测试输出残留</td><td class="loc">CMakeLists.txt:80-86</td><td>阶段0接入</td></tr>
|
||||
<tr><td>E2</td><td><span class="badge p2">P2</span></td><td>构建</td><td>GLOB 反模式;第三方库无版本/许可证记录;CMAKE 版本过老</td><td class="loc">CMakeLists.txt:9,49,53</td><td>阶段0接入</td></tr>
|
||||
<tr><td>E3</td><td><span class="badge p1">P1</span></td><td>配置</td><td>ccuport/iport atoi 无校验、无范围检查</td><td class="loc">PowerManger.cpp:229/233</td><td>阶段0修复</td></tr>
|
||||
<tr><td>E4</td><td><span class="badge p2">P2</span></td><td>性能</td><td>SQLite insertGeneric/onFrame 高频重复 prepare</td><td class="loc">SQLite.cpp:610-625</td><td>阶段1优化</td></tr>
|
||||
<tr><td>E5</td><td><span class="badge p2">P2</span></td><td>规范</td><td>日志/错误输出三套并存(loguru/cerr/cout)</td><td class="loc">driver.cpp / LowerCommManager.cpp</td><td>阶段3统一</td></tr>
|
||||
<tr><td>T1</td><td><span class="badge p0">P0</span></td><td>测试</td><td>状态机/故障注入/上位机三大测试空白</td><td class="loc">test/</td><td>阶段0起持续</td></tr>
|
||||
<tr><td>T2</td><td><span class="badge p1">P1</span></td><td>CI</td><td>集成失败不阻塞;cppcheck 未接入;in-source 构建残留</td><td class="loc">ci/build-test.sh:181</td><td>阶段0</td></tr>
|
||||
</table>
|
||||
|
||||
<p class="small" style="margin-top:40px;border-top:1px solid var(--border);padding-top:16px;">
|
||||
本报告基于 2026-09-03 工作区代码静态审查生成,所有问题均标注文件与行号,关键缺陷(B1、B2、B3、B5)已经人工逐行复核。报告未对任何源代码做修改。
|
||||
</p>
|
||||
|
||||
</main>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,161 @@
|
||||
// MOOS file
|
||||
// 板卡 (RK3588 / Ubuntu 20.04) 专用 mission 配置
|
||||
// 七个 systemd 服务(moosdb / pPowerManger / pPowerMangerHost / pCCU /
|
||||
// pCanBridge / pMotor / pELoad)共用本文件。
|
||||
// 由 scripts/build-board.sh 同步到板卡 /root/work/h100/missions/h100.moos
|
||||
|
||||
ServerHost = localhost
|
||||
ServerPort = 9000
|
||||
Community = h100
|
||||
|
||||
ProcessConfig = pPowerManger
|
||||
{
|
||||
AppTick = 4
|
||||
CommsTick = 4
|
||||
log_level = INFO
|
||||
// 日志文件路径(目录需已存在,由 build-board.sh 部署时创建)
|
||||
logpath = /root/work/h100/data/pPowerManger.log
|
||||
// 数据库存储路径(目录需已存在,由 build-board.sh 部署时创建)
|
||||
dbpath = /root/work/h100/data/power_data.db
|
||||
// CCU 地址(pPowerManger -> pCCU 的 UDP 链路);不配置则默认 127.0.0.1:7000
|
||||
ccuhost = 127.0.0.1
|
||||
ccuport = 7000
|
||||
// 本地输入端口(接收 CCU 数据);默认 5001。
|
||||
// 5001 让给 pCCU 的 rcu 链路接收真实CCU(192.168.0.140) 固定上报的
|
||||
// 配电反馈,故本进程接收端口改为 5002(pCCU 转发的反馈与状态报文发往此处)
|
||||
iport = 5002
|
||||
}
|
||||
|
||||
ProcessConfig = pPowerMangerHost
|
||||
{
|
||||
AppTick = 4
|
||||
CommsTick = 4
|
||||
WEB_PORT = 18080
|
||||
|
||||
// 反馈落盘(SQLite),路径可配置;目录不存在会自动创建
|
||||
DB_FILE = /root/work/h100/data/feedback_data.db
|
||||
FB_LOG_ENABLED = true
|
||||
FB_LOG_KEEP_SECONDS = 86400 // 历史保留时长(秒),24h
|
||||
FB_LOG_PRUNE_INTERVAL_SECONDS = 60 // 清理检查周期(秒)
|
||||
}
|
||||
|
||||
ProcessConfig = pCCU
|
||||
{
|
||||
AppTick = 4
|
||||
CommsTick = 4
|
||||
|
||||
// FC 链路(本机监听 FC 状态;发送 FC 控制指令给燃料电池控制器)
|
||||
fc_local_port = 6000
|
||||
fc_remote_ip = 192.168.1.162
|
||||
fc_remote_port = 7000
|
||||
|
||||
// PM 链路(监听 pPowerManger 指令;向 pPowerManger 周期发送 PM 状态)
|
||||
// pPowerManger 与 pCCU 同机部署;pPowerManger 接收端口为 5002(iport),
|
||||
// 故 PM 状态发送目标用 127.0.0.1:5002。
|
||||
pm_local_port = 7000
|
||||
pm_remote_ip = 127.0.0.1
|
||||
pm_remote_port = 5002
|
||||
|
||||
//======== 真实CCU 桥接链路(配电协议) ========
|
||||
// 真实CCU(192.168.0.140) 设备侧固定上报到 192.168.0.223:5001
|
||||
// (与 pPowerManger 默认 CCU 配置一致:CCUPORT=7000 为其监听口,
|
||||
// 上报目标为控制主机 5001),设备侧不可修改。
|
||||
// 故 pCCU 的 rcu 链路直接绑定 5001 接收其反馈:
|
||||
// 配电反馈 0x0005~0x0008:原帧转发 pPowerManger(127.0.0.1:5002) + 网页显示
|
||||
// 配电指令 0x0001~0x0004:转发目标为真实CCU 监听口 192.168.0.140:7000
|
||||
// 其余帧(旧协议 0x20 0x20 状态帧、无效帧)落库忽略
|
||||
rcu_enable = true
|
||||
rcu_local_port = 5001
|
||||
rcu_remote_ip = 192.168.0.140
|
||||
rcu_remote_port = 7000
|
||||
|
||||
//======== 锂电池 ========
|
||||
// CAN 总线 BMS 协议(docs/BMS_协议字段定义.xlsx),
|
||||
// 经 pCanBridge 发布的 CAN_0x* 消息透传,无需额外配置。
|
||||
dbpath = /root/work/h100/data/pccu_data.db
|
||||
logpath = /root/work/h100/data/pCCU.log
|
||||
|
||||
web_port = 8080
|
||||
web_enable = true
|
||||
}
|
||||
|
||||
ProcessConfig = pCanBridge
|
||||
{
|
||||
AppTick = 4
|
||||
CommsTick = 4
|
||||
|
||||
// CAN<->MOOSDB 多通道透传:CANET(TCP Server 模式)
|
||||
// 每通道一条独立 TCP 连接;工作端口:CAN0=4001,CAN1=4002,...,CAN7=4008
|
||||
channel = CAN0,192.168.0.222,4001
|
||||
channel = CAN1,192.168.0.222,4002
|
||||
// channel = CAN1,192.168.0.222,4002
|
||||
|
||||
// CAN_TX 下行默认通道(pCCU 未指定 m_sSrcAux 时使用;可省略)
|
||||
default_channel = CAN0
|
||||
|
||||
// CAN 帧 SQLite 落库路径(can_frame 表,channel 列区分通道)
|
||||
dbpath = /root/work/h100/data/pCanBridge_data.db
|
||||
}
|
||||
|
||||
ProcessConfig = pMotor
|
||||
{
|
||||
AppTick = 4
|
||||
CommsTick = 4
|
||||
|
||||
// 推进电机控制器:CAN1 通道(经 pCanBridge 透传,docs/推进电机通信协议20260321.docx)
|
||||
// 下行 500ms 周期指令帧 0x18EF2010(网页 /api/motor_cmd 控制启停/复位/转速),
|
||||
// 上行订阅 CAN_0x* 解码故障/转速/母线电压/温度,网页 18081 展示
|
||||
can_channel = CAN1
|
||||
|
||||
// 冗余 CAN 通道(配置后指令帧同内容发 0x18EF2011;留空=不发送)
|
||||
// red_channel = CAN2
|
||||
|
||||
cmd_period_ms = 500
|
||||
reset_hold_sec = 5
|
||||
|
||||
web_port = 18081
|
||||
web_enable = true
|
||||
|
||||
logpath = /root/work/h100/data/pMotor.log
|
||||
}
|
||||
|
||||
ProcessConfig = pELoad
|
||||
{
|
||||
AppTick = 10
|
||||
CommsTick = 4
|
||||
|
||||
//======== 电子负载(IT6000C)以太网地址 ========
|
||||
// 仪器 LAN 配置的 IP 与 Raw Socket 端口号(出厂默认 30000)
|
||||
eload_ip = 192.168.200.100
|
||||
eload_port = 30000
|
||||
|
||||
//======== 功率控制 ========
|
||||
// MOOS 功率消息变量名(实时电机功率,W,正值=负载吸收)
|
||||
power_var = MOTOR_POWER
|
||||
ctrl_period_ms = 100
|
||||
power_stale_sec = 3
|
||||
current_sign = negative
|
||||
nominal_volt = 500
|
||||
max_power = 0
|
||||
max_current = 0
|
||||
slew_limit_wps = 0
|
||||
func_priority = cc
|
||||
|
||||
// CV 优先时的目标电压(V),func_priority=cv 时生效(恒压吸收)
|
||||
volt_set = 0
|
||||
|
||||
//======== 数据存储 ========
|
||||
dbpath = /root/work/h100/data/pELoad.db
|
||||
log_keep_hours = 72
|
||||
meas_log_period_ms = 100
|
||||
|
||||
// 测量命令来源:fetch=FETCh(读设备表头缓存,不触发测量,响应快,推荐);
|
||||
// meas=MEAS(每次触发设备重新测量,响应慢,易超时)
|
||||
meas_source = fetch
|
||||
|
||||
//======== 网页(避开 8080/8090/18080/18081)========
|
||||
web_port = 18082
|
||||
web_enable = true
|
||||
|
||||
logpath = /root/work/h100/data/pELoad.log
|
||||
}
|
||||
@@ -2,4 +2,9 @@ ProcessConfig = pPowerManger
|
||||
{
|
||||
AppTick = 4
|
||||
CommsTick = 4
|
||||
// CCU 地址;不配置则默认 127.0.0.1:7000
|
||||
// ccuhost = 127.0.0.1
|
||||
// ccuport = 7000
|
||||
// 本地输入端口(接收 CCU 数据);不配置则默认 5001
|
||||
// iport = 5001
|
||||
}
|
||||
Executable
+310
@@ -0,0 +1,310 @@
|
||||
#!/bin/bash
|
||||
#=======================================================================
|
||||
# FILE: scripts/build-board.sh
|
||||
# DESC: 把源码同步到目标板卡 (RK3588 / Ubuntu 22.04),在板卡原生编译
|
||||
# (aarch64 直编,比本地 QEMU 模拟快约 10 倍),并把产物部署到
|
||||
# /root/work/h100/bin/,可选重启 systemd 服务。
|
||||
#
|
||||
# 用法:
|
||||
# ./scripts/build-board.sh # 同步+编译+部署(不重启)
|
||||
# ./scripts/build-board.sh --start # 编译后重启全部服务(含 pCanBridge/pMotor/pELoad)
|
||||
# ./scripts/build-board.sh --clean # 板卡上重新 cmake 再编译
|
||||
# ./scripts/build-board.sh --jobs 4 # 指定并行度(默认板卡 nproc)
|
||||
#
|
||||
# 参数:
|
||||
# --host <ip> 目标主机(默认 192.168.0.223)
|
||||
# --user <user> 登录用户(默认 root)
|
||||
# --board-src <dir> 板卡源码目录(默认 /root/work/h100/src)
|
||||
# --board-bin <dir> 板卡部署目录(默认 /root/work/h100/bin)
|
||||
# --jobs <n> 编译并行度(默认板卡 nproc)
|
||||
# --start 编译部署后重启服务
|
||||
# --clean 先重新 cmake(配置变更时用)
|
||||
# --ccu-host <ip> 覆盖 mission 中 pPowerManger 的 CCU 地址 (ccuhost)
|
||||
# --ccu-port <n> 覆盖 mission 中 pPowerManger 的 CCU 端口 (ccuport)
|
||||
# -h, --help 显示帮助
|
||||
#
|
||||
# 前置: 板卡已配免密 SSH,且有编译环境(cmake/g++/MOOS/jsoncpp),
|
||||
# 源码已能本地编译(本脚本只负责同步+板卡编译)。
|
||||
#
|
||||
# !!!! 板卡网络配置(2026-08-26 联调定型,勿随意修改) !!!!
|
||||
#
|
||||
# 板卡与 FC 的组网为"单网卡 + /23 掩码"方案(依据《超滑FC和复合管控器
|
||||
# 通讯协议-0821》1.1.1:CCU 192.168.0.140/23 <-> FC 192.168.1.162):
|
||||
#
|
||||
# enP3p49s0 192.168.0.223/23 (255.255.254.0) <- 唯一业务网口,接交换机
|
||||
# /23 使 192.168.0.x 与 192.168.1.x 同子网直达,
|
||||
# FC(192.168.1.162) 无需网关即可互通。
|
||||
# NM 配置档案: "有线连接 1"(静态 manual,已持久化)
|
||||
# enP4p65s0 已弃用(旧双网卡方案的 FC 专口,物理链路已断)
|
||||
# 回环 lo pPowerManger(5001) <-> pCCU(7000) 同机 UDP 互通
|
||||
#
|
||||
# 关联端口:
|
||||
# FC 状态: FC:7000 -> 板卡:6000 (pCCU 监听)
|
||||
# FC 控制: 板卡:6000 -> FC:7000 (pCCU 发送)
|
||||
# PM 指令: pPowerManger:5001 -> pCCU:7000 (127.0.0.1,
|
||||
# 见 missions/h100.moos ccuhost/ccuport,默认值在 PowerManger.h CCUHOST)
|
||||
# PM 状态: pCCU:7000 -> pPowerManger:5001 (127.0.0.1)
|
||||
#
|
||||
# 排障提示:
|
||||
# - 若收不到 FC 状态,先在板卡上 `ethtool enP3p49s0` 看 Link detected,
|
||||
# 再 `ping 192.168.1.162`;ping 不通通常是物理链路/交换机问题,
|
||||
# 不要改回 /24 掩码或启用 enP4p65s0 来"修"网络。
|
||||
# - 改 IP/掩码须用 `nmcli con mod "有线连接 1" ...` 持久化,
|
||||
# 并保持掩码 /23。
|
||||
#=======================================================================
|
||||
|
||||
set -uo pipefail
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
PROJECT_ROOT="$(dirname "${SCRIPT_DIR}")"
|
||||
|
||||
HOST="192.168.0.223"
|
||||
USER="root"
|
||||
BOARD_SRC="/root/work/h100/src"
|
||||
BOARD_BIN="/root/work/h100/bin"
|
||||
JOBS=""
|
||||
DO_START=0
|
||||
DO_CLEAN=0
|
||||
CCU_HOST=""
|
||||
CCU_PORT=""
|
||||
|
||||
SERVICES=(moosdb pPowerManger pPowerMangerHost pCCU pCanBridge pMotor pELoad)
|
||||
|
||||
info() { printf '\033[1;36m[build-board]\033[0m %s\n' "$*"; }
|
||||
ok() { printf '\033[1;32m[build-board]\033[0m %s\n' "$*"; }
|
||||
warn() { printf '\033[1;33m[build-board]\033[0m %s\n' "$*"; }
|
||||
err() { printf '\033[1;31m[build-board]\033[0m %s\n' "$*"; }
|
||||
|
||||
usage() {
|
||||
sed -n '2,31p' "${BASH_SOURCE[0]}" | sed 's/^# \{0,1\}//'
|
||||
exit 0
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------
|
||||
# 参数解析
|
||||
#-------------------------------------------------------------------
|
||||
while [ $# -gt 0 ]; do
|
||||
case "$1" in
|
||||
--host) [ $# -ge 2 ] || { err "--host 需要参数"; exit 1; }; HOST="$2"; shift 2 ;;
|
||||
--user) [ $# -ge 2 ] || { err "--user 需要参数"; exit 1; }; USER="$2"; shift 2 ;;
|
||||
--board-src) [ $# -ge 2 ] || { err "--board-src 需要参数"; exit 1; }; BOARD_SRC="$2"; shift 2 ;;
|
||||
--board-bin) [ $# -ge 2 ] || { err "--board-bin 需要参数"; exit 1; }; BOARD_BIN="$2"; shift 2 ;;
|
||||
--jobs) [ $# -ge 2 ] || { err "--jobs 需要参数"; exit 1; }; JOBS="$2"; shift 2 ;;
|
||||
--start) DO_START=1; shift ;;
|
||||
--clean) DO_CLEAN=1; shift ;;
|
||||
--ccu-host) [ $# -ge 2 ] || { err "--ccu-host 需要参数"; exit 1; }; CCU_HOST="$2"; shift 2 ;;
|
||||
--ccu-port) [ $# -ge 2 ] || { err "--ccu-port 需要参数"; exit 1; }; CCU_PORT="$2"; shift 2 ;;
|
||||
-h|--help) usage ;;
|
||||
*) err "未知参数: $1(见 --help)"; exit 1 ;;
|
||||
esac
|
||||
done
|
||||
|
||||
SSH_TARGET="${USER}@${HOST}"
|
||||
SSH="ssh -o BatchMode=yes -o ConnectTimeout=5"
|
||||
|
||||
case "${CCU_PORT}" in
|
||||
""|*[!0-9]*) [ -z "${CCU_PORT}" ] || { err "--ccu-port 必须是数字端口: ${CCU_PORT}"; exit 1; } ;;
|
||||
esac
|
||||
|
||||
#-------------------------------------------------------------------
|
||||
# 1. 前置检查
|
||||
#-------------------------------------------------------------------
|
||||
if ! ${SSH} "${SSH_TARGET}" 'true' 2>/dev/null; then
|
||||
err "无法免密 SSH 到 ${SSH_TARGET}"
|
||||
err "请先配置免密登录: ssh-copy-id ${SSH_TARGET}"
|
||||
exit 1
|
||||
fi
|
||||
ok "SSH 连接正常: ${SSH_TARGET}"
|
||||
|
||||
#-------------------------------------------------------------------
|
||||
# mission 中插入/替换 "key = value"(键已存在则替换,否则插到第一个
|
||||
# 顶层 '}' 之前,即 pPowerManger 配置块末尾)
|
||||
#-------------------------------------------------------------------
|
||||
upsert_moos_param() {
|
||||
local f="$1" key="$2" val="$3"
|
||||
if grep -qE "^[[:space:]]*${key}[[:space:]]*=" "${f}"; then
|
||||
sed -i -E "s|^([[:space:]]*)${key}[[:space:]]*=.*|\1${key} = ${val}|" "${f}"
|
||||
else
|
||||
awk -v kv=" ${key} = ${val}" \
|
||||
'!d && /^[[:space:]]*}[[:space:]]*$/ { print kv; d=1 } { print }' \
|
||||
"${f}" > "${f}.tmp" && mv "${f}.tmp" "${f}"
|
||||
fi
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------
|
||||
# 2. 同步源码到板卡(排除构建产物 / git / 数据)
|
||||
#-------------------------------------------------------------------
|
||||
info "同步源码到板卡 ${BOARD_SRC} ..."
|
||||
rsync -az --delete \
|
||||
--exclude='build/' \
|
||||
--exclude='build-arm64/' \
|
||||
--exclude='build-native/' \
|
||||
--exclude='build-nosa-test/' \
|
||||
--exclude='bin/' \
|
||||
--exclude='.git/' \
|
||||
--exclude='.cache/' \
|
||||
--exclude='.kilo/' \
|
||||
--exclude='.vscode/' \
|
||||
--exclude='docs/' \
|
||||
--exclude='reports/' \
|
||||
--exclude='*.log' \
|
||||
--exclude='*.db' \
|
||||
--exclude='CMakeCache.txt' \
|
||||
"${PROJECT_ROOT}/" "${SSH_TARGET}:${BOARD_SRC}/" || { err "rsync 源码失败"; exit 1; }
|
||||
ok "源码已同步"
|
||||
|
||||
if [ -f "${PROJECT_ROOT}/missions/h100.moos" ]; then
|
||||
info "同步 mission h100.moos ..."
|
||||
local_mission="${PROJECT_ROOT}/missions/h100.moos"
|
||||
tmp_moos=""
|
||||
if [ -n "${CCU_HOST}" ] || [ -n "${CCU_PORT}" ]; then
|
||||
tmp_moos="$(mktemp)"
|
||||
cp "${local_mission}" "${tmp_moos}"
|
||||
[ -n "${CCU_HOST}" ] && upsert_moos_param "${tmp_moos}" ccuhost "${CCU_HOST}"
|
||||
[ -n "${CCU_PORT}" ] && upsert_moos_param "${tmp_moos}" ccuport "${CCU_PORT}"
|
||||
local_mission="${tmp_moos}"
|
||||
info "CCU 地址覆盖: ccuhost=${CCU_HOST:-<保持原值>} ccuport=${CCU_PORT:-<保持原值>}"
|
||||
fi
|
||||
rsync -az "${local_mission}" \
|
||||
"${SSH_TARGET}:/root/work/h100/missions/h100.moos" || { err "rsync mission 失败"; [ -n "${tmp_moos}" ] && rm -f "${tmp_moos}"; exit 1; }
|
||||
[ -n "${tmp_moos}" ] && rm -f "${tmp_moos}"
|
||||
ok "mission 已同步"
|
||||
fi
|
||||
|
||||
#-------------------------------------------------------------------
|
||||
# 3. 板卡原生编译
|
||||
#-------------------------------------------------------------------
|
||||
if [ "${DO_CLEAN}" = "1" ]; then
|
||||
info "重新 cmake(--clean)..."
|
||||
${SSH} "${SSH_TARGET}" "rm -rf ${BOARD_SRC}/build-native && mkdir -p ${BOARD_SRC}/build-native && \
|
||||
cd ${BOARD_SRC}/build-native && cmake -DCMAKE_BUILD_TYPE=Release .." \
|
||||
|| { err "cmake 失败"; exit 1; }
|
||||
ok "cmake 完成"
|
||||
else
|
||||
${SSH} "${SSH_TARGET}" "mkdir -p ${BOARD_SRC}/build-native"
|
||||
# 若首次未配置过则先 cmake
|
||||
if ! ${SSH} "${SSH_TARGET}" "[ -f ${BOARD_SRC}/build-native/Makefile ]"; then
|
||||
info "首次编译,先 cmake ..."
|
||||
${SSH} "${SSH_TARGET}" "cd ${BOARD_SRC}/build-native && cmake -DCMAKE_BUILD_TYPE=Release .." \
|
||||
|| { err "cmake 失败"; exit 1; }
|
||||
ok "cmake 完成"
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ -z "${JOBS}" ]; then
|
||||
JOBS="$(${SSH} "${SSH_TARGET}" nproc)"
|
||||
fi
|
||||
|
||||
info "板卡编译 (make -j${JOBS}) ..."
|
||||
if ! ${SSH} "${SSH_TARGET}" "cd ${BOARD_SRC}/build-native && make -j${JOBS}"; then
|
||||
err "板卡编译失败(见上方输出)"
|
||||
exit 1
|
||||
fi
|
||||
ok "板卡编译完成"
|
||||
|
||||
#-------------------------------------------------------------------
|
||||
# 4. 部署产物到板卡运行目录
|
||||
#-------------------------------------------------------------------
|
||||
info "部署产物到 ${BOARD_BIN}/ ..."
|
||||
${SSH} "${SSH_TARGET}" "mkdir -p ${BOARD_BIN} && \
|
||||
cp -f ${BOARD_SRC}/bin/pPowerManger ${BOARD_BIN}/pPowerManger && \
|
||||
cp -f ${BOARD_SRC}/bin/pPowerMangerHost ${BOARD_BIN}/pPowerMangerHost && \
|
||||
cp -f ${BOARD_SRC}/bin/pCCU ${BOARD_BIN}/pCCU && \
|
||||
cp -f ${BOARD_SRC}/bin/pCanBridge ${BOARD_BIN}/pCanBridge && \
|
||||
cp -f ${BOARD_SRC}/bin/pMotor ${BOARD_BIN}/pMotor && \
|
||||
cp -f ${BOARD_SRC}/bin/pELoad ${BOARD_BIN}/pELoad && \
|
||||
chmod +x ${BOARD_BIN}/pPowerManger ${BOARD_BIN}/pPowerMangerHost ${BOARD_BIN}/pCCU ${BOARD_BIN}/pCanBridge ${BOARD_BIN}/pMotor ${BOARD_BIN}/pELoad" \
|
||||
|| { err "部署产物失败"; exit 1; }
|
||||
ok "产物已部署"
|
||||
|
||||
#-------------------------------------------------------------------
|
||||
# 4.5 安装/刷新 pCanBridge systemd unit(幂等,其它 5 个 unit 已装)
|
||||
#-------------------------------------------------------------------
|
||||
info "安装 pCanBridge.service ..."
|
||||
${SSH} "${SSH_TARGET}" "cat > /etc/systemd/system/pCanBridge.service" <<EOF
|
||||
[Unit]
|
||||
Description=pCanBridge for H100 Power Manager
|
||||
After=moosdb.service
|
||||
Requires=moosdb.service
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
WorkingDirectory=${BOARD_BIN}
|
||||
ExecStart=${BOARD_BIN}/pCanBridge --alias=pCanBridge /root/work/h100/missions/h100.moos
|
||||
Restart=on-failure
|
||||
RestartSec=5
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
EOF
|
||||
${SSH} "${SSH_TARGET}" "systemctl daemon-reload && systemctl reset-failed pCanBridge 2>/dev/null || true"
|
||||
ok "pCanBridge.service 已安装"
|
||||
|
||||
#-------------------------------------------------------------------
|
||||
# 4.6 安装/刷新 pMotor systemd unit(幂等)
|
||||
#-------------------------------------------------------------------
|
||||
info "安装 pMotor.service ..."
|
||||
${SSH} "${SSH_TARGET}" "cat > /etc/systemd/system/pMotor.service" <<EOF
|
||||
[Unit]
|
||||
Description=pMotor Propulsion Motor for H100 Power Manager
|
||||
After=moosdb.service pCanBridge.service
|
||||
Requires=moosdb.service
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
WorkingDirectory=${BOARD_BIN}
|
||||
ExecStart=${BOARD_BIN}/pMotor --alias=pMotor /root/work/h100/missions/h100.moos
|
||||
Restart=on-failure
|
||||
RestartSec=5
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
EOF
|
||||
${SSH} "${SSH_TARGET}" "systemctl daemon-reload && systemctl reset-failed pMotor 2>/dev/null || true"
|
||||
ok "pMotor.service 已安装"
|
||||
|
||||
#-------------------------------------------------------------------
|
||||
# 4.7 安装/刷新 pELoad systemd unit(幂等)
|
||||
# 电子负载(IT6000C)控制程序:以太网直连设备,不依赖 pCanBridge
|
||||
#-------------------------------------------------------------------
|
||||
info "安装 pELoad.service ..."
|
||||
${SSH} "${SSH_TARGET}" "cat > /etc/systemd/system/pELoad.service" <<EOF
|
||||
[Unit]
|
||||
Description=pELoad Electronic Load (IT6000C) for H100 Power Manager
|
||||
After=moosdb.service
|
||||
Requires=moosdb.service
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
WorkingDirectory=${BOARD_BIN}
|
||||
ExecStart=${BOARD_BIN}/pELoad --alias=pELoad /root/work/h100/missions/h100.moos
|
||||
Restart=on-failure
|
||||
RestartSec=5
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
EOF
|
||||
${SSH} "${SSH_TARGET}" "systemctl daemon-reload && systemctl reset-failed pELoad 2>/dev/null || true"
|
||||
ok "pELoad.service 已安装"
|
||||
|
||||
echo ""
|
||||
ok "产物: ${BOARD_BIN}/pPowerManger (aarch64)"
|
||||
${SSH} "${SSH_TARGET}" "file ${BOARD_BIN}/pPowerManger | cut -c1-60"
|
||||
|
||||
#-------------------------------------------------------------------
|
||||
# 5. 可选重启服务
|
||||
#-------------------------------------------------------------------
|
||||
if [ "${DO_START}" = "1" ]; then
|
||||
info "重启服务 ..."
|
||||
${SSH} "${SSH_TARGET}" "systemctl restart ${SERVICES[*]}" \
|
||||
|| { err "重启服务失败"; exit 1; }
|
||||
sleep 3
|
||||
ok "服务状态: $(${SSH} "${SSH_TARGET}" "systemctl is-active ${SERVICES[*]}")"
|
||||
else
|
||||
echo ""
|
||||
info "未重启服务。需要重启请加 --start 或手动:"
|
||||
echo " systemctl restart ${SERVICES[*]}"
|
||||
fi
|
||||
|
||||
echo ""
|
||||
ok "完成。"
|
||||
Executable
+147
@@ -0,0 +1,147 @@
|
||||
#!/bin/bash
|
||||
#=======================================================================
|
||||
# FILE: scripts/clean-data.sh
|
||||
# DESC: 清理目标板卡 (RK3588 / Ubuntu 22.04) 上的数据库与日志文件。
|
||||
# 默认清理板卡运行目录 /root/work/h100/data/ 下的:
|
||||
# power_data.db (+ -wal/-shm) 主机功率数据库
|
||||
# feedback_data.db 反馈落盘数据库
|
||||
# pccu_data.db (+ -wal/-shm) pCCU 帧日志数据库
|
||||
# pCanBridge_data.db (+ -wal/-shm) pCanBridge CAN 帧数据库
|
||||
# pPowerManger.log / pCCU.log 运行日志
|
||||
# 默认先停止各服务再清理(避免 SQLite WAL 仍在写入)。
|
||||
#
|
||||
# 用法:
|
||||
# ./scripts/clean-data.sh # 停服务 -> 清理 data 目录(不重启)
|
||||
# ./scripts/clean-data.sh --start # 清理后重新启动各服务
|
||||
# ./scripts/clean-data.sh --no-stop # 不停服务直接清理(慎用)
|
||||
# ./scripts/clean-data.sh --stale # 额外清理 bin/ 与 src/bin/ 下的旧 db/log
|
||||
#
|
||||
# 参数:
|
||||
# --host <ip> 目标主机(默认 192.168.0.223)
|
||||
# --user <user> 登录用户(默认 root)
|
||||
# --board-dir <dir> 板卡部署根目录(默认 /root/work/h100)
|
||||
# --start 清理后重启服务
|
||||
# --no-stop 不停服务直接清理(慎用)
|
||||
# --stale 额外清理历史遗留的 bin/、src/bin/ 下旧数据库与日志
|
||||
# -h, --help 显示帮助
|
||||
#
|
||||
# 前置: 板卡已配免密 SSH(ssh-copy-id root@<host>)。
|
||||
#=======================================================================
|
||||
|
||||
set -uo pipefail
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
PROJECT_ROOT="$(dirname "${SCRIPT_DIR}")"
|
||||
|
||||
HOST="192.168.0.223"
|
||||
USER="root"
|
||||
BOARD_DIR="/root/work/h100"
|
||||
DO_START=0
|
||||
DO_STOP=1
|
||||
DO_STALE=0
|
||||
|
||||
SERVICES=(moosdb pPowerManger pPowerMangerHost pCCU pCanBridge)
|
||||
|
||||
# 板卡 data 目录下需要清理的文件(含 SQLite WAL/SHM)
|
||||
DATA_FILES=(
|
||||
power_data.db power_data.db-wal power_data.db-shm
|
||||
feedback_data.db
|
||||
pccu_data.db pccu_data.db-wal pccu_data.db-shm
|
||||
pCanBridge_data.db pCanBridge_data.db-wal pCanBridge_data.db-shm
|
||||
pPowerManger.log pCCU.log
|
||||
)
|
||||
|
||||
# 历史遗留目录(旧部署位置),仅当 --stale 时清理
|
||||
STALE_DIRS=("${BOARD_DIR}/bin" "${BOARD_DIR}/src/bin")
|
||||
|
||||
info() { printf '\033[1;36m[clean-data]\033[0m %s\n' "$*"; }
|
||||
ok() { printf '\033[1;32m[clean-data]\033[0m %s\n' "$*"; }
|
||||
warn() { printf '\033[1;33m[clean-data]\033[0m %s\n' "$*"; }
|
||||
err() { printf '\033[1;31m[clean-data]\033[0m %s\n' "$*"; }
|
||||
|
||||
usage() {
|
||||
sed -n '2,31p' "${BASH_SOURCE[0]}" | sed 's/^# \{0,1\}//'
|
||||
exit 0
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------
|
||||
# 参数解析
|
||||
#-------------------------------------------------------------------
|
||||
while [ $# -gt 0 ]; do
|
||||
case "$1" in
|
||||
--host) [ $# -ge 2 ] || { err "--host 需要参数"; exit 1; }; HOST="$2"; shift 2 ;;
|
||||
--user) [ $# -ge 2 ] || { err "--user 需要参数"; exit 1; }; USER="$2"; shift 2 ;;
|
||||
--board-dir) [ $# -ge 2 ] || { err "--board-dir 需要参数"; exit 1; }; BOARD_DIR="$2"; shift 2 ;;
|
||||
--start) DO_START=1; shift ;;
|
||||
--no-stop) DO_STOP=0; shift ;;
|
||||
--stale) DO_STALE=1; shift ;;
|
||||
-h|--help) usage ;;
|
||||
*) err "未知参数: $1(见 --help)"; exit 1 ;;
|
||||
esac
|
||||
done
|
||||
|
||||
STALE_DIRS=("${BOARD_DIR}/bin" "${BOARD_DIR}/src/bin")
|
||||
|
||||
SSH_TARGET="${USER}@${HOST}"
|
||||
SSH="ssh -o BatchMode=yes -o ConnectTimeout=5"
|
||||
|
||||
#-------------------------------------------------------------------
|
||||
# 1. 前置检查
|
||||
#-------------------------------------------------------------------
|
||||
if ! ${SSH} "${SSH_TARGET}" 'true' 2>/dev/null; then
|
||||
err "无法免密 SSH 到 ${SSH_TARGET}"
|
||||
err "请先配置免密登录: ssh-copy-id ${SSH_TARGET}"
|
||||
exit 1
|
||||
fi
|
||||
ok "SSH 连接正常: ${SSH_TARGET}"
|
||||
|
||||
#-------------------------------------------------------------------
|
||||
# 2. 停止服务(默认)
|
||||
#-------------------------------------------------------------------
|
||||
if [ "${DO_STOP}" = "1" ]; then
|
||||
info "停止服务 ${SERVICES[*]} ..."
|
||||
# 先停应用,最后停 moosdb
|
||||
${SSH} "${SSH_TARGET}" "systemctl stop pCanBridge pPowerMangerHost pPowerManger pCCU moosdb 2>/dev/null; true"
|
||||
ok "服务已停止"
|
||||
else
|
||||
warn "--no-stop:不停服务直接清理,可能产生脏数据(SQLite 仍在写入)"
|
||||
fi
|
||||
|
||||
#-------------------------------------------------------------------
|
||||
# 3. 清理 data 目录
|
||||
#-------------------------------------------------------------------
|
||||
BOARD_DATA="${BOARD_DIR}/data"
|
||||
info "清理 ${BOARD_DATA}/ ..."
|
||||
for f in "${DATA_FILES[@]}"; do
|
||||
${SSH} "${SSH_TARGET}" "rm -f ${BOARD_DATA}/${f}" \
|
||||
&& ok "删除 ${f}" || warn "删除 ${f} 失败(可能不存在)"
|
||||
done
|
||||
|
||||
#-------------------------------------------------------------------
|
||||
# 4. 可选: 清理历史遗留目录
|
||||
#-------------------------------------------------------------------
|
||||
if [ "${DO_STALE}" = "1" ]; then
|
||||
for d in "${STALE_DIRS[@]}"; do
|
||||
info "清理历史遗留 ${d}/ 下的 db/log ..."
|
||||
${SSH} "${SSH_TARGET}" "rm -f ${d}/power_data.db ${d}/power_data.db-wal ${d}/power_data.db-shm ${d}/feedback_data.db ${d}/pPowerManger.log 2>/dev/null; true"
|
||||
ok "${d} 已清理"
|
||||
done
|
||||
fi
|
||||
|
||||
#-------------------------------------------------------------------
|
||||
# 5. 可选: 重启服务
|
||||
#-------------------------------------------------------------------
|
||||
if [ "${DO_START}" = "1" ]; then
|
||||
info "启动服务 (moosdb -> pPowerManger / pPowerMangerHost / pCCU / pCanBridge) ..."
|
||||
${SSH} "${SSH_TARGET}" "systemctl start moosdb && sleep 1 && \
|
||||
systemctl start pPowerManger pPowerMangerHost pCCU pCanBridge" \
|
||||
|| { err "启动失败"; exit 1; }
|
||||
ok "服务已启动"
|
||||
else
|
||||
echo ""
|
||||
info "清理完成,服务未启动。需要重启请加 --start 或手动:"
|
||||
echo " systemctl start moosdb pPowerManger pPowerMangerHost pCCU pCanBridge"
|
||||
fi
|
||||
|
||||
echo ""
|
||||
ok "完成。"
|
||||
Executable
+133
@@ -0,0 +1,133 @@
|
||||
#!/bin/bash
|
||||
#=======================================================================
|
||||
# FILE: scripts/fetch-data.sh
|
||||
# DESC: 从目标板卡 (RK3588 / Ubuntu 22.04) 下载数据库与日志到本地。
|
||||
# 默认抓取板卡运行目录 /root/work/h100/data/ 下的:
|
||||
# power_data.db (+ -wal/-shm) 主机功率数据库
|
||||
# feedback_data.db 反馈落盘数据库
|
||||
# pccu_data.db (+ -wal/-shm) pCCU 帧日志数据库
|
||||
# pCanBridge_data.db (+ -wal/-shm) pCanBridge CAN 帧数据库
|
||||
# pPowerManger.log / pCCU.log 运行日志
|
||||
# 可选 --journal 一并导出各 systemd 服务的 journal 日志。
|
||||
#
|
||||
# 用法:
|
||||
# ./scripts/fetch-data.sh # 下载 db + 日志到本地 data/board-<时间>/
|
||||
# ./scripts/fetch-data.sh --journal # 额外导出 systemd journal
|
||||
# ./scripts/fetch-data.sh --out-dir /tmp/xx # 指定本地保存目录
|
||||
#
|
||||
# 参数:
|
||||
# --host <ip> 目标主机(默认 192.168.0.223)
|
||||
# --user <user> 登录用户(默认 root)
|
||||
# --board-dir <dir> 板卡部署根目录(默认 /root/work/h100)
|
||||
# --out-dir <dir> 本地保存目录(默认 data/board-<时间>)
|
||||
# --journal 额外导出各服务的 systemd journal 日志
|
||||
# -h, --help 显示帮助
|
||||
#
|
||||
# 前置: 板卡已配免密 SSH(ssh-copy-id root@<host>)。
|
||||
#=======================================================================
|
||||
|
||||
set -uo pipefail
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
PROJECT_ROOT="$(dirname "${SCRIPT_DIR}")"
|
||||
|
||||
HOST="192.168.0.223"
|
||||
USER="root"
|
||||
BOARD_DIR="/root/work/h100"
|
||||
OUT_DIR=""
|
||||
DO_JOURNAL=0
|
||||
|
||||
SERVICES=(moosdb pPowerManger pPowerMangerHost pCCU pCanBridge)
|
||||
|
||||
# 板卡 data 目录下需要下载的文件(含 SQLite WAL/SHM 以保证数据完整)
|
||||
DATA_FILES=(
|
||||
power_data.db power_data.db-wal power_data.db-shm
|
||||
feedback_data.db
|
||||
pccu_data.db pccu_data.db-wal pccu_data.db-shm
|
||||
pCanBridge_data.db pCanBridge_data.db-wal pCanBridge_data.db-shm
|
||||
pPowerManger.log pCCU.log
|
||||
)
|
||||
|
||||
info() { printf '\033[1;36m[fetch-data]\033[0m %s\n' "$*"; }
|
||||
ok() { printf '\033[1;32m[fetch-data]\033[0m %s\n' "$*"; }
|
||||
warn() { printf '\033[1;33m[fetch-data]\033[0m %s\n' "$*"; }
|
||||
err() { printf '\033[1;31m[fetch-data]\033[0m %s\n' "$*"; }
|
||||
|
||||
usage() {
|
||||
sed -n '2,28p' "${BASH_SOURCE[0]}" | sed 's/^# \{0,1\}//'
|
||||
exit 0
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------
|
||||
# 参数解析
|
||||
#-------------------------------------------------------------------
|
||||
while [ $# -gt 0 ]; do
|
||||
case "$1" in
|
||||
--host) [ $# -ge 2 ] || { err "--host 需要参数"; exit 1; }; HOST="$2"; shift 2 ;;
|
||||
--user) [ $# -ge 2 ] || { err "--user 需要参数"; exit 1; }; USER="$2"; shift 2 ;;
|
||||
--board-dir) [ $# -ge 2 ] || { err "--board-dir 需要参数"; exit 1; }; BOARD_DIR="$2"; shift 2 ;;
|
||||
--out-dir) [ $# -ge 2 ] || { err "--out-dir 需要参数"; exit 1; }; OUT_DIR="$2"; shift 2 ;;
|
||||
--journal) DO_JOURNAL=1; shift ;;
|
||||
-h|--help) usage ;;
|
||||
*) err "未知参数: $1(见 --help)"; exit 1 ;;
|
||||
esac
|
||||
done
|
||||
|
||||
SSH_TARGET="${USER}@${HOST}"
|
||||
SSH="ssh -o BatchMode=yes -o ConnectTimeout=5"
|
||||
SCP="scp -o BatchMode=yes -o ConnectTimeout=5"
|
||||
|
||||
#-------------------------------------------------------------------
|
||||
# 1. 前置检查
|
||||
#-------------------------------------------------------------------
|
||||
if ! ${SSH} "${SSH_TARGET}" 'true' 2>/dev/null; then
|
||||
err "无法免密 SSH 到 ${SSH_TARGET}"
|
||||
err "请先配置免密登录: ssh-copy-id ${SSH_TARGET}"
|
||||
exit 1
|
||||
fi
|
||||
ok "SSH 连接正常: ${SSH_TARGET}"
|
||||
|
||||
if [ -z "${OUT_DIR}" ]; then
|
||||
OUT_DIR="${PROJECT_ROOT}/data/board-$(date +%Y%m%d-%H%M%S)"
|
||||
fi
|
||||
mkdir -p "${OUT_DIR}" || { err "无法创建本地目录 ${OUT_DIR}"; exit 1; }
|
||||
info "本地保存目录: ${OUT_DIR}"
|
||||
|
||||
#-------------------------------------------------------------------
|
||||
# 2. 下载 data 目录下的数据库与日志
|
||||
#-------------------------------------------------------------------
|
||||
BOARD_DATA="${BOARD_DIR}/data"
|
||||
missing=0
|
||||
for f in "${DATA_FILES[@]}"; do
|
||||
if ${SSH} "${SSH_TARGET}" "[ -f ${BOARD_DATA}/${f} ]" 2>/dev/null; then
|
||||
info "下载 ${f} ..."
|
||||
${SCP} -q "${SSH_TARGET}:${BOARD_DATA}/${f}" "${OUT_DIR}/" \
|
||||
|| { err "下载 ${f} 失败"; exit 1; }
|
||||
ok "${f}"
|
||||
else
|
||||
warn "板卡上不存在: ${BOARD_DATA}/${f}(跳过)"
|
||||
missing=$((missing+1))
|
||||
fi
|
||||
done
|
||||
[ "${missing}" -eq "${#DATA_FILES[@]}" ] && { err "板卡 data 目录下没有任何可下载文件"; exit 1; }
|
||||
|
||||
#-------------------------------------------------------------------
|
||||
# 3. 可选: 导出 systemd journal
|
||||
#-------------------------------------------------------------------
|
||||
if [ "${DO_JOURNAL}" = "1" ]; then
|
||||
for s in "${SERVICES[@]}"; do
|
||||
info "导出 journal: ${s} ..."
|
||||
${SSH} "${SSH_TARGET}" "journalctl --no-pager -u ${s} 2>/dev/null" > "${OUT_DIR}/${s}.journal.log" \
|
||||
|| { warn "导出 ${s} journal 失败(可能无记录)"; }
|
||||
ok "${s}.journal.log"
|
||||
done
|
||||
fi
|
||||
|
||||
#-------------------------------------------------------------------
|
||||
# 4. 完成
|
||||
#-------------------------------------------------------------------
|
||||
echo ""
|
||||
ok "下载完成。本地文件:"
|
||||
ls -lah "${OUT_DIR}" | sed 's/^/ /'
|
||||
echo ""
|
||||
info "查看数据库可用: sqlite3 ${OUT_DIR}/power_data.db .tables"
|
||||
Executable
+306
@@ -0,0 +1,306 @@
|
||||
#!/bin/bash
|
||||
#=======================================================================
|
||||
# FILE: scripts/run_host_sim.sh
|
||||
# DESC: 运行与测试 pPowerMangerHost(模拟 pPowerManger 上位机的网页程序)
|
||||
#
|
||||
# 用法:
|
||||
# ./scripts/run_host_sim.sh run 启动 MOOSDB + pPowerManger
|
||||
# + pPowerMangerHost(前台运行,
|
||||
# Ctrl-C 退出并清理)
|
||||
# ./scripts/run_host_sim.sh test 自动化测试 pPowerMangerHost:
|
||||
# 网页 HTTP / WebSocket 反馈 /
|
||||
# 指令下发到 MOOSDB
|
||||
# ./scripts/run_host_sim.sh build 仅编译需要的目标
|
||||
# ./scripts/run_host_sim.sh stop 清理残留进程
|
||||
# ./scripts/run_host_sim.sh help 显示帮助
|
||||
#
|
||||
# 环境变量(可覆盖):
|
||||
# SERVER_HOST MOOSDB 地址(默认 localhost)
|
||||
# SERVER_PORT MOOSDB 端口(默认 9000)
|
||||
# WEB_PORT 网页监听端口(默认 18080)
|
||||
# WITH_POWERMANGER run 模式是否同时启动 pPowerManger(默认 1)
|
||||
#=======================================================================
|
||||
set -uo pipefail
|
||||
|
||||
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
||||
BIN_DIR="${ROOT}/bin"
|
||||
MOOS_TEMPLATE="${ROOT}/src/pPowerMangerHost/pPowerMangerHost.moos"
|
||||
|
||||
SERVER_HOST="${SERVER_HOST:-localhost}"
|
||||
SERVER_PORT="${SERVER_PORT:-9000}"
|
||||
WEB_PORT="${WEB_PORT:-18080}"
|
||||
WITH_POWERMANGER="${WITH_POWERMANGER:-1}"
|
||||
|
||||
MOOSDB_BIN="${MOOSDB_BIN:-$(command -v MOOSDB || true)}"
|
||||
POKE_BIN="$(command -v uPokeDB || true)"
|
||||
PM_BIN="${BIN_DIR}/pPowerManger"
|
||||
HOST_BIN="${BIN_DIR}/pPowerMangerHost"
|
||||
|
||||
MOOSDB_PID=""
|
||||
PM_PID=""
|
||||
HOST_PID=""
|
||||
WORKDIR=""
|
||||
MISSION=""
|
||||
|
||||
info() { printf '\033[1;36m[host-sim]\033[0m %s\n' "$*"; }
|
||||
ok() { printf '\033[1;32m[host-sim]\033[0m %s\n' "$*"; }
|
||||
warn() { printf '\033[1;33m[host-sim]\033[0m %s\n' "$*"; }
|
||||
err() { printf '\033[1;31m[host-sim]\033[0m %s\n' "$*"; }
|
||||
|
||||
usage() {
|
||||
sed -n '2,23p' "${BASH_SOURCE[0]}" | sed 's/^# \{0,1\}//'
|
||||
exit 0
|
||||
}
|
||||
|
||||
# 生成临时 mission 文件(同时含 pPowerManger 与 pPowerMangerHost 两个配置块)
|
||||
make_mission() {
|
||||
WORKDIR="$(mktemp -d)"
|
||||
MISSION="${WORKDIR}/host_sim.moos"
|
||||
cat > "${MISSION}" <<EOF
|
||||
ServerHost = ${SERVER_HOST}
|
||||
ServerPort = ${SERVER_PORT}
|
||||
Community = h100hostsim
|
||||
|
||||
ProcessConfig = pPowerManger
|
||||
{
|
||||
AppTick = 4
|
||||
CommsTick = 4
|
||||
}
|
||||
|
||||
ProcessConfig = pPowerMangerHost
|
||||
{
|
||||
AppTick = 4
|
||||
CommsTick = 4
|
||||
WEB_PORT = ${WEB_PORT}
|
||||
}
|
||||
EOF
|
||||
}
|
||||
|
||||
kill_proc() {
|
||||
[ -n "$1" ] && kill "$1" 2>/dev/null && wait "$1" 2>/dev/null
|
||||
}
|
||||
|
||||
cleanup() {
|
||||
kill_proc "${HOST_PID}"
|
||||
kill_proc "${PM_PID}"
|
||||
kill_proc "${MOOSDB_PID}"
|
||||
[ -n "${WORKDIR}" ] && rm -rf "${WORKDIR}"
|
||||
}
|
||||
|
||||
build_targets() {
|
||||
info "编译 pPowerManger / pPowerMangerHost ..."
|
||||
mkdir -p "${ROOT}/build"
|
||||
cd "${ROOT}/build"
|
||||
cmake -DCMAKE_BUILD_TYPE=Release "${ROOT}" >/dev/null 2>&1 || { err "cmake 失败"; return 1; }
|
||||
make -j2 pPowerManger pPowerMangerHost >/dev/null 2>&1 || { err "make 失败"; return 1; }
|
||||
cd "${ROOT}"
|
||||
ok "编译完成"
|
||||
}
|
||||
|
||||
check_binaries() {
|
||||
local missing=0
|
||||
[ -n "${MOOSDB_BIN}" ] || { err "未找到 MOOSDB(请加入 PATH)"; missing=1; }
|
||||
[ -x "${HOST_BIN}" ] || { err "未找到 ${HOST_BIN}(请先运行: $0 build)"; missing=1; }
|
||||
if [ "${WITH_POWERMANGER}" = "1" ]; then
|
||||
[ -x "${PM_BIN}" ] || { err "未找到 ${PM_BIN}(请先运行: $0 build)"; missing=1; }
|
||||
fi
|
||||
return "${missing}"
|
||||
}
|
||||
|
||||
start_moosdb() {
|
||||
make_mission
|
||||
info "启动 MOOSDB (${SERVER_HOST}:${SERVER_PORT}) ..."
|
||||
"${MOOSDB_BIN}" --moos_no_colour "${MISSION}" > "${WORKDIR}/moosdb.log" 2>&1 &
|
||||
MOOSDB_PID=$!
|
||||
sleep 1
|
||||
kill -0 "${MOOSDB_PID}" 2>/dev/null || { err "MOOSDB 未存活"; return 1; }
|
||||
}
|
||||
|
||||
start_pm() {
|
||||
info "启动 pPowerManger ..."
|
||||
( cd "${WORKDIR}" && exec "${PM_BIN}" "${MISSION}" ) > "${WORKDIR}/pm.log" 2>&1 &
|
||||
PM_PID=$!
|
||||
sleep 1
|
||||
kill -0 "${PM_PID}" 2>/dev/null || warn "pPowerManger 未存活(无 CCU 硬件属正常)"
|
||||
}
|
||||
|
||||
start_host() {
|
||||
info "启动 pPowerMangerHost (网页端口 ${WEB_PORT}) ..."
|
||||
( cd "${WORKDIR}" && exec "${HOST_BIN}" "${MISSION}" ) > "${WORKDIR}/host.log" 2>&1 &
|
||||
HOST_PID=$!
|
||||
sleep 2
|
||||
kill -0 "${HOST_PID}" 2>/dev/null || { err "pPowerMangerHost 未存活"; return 1; }
|
||||
}
|
||||
|
||||
#-----------------------------------------------------------------------
|
||||
# 测试项
|
||||
#-----------------------------------------------------------------------
|
||||
test_http() {
|
||||
info "测试: 网页 HTTP (http://${SERVER_HOST}:${WEB_PORT}/) ..."
|
||||
local code
|
||||
code="$(curl -s -o /dev/null -w '%{http_code}' "http://${SERVER_HOST}:${WEB_PORT}/" 2>/dev/null || echo 000)"
|
||||
if [ "${code}" = "200" ]; then
|
||||
ok "网页 HTTP 200 通过"
|
||||
return 0
|
||||
else
|
||||
err "网页 HTTP 失败 (code=${code})"
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
# 反馈链路:向 MOOSDB 注入一条假的反馈变量 → 宿主订阅后应经 WS 推给浏览器
|
||||
test_monitor_loop() {
|
||||
info "测试: 反馈链路 (MOOSDB -> pPowerMangerHost -> WebSocket) ..."
|
||||
if [ -z "${POKE_BIN}" ]; then
|
||||
warn "未找到 uPokeDB,跳过反馈链路测试"
|
||||
return 0
|
||||
fi
|
||||
if ! python3 -c "import websockets" >/dev/null 2>&1; then
|
||||
warn "未安装 python3 websockets,跳过反馈链路测试"
|
||||
return 0
|
||||
fi
|
||||
|
||||
local fb_key="uPower_pmState_fb"
|
||||
local fb_val='{"workCondition_uint8":9,"currentMod_uint8":1,"powerState_uint8":1,"faultLevel_uint8":0,"soc_uint16":88,"sustainableTime_int64":3600,"leakage_uint8":0,"info_str":"host-sim-test"}'
|
||||
|
||||
# 先让 WS 客户端连接等待快照,再注入反馈
|
||||
FB_KEY="${fb_key}" python3 - "${WEB_PORT}" > "${WORKDIR}/ws_fb.log" 2>&1 <<'PY' &
|
||||
import asyncio, json, os, sys
|
||||
import websockets
|
||||
|
||||
PORT = int(sys.argv[1])
|
||||
KEY = os.environ["FB_KEY"]
|
||||
|
||||
async def main():
|
||||
uri = f"ws://localhost:{PORT}/ws"
|
||||
async with websockets.connect(uri) as ws:
|
||||
try:
|
||||
while True:
|
||||
msg = await asyncio.wait_for(ws.recv(), timeout=8)
|
||||
snap = json.loads(msg)
|
||||
if isinstance(snap, dict) and KEY in snap:
|
||||
print(f"FEEDBACK_OK {KEY}")
|
||||
return
|
||||
except asyncio.TimeoutError:
|
||||
pass
|
||||
print("FEEDBACK_TIMEOUT")
|
||||
|
||||
asyncio.run(main())
|
||||
PY
|
||||
WS_PID=$!
|
||||
sleep 1
|
||||
|
||||
"${POKE_BIN}" --host="${SERVER_HOST}" --port="${SERVER_PORT}" "${fb_key}=${fb_val}" >/dev/null 2>&1
|
||||
wait "${WS_PID}" 2>/dev/null
|
||||
|
||||
if grep -q "FEEDBACK_OK" "${WORKDIR}/ws_fb.log" 2>/dev/null; then
|
||||
ok "反馈链路通过(${fb_key} 已推送到浏览器)"
|
||||
return 0
|
||||
else
|
||||
err "反馈链路失败(WS 未收到 ${fb_key})"
|
||||
cat "${WORKDIR}/ws_fb.log" >&2
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
# 指令下发:网页 WS 下发 -> 宿主 Notify -> MOOSDB -> (宿主订阅回环) -> 推回浏览器
|
||||
# 利用宿主订阅了 uPower_pmState_fb,下发该变量后经 MOOSDB 回环,能收到即证明
|
||||
# 指令确实进入了 MOOSDB。
|
||||
test_command_notify() {
|
||||
info "测试: 指令下发 (WebSocket -> pPowerMangerHost -> MOOSDB) ..."
|
||||
if ! python3 -c "import websockets" >/dev/null 2>&1; then
|
||||
warn "未安装 python3 websockets,跳过指令下发校验"
|
||||
return 0
|
||||
fi
|
||||
|
||||
python3 - "${WEB_PORT}" > "${WORKDIR}/ws_cmd.log" 2>&1 <<'PY'
|
||||
import asyncio, json, sys
|
||||
import websockets
|
||||
|
||||
PORT = int(sys.argv[1])
|
||||
KEY = "uPower_pmState_fb"
|
||||
TAG = "cmd-loopback-test"
|
||||
|
||||
async def main():
|
||||
uri = f"ws://localhost:{PORT}/ws"
|
||||
async with websockets.connect(uri) as ws:
|
||||
await ws.send(json.dumps({"key": KEY, "value": {"info_str": TAG, "workCondition_uint8": 7}}))
|
||||
try:
|
||||
while True:
|
||||
msg = await asyncio.wait_for(ws.recv(), timeout=8)
|
||||
snap = json.loads(msg)
|
||||
if isinstance(snap, dict) and KEY in snap:
|
||||
obj = json.loads(snap[KEY])
|
||||
if obj.get("info_str") == TAG:
|
||||
print("CMD_OK")
|
||||
return
|
||||
except asyncio.TimeoutError:
|
||||
pass
|
||||
print("CMD_TIMEOUT")
|
||||
|
||||
asyncio.run(main())
|
||||
PY
|
||||
local r=$?
|
||||
|
||||
if [ ${r} -eq 0 ] && grep -q "CMD_OK" "${WORKDIR}/ws_cmd.log" 2>/dev/null; then
|
||||
ok "指令下发到 MOOSDB 通过(uPower_pmState_fb 已回环)"
|
||||
return 0
|
||||
else
|
||||
err "指令下发校验失败:未收到回环快照"
|
||||
cat "${WORKDIR}/ws_cmd.log" >&2
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
#-----------------------------------------------------------------------
|
||||
# 命令入口
|
||||
#-----------------------------------------------------------------------
|
||||
cmd_run() {
|
||||
check_binaries || return 1
|
||||
start_moosdb || return 1
|
||||
[ "${WITH_POWERMANGER}" = "1" ] && start_pm
|
||||
start_host || return 1
|
||||
|
||||
info "全部启动完成。"
|
||||
info "浏览器访问: http://${SERVER_HOST}:${WEB_PORT}/"
|
||||
info "按 Ctrl-C 退出并清理。"
|
||||
echo ""
|
||||
|
||||
trap 'info "退出清理..."; cleanup; exit 0' INT TERM
|
||||
while kill -0 "${HOST_PID}" 2>/dev/null; do sleep 1; done
|
||||
info "pPowerMangerHost 已退出。"
|
||||
cleanup
|
||||
}
|
||||
|
||||
cmd_test() {
|
||||
check_binaries || return 1
|
||||
start_moosdb || return 1
|
||||
start_host || return 1
|
||||
|
||||
local pass=0 fail=0 r
|
||||
|
||||
test_http; r=$?; [ $r -eq 0 ] && pass=$((pass+1)) || fail=$((fail+1))
|
||||
test_monitor_loop; r=$?; [ $r -eq 0 ] && pass=$((pass+1)) || fail=$((fail+1))
|
||||
test_command_notify;r=$?; [ $r -eq 0 ] && pass=$((pass+1)) || fail=$((fail+1))
|
||||
|
||||
echo ""
|
||||
info "==== 测试结果: 通过 ${pass} / 失败 ${fail} ===="
|
||||
cleanup
|
||||
[ "${fail}" -eq 0 ]
|
||||
}
|
||||
|
||||
cmd_stop() {
|
||||
pkill -f "${HOST_BIN}" 2>/dev/null
|
||||
pkill -f "${PM_BIN}" 2>/dev/null
|
||||
pkill -x MOOSDB 2>/dev/null
|
||||
ok "已清理残留进程"
|
||||
}
|
||||
|
||||
case "${1:-run}" in
|
||||
run) cmd_run ;;
|
||||
test) cmd_test ;;
|
||||
build) build_targets ;;
|
||||
stop) cmd_stop ;;
|
||||
help|-h|--help) usage ;;
|
||||
*) usage ;;
|
||||
esac
|
||||
Executable
+176
@@ -0,0 +1,176 @@
|
||||
#!/bin/bash
|
||||
#=======================================================================
|
||||
# FILE: scripts/sync-board-time.sh
|
||||
# DESC: 校正 223 板卡(RK3588,默认 192.168.0.223)的系统时间:以
|
||||
# 本机时间(或 --time 指定时间)为基准,经 SSH 设置板卡系统时
|
||||
# 钟,并尽力写入硬件时钟 (RTC)。板卡网络隔离无 NTP,用本脚本对时。
|
||||
#
|
||||
# 用法:
|
||||
# ./scripts/sync-board-time.sh # 用本机时间校正板卡
|
||||
# ./scripts/sync-board-time.sh status # 只查看时间与偏差
|
||||
# ./scripts/sync-board-time.sh --time "2026-09-01 12:00:00"
|
||||
# # 用指定时间校正(本地时区)
|
||||
#
|
||||
# 参数:
|
||||
# --host <ip> 目标主机(默认 192.168.0.223)
|
||||
# --user <user> 登录用户(默认 root)
|
||||
# --time <str> 手动指定基准时间(date 可解析的格式,按本地时区解释)
|
||||
# --keep-ntp 不执行 timedatectl set-ntp false
|
||||
# --no-rtc 不写硬件时钟(跳过 hwclock --systohc)
|
||||
# -h, --help 显示帮助
|
||||
#
|
||||
# 说明:
|
||||
# - 需要 root 登录与免密 SSH(ssh-copy-id root@<host>)。
|
||||
# - 对时经 SSH 往返时延 (RTT) 折半补偿,精度约 ±0.1s(受网络抖动影响)。
|
||||
# - 板卡若无可用 RTC,hwclock 失败仅告警;重启后时间可能回跳。
|
||||
# - 对时会调整系统时钟,运行中的服务日志时间戳会跳变,属正常现象。
|
||||
#=======================================================================
|
||||
|
||||
set -uo pipefail
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
|
||||
HOST="192.168.0.223"
|
||||
USER="root"
|
||||
SET_TIME=""
|
||||
KEEP_NTP=0
|
||||
NO_RTC=0
|
||||
|
||||
info() { printf '\033[1;36m[time]\033[0m %s\n' "$*"; }
|
||||
ok() { printf '\033[1;32m[time]\033[0m %s\n' "$*"; }
|
||||
warn() { printf '\033[1;33m[time]\033[0m %s\n' "$*"; }
|
||||
err() { printf '\033[1;31m[time]\033[0m %s\n' "$*"; }
|
||||
|
||||
usage() {
|
||||
sed -n '2,26p' "${BASH_SOURCE[0]}" | sed 's/^# \{0,1\}//'
|
||||
exit 0
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------
|
||||
# 参数解析
|
||||
#-------------------------------------------------------------------
|
||||
ACTION=""
|
||||
while [ $# -gt 0 ]; do
|
||||
case "$1" in
|
||||
--host) [ $# -ge 2 ] || { err "--host 需要参数"; exit 1; }; HOST="$2"; shift 2 ;;
|
||||
--user) [ $# -ge 2 ] || { err "--user 需要参数"; exit 1; }; USER="$2"; shift 2 ;;
|
||||
--time) [ $# -ge 2 ] || { err "--time 需要参数"; exit 1; }; SET_TIME="$2"; shift 2 ;;
|
||||
--keep-ntp) KEEP_NTP=1; shift ;;
|
||||
--no-rtc) NO_RTC=1; shift ;;
|
||||
status|help|-h|--help) ACTION="$1"; shift ;;
|
||||
"") shift ;;
|
||||
*) err "未知参数: $1(见 help)"; exit 1 ;;
|
||||
esac
|
||||
done
|
||||
[ -n "${ACTION}" ] || ACTION="sync"
|
||||
|
||||
SSH_TARGET="${USER}@${HOST}"
|
||||
SSH="ssh -o BatchMode=yes -o ConnectTimeout=5"
|
||||
|
||||
#-------------------------------------------------------------------
|
||||
# 读取板卡时间并测 RTT
|
||||
# 输出: "<epoch>|<板卡可读时间> <t0> <t1>"(t0/t1 为本机采样时刻)
|
||||
#-------------------------------------------------------------------
|
||||
read_board_time() {
|
||||
local t0 t1 out
|
||||
t0="$(date +%s.%N)"
|
||||
out="$(${SSH} "${SSH_TARGET}" 'date "+%s.%N|%F %T %Z"' 2>/dev/null)" || {
|
||||
err "无法免密 SSH 到 ${SSH_TARGET}(先配置免密: ssh-copy-id ${SSH_TARGET})" >&2
|
||||
return 1
|
||||
}
|
||||
t1="$(date +%s.%N)"
|
||||
printf '%s %.3f %.3f\n' "${out}" "${t0}" "${t1}"
|
||||
}
|
||||
|
||||
# 从 read_board_time 输出解析: set -- <out> 后取 $1/$2/$3
|
||||
parse_board_time() {
|
||||
B_EPOCH="${1%%|*}"
|
||||
B_DATE="${1#*|}"
|
||||
T0="$2"
|
||||
T1="$3"
|
||||
MID="$(awk -v t0="${T0}" -v t1="${T1}" 'BEGIN{printf "%.3f", t0 + (t1-t0)/2}')"
|
||||
DIFF="$(awk -v b="${B_EPOCH}" -v m="${MID}" 'BEGIN{printf "%+.3f", b - m}')"
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------
|
||||
# 命令: status
|
||||
#-------------------------------------------------------------------
|
||||
cmd_status() {
|
||||
local out
|
||||
out="$(read_board_time)" || return 1
|
||||
parse_board_time ${out}
|
||||
local rtt
|
||||
rtt="$(awk -v t0="${T0}" -v t1="${T1}" 'BEGIN{printf "%.3f", t1-t0}')"
|
||||
printf '本机时间: %s (RTT %.3fs)\n' "$(date -d "@${MID}" '+%F %T')" "${rtt}"
|
||||
printf '板卡时间: %s\n' "${B_DATE}"
|
||||
printf '偏差: 板卡比本机快 %s 秒\n' "${DIFF}"
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------
|
||||
# 命令: sync(默认)
|
||||
#-------------------------------------------------------------------
|
||||
cmd_sync() {
|
||||
local out target board_reply
|
||||
|
||||
# 前置检查:SSH 连通 + 板卡 root 权限
|
||||
out="$(read_board_time)" || return 1
|
||||
parse_board_time ${out}
|
||||
if ! ${SSH} "${SSH_TARGET}" '[ "$(id -u)" = 0 ]' 2>/dev/null; then
|
||||
err "板卡登录用户需要 root 权限(当前 --user ${USER})"
|
||||
return 1
|
||||
fi
|
||||
ok "SSH 连接正常: ${SSH_TARGET}"
|
||||
info "当前偏差: 板卡比本机快 ${DIFF} 秒"
|
||||
|
||||
# 关闭 NTP 自动同步(板卡网络隔离本就无 NTP 源,防止干扰手动对时)
|
||||
if [ "${KEEP_NTP}" = "0" ]; then
|
||||
info "关闭板卡 NTP 自动同步 (timedatectl set-ntp false) ..."
|
||||
${SSH} "${SSH_TARGET}" "command -v timedatectl >/dev/null 2>&1 && timedatectl set-ntp false || true"
|
||||
fi
|
||||
|
||||
# 计算目标时间:手动指定值直接用;否则取本机时间 + RTT/2 补偿
|
||||
if [ -n "${SET_TIME}" ]; then
|
||||
target="$(date -d "${SET_TIME}" '+%s.%N' 2>/dev/null)" || {
|
||||
err "无法解析时间: ${SET_TIME}"; return 1;
|
||||
}
|
||||
info "基准时间(手动): ${SET_TIME}"
|
||||
else
|
||||
local t2
|
||||
t2="$(date +%s.%N)"
|
||||
target="$(awk -v t2="${t2}" -v t0="${T0}" -v t1="${T1}" 'BEGIN{printf "%.3f", t2 + (t1-t0)/2}')"
|
||||
info "基准时间(本机 + RTT/2 补偿)"
|
||||
fi
|
||||
info "设置板卡系统时间 -> $(date -d "@${target}" '+%F %T') ..."
|
||||
|
||||
board_reply="$(${SSH} "${SSH_TARGET}" "date -s @${target} 2>&1")" || {
|
||||
err "date -s 失败: ${board_reply}"
|
||||
return 1
|
||||
}
|
||||
ok "板卡返回: ${board_reply}"
|
||||
|
||||
# 写硬件时钟(无 RTC 时仅告警)
|
||||
if [ "${NO_RTC}" = "0" ]; then
|
||||
info "同步硬件时钟 (hwclock --systohc) ..."
|
||||
if ${SSH} "${SSH_TARGET}" "hwclock --systohc" 2>/dev/null; then
|
||||
ok "RTC 已同步"
|
||||
else
|
||||
warn "hwclock 失败(板卡可能无 RTC 或驱动未加载),重启后时间可能回跳"
|
||||
fi
|
||||
fi
|
||||
|
||||
# 校验
|
||||
out="$(read_board_time)" || return 1
|
||||
parse_board_time ${out}
|
||||
info "校正后偏差: 板卡比本机快 ${DIFF} 秒"
|
||||
ok "板卡时间: ${B_DATE}"
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------
|
||||
# 命令入口
|
||||
#-------------------------------------------------------------------
|
||||
case "${ACTION}" in
|
||||
sync) cmd_sync ;;
|
||||
status) cmd_status ;;
|
||||
help|-h|--help) usage ;;
|
||||
*) usage ;;
|
||||
esac
|
||||
@@ -19,6 +19,11 @@ INCLUDE_DIRECTORIES(${LOCAL_LIBRARY_DIRS})
|
||||
ADD_SUBDIRECTORY(pPowerManger)
|
||||
# ADD_SUBDIRECTORY(appPowerMangerWebUI)
|
||||
add_subdirectory(pPMtest)
|
||||
add_subdirectory(pPowerMangerHost)
|
||||
add_subdirectory(pCCU)
|
||||
add_subdirectory(pCanBridge)
|
||||
add_subdirectory(pMotor)
|
||||
add_subdirectory(pELoad)
|
||||
##############################################################################
|
||||
# END of CMakeLists.txt
|
||||
##############################################################################
|
||||
|
||||
@@ -1,37 +0,0 @@
|
||||
#--------------------------------------------------------
|
||||
# The CMakeLists.txt for: appPowerMangerWebUI
|
||||
# Author(s):
|
||||
#--------------------------------------------------------
|
||||
set(CMAKE_CXX_STANDARD 17)
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||
|
||||
# 设置 vcpkg 工具链文件路径
|
||||
set(CMAKE_TOOLCHAIN_FILE "/home/zjk/project/lib/vcpkg/scripts/buildsystems/vcpkg.cmake" CACHE STRING "")
|
||||
|
||||
# 查找Boost库
|
||||
find_package(Boost REQUIRED COMPONENTS system thread)
|
||||
|
||||
#find crow库
|
||||
find_package(Crow CONFIG REQUIRED)
|
||||
# Find SQLite3 package
|
||||
find_package(SQLite3 REQUIRED)
|
||||
|
||||
SET(SRC
|
||||
main.cpp
|
||||
DBImage.cpp
|
||||
)
|
||||
|
||||
ADD_EXECUTABLE(appPowerMangerWebUI ${SRC})
|
||||
|
||||
TARGET_LINK_LIBRARIES(appPowerMangerWebUI
|
||||
${MOOS_LIBRARIES}
|
||||
mbutil
|
||||
m
|
||||
pthread
|
||||
Crow::Crow
|
||||
asio::asio
|
||||
jsoncpp
|
||||
SQLiteDB
|
||||
sqlite3
|
||||
Boost::system
|
||||
Boost::thread)
|
||||
@@ -1,230 +0,0 @@
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// MOOS - Mission Oriented Operating Suite
|
||||
//
|
||||
// A suit of Applications and Libraries for Mobile Robotics Research
|
||||
// Copyright (C) 2001-2005 Massachusetts Institute of Technology and
|
||||
// Oxford University.
|
||||
//
|
||||
// This software was written by Paul Newman at MIT 2001-2002 and Oxford
|
||||
// University 2003-2005. email: pnewman@robots.ox.ac.uk.
|
||||
//
|
||||
// This file is part of a MOOS Utility Component.
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License as
|
||||
// published by the Free Software Foundation; either version 2 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
|
||||
// 02111-1307, USA.
|
||||
//
|
||||
////////////////////////// END_GPL //////////////////////////////////
|
||||
// DBImage.cpp: implementation of the CDBImage class.
|
||||
|
||||
|
||||
|
||||
//
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "DBImage.h"
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// Construction/Destruction
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
bool CDBImage::Set(MOOSMSG_LIST & InMail)
|
||||
{
|
||||
MOOSMSG_LIST::iterator p;
|
||||
|
||||
|
||||
m_Lock.Lock();
|
||||
//MOOSTrace("Rx'd %d \n",InMail.size());
|
||||
|
||||
for(p = InMail.begin();p!=InMail.end();p++)
|
||||
{
|
||||
CMOOSMsg & rMsg= *p;
|
||||
//MOOSTrace("Rx'd %s \n",rMsg.m_sKey.c_str());
|
||||
|
||||
if(!m_Mask.empty() && m_Mask.find(rMsg.GetSource())!=m_Mask.end())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if(rMsg.IsDataType(MOOS_NOT_SET) && !m_bShowPending)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
int nNdx = GetIndex(rMsg.m_sKey);
|
||||
if(nNdx<0)
|
||||
{
|
||||
m_IndexMap[rMsg.m_sKey] = m_DBData.size();
|
||||
m_DBData.push_back(CVar(rMsg));
|
||||
}
|
||||
else
|
||||
{
|
||||
bool bChanging = !( rMsg.GetTime()==m_DBData[nNdx].GetTimeVal());
|
||||
m_DBData[nNdx]= CVar(rMsg);
|
||||
m_DBData[nNdx].Changed(bChanging);
|
||||
}
|
||||
}
|
||||
m_Lock.UnLock();
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
int CDBImage::GetIndex(const std::string & sName)
|
||||
{
|
||||
std::map<std::string,int>::iterator q = m_IndexMap.find(sName);
|
||||
|
||||
if(q!=m_IndexMap.end())
|
||||
{
|
||||
int n = q->second;
|
||||
return n;
|
||||
}
|
||||
else
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
bool CDBImage:: HasChanged(int n)
|
||||
{
|
||||
if(n >= static_cast<int> (m_DBData.size()) || n<0)
|
||||
return false;
|
||||
return m_DBData[n].IsChanged();
|
||||
}
|
||||
|
||||
|
||||
bool CDBImage::Get(CVar & rVar, int n)
|
||||
{
|
||||
m_Lock.Lock();
|
||||
|
||||
if(n>=static_cast<int> (m_DBData.size()) || n<0)
|
||||
{
|
||||
m_Lock.UnLock();
|
||||
return false;
|
||||
}
|
||||
|
||||
rVar = m_DBData[n];
|
||||
|
||||
m_Lock.UnLock();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool CDBImage::SetProcInfo(MOOSMSG_LIST & InMail)
|
||||
{
|
||||
m_Lock.Lock();
|
||||
// TODO: Add your control notification handler code here
|
||||
m_nClients = InMail.size();
|
||||
m_Processes.clear();
|
||||
MOOSMSG_LIST::iterator p;
|
||||
for(p=InMail.begin();p!=InMail.end();p++)
|
||||
{
|
||||
|
||||
CMOOSMsg & rMsg = *p;
|
||||
std::string sTmp = rMsg.m_sVal;
|
||||
std::string sWho = MOOSChomp(sTmp,":");
|
||||
|
||||
if(m_Processes.find(sWho)==m_Processes.end())
|
||||
{
|
||||
ProcInfo Info;
|
||||
m_Processes[sWho] = Info;
|
||||
}
|
||||
|
||||
std::string sSubscribed,sPublished;
|
||||
sSubscribed = MOOSChomp(sTmp,"PUBLISHED=");
|
||||
sPublished = sTmp;
|
||||
MOOSChomp(sSubscribed,"SUBSCRIBED=");
|
||||
|
||||
while(!sSubscribed.empty())
|
||||
{
|
||||
sTmp = MOOSChomp(sSubscribed,",");
|
||||
if(!sTmp.empty())
|
||||
{
|
||||
m_Processes[sWho].m_Subscribed.push_front(sTmp);
|
||||
}
|
||||
}
|
||||
|
||||
while(!sPublished.empty())
|
||||
{
|
||||
sTmp = MOOSChomp(sPublished,",");
|
||||
if(!sTmp.empty())
|
||||
{
|
||||
m_Processes[sWho].m_Published.push_front(sTmp);
|
||||
}
|
||||
}
|
||||
}
|
||||
m_Lock.UnLock();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CDBImage::GetProcInfo(const std::string & sWhat,STRING_LIST & sSubs,STRING_LIST & sPubs)
|
||||
{
|
||||
bool bRes = false;
|
||||
m_Lock.Lock();
|
||||
PROC_INFO_MAP::iterator q = m_Processes.find(sWhat);
|
||||
if(q!=m_Processes.end())
|
||||
{
|
||||
sSubs = q->second.m_Subscribed;
|
||||
sPubs = q->second.m_Published;
|
||||
bRes = true;
|
||||
}
|
||||
m_Lock.UnLock();
|
||||
return bRes;
|
||||
|
||||
}
|
||||
|
||||
bool CDBImage::GetProcesses(STRING_LIST & sProcs)
|
||||
{
|
||||
m_Lock.Lock();
|
||||
|
||||
sProcs.clear();
|
||||
|
||||
PROC_INFO_MAP::iterator q;
|
||||
for(q=m_Processes.begin();q!=m_Processes.end();q++)
|
||||
{
|
||||
sProcs.push_back(q->first.c_str());
|
||||
}
|
||||
m_Lock.UnLock();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool CDBImage::SetMask(std::set<std::string> Mask)
|
||||
{
|
||||
m_Mask = Mask;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CDBImage::Clear()
|
||||
{
|
||||
m_Lock.Lock();
|
||||
m_DBData.clear();
|
||||
m_IndexMap.clear();
|
||||
m_Lock.UnLock();
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -1,170 +0,0 @@
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// MOOS - Mission Oriented Operating Suite
|
||||
//
|
||||
// A suit of Applications and Libraries for Mobile Robotics Research
|
||||
// Copyright (C) 2001-2005 Massachusetts Institute of Technology and
|
||||
// Oxford University.
|
||||
//
|
||||
// This software was written by Paul Newman at MIT 2001-2002 and Oxford
|
||||
// University 2003-2005. email: pnewman@robots.ox.ac.uk.
|
||||
//
|
||||
// This file is part of a MOOS Utility Component.
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License as
|
||||
// published by the Free Software Foundation; either version 2 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
|
||||
// 02111-1307, USA.
|
||||
//
|
||||
////////////////////////// END_GPL //////////////////////////////////
|
||||
// DBImage.h: interface for the CDBImage class.
|
||||
|
||||
//
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifdef _WIN32
|
||||
#pragma warning(disable : 4786)
|
||||
#endif
|
||||
|
||||
|
||||
#if !defined(AFX_DBIMAGE_H__E4F9EC4D_7049_4EC8_86BA_0AF21BBCA23C__INCLUDED_)
|
||||
|
||||
#define AFX_DBIMAGE_H__E4F9EC4D_7049_4EC8_86BA_0AF21BBCA23C__INCLUDED_
|
||||
|
||||
#if _MSC_VER > 1000
|
||||
#pragma once
|
||||
#endif // _MSC_VER > 1000
|
||||
|
||||
#include "MOOS/libMOOS/MOOSLib.h"
|
||||
#include <string>
|
||||
#include <map>
|
||||
#include <vector>
|
||||
|
||||
|
||||
class CDBImage
|
||||
{
|
||||
public:
|
||||
bool Clear();
|
||||
|
||||
CDBImage()
|
||||
{
|
||||
m_bShowPending = false;
|
||||
}
|
||||
|
||||
struct ProcInfo
|
||||
{
|
||||
std::string m_sName;
|
||||
STRING_LIST m_Published;
|
||||
STRING_LIST m_Subscribed;
|
||||
};
|
||||
|
||||
typedef std::map<std::string,ProcInfo> PROC_INFO_MAP;
|
||||
|
||||
class CVar
|
||||
|
||||
{
|
||||
public:
|
||||
CVar()
|
||||
{
|
||||
m_dfTime = -1;
|
||||
}
|
||||
|
||||
CVar(CMOOSMsg & rMsg)
|
||||
{
|
||||
m_dfTime = rMsg.m_dfTime;
|
||||
switch(rMsg.m_cDataType)
|
||||
{
|
||||
case MOOS_STRING:
|
||||
m_eType = STR;
|
||||
break;
|
||||
case MOOS_DOUBLE:
|
||||
m_eType = DBL;
|
||||
break;
|
||||
case MOOS_BINARY_STRING:
|
||||
m_eType = BIN;
|
||||
break;
|
||||
default:
|
||||
m_eType = UNKNOWN;
|
||||
}
|
||||
m_sStr = rMsg.GetAsString();
|
||||
m_sCommunity = rMsg.m_sOriginatingCommunity;
|
||||
m_sName = rMsg.m_sKey;
|
||||
m_sFreq = MOOSFormat("%.1f",rMsg.m_dfVal2);
|
||||
m_sSource = rMsg.m_sSrc;
|
||||
m_bChanged = false;
|
||||
}
|
||||
|
||||
std::string GetTime(){return MOOSFormat("%.3f",m_dfTime);};
|
||||
double GetTimeVal(){return m_dfTime;};
|
||||
std::string GetValue(){return m_eType==UNKNOWN?"":m_sStr;};
|
||||
std::string GetCommunity(){return m_sCommunity;};
|
||||
std::string GetName(){return m_sName;};
|
||||
std::string GetFrequency(){return m_sFreq;};
|
||||
std::string GetSource(){return m_sSource;};
|
||||
bool IsChanged(){return m_bChanged;};
|
||||
void Changed(bool b){m_bChanged = b;};
|
||||
std::string GetType()
|
||||
{
|
||||
switch(m_eType)
|
||||
{
|
||||
case STR:
|
||||
return "$";
|
||||
case DBL:
|
||||
return "D";
|
||||
case BIN:
|
||||
return "B";
|
||||
default:
|
||||
return "?";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
protected:
|
||||
double m_dfTime;
|
||||
std::string m_sStr;
|
||||
enum Type{ STR,DBL,BIN,UNKNOWN};
|
||||
Type m_eType;
|
||||
std::string m_sCommunity;
|
||||
std::string m_sSrc;
|
||||
std::string m_sName;
|
||||
std::string m_sFreq;
|
||||
std::string m_sSource;
|
||||
bool m_bChanged;
|
||||
};
|
||||
|
||||
bool Set(MOOSMSG_LIST & InMail);
|
||||
bool Get(CVar & rVar, int n);
|
||||
bool HasChanged(int n);
|
||||
bool SetProcInfo(MOOSMSG_LIST & InMail) ;
|
||||
bool GetProcesses(STRING_LIST & sProcs);
|
||||
int GetNumVariables(){return m_DBData.size();}
|
||||
bool GetProcInfo(const std::string & sWhat,STRING_LIST & sSubs,STRING_LIST & sPubs);
|
||||
bool SetMask(std::set<std::string> Mask);
|
||||
bool ShowPending(bool b){m_bShowPending = b;return true;};
|
||||
protected:
|
||||
int GetIndex(const std::string & sName);
|
||||
std::vector<CVar> m_DBData;
|
||||
std::map<std::string,int> m_IndexMap;
|
||||
std::set<std::string> m_Mask;
|
||||
|
||||
bool m_bShowPending ;
|
||||
int m_nClients;
|
||||
int m_nVariables;
|
||||
PROC_INFO_MAP m_Processes;
|
||||
CMOOSLock m_Lock;
|
||||
};
|
||||
|
||||
|
||||
#endif // !defined(AFX_DBIMAGE_H__E4F9EC4D_7049_4EC8_86BA_0AF21BBCA23C__INCLUDED_)
|
||||
|
||||
@@ -1,305 +0,0 @@
|
||||
#include <string>
|
||||
#include "crow.h"
|
||||
#include <iostream>
|
||||
#include "json/json.h"
|
||||
#include <sys/inotify.h>
|
||||
#include <unistd.h>
|
||||
#include <dirent.h>
|
||||
#include <fstream>
|
||||
#include <vector>
|
||||
#include <thread>
|
||||
#include <mutex>
|
||||
#include <memory>
|
||||
#include "../pPowerManger/SQLiteDB.h"
|
||||
#include "../pPowerManger/pmSysvariable.h"
|
||||
#include <MOOS/libMOOS/Comms/MOOSAsyncCommClient.h>
|
||||
#include "DBImage.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
// 定义全局变量
|
||||
ccuState ccustate;
|
||||
StateData stateData;
|
||||
mutex wsMutex;
|
||||
vector<crow::websocket::connection*> wsConnections;
|
||||
shared_ptr<SQLiteDB> db;
|
||||
shared_ptr<MOOS::MOOSAsyncCommClient> moosClient;
|
||||
shared_ptr<CDBImage> dbImage;
|
||||
|
||||
bool bContinue = true;
|
||||
|
||||
// WebSocket消息处理
|
||||
void sendStateUpdate() {
|
||||
crow::json::wvalue msg;
|
||||
string time;
|
||||
{
|
||||
lock_guard<mutex> lock(wsMutex);
|
||||
db->getStateData(stateData, time);
|
||||
}
|
||||
|
||||
// 基本状态信息
|
||||
msg["state"] = {
|
||||
{"time", time},
|
||||
{"state_id", stateData.state_id},
|
||||
{"state_name", stateData.state_name},
|
||||
{"event", stateData.event},
|
||||
{"event_id", stateData.event_id},
|
||||
{"fault_code", stateData.fault_code},
|
||||
{"note", stateData.note}
|
||||
};
|
||||
|
||||
// 数据库状态信息
|
||||
msg["db_status"] = {
|
||||
{"connected", db->isDatabaseConnected("/home/zjk/project/H100/H100PowerManger/data", "power_data.db")},
|
||||
{"database", db->getDBPatch()},
|
||||
{"size", db->getDatabaseSize()}
|
||||
};
|
||||
|
||||
// MOOS数据库状态信息
|
||||
msg["moos_db_status"] = {
|
||||
{"connected", moosClient->IsConnected()},
|
||||
{"host", "localhost"},
|
||||
{"port", 9000}
|
||||
};
|
||||
|
||||
// 进程详细信息
|
||||
{
|
||||
lock_guard<mutex> lock(wsMutex);
|
||||
STRING_LIST processes;
|
||||
dbImage->GetProcesses(processes);
|
||||
|
||||
crow::json::wvalue::list processList;
|
||||
for(const auto& proc : processes) {
|
||||
STRING_LIST subs, pubs;
|
||||
if(dbImage->GetProcInfo(proc, subs, pubs)) {
|
||||
crow::json::wvalue processInfo;
|
||||
processInfo["name"] = proc;
|
||||
std::vector<std::string> subs_vec(subs.begin(), subs.end());
|
||||
std::vector<std::string> pubs_vec(pubs.begin(), pubs.end());
|
||||
processInfo["subscribed"] = subs_vec;
|
||||
processInfo["published"] = pubs_vec;
|
||||
processList.push_back(std::move(processInfo));
|
||||
}
|
||||
}
|
||||
|
||||
msg["processes"] = {
|
||||
{"count", processes.size()},
|
||||
{"list", std::move(processList)}
|
||||
};
|
||||
}
|
||||
|
||||
// 数据库变量信息
|
||||
{
|
||||
lock_guard<mutex> lock(wsMutex);
|
||||
int varCount = dbImage->GetNumVariables();
|
||||
crow::json::wvalue::list varList;
|
||||
|
||||
// 遍历所有变量
|
||||
for(int i = 0; i < varCount; i++) {
|
||||
CDBImage::CVar var;
|
||||
if(dbImage->Get(var, i)) {
|
||||
varList.push_back({
|
||||
{"name", var.GetName()},
|
||||
{"value", var.GetValue()},
|
||||
{"time", var.GetTime()},
|
||||
{"type", var.GetType()},
|
||||
{"source", var.GetSource()}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
msg["variables"] = {
|
||||
{"count", varCount},
|
||||
{"data", std::move(varList)} // 包含所有变量的数组
|
||||
};
|
||||
}
|
||||
|
||||
// 发送WebSocket消息
|
||||
{
|
||||
lock_guard<mutex> lock(wsMutex);
|
||||
for(auto conn : wsConnections) {
|
||||
conn->send_text(msg.dump());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 订阅MOOS变量
|
||||
bool FetchLoop(MOOS::MOOSAsyncCommClient* comms, CDBImage* m_DBImage)
|
||||
{
|
||||
int nCounts = 0;
|
||||
while(true) // 外部需要控制循环退出条件
|
||||
{
|
||||
if(comms->IsConnected())
|
||||
{
|
||||
// 每5次循环获取一次进程摘要
|
||||
if(nCounts++ % 5 == 0)
|
||||
{
|
||||
MOOSMSG_LIST procMail;
|
||||
if(comms->ServerRequest("PROC_SUMMARY", procMail))
|
||||
{
|
||||
m_DBImage->SetProcInfo(procMail);
|
||||
|
||||
// 打印进程信息
|
||||
// STRING_LIST processes;
|
||||
// m_DBImage->GetProcesses(processes);
|
||||
// std::cout << "Active processes: " << processes.size() << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
// 每次循环都获取数据库摘要
|
||||
MOOSMSG_LIST dbMail;
|
||||
if(comms->ServerRequest("ALL", dbMail))
|
||||
{
|
||||
m_DBImage->Set(dbMail);
|
||||
|
||||
// 打印数据库变量信息
|
||||
int varCount = m_DBImage->GetNumVariables();
|
||||
// std::cout << "Database variables: " << varCount << std::endl;
|
||||
|
||||
// 打印最近更新的变量
|
||||
if(varCount > 0) {
|
||||
CDBImage::CVar lastVar;
|
||||
if(m_DBImage->Get(lastVar, varCount-1)) {
|
||||
// std::cout << "Last updated variable: "
|
||||
// << lastVar.GetName() << " = "
|
||||
// << lastVar.GetValue() << std::endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 保持大约4Hz的频率
|
||||
MOOSPause(250);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
int main() {
|
||||
crow::SimpleApp app;
|
||||
db = make_shared<SQLiteDB>("/home/zjk/project/H100/H100PowerManger/data/power_data.db");
|
||||
moosClient = make_shared<MOOS::MOOSAsyncCommClient>();
|
||||
dbImage = make_shared<CDBImage>();
|
||||
moosClient->Run("localhost", 9000, "appPowerMangerWebUI");
|
||||
|
||||
// WebSocket路由
|
||||
CROW_WEBSOCKET_ROUTE(app, "/ws/state")
|
||||
.onopen([&](crow::websocket::connection& conn){
|
||||
lock_guard<mutex> lock(wsMutex);
|
||||
wsConnections.push_back(&conn);
|
||||
cout << "New WebSocket connection" << endl;
|
||||
})
|
||||
.onclose([&](crow::websocket::connection& conn, const string& /*reason*/, uint16_t /*code*/){
|
||||
lock_guard<mutex> lock(wsMutex);
|
||||
wsConnections.erase(
|
||||
remove(wsConnections.begin(), wsConnections.end(), &conn),
|
||||
wsConnections.end());
|
||||
cout << "WebSocket connection closed" << endl;
|
||||
})
|
||||
.onmessage([&](crow::websocket::connection& conn, const string& data, bool is_binary){
|
||||
cout << "Received WebSocket message: " << data << endl;
|
||||
});
|
||||
|
||||
// 状态更新定时器
|
||||
thread([](){
|
||||
while(true) {
|
||||
sendStateUpdate();
|
||||
this_thread::sleep_for(chrono::seconds(1));
|
||||
}
|
||||
}).detach();
|
||||
|
||||
//MOOS数据库更新定时器
|
||||
std::thread fetchThread([&](){
|
||||
while(bContinue) {
|
||||
FetchLoop(moosClient.get(), dbImage.get());
|
||||
}
|
||||
});
|
||||
|
||||
// 绑定主页路由
|
||||
CROW_ROUTE(app, "/")([]() {
|
||||
auto page = crow::mustache::load_text("index.html");
|
||||
return page;
|
||||
});
|
||||
|
||||
// MOOS通知API
|
||||
CROW_ROUTE(app, "/api/moos-notify")
|
||||
.methods("POST"_method)
|
||||
([](const crow::request& req) {
|
||||
auto json = crow::json::load(req.body);
|
||||
if (!json) {
|
||||
return crow::response(400, "Invalid JSON");
|
||||
}
|
||||
|
||||
string var = json["var"].s();
|
||||
string key = json["key"].s();
|
||||
|
||||
if (var.empty() || key.empty()) {
|
||||
return crow::response(400, "Var and Key are required");
|
||||
}
|
||||
|
||||
try {
|
||||
moosClient->Notify(var, key);
|
||||
return crow::response(200, "{\"success\":true}");
|
||||
} catch (const exception& e) {
|
||||
return crow::response(500,
|
||||
crow::json::wvalue{{"success", false}, {"message", e.what()}}.dump());
|
||||
}
|
||||
});
|
||||
|
||||
// 下载数据库API
|
||||
CROW_ROUTE(app, "/api/download-db")
|
||||
([]() {
|
||||
const std::string dbPath = "/home/zjk/project/H100/H100PowerManger/data/power_data.db";
|
||||
const size_t chunkSize = 4096; // 4KB chunks
|
||||
|
||||
std::ifstream file(dbPath, std::ios::binary | std::ios::ate);
|
||||
if (!file) {
|
||||
return crow::response(404, "Database file not found");
|
||||
}
|
||||
|
||||
// 获取文件大小
|
||||
std::streamsize fileSize = file.tellg();
|
||||
file.seekg(0, std::ios::beg);
|
||||
|
||||
if (fileSize == 0) {
|
||||
return crow::response(500, "Database file is empty");
|
||||
}
|
||||
|
||||
// 创建响应
|
||||
crow::response res;
|
||||
res.code = 200;
|
||||
res.set_header("Content-Type", "application/octet-stream");
|
||||
res.set_header("Content-Disposition", "attachment; filename=power_data.db");
|
||||
res.set_header("Content-Length", std::to_string(fileSize));
|
||||
|
||||
try {
|
||||
// 分块读取和写入文件
|
||||
auto buffer = std::make_unique<char[]>(chunkSize);
|
||||
size_t totalSent = 0;
|
||||
|
||||
while (totalSent < fileSize) {
|
||||
size_t remaining = fileSize - totalSent;
|
||||
size_t readSize = std::min(remaining, chunkSize);
|
||||
|
||||
file.read(buffer.get(), readSize);
|
||||
if (file.gcount() <= 0) break;
|
||||
|
||||
res.write(std::string(buffer.get(), file.gcount()));
|
||||
totalSent += file.gcount();
|
||||
}
|
||||
|
||||
file.close();
|
||||
return res;
|
||||
} catch (const std::exception& e) {
|
||||
file.close();
|
||||
return crow::response(500, std::string("Download failed: ") + e.what());
|
||||
}
|
||||
});
|
||||
|
||||
// 启动服务器
|
||||
app.port(18080)
|
||||
.multithreaded()
|
||||
.concurrency(16)
|
||||
.run();
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1,108 +0,0 @@
|
||||
#--------------------------------------------------------
|
||||
# The CMakeLists.txt for: pPowerManger
|
||||
# Author(s):
|
||||
#--------------------------------------------------------
|
||||
|
||||
# Set System Specific Libraries
|
||||
if (${WIN32})
|
||||
# Windows Libraries
|
||||
SET(SYSTEM_LIBS
|
||||
wsock32 )
|
||||
else (${WIN32})
|
||||
# Linux and Apple Libraries
|
||||
SET(SYSTEM_LIBS
|
||||
m
|
||||
pthread )
|
||||
endif (${WIN32})
|
||||
|
||||
# Use local SQLite3 source
|
||||
SET(SQLITE_SRC
|
||||
sqlit3/SQLite.cpp
|
||||
sqlit3/sqlite3.c
|
||||
)
|
||||
|
||||
SET(HTTP_SRC
|
||||
httpserver/mongoose.c
|
||||
httpserver/httpserver.cpp)
|
||||
|
||||
SET(LOG_SRC
|
||||
logc/loguru.cpp)
|
||||
|
||||
SET(UDP_COMM_SRC
|
||||
udpcomm/udpComm.cpp)
|
||||
|
||||
SET(FSMLIB_SRC
|
||||
fsm/PowerManagerFsm.cpp
|
||||
fsm/CruiseMode.cpp
|
||||
fsm/DJMode.cpp
|
||||
fsm/FaultState.cpp
|
||||
fsm/FloatAdjust.cpp
|
||||
fsm/FloatDown.cpp
|
||||
fsm/HighSpeedMode.cpp
|
||||
fsm/InitState.cpp
|
||||
fsm/RemoteControl.cpp
|
||||
fsm/ShoreBasedReady.cpp
|
||||
fsm/StandbyState.cpp
|
||||
fsm/SurfaceSurvey.cpp
|
||||
fsm/UnderwaterSurvey.cpp
|
||||
fsm/WaterBasedReady.cpp
|
||||
)
|
||||
|
||||
SET(SRC
|
||||
${FSMLIB_SRC}
|
||||
${SQLITE_SRC}
|
||||
${HTTP_SRC}
|
||||
${UDP_COMM_SRC}
|
||||
${LOG_SRC}
|
||||
PowerManger.cpp
|
||||
PowerManger_Info.cpp
|
||||
# udpComm.cpp
|
||||
main.cpp
|
||||
# SQLiteDB.cpp
|
||||
driver.cpp
|
||||
LowerCommManager.cpp
|
||||
UpperCommManager.cpp
|
||||
# loguru.cpp
|
||||
upmsg/upmsg_definitions.cpp
|
||||
)
|
||||
|
||||
ADD_EXECUTABLE(pPowerManger ${SRC})
|
||||
|
||||
TARGET_INCLUDE_DIRECTORIES(pPowerManger PRIVATE sqlit3)
|
||||
|
||||
TARGET_LINK_LIBRARIES(pPowerManger
|
||||
${MOOS_LIBRARIES}
|
||||
apputil
|
||||
mbutil
|
||||
m
|
||||
pthread
|
||||
jsoncpp
|
||||
${SYSTEM_LIBS}
|
||||
dl
|
||||
)
|
||||
|
||||
# Add SQLiteDB static library
|
||||
SET(UDPCOMM_SRC
|
||||
udpComm.cpp
|
||||
)
|
||||
|
||||
# SET(SQLITEDB_SRC
|
||||
# SQLiteDB.cpp
|
||||
# )
|
||||
|
||||
SET(DRIVER_SRC
|
||||
driver.cpp)
|
||||
|
||||
# SET(POWERMANGE_SRC
|
||||
# PowerManger.cpp
|
||||
# PowerManger_Info.cpp
|
||||
# udpComm.cpp
|
||||
# SQLiteDB.cpp
|
||||
# driver.cpp
|
||||
# PowerManagerFsm.cpp)
|
||||
|
||||
# ADD_LIBRARY(SQLiteDB STATIC ${SQLITEDB_SRC})
|
||||
# ADD_LIBRARY(UDPComm STATIC ${UDPCOMM_SRC})
|
||||
# # ADD_LIBRARY(FSMLib STATIC ${FSMLIB_SRC})
|
||||
# ADD_LIBRARY(Driver STATIC ${DRIVER_SRC})
|
||||
# ADD_LIBRARY(PowerMange STATIC ${POWERMANGE_SRC})
|
||||
@@ -1,929 +0,0 @@
|
||||
#include "LowerCommManager.h"
|
||||
#include "PowerManger.h"
|
||||
#include "driver.h"
|
||||
#include "udpcomm/udpComm.h"
|
||||
|
||||
bool _ListenCB(void * pParam)
|
||||
{
|
||||
LowerCommManager* pMe = (LowerCommManager* )pParam;
|
||||
return pMe->listenThreadFunc();
|
||||
}
|
||||
|
||||
LowerCommManager::LowerCommManager(PowerManger* pm, long myPort, long ccuPort, const std::string& cccHost){
|
||||
m_pm = pm;
|
||||
m_udpComm = new udpComm();
|
||||
m_port = myPort;
|
||||
m_udpComm->ccuHost = cccHost;
|
||||
m_udpComm->ccuPort = ccuPort;
|
||||
m_udpComm->udpScoket = new XPCUdpSocket(m_port);
|
||||
|
||||
std::cout << MOOS::ConsoleColours::yellow() << "╔════════════════════════╗" << MOOS::ConsoleColours::reset() << std::endl;
|
||||
std::cout << MOOS::ConsoleColours::yellow() << "║ [LOCAL PORT] "
|
||||
<< MOOS::ConsoleColours::cyan() << m_port
|
||||
<< MOOS::ConsoleColours::yellow() << std::setw(15) << " ║" << MOOS::ConsoleColours::reset() << std::endl;
|
||||
|
||||
std::cout << MOOS::ConsoleColours::yellow() << "║ [CCU HOST ] "
|
||||
<< MOOS::ConsoleColours::cyan() << m_udpComm->ccuHost
|
||||
<< MOOS::ConsoleColours::yellow() << std::setw(8) << " ║" << MOOS::ConsoleColours::reset() << std::endl;
|
||||
|
||||
std::cout << MOOS::ConsoleColours::yellow() << "║ [CCU PORT ] "
|
||||
<< MOOS::ConsoleColours::cyan() << m_udpComm->ccuPort
|
||||
<< MOOS::ConsoleColours::yellow() << std::setw(15) << " ║" << MOOS::ConsoleColours::reset() << std::endl;
|
||||
std::cout << MOOS::ConsoleColours::yellow() << "╚════════════════════════╝" << MOOS::ConsoleColours::reset() << std::endl;
|
||||
}
|
||||
|
||||
LowerCommManager::~LowerCommManager(){
|
||||
try {
|
||||
stopListenThread();
|
||||
if (m_udpComm) {
|
||||
delete m_udpComm;
|
||||
m_udpComm = nullptr;
|
||||
}
|
||||
} catch (...) {
|
||||
cerr << "Error during cleanup" << endl;
|
||||
}
|
||||
}
|
||||
bool LowerCommManager::initUdpComm(){
|
||||
if (m_udpComm->udpScoket) {
|
||||
try {
|
||||
std::cout << MOOS::ConsoleColours::yellow() << "Attempting to bind UDP socket..." << MOOS::ConsoleColours::reset() << std::endl;
|
||||
m_udpComm->udpScoket->vBindSocket(); // 可能会抛出 XPCException 或其他 std::exception
|
||||
std::cout << MOOS::ConsoleColours::green() << "UDP bind succeeded!" << MOOS::ConsoleColours::reset() << std::endl;
|
||||
LOG_F(INFO, "UDP bind succeeded!");
|
||||
}
|
||||
catch (const std::exception& e) {
|
||||
std::cerr << MOOS::ConsoleColours::red()
|
||||
<< "[UDP Bind Failed] Exception: " << e.what()
|
||||
<< MOOS::ConsoleColours::reset() << std::endl;
|
||||
LOG_F(ERROR, "UDP bind failed: %s", e.what());
|
||||
return false;
|
||||
}
|
||||
catch (...) {
|
||||
std::cerr << MOOS::ConsoleColours::red()
|
||||
<< "[UDP Bind Failed] Unknown exception occurred!"
|
||||
<< MOOS::ConsoleColours::reset() << std::endl;
|
||||
LOG_F(ERROR, "Unknown exception occurred during UDP bind");
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
std::cerr << MOOS::ConsoleColours::red()
|
||||
<< "[UDP Init Failed] udpSocket is null!"
|
||||
<< MOOS::ConsoleColours::reset() << std::endl;
|
||||
LOG_F(ERROR, "udpSocket is null!");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
void LowerCommManager::processPeriodicTasks() {
|
||||
sendCcuCommand(m_pm->m_CcuColCmd);
|
||||
m_pm->m_db->insertData(m_pm->m_CcuColCmd);
|
||||
//延时5ms
|
||||
usleep(5000);
|
||||
if(m_pm->m_systemData->device_common_status.dis_hv_c1.isTimeout )
|
||||
{
|
||||
disHighVolBusCmd clr1{};
|
||||
m_udpComm->sendDisSysCmd(clr1);
|
||||
MOOSPause(200);
|
||||
}
|
||||
if(m_pm->m_systemData->device_common_status.dis_lv_c1.isTimeout )
|
||||
{
|
||||
disHighBVolBusCmd clr3{};
|
||||
m_udpComm->sendDisSysCmd(clr3);
|
||||
MOOSPause(200);
|
||||
}
|
||||
m_udpComm->clearMsgQueue();
|
||||
}
|
||||
void LowerCommManager::operate_hold()
|
||||
{
|
||||
disHighVolBusCmd clr1{};
|
||||
disHighAVolBusCmd clr2{};
|
||||
disHighBVolBusCmd clr3{};
|
||||
disLowBusCmd clr4{};
|
||||
m_udpComm->sendDisSysCmd(clr1);
|
||||
MOOSPause(200);
|
||||
m_udpComm->sendDisSysCmd(clr2);
|
||||
MOOSPause(200);
|
||||
m_udpComm->sendDisSysCmd(clr3);
|
||||
MOOSPause(200);
|
||||
m_udpComm->sendDisSysCmd(clr4);
|
||||
}
|
||||
bool LowerCommManager::sendCcuCommand(const ccuColCmd cmd){
|
||||
// m_pm->m_db->insertCcuSysCmd(cmd);
|
||||
if(!m_udpComm->sendCcuColCmd(cmd))
|
||||
cout << "send ccu command failed!" << endl;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool LowerCommManager::sendDisSysCommand(const disSysBreakerList& cmd){
|
||||
//根据目标状态进行断路器操作
|
||||
//a. 高压母线的断路器
|
||||
disHighVolBusCmd a;
|
||||
a.fuelCellCircuitBreaker = getBreakerOption(cmd.bus1Breaker.fuelCellCircuitBreaker);
|
||||
a.lithiumBatteryGroupInstrumentCircuitBreaker = getBreakerOption(cmd.bus1Breaker.lithiumBatteryGroupInstrumentCircuitBreaker);
|
||||
a.dcDc5ModuleCircuitBreaker = getBreakerOption(cmd.bus1Breaker.dcDc5ModuleCircuitBreaker);
|
||||
a.powerLithiumBatteryCircuitBreaker = getBreakerOption(cmd.bus1Breaker.powerLithiumBatteryCircuitBreaker);
|
||||
a.propulsionMotorCircuitBreaker = getBreakerOption(cmd.bus1Breaker.propulsionMotorCircuitBreaker);
|
||||
a.bowHighVoltageDistributionBoxCircuitBreaker = getBreakerOption(cmd.bus1Breaker.bowHighVoltageDistributionBoxCircuitBreaker);
|
||||
a.tyzReservedCircuitBreaker = getBreakerOption(cmd.bus1Breaker.tyzReservedCircuitBreaker);
|
||||
a.sternFTDevice45CircuitBreaker = getBreakerOption(cmd.bus1Breaker.sternFTDevice45CircuitBreaker);
|
||||
a.sternRudderSwitch1CircuitBreaker = getBreakerOption(cmd.bus1Breaker.sternRudderSwitch1CircuitBreaker);
|
||||
a.sternRudderSwitch2CircuitBreaker = getBreakerOption(cmd.bus1Breaker.sternRudderSwitch2CircuitBreaker);
|
||||
a.reservedCircuitBreaker = getBreakerOption(cmd.bus1Breaker.reservedCircuitBreaker);
|
||||
a.fbReservedCircuitBreaker = getBreakerOption(cmd.bus1Breaker.fbReservedCircuitBreaker);
|
||||
a.dcdc5Module = getBreakerOption(cmd.bus1Breaker.dcdcmodel);
|
||||
a.coolingSystem = getBreakerOption(cmd.bus1Breaker.coolingSystem);
|
||||
|
||||
m_udpComm->sendDisSysCmd(a);
|
||||
m_pm->m_db->insertData(a);
|
||||
usleep(5000);
|
||||
//b. 高压汇流排A断路器
|
||||
disHighAVolBusCmd b;
|
||||
b.bowFTDevice123CircuitBreaker = getBreakerOption(cmd.bus2Breaker.bowFTDevice123CircuitBreaker);
|
||||
b.actuatorCircuitBreaker = getBreakerOption(cmd.bus2Breaker.actuatorCircuitBreaker);
|
||||
b.mastSteeringGearControlBoxCircuitBreaker = getBreakerOption(cmd.bus2Breaker.mastSteeringGearControlBoxCircuitBreaker);
|
||||
b.xczCircuitBreaker = getBreakerOption(cmd.bus2Breaker.xczCircuitBreaker);
|
||||
b.bowRudderControlBoxCircuitBreaker = getBreakerOption(cmd.bus2Breaker.bowRudderControlBoxCircuitBreaker);
|
||||
b.openWaterCoverStartCylinderCircuitBreaker = getBreakerOption(cmd.bus2Breaker.openWaterCoverStartCylinderCircuitBreaker);
|
||||
m_udpComm->sendDisSysCmd(b);
|
||||
m_pm->m_db->insertData(b);
|
||||
usleep(5000);
|
||||
//c. 低压主母线断路器
|
||||
disHighBVolBusCmd c;
|
||||
|
||||
c.lithiumBatteryGroupInstrumentCircuitBreaker = 0x55;
|
||||
c.bowLowVoltageDistributionBoxCircuitBreaker = 0xAA;
|
||||
c.unit4InstrumentDC48VCircuitBreaker = 0xAA;
|
||||
c.dcC1DCDistributionPanelCircuitBreaker = 0xAA;
|
||||
c.reservedCircuitBreaker1 = 0xAA;
|
||||
c.reservedCircuitBreaker2 = 0xAA;
|
||||
c.emergencyLithiumBatteryGroup2CircuitBreaker = 0xAA;
|
||||
|
||||
m_udpComm->sendDisSysCmd(c);
|
||||
m_pm->m_db->insertData(c);
|
||||
usleep(5000);
|
||||
//d. 闭合低压汇流排断路器
|
||||
disLowBusCmd d;
|
||||
d.unit1CircuitBreaker = getBreakerOption(cmd.bus4Breaker.unit1CircuitBreaker);
|
||||
d.unit2CircuitBreaker = getBreakerOption(cmd.bus4Breaker.unit2CircuitBreaker);
|
||||
d.unit3CircuitBreaker = getBreakerOption(cmd.bus4Breaker.unit3CircuitBreaker);
|
||||
d.unit5CircuitBreaker = getBreakerOption(cmd.bus4Breaker.unit5CircuitBreaker);
|
||||
d.bowPZDeviceCircuitBreaker = getBreakerOption(cmd.bus4Breaker.bowPZDeviceCircuitBreaker);
|
||||
d.reservedCircuitBreaker1 = getBreakerOption(cmd.bus4Breaker.reservedCircuitBreaker1);
|
||||
d.reservedCircuitBreaker2 = getBreakerOption(cmd.bus4Breaker.reservedCircuitBreaker2);
|
||||
d.emergencyLithiumBatteryGroup1CircuitBreaker = getBreakerOption(cmd.bus4Breaker.emergencyLithiumBatteryGroup1CircuitBreaker);
|
||||
m_udpComm->sendDisSysCmd(d);
|
||||
m_pm->m_db->insertData(d);
|
||||
usleep(5000);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void LowerCommManager::clearMsgQueue(){
|
||||
m_udpComm->clearMsgQueue();
|
||||
}
|
||||
|
||||
|
||||
bool LowerCommManager::updatePoweSystemStates(){
|
||||
// std::cout << "updatePoweSystemStates" << std::endl;
|
||||
if(!m_udpComm->m_qReceiveCcuStateBuffer.empty())
|
||||
{
|
||||
double time;
|
||||
m_udpComm->popMsgFormQueue(time,m_CcuCurrentState);
|
||||
m_pm->m_pmCurrentState.ccustate = m_CcuCurrentState.data;
|
||||
m_pm->m_db->insertData(m_pm->m_pmCurrentState.ccustate); //写入数据库
|
||||
//DEBUG
|
||||
//写入文件
|
||||
// std::ofstream outFile("ccuState.txt", std::ios::app);
|
||||
// coutMsg(m_CcuCurrentState, outFile);
|
||||
// coutMsg(m_CcuCurrentState,std::cout);
|
||||
msg_CcuStateFbMsg_Update_time = time;
|
||||
}
|
||||
if(!m_udpComm->m_qReceiveDisHighVolBusBuffer.empty())
|
||||
{
|
||||
double time;
|
||||
m_udpComm->popMsgFormQueue(time,m_disHighVolBusCurrentState);
|
||||
m_pm->m_pmCurrentState.bus1State = m_disHighVolBusCurrentState.data;
|
||||
m_pm->m_db->insertData(m_pm->m_pmCurrentState.bus1State); //写入数据库
|
||||
msg_disHighVolBusFbMsg_Update_time = time;
|
||||
|
||||
disBus1Breaker* pdis1=new disBus1Breaker;
|
||||
(m_pm->m_pmCurrentState.bus1State.fuelCellCircuitBreaker == BREAK_ON) ? pdis1 -> fuelCellCircuitBreaker = 1 : pdis1 -> fuelCellCircuitBreaker = 0;
|
||||
(m_pm->m_pmCurrentState.bus1State.powerLithiumBatteryCircuitBreaker == BREAK_ON) ? pdis1 -> powerLithiumBatteryCircuitBreaker = 1 : pdis1 -> powerLithiumBatteryCircuitBreaker = 0;
|
||||
(m_pm->m_pmCurrentState.bus1State.propulsionMotorCircuitBreaker == BREAK_ON) ? pdis1 -> propulsionMotorCircuitBreaker = 1 : pdis1 -> propulsionMotorCircuitBreaker = 0;
|
||||
(m_pm->m_pmCurrentState.bus1State.lithiumBatteryGroupInstrumentCircuitBreaker == BREAK_ON) ? pdis1 -> lithiumBatteryGroupInstrumentCircuitBreaker = 1 : pdis1 -> lithiumBatteryGroupInstrumentCircuitBreaker = 0;
|
||||
(m_pm->m_pmCurrentState.bus1State.dcDc5ModuleCircuitBreaker == BREAK_ON) ? pdis1 -> dcDc5ModuleCircuitBreaker = 1 : pdis1 -> dcDc5ModuleCircuitBreaker = 0;
|
||||
(m_pm->m_pmCurrentState.bus1State.bowHighVoltageDistributionBoxCircuitBreaker == BREAK_ON) ? pdis1 -> bowHighVoltageDistributionBoxCircuitBreaker = 1 : pdis1 -> bowHighVoltageDistributionBoxCircuitBreaker = 0;
|
||||
(m_pm->m_pmCurrentState.bus1State.sternFTDevice45CircuitBreaker == BREAK_ON) ? pdis1 -> sternFTDevice45CircuitBreaker = 1 : pdis1 -> sternFTDevice45CircuitBreaker = 0;
|
||||
(m_pm->m_pmCurrentState.bus1State.sternRudderSwitch1CircuitBreaker == BREAK_ON) ? pdis1 -> sternRudderSwitch1CircuitBreaker = 1 : pdis1 -> sternRudderSwitch1CircuitBreaker = 0;
|
||||
(m_pm->m_pmCurrentState.bus1State.sternRudderSwitch2CircuitBreaker == BREAK_ON) ? pdis1 -> sternRudderSwitch2CircuitBreaker = 1 : pdis1 -> sternRudderSwitch2CircuitBreaker = 0;
|
||||
(m_pm->m_pmCurrentState.bus1State.fbReservedCircuitBreaker == BREAK_ON) ? pdis1 -> fbReservedCircuitBreaker = 1 : pdis1 -> fbReservedCircuitBreaker = 0;
|
||||
(m_pm->m_pmCurrentState.bus1State.tyzReservedCircuitBreaker == BREAK_ON) ? pdis1 -> tyzReservedCircuitBreaker = 1 : pdis1 -> tyzReservedCircuitBreaker = 0;
|
||||
(m_pm->m_pmCurrentState.bus1State.reservedCircuitBreaker == BREAK_ON) ? pdis1 -> reservedCircuitBreaker = 1 : pdis1 -> reservedCircuitBreaker = 0;
|
||||
pdis1 -> paceholder = 0;
|
||||
m_pm->m_currentDisBreakerState.bus1Breaker = *pdis1;
|
||||
delete pdis1;
|
||||
}
|
||||
if(!m_udpComm->m_qReceiveDisHighAVolBusBuffer.empty())
|
||||
{
|
||||
double time;
|
||||
m_udpComm->popMsgFormQueue(time,m_disHighAVolBusCurrentState);
|
||||
m_pm->m_pmCurrentState.bus2State = m_disHighAVolBusCurrentState.data;
|
||||
m_pm->m_db->insertData(m_pm->m_pmCurrentState.bus2State); //写入数据库
|
||||
msg_disHighAVolBusFbMsg_Update_time = time;
|
||||
|
||||
disBus2Breaker* pdis2=new disBus2Breaker;
|
||||
(m_pm->m_pmCurrentState.bus2State.bowFTDevice123CircuitBreaker == BREAK_ON)? pdis2 -> bowFTDevice123CircuitBreaker = 1 : pdis2 -> bowFTDevice123CircuitBreaker = 0;
|
||||
(m_pm->m_pmCurrentState.bus2State.actuatorCircuitBreaker == BREAK_ON)? pdis2 -> actuatorCircuitBreaker = 1 : pdis2 -> actuatorCircuitBreaker = 0;
|
||||
(m_pm->m_pmCurrentState.bus2State.mastSteeringGearControlBoxCircuitBreaker == BREAK_ON)? pdis2 -> mastSteeringGearControlBoxCircuitBreaker = 1 : pdis2 -> mastSteeringGearControlBoxCircuitBreaker = 0;
|
||||
(m_pm->m_pmCurrentState.bus2State.xczCircuitBreaker == BREAK_ON)? pdis2 -> xczCircuitBreaker = 1 : pdis2 -> xczCircuitBreaker = 0;
|
||||
(m_pm->m_pmCurrentState.bus2State.bowRudderControlBoxCircuitBreaker == BREAK_ON)? pdis2 -> bowRudderControlBoxCircuitBreaker = 1 : pdis2 -> bowRudderControlBoxCircuitBreaker = 0;
|
||||
(m_pm->m_pmCurrentState.bus2State.openWaterCoverStartCylinderCircuitBreaker == BREAK_ON)? pdis2 -> openWaterCoverStartCylinderCircuitBreaker = 1 : pdis2 -> openWaterCoverStartCylinderCircuitBreaker = 0;
|
||||
pdis2 -> paceholder = 0;
|
||||
m_pm->m_currentDisBreakerState.bus2Breaker = *pdis2;
|
||||
delete pdis2;
|
||||
}
|
||||
if(!m_udpComm->m_qReceiveDisHighBVolBusBuffer.empty())
|
||||
{
|
||||
double time;
|
||||
m_udpComm->popMsgFormQueue(time,m_disHighBVolBusCurrentState);
|
||||
m_pm->m_pmCurrentState.bus3State = m_disHighBVolBusCurrentState.data;
|
||||
m_pm->m_db->insertData(m_pm->m_pmCurrentState.bus3State); //写入数据库
|
||||
msg_disHighBVolBusFbMsg_Update_time = time;
|
||||
|
||||
disBus3Breaker* pdis3=new disBus3Breaker;
|
||||
(m_pm->m_pmCurrentState.bus3State.lithiumBatteryGroupInstrumentCircuitBreaker == BREAK_ON)? pdis3 -> lithiumBatteryGroupInstrumentCircuitBreaker = 1 : pdis3 -> lithiumBatteryGroupInstrumentCircuitBreaker = 0;
|
||||
(m_pm->m_pmCurrentState.bus3State.bowLowVoltageDistributionBoxCircuitBreaker == BREAK_ON)? pdis3 -> bowLowVoltageDistributionBoxCircuitBreaker = 1 : pdis3 -> bowLowVoltageDistributionBoxCircuitBreaker = 0;
|
||||
(m_pm->m_pmCurrentState.bus3State.unit4InstrumentDC48VCircuitBreaker == BREAK_ON)? pdis3 -> unit4InstrumentDC48VCircuitBreaker = 1 : pdis3 -> unit4InstrumentDC48VCircuitBreaker = 0;
|
||||
(m_pm->m_pmCurrentState.bus3State.dcC1DCDistributionPanelCircuitBreaker == BREAK_ON)? pdis3 -> dcC1DCDistributionPanelCircuitBreaker = 1 : pdis3 -> dcC1DCDistributionPanelCircuitBreaker = 0;
|
||||
(m_pm->m_pmCurrentState.bus3State.reservedCircuitBreaker1 == BREAK_ON)? pdis3 -> reservedCircuitBreaker1 = 1 : pdis3 -> reservedCircuitBreaker1 = 0;
|
||||
(m_pm->m_pmCurrentState.bus3State.reservedCircuitBreaker2 == BREAK_ON)? pdis3 -> reservedCircuitBreaker2 = 1 : pdis3 -> reservedCircuitBreaker2 = 0;
|
||||
(m_pm->m_pmCurrentState.bus3State.emergencyLithiumBatteryGroup2CircuitBreaker == BREAK_ON)? pdis3 -> emergencyLithiumBatteryGroup2CircuitBreaker = 1 : pdis3 -> emergencyLithiumBatteryGroup2CircuitBreaker = 0;
|
||||
pdis3->paceholder = 0;
|
||||
m_pm->m_currentDisBreakerState.bus3Breaker = *pdis3;
|
||||
delete pdis3;
|
||||
}
|
||||
if(!m_udpComm->m_qReceiveDisLowBusBuffer.empty())
|
||||
{
|
||||
double time;
|
||||
m_udpComm->popMsgFormQueue(time,m_disLowBusState);
|
||||
m_pm->m_pmCurrentState.bus4State = m_disLowBusState.data;
|
||||
m_pm->m_db->insertData(m_pm->m_pmCurrentState.bus4State); //写入数据库
|
||||
msg_disLowBusFbMsg_Update_time = time;
|
||||
|
||||
disBus4Breaker* pdis4=new disBus4Breaker;
|
||||
(m_pm->m_pmCurrentState.bus4State.unit1CircuitBreaker == BREAK_ON)? pdis4 -> unit1CircuitBreaker = 1 : pdis4 -> unit1CircuitBreaker = 0;
|
||||
(m_pm->m_pmCurrentState.bus4State.unit2CircuitBreaker == BREAK_ON)? pdis4 -> unit2CircuitBreaker = 1 : pdis4 -> unit2CircuitBreaker = 0;
|
||||
(m_pm->m_pmCurrentState.bus4State.unit3CircuitBreaker == BREAK_ON)? pdis4 -> unit3CircuitBreaker = 1 : pdis4 -> unit3CircuitBreaker = 0;
|
||||
(m_pm->m_pmCurrentState.bus4State.unit5CircuitBreaker == BREAK_ON)? pdis4 -> unit5CircuitBreaker = 1 : pdis4 -> unit5CircuitBreaker = 0;
|
||||
(m_pm->m_pmCurrentState.bus4State.bowPZDeviceCircuitBreaker == BREAK_ON)? pdis4 -> bowPZDeviceCircuitBreaker = 1 : pdis4 -> bowPZDeviceCircuitBreaker = 0;
|
||||
(m_pm->m_pmCurrentState.bus4State.reservedCircuitBreaker1 == BREAK_ON)? pdis4 -> reservedCircuitBreaker1 = 1 : pdis4 -> reservedCircuitBreaker1 = 0;
|
||||
(m_pm->m_pmCurrentState.bus4State.reservedCircuitBreaker2 == BREAK_ON)? pdis4 -> reservedCircuitBreaker2 = 1 : pdis4 -> reservedCircuitBreaker2 = 0;
|
||||
(m_pm->m_pmCurrentState.bus4State.emergencyLithiumBatteryGroup1CircuitBreaker == BREAK_ON)? pdis4 -> emergencyLithiumBatteryGroup1CircuitBreaker = 1 : pdis4 -> emergencyLithiumBatteryGroup1CircuitBreaker = 0;
|
||||
pdis4 -> paceholder = 0;
|
||||
m_pm->m_currentDisBreakerState.bus4Breaker = *pdis4;
|
||||
delete pdis4;
|
||||
}
|
||||
m_pm->m_systemData->updateSystemData(m_pm->m_pmCurrentState.ccustate);
|
||||
m_pm->m_systemData->updateSystemData(m_pm->m_pmCurrentState.bus1State);
|
||||
m_pm->m_systemData->updateSystemData(m_pm->m_pmCurrentState.bus2State);
|
||||
m_pm->m_systemData->updateSystemData(m_pm->m_pmCurrentState.bus3State);
|
||||
m_pm->m_systemData->updateSystemData(m_pm->m_pmCurrentState.bus4State);
|
||||
m_pm->m_systemData->device_common_status.ccu_status.lastUpdateTime = m_pm->m_lowerCommManager->msg_CcuStateFbMsg_Update_time;
|
||||
m_pm->m_systemData->device_common_status.dis_hv_c1.lastUpdateTime = m_pm->m_lowerCommManager->msg_disHighVolBusFbMsg_Update_time;
|
||||
m_pm->m_systemData->device_common_status.dis_hv_c2.lastUpdateTime = m_pm->m_lowerCommManager->msg_disHighAVolBusFbMsg_Update_time;
|
||||
m_pm->m_systemData->device_common_status.dis_lv_c1.lastUpdateTime = m_pm->m_lowerCommManager->msg_disHighBVolBusFbMsg_Update_time;
|
||||
m_pm->m_systemData->device_common_status.dis_lv_c2.lastUpdateTime = m_pm->m_lowerCommManager->msg_disLowBusFbMsg_Update_time;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool LowerCommManager::listenThreadFunc()
|
||||
{
|
||||
cout<<MOOS::ConsoleColours::green()<< "LowerCommManager::listenThreadFunc" << MOOS::ConsoleColours::reset() << endl;
|
||||
unsigned char Buff[1024];
|
||||
while(!m_ListenThread.IsQuitRequested())
|
||||
{
|
||||
try
|
||||
{
|
||||
int nRead = m_udpComm->udpScoket->iRecieveMessage(Buff, sizeof(Buff));
|
||||
cout<<MOOS::ConsoleColours::yellow()<< "RECEVE DATA COUNT:" << nRead << MOOS::ConsoleColours::reset() << endl;
|
||||
if(nRead > 0)
|
||||
{
|
||||
try {
|
||||
if(!m_udpComm->pushMsgToQueue(Buff))
|
||||
{
|
||||
for(int i=0; i<m_udpComm->sError.size(); i++)
|
||||
{
|
||||
cout<<MOOS::ConsoleColours::red()<< m_udpComm->sError[i] << MOOS::ConsoleColours::reset() << endl;
|
||||
}
|
||||
}
|
||||
//更新当前状态
|
||||
if(!updatePoweSystemStates())
|
||||
{
|
||||
std::cerr << "Error updating power system states" << std::endl;
|
||||
}
|
||||
}
|
||||
catch(const std::exception& e) {
|
||||
cerr << "Error processing message: " << e.what() << endl;
|
||||
}
|
||||
}
|
||||
|
||||
// 打印通信错误信息
|
||||
if(!m_udpComm->sError.empty())
|
||||
{
|
||||
for(int i=0; i<m_udpComm->sError.size(); i++)
|
||||
{
|
||||
cout<<MOOS::ConsoleColours::red() << m_udpComm->sError[i] << MOOS::ConsoleColours::reset() << endl;
|
||||
}
|
||||
m_udpComm->sError.clear();
|
||||
}
|
||||
}
|
||||
catch(const XPCException& e)
|
||||
{
|
||||
cerr << "XPCException in listenThreadFunc" << endl;
|
||||
// 短暂休眠后继续尝试
|
||||
MOOSPause(100);
|
||||
}
|
||||
catch(const std::exception& e)
|
||||
{
|
||||
cerr << "Exception in listenThreadFunc: " << e.what() << endl;
|
||||
MOOSPause(100);
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
cerr << "Unknown exception in listenThreadFunc" << endl;
|
||||
MOOSPause(100);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void LowerCommManager::startListenThread()
|
||||
{
|
||||
if(!m_ListenThread.IsThreadRunning())
|
||||
{
|
||||
m_ListenThread.Initialise(_ListenCB,this);
|
||||
m_ListenThread.Start();
|
||||
std::cout << "LowerCommManager::startListenThread" << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
void LowerCommManager::stopListenThread()
|
||||
{
|
||||
if(m_ListenThread.IsThreadRunning())
|
||||
{
|
||||
m_ListenThread.Stop();
|
||||
std::cout << "LowerCommManager::stopListenThread" << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
char LowerCommManager::getBreakerOption(char cmd)
|
||||
{
|
||||
if(cmd ==1)
|
||||
return 0x55;
|
||||
else if(cmd ==0)
|
||||
return 0xAA;
|
||||
else
|
||||
return 0x00;
|
||||
}
|
||||
|
||||
void LowerCommManager::coutMsg(const msg_CcuStateFbMsg& p, std::ostream& os){
|
||||
os << std::hex << std::setfill('0') << std::uppercase;
|
||||
|
||||
os << "起始符1 (start1): 0x" << std::setw(2) << static_cast<int>(p.header.start1) << "\n";
|
||||
os << "起始符2 (start2): 0x" << std::setw(2) << static_cast<int>(p.header.start2) << "\n";
|
||||
os << "标识符 (identifier): 0x" << std::setw(4) << p.header.id << "\n";
|
||||
os << std::dec << "数据长度 (length): " << p.header.length << "\n";
|
||||
|
||||
|
||||
os << "运行模式 (fc_mode): 0x" << std::hex << std::setw(2) << static_cast<int>(p.data.fc_mode) << "\n";
|
||||
os << "燃料电池状态 (fc_status): 0x" << std::setw(2) << static_cast<int>(p.data.fc_status) << "\n";
|
||||
os << "故障等级 (fc_fault_level): 0x" << std::setw(2) << static_cast<int>(p.data.fc_fault_level) << "\n";
|
||||
|
||||
os << std::dec;
|
||||
os << "输出功率限制 (output_power_limit): " << p.data.output_power_limit << " W\n";
|
||||
os << "累计发电时间 (total_generation_time): " << p.data.total_generation_time * 0.1 << " 小时\n";
|
||||
os << "发电总功率 (total_generation_power): " << p.data.total_generation_power << " W\n";
|
||||
os << "一级故障字 (fault_level_1): 0x" << std::hex << p.data.fault_level_1 << "\n";
|
||||
os << "二级故障字 (fault_level_2): 0x" << p.data.fault_level_2 << "\n";
|
||||
os << "三级故障字 (fault_level_3): 0x" << p.data.fault_level_3 << "\n";
|
||||
os << "四级故障字 (fault_level_4): 0x" << p.data.fault_level_4 << "\n";
|
||||
|
||||
os << std::dec;
|
||||
os << "储氢剩余容量 (hydrogen_capacity): " << static_cast<int>(p.data.hydrogen_capacity) << "%\n";
|
||||
os << "液氧剩余容量 (liquid_oxygen_capacity): " << static_cast<int>(p.data.liquid_oxygen_capacity) << "%\n";
|
||||
os << "钯膜最高温度 (palladium_temp): " << p.data.palladium_temp << " ℃\n";
|
||||
os << "主水路压力 (main_pipe_pressure): " << p.data.main_pipe_pressure * 0.01 << " kPa\n";
|
||||
os << "辅水路压力 (aux_pipe_pressure): " << p.data.aux_pipe_pressure * 0.01 << " kPa\n";
|
||||
|
||||
os << "舱室压力1 (cabin_pressure1): " << p.data.cabin_pressure1 * 0.01 << " kPa\n";
|
||||
os << "舱室压力2 (cabin_pressure2): " << p.data.cabin_pressure2 * 0.01 << " kPa\n";
|
||||
os << "舱室温度1 (cabin_temp1): " << p.data.cabin_temp1 * 0.01 << " ℃\n";
|
||||
os << "舱室温度2 (cabin_temp2): " << p.data.cabin_temp2 * 0.01 << " ℃\n";
|
||||
os << "舱室湿度1 (cabin_humidity1): " << p.data.cabin_humidity1 * 0.01 << " %RH\n";
|
||||
os << "舱室湿度2 (cabin_humidity2): " << p.data.cabin_humidity2 * 0.01 << " %RH\n";
|
||||
|
||||
os << "火焰探测器1状态 (flame_detector1): 0x" << std::hex << static_cast<int>(p.data.flame_detector1) << "\n";
|
||||
os << "火焰探测器2状态 (flame_detector2): 0x" << static_cast<int>(p.data.flame_detector2) << "\n";
|
||||
|
||||
os << std::dec;
|
||||
os << "氢气浓度1 (h2_concentration1): " << p.data.h2_concentration1 * 0.01 << "% LEL\n";
|
||||
os << "氢气浓度2 (h2_concentration2): " << p.data.h2_concentration2 * 0.01 << "% LEL\n";
|
||||
os << "氢气浓度3 (h2_concentration3): " << p.data.h2_concentration3 * 0.01 << "% LEL\n";
|
||||
os << "氧气浓度1 (o2_concentration1): " << p.data.o2_concentration1 * 0.01 << "% LEL\n";
|
||||
os << "氧气浓度2 (o2_concentration2): " << p.data.o2_concentration2 * 0.01 << "% LEL\n";
|
||||
os << "甲醇浓度1 (ch3oh_concentration1): " << p.data.ch3oh_concentration1 * 0.01 << "% LEL\n";
|
||||
os << "甲醇浓度2 (ch3oh_concentration2): " << p.data.ch3oh_concentration2 * 0.01 << "% LEL\n";
|
||||
|
||||
for (int i = 0; i < 10; ++i)
|
||||
os << "保留字段 reserved1[" << i << "]: 0x" << std::hex << p.data.reserved1[i] << "\n";
|
||||
|
||||
os << "仪表舱 氧气浓度 (cabin_ox_concentration): " << p.data.cabin_ox_concentration * 0.1 << "%\n";
|
||||
os << "仪表舱 温度 (cabin_temperature): " << static_cast<int16_t> (p.data.cabin_temperature) * 0.1 << "°C\n";
|
||||
os << "仪表舱 湿度 (cabin_humidity): " << p.data.cabin_humidity * 0.1 << "% RH\n";
|
||||
os << "仪表舱 大气压 (cabin_pressure): " << p.data.cabin_pressure * 0.2 << " kPa\n";
|
||||
|
||||
os << "动力舱 氧气浓度 (power_cabin_ox_concentration): " << p.data.power_cabin_ox_concentration * 0.1 << "%\n";
|
||||
os << "动力舱 温度 (power_cabin_temperature): " << static_cast<int16_t> (p.data.power_cabin_temperature) * 0.1 << "°C\n";
|
||||
os << "动力舱 湿度 (power_cabin_humidity): " << p.data.power_cabin_humidity * 0.1 << "% RH\n";
|
||||
os << "动力舱 大气压 (power_cabin_pressure): " << p.data.power_cabin_pressure * 0.2 << " kPa\n";
|
||||
|
||||
for (int i = 0; i < 6; ++i)
|
||||
os << "动力电池报警标志 dyn_alarm_flag[" << i << "]: 0x" << std::hex << static_cast<int>(p.data.dyn_alarm_flag[i]) << "\n";
|
||||
for (int i = 0; i < 6; ++i)
|
||||
os << "仪表电池报警标志 ins_alarm_flag[" << i << "]: 0x" << std::hex << static_cast<int>(p.data.ins_alarm_flag[i]) << "\n";
|
||||
|
||||
|
||||
os << "仪表正极/充电继电器状态 (ins_relay_status1): 0x" << std::hex << static_cast<int>(p.data.ins_relay_status1) << "\n";
|
||||
os << "仪表预充/负极继电器状态 (ins_relay_status2): 0x" << static_cast<int>(p.data.ins_relay_status2) << "\n";
|
||||
os << "动力正极/充电继电器状态 (dyn_relay_status1): 0x" << static_cast<int>(p.data.dyn_relay_status1) << "\n";
|
||||
os << "动力预充/负极继电器状态 (dyn_relay_status2): 0x" << static_cast<int>(p.data.dyn_relay_status2) << "\n";
|
||||
|
||||
os << std::dec;
|
||||
os << "仪表最大放电功率 (ins_max_discharge_power): " << p.data.ins_max_discharge_power * 0.05 << " kW\n";
|
||||
os << "动力最大放电功率 (dyn_max_discharge_power): " << p.data.dyn_max_discharge_power * 0.05 << " kW\n";
|
||||
|
||||
os << "仪表SOC (ins_soc): " << static_cast<int>(p.data.ins_soc) << "%\n";
|
||||
os << "动力SOC (dyn_soc): " << static_cast<int>(p.data.dyn_soc) << "%\n";
|
||||
|
||||
os << "仪表电池总能量 (ins_total_energy): " << p.data.ins_total_energy * 0.1 << " kWh\n";
|
||||
os << "动力电池总能量 (dyn_total_energy): " << p.data.dyn_total_energy * 0.1 << " kWh\n";
|
||||
|
||||
os << "仪表输入功率 (ins_power_input): " << p.data.ins_power_input * 0.1 << " kW\n";
|
||||
os << "动力输入功率 (dyn_power_input): " << p.data.dyn_power_input * 0.1 << " kW\n";
|
||||
|
||||
os << "仪表充电状态 (ins_charge_status): 0x" << std::hex << static_cast<int>(p.data.ins_charge_status) << "\n";
|
||||
os << "动力充电状态 (dyn_charge_status): 0x" << static_cast<int>(p.data.dyn_charge_status) << "\n";
|
||||
|
||||
os << std::dec;
|
||||
os << "仪表LINK电压: " << p.data.ins_voltage_link * 0.01 << " V\n";
|
||||
os << "仪表PACK电压: " << p.data.ins_voltage_pack * 0.01 << " V\n";
|
||||
os << "仪表电流: " << static_cast<int16_t> (p.data.ins_current) * 0.05 << " A\n";
|
||||
os << "仪表正端绝缘电阻: " << p.data.ins_resistance_pos << " kΩ\n";
|
||||
os << "仪表负端绝缘电阻: " << p.data.ins_resistance_neg << " kΩ\n";
|
||||
os << "动力LINK电压: " << p.data.dyn_voltage_link * 0.01 << " V\n";
|
||||
os << "动力PACK电压: " << p.data.dyn_voltage_pack * 0.01 << " V\n";
|
||||
os << "动力电流: " << static_cast<int16_t> (p.data.dyn_current) * 0.05 << " A\n";
|
||||
os << "动力正端绝缘电阻: " << p.data.dyn_resistance_pos << " kΩ\n";
|
||||
os << "动力负端绝缘电阻: " << p.data.dyn_resistance_neg << " kΩ\n";
|
||||
|
||||
os << "仪表紧急状态 (ins_emergency_status): 0x" << std::hex << static_cast<int>(p.data.ins_emergency_status) << "\n";
|
||||
os << "动力紧急状态 (dyn_emergency_status): 0x" << static_cast<int>(p.data.dyn_emergency_status) << "\n";
|
||||
|
||||
for (int i = 0; i < 2; ++i)
|
||||
os << "保留字段 reserved2[" << i << "]: 0x" << std::hex << static_cast<int>(p.data.reserved2[i]) << "\n";
|
||||
for (int i = 0; i < 6; ++i)
|
||||
os << "SOC门限值 ins_soc_threshold" << i+1 << ": 0x" << std::hex << static_cast<int>(p.data.ins_soc_threshold1) << "\n";
|
||||
for (int i = 0; i < 4; ++i)
|
||||
os << "功率限制 ins_power_limit" << i+1 << ": 0x" << std::hex << static_cast<int>(p.data.ins_power_limit1) << "\n";
|
||||
|
||||
os << "设备在线状态1 (device_online_flag1): 0x" << std::hex << p.data.device_online_flag1 << "\n";
|
||||
os << "设备在线状态2 (device_online_flag2): 0x" << p.data.device_online_flag2 << "\n";
|
||||
|
||||
// os << "保留字段 reserved3: 0x" << p.data.reserved1 << "\n";
|
||||
os << "主机心跳 (reserved4): 0x" << p.data.heartbeat << "\n";
|
||||
os << "校验和 (checksum): 0x" << p.checkCode << "\n";
|
||||
|
||||
os << std::dec;
|
||||
}
|
||||
//================================================================================================================
|
||||
// 高电压母线断路器操作函数
|
||||
bool LowerCommManager::operate_HV_fuelCellCircuit_Breaker(char opt){
|
||||
return operateBreakerGeneric<disHighVolBusCmd, char>(
|
||||
"HV_fuelCellCircuit_Breaker",
|
||||
opt,
|
||||
[&](disHighVolBusCmd& c){ c.fuelCellCircuitBreaker = getBreakerOption(opt); },
|
||||
[&](){ return m_pm->m_pmCurrentState.bus1State.fuelCellCircuitBreaker; }
|
||||
);
|
||||
}
|
||||
bool LowerCommManager::operate_HV_powerLithiumBattery_Breaker(char opt){
|
||||
return operateBreakerGeneric<disHighVolBusCmd, char>(
|
||||
"HV_powerLithiumBattery_Breaker",
|
||||
opt,
|
||||
[&](disHighVolBusCmd& c){ c.powerLithiumBatteryCircuitBreaker = getBreakerOption(opt); },
|
||||
[&](){ return m_pm->m_pmCurrentState.bus1State.powerLithiumBatteryCircuitBreaker; }
|
||||
);
|
||||
}
|
||||
bool LowerCommManager::operate_HV_propulsionMotor_Breaker(char opt){
|
||||
return operateBreakerGeneric<disHighVolBusCmd, char>(
|
||||
"HV_propulsionMotor_Breaker",
|
||||
opt,
|
||||
[&](disHighVolBusCmd& c){ c.propulsionMotorCircuitBreaker = getBreakerOption(opt); },
|
||||
[&](){ return m_pm->m_pmCurrentState.bus1State.propulsionMotorCircuitBreaker; }
|
||||
);
|
||||
}
|
||||
bool LowerCommManager::operate_HV_lithiumBatteryMeter_Breaker(char opt){
|
||||
return operateBreakerGeneric<disHighVolBusCmd, char>(
|
||||
"HV_lithiumBatteryMeter_Breaker",
|
||||
opt,
|
||||
[&](disHighVolBusCmd& c){ c.lithiumBatteryGroupInstrumentCircuitBreaker = getBreakerOption(opt); },
|
||||
[&](){ return m_pm->m_pmCurrentState.bus1State.lithiumBatteryGroupInstrumentCircuitBreaker; }
|
||||
);
|
||||
}
|
||||
bool LowerCommManager::operate_HV_dcDc5Module_Breaker(char opt){
|
||||
return operateBreakerGeneric<disHighVolBusCmd, char>(
|
||||
"HV_dcDc5Module_Breaker",
|
||||
opt,
|
||||
[&](disHighVolBusCmd& c){ c.dcDc5ModuleCircuitBreaker = getBreakerOption(opt); },
|
||||
[&](){ return m_pm->m_pmCurrentState.bus1State.dcDc5ModuleCircuitBreaker; }
|
||||
);
|
||||
}
|
||||
bool LowerCommManager::operate_HV_bowHighVoltageBox_Breaker(char opt){
|
||||
return operateBreakerGeneric<disHighVolBusCmd, char>(
|
||||
"HV_bowHighVoltageBox_Breaker",
|
||||
opt,
|
||||
[&](disHighVolBusCmd& c){ c.bowHighVoltageDistributionBoxCircuitBreaker = getBreakerOption(opt); },
|
||||
[&](){ return m_pm->m_pmCurrentState.bus1State.bowHighVoltageDistributionBoxCircuitBreaker; }
|
||||
);
|
||||
}
|
||||
bool LowerCommManager::operate_HV_sternFt45_Breaker(char opt){
|
||||
return operateBreakerGeneric<disHighVolBusCmd, char>(
|
||||
"HV_sternFt45_Breaker",
|
||||
opt,
|
||||
[&](disHighVolBusCmd& c){ c.sternFTDevice45CircuitBreaker = getBreakerOption(opt); },
|
||||
[&](){ return m_pm->m_pmCurrentState.bus1State.sternFTDevice45CircuitBreaker; }
|
||||
);
|
||||
}
|
||||
bool LowerCommManager::operate_HV_sternRudder1_Breaker(char opt){
|
||||
return operateBreakerGeneric<disHighVolBusCmd, char>(
|
||||
"HV_sternRudder1_Breaker",
|
||||
opt,
|
||||
[&](disHighVolBusCmd& c){ c.sternRudderSwitch1CircuitBreaker = getBreakerOption(opt); },
|
||||
[&](){ return m_pm->m_pmCurrentState.bus1State.sternRudderSwitch1CircuitBreaker; }
|
||||
);
|
||||
}
|
||||
bool LowerCommManager::operate_HV_sternRudder2_Breaker(char opt){
|
||||
return operateBreakerGeneric<disHighVolBusCmd, char>(
|
||||
"HV_sternRudder2_Breaker",
|
||||
opt,
|
||||
[&](disHighVolBusCmd& c){ c.sternRudderSwitch2CircuitBreaker = getBreakerOption(opt); },
|
||||
[&](){ return m_pm->m_pmCurrentState.bus1State.sternRudderSwitch2CircuitBreaker; }
|
||||
);
|
||||
}
|
||||
bool LowerCommManager::operate_HV_fbReserved_Breaker(char opt){
|
||||
return operateBreakerGeneric<disHighVolBusCmd, char>(
|
||||
"HV_fbReserved_Breaker",
|
||||
opt,
|
||||
[&](disHighVolBusCmd& c){ c.fbReservedCircuitBreaker = getBreakerOption(opt); },
|
||||
[&](){ return m_pm->m_pmCurrentState.bus1State.fbReservedCircuitBreaker; }
|
||||
);
|
||||
}
|
||||
bool LowerCommManager::operate_HV_tyzReserved_Breaker(char opt){
|
||||
return operateBreakerGeneric<disHighVolBusCmd, char>(
|
||||
"HV_tyzReserved_Breaker",
|
||||
opt,
|
||||
[&](disHighVolBusCmd& c){ c.tyzReservedCircuitBreaker = getBreakerOption(opt); },
|
||||
[&](){ return m_pm->m_pmCurrentState.bus1State.tyzReservedCircuitBreaker; }
|
||||
);
|
||||
}
|
||||
bool LowerCommManager::operate_HV_reserved_Breaker(char opt){
|
||||
return operateBreakerGeneric<disHighVolBusCmd, char>(
|
||||
"HV_reserved_Breaker",
|
||||
opt,
|
||||
[&](disHighVolBusCmd& c){ c.reservedCircuitBreaker = getBreakerOption(opt); },
|
||||
[&](){ return m_pm->m_pmCurrentState.bus1State.reservedCircuitBreaker; }
|
||||
);
|
||||
}
|
||||
// bool LowerCommManager::operate_HV_dcDc5_Breaker(char opt){
|
||||
// return operateBreakerGeneric<disHighVolBusCmd, char>(
|
||||
// "HV_dcDc5_Breaker",
|
||||
// opt,
|
||||
// [&](disHighVolBusCmd& c){ c.dcdc5Module = getBreakerOption(opt); },
|
||||
// [&](){ return m_pm->m_pmCurrentState.bus1State.dcDcFaultWord1&(0x02); }
|
||||
// );
|
||||
// }
|
||||
bool LowerCommManager::operate_HV_dcDc5_Breaker(char opt)
|
||||
{
|
||||
disHighVolBusCmd cmd{}; // 默认全零
|
||||
double t0 = MOOSTime();
|
||||
bool ok = false;
|
||||
string name = "DCDC Module";
|
||||
LOG_F(INFO, "operate %s: opt=%d", name, opt);
|
||||
|
||||
cmd.dcdc5Module = getBreakerOption(opt);
|
||||
|
||||
m_udpComm->sendDisSysCmd(cmd);
|
||||
|
||||
// ok = m_pm->m_pmCurrentState.bus1State.dcDcFaultWord1&(0x02);
|
||||
ok = m_pm->m_systemData->m_dcdcStatus.workingStatus;
|
||||
|
||||
MOOSPause(100);
|
||||
while ( !ok ) {
|
||||
if( m_pm->m_systemData->m_dcdcStatus.workingStatus )
|
||||
{
|
||||
ok = true;
|
||||
break;
|
||||
}
|
||||
if (!m_udpComm->sendDisSysCmd(cmd)) {
|
||||
LOG_F(ERROR, "operate %s: sendDisSysCmd failed", name);
|
||||
ok = false;
|
||||
break;
|
||||
}
|
||||
if (MOOSTime() > t0 + 6) {
|
||||
LOG_F(ERROR, "operate %s: timeout", name);
|
||||
ok = false;
|
||||
break;
|
||||
}
|
||||
MOOSPause(200);
|
||||
}
|
||||
//继电器复位
|
||||
disHighVolBusCmd clr{};
|
||||
for (int i = 0; i < 3; ++i)
|
||||
{
|
||||
m_udpComm->sendDisSysCmd(clr);
|
||||
MOOSPause(200);
|
||||
}
|
||||
return ok;
|
||||
}
|
||||
|
||||
// bool LowerCommManager::operate_HV_coolingSystem_Breaker(char opt){
|
||||
// return operateBreakerGeneric<disHighVolBusCmd, char>(
|
||||
// "HV_coolingSystem_Breaker",
|
||||
// opt,
|
||||
// [&](disHighVolBusCmd& c){ c.coolingSystem = getBreakerOption(opt); },
|
||||
// [&](){ return (m_pm->m_pmCurrentState.bus1State.dcDcFaultWord1 & 0x20) ? 0x55 : 0xAA; }
|
||||
// );
|
||||
// }
|
||||
bool LowerCommManager::operate_HV_coolingSystem_Breaker(char opt)
|
||||
{
|
||||
disHighVolBusCmd cmd{}; // 默认全零
|
||||
double t0 = MOOSTime();
|
||||
bool ok = false;
|
||||
string name = "CoolingSystem";
|
||||
LOG_F(INFO, "operate %s: opt=%d", name, opt);
|
||||
|
||||
cmd.coolingSystem = getBreakerOption(opt);
|
||||
|
||||
m_udpComm->sendDisSysCmd(cmd);
|
||||
|
||||
// ok = m_pm->m_pmCurrentState.bus1State.dcDcFaultWord1 & 0x60;
|
||||
ok = m_pm->m_systemData->m_dcdcStatus.coolingPump1Running || m_pm->m_systemData->m_dcdcStatus.coolingPump2Running;
|
||||
|
||||
MOOSPause(100);
|
||||
while ( !ok ) {
|
||||
if( (m_pm->m_systemData->m_dcdcStatus.coolingPump1Running || m_pm->m_systemData->m_dcdcStatus.coolingPump2Running) )
|
||||
{
|
||||
ok = true;
|
||||
break;
|
||||
}
|
||||
if (!m_udpComm->sendDisSysCmd(cmd)) {
|
||||
LOG_F(ERROR, "operate %s: sendDisSysCmd failed", name);
|
||||
ok = false;
|
||||
break;
|
||||
}
|
||||
if (MOOSTime() > t0 + 6) {
|
||||
LOG_F(ERROR, "operate %s: timeout", name);
|
||||
ok = false;
|
||||
break;
|
||||
}
|
||||
MOOSPause(200);
|
||||
}
|
||||
//继电器复位
|
||||
disHighVolBusCmd clr{};
|
||||
for (int i = 0; i < 3; ++i)
|
||||
{
|
||||
m_udpComm->sendDisSysCmd(clr);
|
||||
MOOSPause(200);
|
||||
}
|
||||
return ok;
|
||||
}
|
||||
|
||||
// 高压汇流排断路器操作函数
|
||||
bool LowerCommManager::operate_HVA_bowFTDevice123Circuit_Breaker(char opt){
|
||||
return operateBreakerGeneric<disHighAVolBusCmd, char>(
|
||||
"HVA_bowFTDevice123Circuit_Breaker",
|
||||
opt,
|
||||
[&](disHighAVolBusCmd& c){ c.bowFTDevice123CircuitBreaker = getBreakerOption(opt); },
|
||||
[&](){ return m_pm->m_pmCurrentState.bus2State.bowFTDevice123CircuitBreaker; }
|
||||
);
|
||||
}
|
||||
bool LowerCommManager::operate_HVA_actuatorCircuit_Breaker(char opt){
|
||||
return operateBreakerGeneric<disHighAVolBusCmd, char>(
|
||||
"HVA_actuatorCircuit_Breaker",
|
||||
opt,
|
||||
[&](disHighAVolBusCmd& c){ c.actuatorCircuitBreaker = getBreakerOption(opt); },
|
||||
[&](){ return m_pm->m_pmCurrentState.bus2State.actuatorCircuitBreaker; }
|
||||
);
|
||||
}
|
||||
bool LowerCommManager::operate_HVA_mastSteeringGearControlBoxCircuit_Breaker(char opt){
|
||||
return operateBreakerGeneric<disHighAVolBusCmd, char>(
|
||||
"HVA_mastSteeringGearControlBoxCircuit_Breaker",
|
||||
opt,
|
||||
[&](disHighAVolBusCmd& c){ c.mastSteeringGearControlBoxCircuitBreaker = getBreakerOption(opt); },
|
||||
[&](){ return m_pm->m_pmCurrentState.bus2State.mastSteeringGearControlBoxCircuitBreaker; }
|
||||
);
|
||||
}
|
||||
bool LowerCommManager::operate_HVA_xczCircuit_Breaker(char opt){
|
||||
return operateBreakerGeneric<disHighAVolBusCmd, char>(
|
||||
"HVA_xczCircuit_Breaker",
|
||||
opt,
|
||||
[&](disHighAVolBusCmd& c){ c.xczCircuitBreaker = getBreakerOption(opt); },
|
||||
[&](){ return m_pm->m_pmCurrentState.bus2State.xczCircuitBreaker; }
|
||||
);
|
||||
}
|
||||
bool LowerCommManager::operate_HVA_bowRudderControlBoxCircuit_Breaker(char opt){
|
||||
return operateBreakerGeneric<disHighAVolBusCmd, char>(
|
||||
"HVA_bowRudderControlBoxCircuit_Breaker",
|
||||
opt,
|
||||
[&](disHighAVolBusCmd& c){ c.bowRudderControlBoxCircuitBreaker = getBreakerOption(opt); },
|
||||
[&](){ return m_pm->m_pmCurrentState.bus2State.bowRudderControlBoxCircuitBreaker; }
|
||||
);
|
||||
}
|
||||
bool LowerCommManager::operate_HVA_openWaterCoverStartCylinderCircuit_Breaker(char opt){
|
||||
return operateBreakerGeneric<disHighAVolBusCmd, char>(
|
||||
"HVA_openWaterCoverStartCylinderCircuit_Breaker",
|
||||
opt,
|
||||
[&](disHighAVolBusCmd& c){ c.openWaterCoverStartCylinderCircuitBreaker = getBreakerOption(opt); },
|
||||
[&](){ return m_pm->m_pmCurrentState.bus2State.openWaterCoverStartCylinderCircuitBreaker; }
|
||||
);
|
||||
}
|
||||
|
||||
// 仪表汇流排断路器操作函数
|
||||
|
||||
bool LowerCommManager::operate_LVA_unit1Circuit_Breaker(char opt){
|
||||
return operateBreakerGeneric<disLowBusCmd, char>(
|
||||
"LVA_unit1Circuit_Breaker",
|
||||
opt,
|
||||
[&](disLowBusCmd& c){ c.unit1CircuitBreaker = getBreakerOption(opt); },
|
||||
[&](){ return m_pm->m_pmCurrentState.bus4State.unit1CircuitBreaker; }
|
||||
);
|
||||
}
|
||||
bool LowerCommManager::operate_LVA_unit2Circuit_Breaker(char opt){
|
||||
return operateBreakerGeneric<disLowBusCmd, char>(
|
||||
"LVA_unit2Circuit_Breaker",
|
||||
opt,
|
||||
[&](disLowBusCmd& c){ c.unit2CircuitBreaker = getBreakerOption(opt); },
|
||||
[&](){ return m_pm->m_pmCurrentState.bus4State.unit2CircuitBreaker; }
|
||||
);
|
||||
}
|
||||
bool LowerCommManager::operate_LVA_unit3Circuit_Breaker(char opt){
|
||||
return operateBreakerGeneric<disLowBusCmd, char>(
|
||||
"LVA_unit3Circuit_Breaker",
|
||||
opt,
|
||||
[&](disLowBusCmd& c){ c.unit3CircuitBreaker = getBreakerOption(opt); },
|
||||
[&](){ return m_pm->m_pmCurrentState.bus4State.unit3CircuitBreaker; }
|
||||
);
|
||||
}
|
||||
bool LowerCommManager::operate_LVA_unit5Circuit_Breaker(char opt){
|
||||
return operateBreakerGeneric<disLowBusCmd, char>(
|
||||
"LVA_unit5Circuit_Breaker",
|
||||
opt,
|
||||
[&](disLowBusCmd& c){ c.unit5CircuitBreaker = getBreakerOption(opt); },
|
||||
[&](){ return m_pm->m_pmCurrentState.bus4State.unit5CircuitBreaker; }
|
||||
);
|
||||
}
|
||||
bool LowerCommManager::operate_LVA_bowPZDeviceCircuit_Breaker(char opt){
|
||||
return operateBreakerGeneric<disLowBusCmd, char>(
|
||||
"LVA_bowPZDeviceCircuit_Breaker",
|
||||
opt,
|
||||
[&](disLowBusCmd& c){ c.bowPZDeviceCircuitBreaker = getBreakerOption(opt); },
|
||||
[&](){ return m_pm->m_pmCurrentState.bus4State.bowPZDeviceCircuitBreaker; }
|
||||
);
|
||||
}
|
||||
bool LowerCommManager::operate_LVA_reservedCircuit1_Breaker(char opt){
|
||||
return operateBreakerGeneric<disLowBusCmd, char>(
|
||||
"LVA_reservedCircuit1_Breaker",
|
||||
opt,
|
||||
[&](disLowBusCmd& c){ c.reservedCircuitBreaker1 = getBreakerOption(opt); },
|
||||
[&](){ return m_pm->m_pmCurrentState.bus4State.reservedCircuitBreaker1; }
|
||||
);
|
||||
}
|
||||
bool LowerCommManager::operate_LVA_reservedCircuit2_Breaker(char opt){
|
||||
return operateBreakerGeneric<disLowBusCmd, char>(
|
||||
"LVA_reservedCircuit2_Breaker",
|
||||
opt,
|
||||
[&](disLowBusCmd& c){ c.reservedCircuitBreaker2 = getBreakerOption(opt); },
|
||||
[&](){ return m_pm->m_pmCurrentState.bus4State.reservedCircuitBreaker2; }
|
||||
);
|
||||
}
|
||||
bool LowerCommManager::operate_LVA_mergencyLithiumBatteryGroup1Circuit_Breaker(char opt){
|
||||
return operateBreakerGeneric<disLowBusCmd, char>(
|
||||
"LVA_mergencyLithiumBatteryGroup1Circuit_Breaker",
|
||||
opt,
|
||||
[&](disLowBusCmd& c){ c.emergencyLithiumBatteryGroup1CircuitBreaker = getBreakerOption(opt); },
|
||||
[&](){ return m_pm->m_pmCurrentState.bus4State.emergencyLithiumBatteryGroup1CircuitBreaker; }
|
||||
);
|
||||
}
|
||||
|
||||
// 仪表母线断路器操作函数
|
||||
bool LowerCommManager::operate_LV_lithiumBatteryGroupInstrumentCircuit_Breaker(char opt){
|
||||
return operateBreakerGeneric<disLowMainBusCmd, char>(
|
||||
"lithiumBatteryGroupInstrumentCircuitBreaker",
|
||||
opt,
|
||||
[&](disLowMainBusCmd& c){ c.lithiumBatteryGroupInstrumentCircuitBreaker = getBreakerOption(opt); },
|
||||
[&](){ return m_pm->m_pmCurrentState.bus3State.lithiumBatteryGroupInstrumentCircuitBreaker; }
|
||||
);
|
||||
}
|
||||
bool LowerCommManager::operate_LV_bowLowVoltageDistributionBoxCircuit_Breaker(char opt){
|
||||
return operateBreakerGeneric<disLowMainBusCmd, char>(
|
||||
"bowLowVoltageDistributionBoxCircuitBreaker",
|
||||
opt,
|
||||
[&](disLowMainBusCmd& c){ c.bowLowVoltageDistributionBoxCircuitBreaker = getBreakerOption(opt); },
|
||||
[&](){ return m_pm->m_pmCurrentState.bus3State.bowLowVoltageDistributionBoxCircuitBreaker; }
|
||||
);
|
||||
}
|
||||
bool LowerCommManager::operate_LV_unit4Dc48V_Breaker(char opt){
|
||||
return operateBreakerGeneric<disLowMainBusCmd, char>(
|
||||
"unit4InstrumentDC48VCircuitBreaker",
|
||||
opt,
|
||||
[&](disLowMainBusCmd& c){ c.unit4InstrumentDC48VCircuitBreaker = getBreakerOption(opt); },
|
||||
[&](){ return m_pm->m_pmCurrentState.bus3State.unit4InstrumentDC48VCircuitBreaker; }
|
||||
);
|
||||
}
|
||||
bool LowerCommManager::operate_LV_dcC1Panel_Breaker(char opt){
|
||||
return operateBreakerGeneric<disLowMainBusCmd, char>(
|
||||
"dcC1DCDistributionPanelCircuitBreaker",
|
||||
opt,
|
||||
[&](disLowMainBusCmd& c){ c.dcC1DCDistributionPanelCircuitBreaker = getBreakerOption(opt); },
|
||||
[&](){ return m_pm->m_pmCurrentState.bus3State.dcC1DCDistributionPanelCircuitBreaker; }
|
||||
);
|
||||
}
|
||||
bool LowerCommManager::operate_LV_reservedCircuit1_Breaker(char opt){
|
||||
return operateBreakerGeneric<disLowMainBusCmd, char>(
|
||||
"reservedCircuitBreaker1",
|
||||
opt,
|
||||
[&](disLowMainBusCmd& c){ c.reservedCircuitBreaker1 = getBreakerOption(opt); },
|
||||
[&](){ return m_pm->m_pmCurrentState.bus3State.reservedCircuitBreaker1; }
|
||||
);
|
||||
}
|
||||
bool LowerCommManager::operate_LV_reservedCircuit2_Breaker(char opt){
|
||||
return operateBreakerGeneric<disLowMainBusCmd, char>(
|
||||
"reservedCircuitBreaker2",
|
||||
opt,
|
||||
[&](disLowMainBusCmd& c){ c.reservedCircuitBreaker2 = getBreakerOption(opt); },
|
||||
[&](){ return m_pm->m_pmCurrentState.bus3State.reservedCircuitBreaker2; }
|
||||
);
|
||||
}
|
||||
bool LowerCommManager::operate_LV_mergencyLithiumBatteryGroup2Circuit_Breaker(char opt){
|
||||
return operateBreakerGeneric<disLowMainBusCmd, char>(
|
||||
"emergencyLithiumBatteryGroup2CircuitBreaker",
|
||||
opt,
|
||||
[&](disLowMainBusCmd& c){ c.emergencyLithiumBatteryGroup2CircuitBreaker = getBreakerOption(opt); },
|
||||
[&](){ return m_pm->m_pmCurrentState.bus3State.emergencyLithiumBatteryGroup2CircuitBreaker; }
|
||||
);
|
||||
}
|
||||
|
||||
// 通用模板
|
||||
template<typename CmdT, typename StateT>
|
||||
bool LowerCommManager::operateBreakerGeneric(
|
||||
char const* name,
|
||||
char opt,
|
||||
std::function<void(CmdT&)> fillCmd, // 填 cmd 对应字段
|
||||
std::function<StateT()> readState // 读 pmCurrentState 对应字段
|
||||
) {
|
||||
CmdT cmd{}; // 默认全零
|
||||
double t0 = MOOSTime();
|
||||
bool ok = false;
|
||||
LOG_F(INFO, "operate %s: opt=%d", name, opt);
|
||||
|
||||
// 第一次发包
|
||||
fillCmd(cmd);
|
||||
m_udpComm->sendDisSysCmd(cmd);
|
||||
MOOSPause(100);
|
||||
while ( !ok ) {
|
||||
if( readState() == getBreakerOption(opt) )
|
||||
{
|
||||
ok = true;
|
||||
break;
|
||||
}
|
||||
if (!m_udpComm->sendDisSysCmd(cmd)) {
|
||||
LOG_F(ERROR, "operate %s: sendDisSysCmd failed", name);
|
||||
ok = false;
|
||||
break;
|
||||
}
|
||||
if (MOOSTime() > t0 + 6) {
|
||||
LOG_F(ERROR, "operate %s: timeout", name);
|
||||
ok = false;
|
||||
break;
|
||||
}
|
||||
MOOSPause(200);
|
||||
}
|
||||
//继电器复位
|
||||
CmdT clr{};
|
||||
for (int i = 0; i < 3; ++i)
|
||||
{
|
||||
m_udpComm->sendDisSysCmd(clr);
|
||||
MOOSPause(200);
|
||||
}
|
||||
return ok;
|
||||
}
|
||||
@@ -1,128 +0,0 @@
|
||||
#ifndef LOWER_COMM_MANAGER_H
|
||||
#define LOWER_COMM_MANAGER_H
|
||||
#define UNIX
|
||||
|
||||
#include "MOOS/libMOOS/Comms/XPCUdpSocket.h"
|
||||
#include "MOOS/libMOOS/Utils/MOOSThread.h"
|
||||
#include "MOOS/libMOOS/Utils/MOOSLock.h"
|
||||
#include "../udpcomm/ccuUdpMsg.h"
|
||||
#include "pmSysvariable.h"
|
||||
#include <queue>
|
||||
#include <map>
|
||||
#include <functional>
|
||||
#include <atomic>
|
||||
#include <vector>
|
||||
#include "udpcomm/udpComm.h"
|
||||
#include <functional>
|
||||
|
||||
class PowerManger; // 前向声明
|
||||
|
||||
class LowerCommManager {
|
||||
public:
|
||||
LowerCommManager(PowerManger* pm, long myPort, long ccuPort, const std::string& cccHost);
|
||||
~LowerCommManager();
|
||||
|
||||
//processPeriodicTasks
|
||||
void processPeriodicTasks();
|
||||
//clearMsgQueue
|
||||
void clearMsgQueue();
|
||||
|
||||
public:
|
||||
// 初始化UDP通信
|
||||
bool initUdpComm();
|
||||
|
||||
// 更新设备状态
|
||||
bool updatePoweSystemStates();
|
||||
//================================断路器操作函数=======================================
|
||||
template<typename CmdT, typename StateT>
|
||||
bool operateBreakerGeneric(
|
||||
char const* name,
|
||||
char opt,
|
||||
std::function<void(CmdT&)> fillCmd, // 填 cmd 对应字段
|
||||
std::function<StateT()> readState // 读 pmCurrentState 对应字段
|
||||
);
|
||||
// 高电压母线
|
||||
bool operate_HV_fuelCellCircuit_Breaker(char opt);
|
||||
bool operate_HV_powerLithiumBattery_Breaker(char opt);
|
||||
bool operate_HV_propulsionMotor_Breaker(char opt);
|
||||
bool operate_HV_lithiumBatteryMeter_Breaker(char opt);
|
||||
bool operate_HV_dcDc5Module_Breaker(char opt);
|
||||
bool operate_HV_bowHighVoltageBox_Breaker(char opt);
|
||||
bool operate_HV_sternFt45_Breaker(char opt);
|
||||
bool operate_HV_sternRudder1_Breaker(char opt);
|
||||
bool operate_HV_sternRudder2_Breaker(char opt);
|
||||
bool operate_HV_fbReserved_Breaker(char opt);
|
||||
bool operate_HV_tyzReserved_Breaker(char opt);
|
||||
bool operate_HV_reserved_Breaker(char opt);
|
||||
bool operate_HV_dcDc5_Breaker(char opt);
|
||||
bool operate_HV_coolingSystem_Breaker(char opt);
|
||||
// 高压汇流排
|
||||
bool operate_HVA_bowFTDevice123Circuit_Breaker(char opt);
|
||||
bool operate_HVA_actuatorCircuit_Breaker(char opt);
|
||||
bool operate_HVA_mastSteeringGearControlBoxCircuit_Breaker(char opt);
|
||||
bool operate_HVA_xczCircuit_Breaker(char opt);
|
||||
bool operate_HVA_bowRudderControlBoxCircuit_Breaker(char opt);
|
||||
bool operate_HVA_openWaterCoverStartCylinderCircuit_Breaker(char opt);
|
||||
// 仪表母线
|
||||
bool operate_LV_lithiumBatteryGroupInstrumentCircuit_Breaker(char opt);
|
||||
bool operate_LV_bowLowVoltageDistributionBoxCircuit_Breaker(char opt);
|
||||
bool operate_LV_unit4Dc48V_Breaker(char opt);
|
||||
bool operate_LV_dcC1Panel_Breaker(char opt);
|
||||
bool operate_LV_reservedCircuit1_Breaker(char opt);
|
||||
bool operate_LV_reservedCircuit2_Breaker(char opt);
|
||||
bool operate_LV_mergencyLithiumBatteryGroup2Circuit_Breaker(char opt);
|
||||
// 仪表汇流排
|
||||
bool operate_LVA_unit1Circuit_Breaker(char opt);
|
||||
bool operate_LVA_unit2Circuit_Breaker(char opt);
|
||||
bool operate_LVA_unit3Circuit_Breaker(char opt);
|
||||
bool operate_LVA_unit5Circuit_Breaker(char opt);
|
||||
bool operate_LVA_bowPZDeviceCircuit_Breaker(char opt);
|
||||
bool operate_LVA_reservedCircuit1_Breaker(char opt);
|
||||
bool operate_LVA_reservedCircuit2_Breaker(char opt);
|
||||
bool operate_LVA_mergencyLithiumBatteryGroup1Circuit_Breaker(char opt);
|
||||
|
||||
//保持指令
|
||||
void operate_hold();
|
||||
//================================复合管控器操作函数====================================
|
||||
// 发送CCU控制命令
|
||||
bool sendCcuCommand(const ccuColCmd cmd);
|
||||
bool sendDisSysCommand(const disSysBreakerList& cmd); //已废弃,不同时操作多个继电器设备
|
||||
|
||||
// 启动/停止监听线程
|
||||
void startListenThread();
|
||||
void stopListenThread();
|
||||
void coutMsg(const msg_CcuStateFbMsg& p, std::ostream& os = std::cout);
|
||||
|
||||
//转换函数
|
||||
char getBreakerOption(char cmd);
|
||||
|
||||
// 配电和CCU的反馈状态
|
||||
msg_CcuStateFbMsg m_CcuCurrentState;
|
||||
msg_disHighVolBusFbMsg m_disHighVolBusCurrentState;
|
||||
msg_disHighAVolBusFbMsg m_disHighAVolBusCurrentState;
|
||||
msg_disLowMainBusFbMsg m_disHighBVolBusCurrentState;
|
||||
msg_disLowBusFbMsg m_disLowBusState;
|
||||
// 配电和CCU的反馈状态时间戳
|
||||
double msg_CcuStateFbMsg_Update_time;
|
||||
// double msg_CcuSetParmFbMsg_Update_time;
|
||||
double msg_disHighVolBusFbMsg_Update_time;
|
||||
double msg_disHighAVolBusFbMsg_Update_time;
|
||||
double msg_disHighBVolBusFbMsg_Update_time;
|
||||
double msg_disLowBusFbMsg_Update_time;
|
||||
public:
|
||||
long m_port;
|
||||
long m_ccuPort;
|
||||
std::string m_ccuHost;
|
||||
std::string m_host;
|
||||
|
||||
PowerManger* m_pm;
|
||||
udpComm* m_udpComm;
|
||||
|
||||
CMOOSThread m_ListenThread;
|
||||
int m_connectState;
|
||||
|
||||
// UDP监听线程函数
|
||||
bool listenThreadFunc();
|
||||
};
|
||||
|
||||
#endif // LOWER_COMM_MANAGER_H
|
||||
@@ -1,403 +0,0 @@
|
||||
/************************************************************/
|
||||
/* 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 = {};
|
||||
//初始化控制指令
|
||||
initControlCmd();
|
||||
|
||||
//初始化下位机通信
|
||||
m_lowerCommManager = new LowerCommManager(this,IPORT,CCUPORT,CCUHOST);
|
||||
m_lowerCommManager->initUdpComm();
|
||||
m_lowerCommManager->startListenThread();
|
||||
|
||||
//初始化上位机通信
|
||||
m_upperCommManager = new UpperCommManager(this);
|
||||
|
||||
//初始化数据库
|
||||
m_db = new SQLite("power_data.db");
|
||||
m_db->createTable();
|
||||
|
||||
//初始化系统数据
|
||||
m_systemData = new SystemData();
|
||||
|
||||
//初始化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();
|
||||
delete m_db;
|
||||
delete m_lowerCommManager;
|
||||
delete m_upperCommManager;
|
||||
delete m_systemData;
|
||||
delete m_httpServer;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------
|
||||
// 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());
|
||||
|
||||
STRING_LIST::iterator p;
|
||||
for(p=sParams.begin(); p!=sParams.end(); p++) {
|
||||
string orig = *p;
|
||||
string line = *p;
|
||||
string param = tolower(biteStringX(line, '='));
|
||||
string value = line;
|
||||
|
||||
bool handled = false;
|
||||
if(param == "foo") {
|
||||
handled = true;
|
||||
}
|
||||
else if(param == "bar") {
|
||||
handled = true;
|
||||
}
|
||||
|
||||
if(!handled)
|
||||
reportUnhandledConfigWarning(orig);
|
||||
|
||||
}
|
||||
|
||||
registerVariables();
|
||||
|
||||
// 初始化状态机
|
||||
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 = 8; //默认为8kw
|
||||
m_CcuColCmd.insChargeEnable = 0x30; //不允许充电
|
||||
m_CcuColCmd.insBatCmd = 0x00; //无效指令
|
||||
m_CcuColCmd.powerBatCmd = 0x00; //无效指令
|
||||
m_CcuColCmd.powerBatEfficiency = 00; //默认为最大
|
||||
m_CcuColCmd.heartbeat = 0;
|
||||
m_CcuColCmd.masterState = 0xAA;//主站状态,运行中
|
||||
//================初始化上位机指令=========================
|
||||
m_msCmd.modCMD = 99;
|
||||
m_msCmd.powerCMD = 99;
|
||||
m_msCmd.workCMD = 99;
|
||||
//================初始化设备驱动指令========================
|
||||
|
||||
}
|
||||
|
||||
unsigned char PowerManger::getFaultLevel()
|
||||
{
|
||||
unsigned char maxLevel = 0;
|
||||
for (auto code : faultCode) {
|
||||
// 提取0xabcd中的b位 (右移8位后取低4位)
|
||||
unsigned char level = (code >> 8) & 0xF;
|
||||
if (level > maxLevel) {
|
||||
maxLevel = level;
|
||||
}
|
||||
}
|
||||
return maxLevel;
|
||||
}
|
||||
|
||||
bool PowerManger::commLoop()
|
||||
{
|
||||
while(!m_commThread.IsQuitRequested())
|
||||
{
|
||||
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();
|
||||
}
|
||||
@@ -1,165 +0,0 @@
|
||||
/*
|
||||
* @Author: zhaojingkui 1553836110@qq.com
|
||||
* @Date: 2024-10-22 16:47:01
|
||||
* @LastEditors: zhaojingkui 1553836110@qq.com
|
||||
* @LastEditTime: 2024-10-22 18:03:29
|
||||
* @FilePath: /H100PowerManger/src/pPowerManger/PowerManger.h
|
||||
* @Description:
|
||||
*
|
||||
* Copyright (c) 2024 by ${git_name_email}, All Rights Reserved.
|
||||
*/
|
||||
/************************************************************/
|
||||
/* NAME: */
|
||||
/* ORGN: MIT, Cambridge MA */
|
||||
/* FILE: PowerManger.h */
|
||||
/* DATE: December 29th, 1963 */
|
||||
/************************************************************/
|
||||
|
||||
#ifndef PowerManger_HEADER
|
||||
#define PowerManger_HEADER
|
||||
#define UNIX
|
||||
#define JSON_USE_EXCEPTION 1
|
||||
|
||||
#include <queue>
|
||||
#include "logc/loguru.hpp"
|
||||
#include "MOOS/libMOOS/Thirdparty/AppCasting/AppCastingMOOSApp.h"
|
||||
#include "MOOS/libMOOS/Utils/MOOSThread.h"
|
||||
#include "MOOS/libMOOS/Utils/MOOSUtilityFunctions.h"
|
||||
#include "MOOS/libMOOS/Utils/ConsoleColours.h"
|
||||
#include "../udpcomm/ccuUdpMsg.h"
|
||||
#include "json/json.h"
|
||||
#include "udpcomm/udpComm.h"
|
||||
#include "pmSysvariable.h"
|
||||
#include "fsm/PowerManagerFsm.hpp"
|
||||
#include "driver.h"
|
||||
#include "LowerCommManager.h"
|
||||
#include "UpperCommManager.h"
|
||||
#include "sqlit3/SQLite.h"
|
||||
#include "systemData.h"
|
||||
#include "httpserver/httpserver.h"
|
||||
#include "faultCode.h"
|
||||
#define IPORT 5001
|
||||
#define CCUPORT 7000
|
||||
#define CCUHOST "192.168.0.140"
|
||||
// #define CCUHOST "127.0.0.0"
|
||||
#define MAX_UDP_PKT_SIZE 65535
|
||||
#define SKEW_TOLERANCE 5
|
||||
|
||||
class PowerManger : public AppCastingMOOSApp
|
||||
{
|
||||
public:
|
||||
PowerManger();
|
||||
~PowerManger();
|
||||
public:
|
||||
bool FsmLoop();
|
||||
|
||||
protected: // Standard MOOSApp functions to overload
|
||||
bool OnNewMail(MOOSMSG_LIST &NewMail);
|
||||
bool Iterate();
|
||||
bool OnConnectToServer();
|
||||
bool OnStartUp();
|
||||
bool buildReport();
|
||||
void registerVariables();
|
||||
|
||||
public:
|
||||
void updateTime(){m_current_time = MOOSTime();}
|
||||
unsigned char getFaultLevel();
|
||||
//数据库
|
||||
SQLite* m_db;
|
||||
//http
|
||||
HttpServer* m_httpServer;
|
||||
//系统数据
|
||||
SystemData* m_systemData;
|
||||
/************************************************************/
|
||||
/* |<------------FEEDBACK--------<-- */
|
||||
/* | | */
|
||||
/* IN-->+-------[STATE CONTROL]---------+--->OUT */
|
||||
/* */
|
||||
/************************************************************/
|
||||
public:
|
||||
//===========================IN============================================
|
||||
DriverTable m_MSDriverCmd;
|
||||
MSControlCmd m_msCmd;
|
||||
//===========================OUT===========================================
|
||||
DriverTable m_subDisSysCmd;
|
||||
ccuColCmd m_CcuColCmd;
|
||||
disSysBreakerList m_targetDisBreakerState;
|
||||
//===========================FEEDBACK======================================
|
||||
pmState m_pmCurrentState; //能源系统的当前状态(由下位机线程修改)
|
||||
disSysBreakerList m_currentDisBreakerState; //配电断路器状态
|
||||
DriverTable m_currentDriverState;
|
||||
DriverTable m_subDisSysState;
|
||||
DriverTable m_subDisSysFault;
|
||||
int m_depth;
|
||||
MissionState m_missionState;
|
||||
//===========================STATE=========================================
|
||||
unsigned char workCondition;
|
||||
unsigned char currentMod;
|
||||
unsigned char powerState;
|
||||
unsigned char faultLevel;
|
||||
vector<unsigned int> faultCode;
|
||||
|
||||
unsigned int soc;
|
||||
unsigned int sustainableTime;
|
||||
unsigned int m_faultNum;
|
||||
Driver m_driver; //设备表处理
|
||||
unsigned char m_leakage;
|
||||
std::set<unsigned int> m_faultCodes;
|
||||
int m_thrustRpm;
|
||||
int m_thrustEnable;
|
||||
// std::set<unsigned int> m_disSysFaultCodes;
|
||||
//============================Device Option================================
|
||||
std::queue<DeviceSwitchCmd> m_deviceCmdQuenue;
|
||||
mutable std::mutex m_deviceCmdMutex;
|
||||
void pushDeviceCommand(DeviceSwitchCmd cmd);
|
||||
bool popDeviceCommand(DeviceSwitchCmd &cmd);
|
||||
bool isDeviceCmdEmpty() const;
|
||||
//===========================CONFIG========================================
|
||||
long m_lPort;
|
||||
unsigned int m_nReceiveBufferSizeKB;
|
||||
unsigned int m_nSendBufferSizeKB;
|
||||
double m_current_time;
|
||||
unsigned int m_ticker;
|
||||
double m_skew;
|
||||
int connectState;
|
||||
//=============================过程函数======================================
|
||||
void initControlCmd();
|
||||
|
||||
public:
|
||||
CMOOSThread m_commThread;
|
||||
LowerCommManager* m_lowerCommManager;
|
||||
UpperCommManager* m_upperCommManager;
|
||||
|
||||
// PowerManagerFsm m_fsm;
|
||||
|
||||
public:
|
||||
//===========================状态机接口=======================================
|
||||
void printState(const std::string& stateName, const std::string& desp);
|
||||
bool FSM_RUN_IS_OK = true;
|
||||
|
||||
//==================================================================================
|
||||
bool commLoop();
|
||||
int checkError();
|
||||
|
||||
bool sendNotification(const std::string& key, const std::string& value) {
|
||||
return Notify(key, value);
|
||||
}
|
||||
bool sendNotification(const std::string& key, double value) {
|
||||
return Notify(key, value);
|
||||
}
|
||||
public:
|
||||
double GetPublicAppFreq() { return GetAppFreq(); }
|
||||
unsigned int GetPublicCommsFreq() { return GetCommsFreq(); }
|
||||
double GetPublicAppStartTime() { return GetAppStartTime(); }
|
||||
double GetPublicCPULoad() { return GetCPULoad(); }
|
||||
double GetPublicTimeSinceIterate() { return GetTimeSinceIterate(); }
|
||||
double GetPublicLastIterateTime() { return GetLastIterateTime(); }
|
||||
int GetPublicIterateCount() { return GetIterateCount(); }
|
||||
string GetServerHost() { return m_sServerHost; }
|
||||
int GetServerPort() { return m_lServerPort; }
|
||||
public:
|
||||
//故障注入
|
||||
void injectFault(unsigned type,unsigned int faultCode);
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -1,18 +0,0 @@
|
||||
/****************************************************************/
|
||||
/* NAME: */
|
||||
/* ORGN: MIT, Cambridge MA */
|
||||
/* FILE: PowerManger_Info.h */
|
||||
/* DATE: Dececmber 29th, 1963 */
|
||||
/****************************************************************/
|
||||
|
||||
#ifndef PowerManger_INFO_HEADER
|
||||
#define PowerManger_INFO_HEADER
|
||||
|
||||
void showSynopsis();
|
||||
void showHelpAndExit();
|
||||
void showExampleConfigAndExit();
|
||||
void showInterfaceAndExit();
|
||||
void showReleaseInfoAndExit();
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,242 +0,0 @@
|
||||
#include "UpperCommManager.h"
|
||||
#include "PowerManger.h"
|
||||
#include "driver.h"
|
||||
#include "fsm/PowerManagerFsm.hpp"
|
||||
|
||||
UpperCommManager::UpperCommManager(PowerManger* pm) :
|
||||
m_pm(pm),
|
||||
m_secdistStateMsg(),
|
||||
m_setOpConditionMsg(),
|
||||
m_depthMsg(),
|
||||
m_taskStartMsg(),
|
||||
m_equInsStateMsg(),
|
||||
m_equStateMsg(),
|
||||
m_setPMSysMsg(),
|
||||
m_disSysStateMsg(),
|
||||
m_currentStateMsg(),
|
||||
m_pmStateMsg(),
|
||||
m_fcsStateMsg(),
|
||||
m_liBatStateMsg(),
|
||||
m_setOpModeMsg(),
|
||||
m_taskStopMsg(),
|
||||
m_setDevSwitchMsg(),
|
||||
m_sysStateMsg(),
|
||||
m_msCmd(),
|
||||
m_driver() {
|
||||
}
|
||||
DriverTable uDevice_secdistStateMsg::fault_state = {0};
|
||||
|
||||
bool UpperCommManager::processUpperMsg(const string& key, const string& strJson) {
|
||||
if (key == m_sysStateMsg.key)
|
||||
{
|
||||
#ifdef _DEBUG
|
||||
m_sysStateMsg_st_debug = std::make_pair(key, strJson);
|
||||
#endif
|
||||
m_pm->m_msCmd = m_sysStateMsg.getMasterControlCmd(key, strJson);
|
||||
MasterCommandEvent event;
|
||||
PowerManagerFsm::dispatch(event);
|
||||
return true;
|
||||
}
|
||||
// 设备状态处理
|
||||
else if(key == m_equStateMsg.key_cmd)
|
||||
{
|
||||
#ifdef _DEBUG
|
||||
m_equStateMsg_cmd_debug = std::make_pair(key, strJson);
|
||||
#endif
|
||||
m_pm->m_MSDriverCmd = m_equStateMsg.getEquipmentCmd(key, strJson);
|
||||
vector<DriverCommand> devCmdExt = m_pm->m_driver.loadDriverIdFromJson(strJson);
|
||||
if (devCmdExt.empty())
|
||||
{
|
||||
LOG_F(WARNING, "控制指令为空");
|
||||
}
|
||||
else {
|
||||
for (auto& cmd : devCmdExt) {
|
||||
DevCmdExt event(cmd.id, cmd.cmd);
|
||||
PowerManagerFsm::dispatch(event);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
// 次级配电状态处理
|
||||
else if(key == m_secdistStateMsg.key_fb)
|
||||
{
|
||||
#ifdef _DEBUG
|
||||
m_secdistStateMsg_fb_debug = std::make_pair(key, strJson);
|
||||
#endif
|
||||
m_secdistStateMsg.parseMsg(strJson, m_pm->m_subDisSysState);
|
||||
//TODO:自动更新到设备状态 调试
|
||||
//m_pm->m_subDisSysState = m_pm->m_deviceState;
|
||||
return true;
|
||||
}
|
||||
// 深度获取
|
||||
else if(key == m_depthMsg.key)
|
||||
{
|
||||
#ifdef _DEBUG
|
||||
m_depthMsg_st_debug = std::make_pair(key, strJson);
|
||||
#endif
|
||||
m_pm->m_depth = m_depthMsg.getDepth(key, strJson);
|
||||
return true;
|
||||
}
|
||||
else if(key == m_taskStartMsg.key)
|
||||
{
|
||||
#ifdef _DEBUG
|
||||
m_taskStartMsg_st_debug = std::make_pair(key, strJson);
|
||||
#endif
|
||||
m_pm->m_missionState = m_taskStartMsg.getMission(key, strJson);
|
||||
TaskStartEvent event;
|
||||
event.type = m_pm->m_missionState.type;
|
||||
event.enableBowRudder = m_pm->m_missionState.enableBowRudder;
|
||||
event.enableBuoyancyAdjustment = m_pm->m_missionState.enableBuoyancyAdjustment;
|
||||
PowerManagerFsm::dispatch(event);
|
||||
return true;
|
||||
}
|
||||
else if(key == m_setOpModeMsg.key)
|
||||
{
|
||||
#ifdef _DEBUG
|
||||
m_setOpModeMsg_st_debug = std::make_pair(key, strJson);
|
||||
#endif
|
||||
m_pm->m_msCmd.modCMD = m_setOpModeMsg.getSetOpMode(key, strJson);
|
||||
MasterCommandEvent event;
|
||||
PowerManagerFsm::dispatch(event);
|
||||
return true;
|
||||
} else if(key == m_setOpConditionMsg.key)
|
||||
{
|
||||
#ifdef _DEBUG
|
||||
m_setOpConditionMsg_st_debug = std::make_pair(key, strJson);
|
||||
#endif
|
||||
m_pm->m_msCmd.workCMD = m_setOpConditionMsg.getSetOpCondition(key, strJson);
|
||||
MasterCommandEvent event;
|
||||
PowerManagerFsm::dispatch(event);
|
||||
return true;
|
||||
}
|
||||
else if(key == m_setPMSysMsg.key)
|
||||
{
|
||||
#ifdef _DEBUG
|
||||
m_setPMSysMsg_st_debug = std::make_pair(key, strJson);
|
||||
#endif
|
||||
m_pm->m_msCmd.powerCMD = m_setPMSysMsg.getSetPMSys(key, strJson);
|
||||
MasterCommandEvent event;
|
||||
PowerManagerFsm::dispatch(event);
|
||||
return true;
|
||||
}
|
||||
else if(key == m_setDevSwitchMsg.key)
|
||||
{
|
||||
#ifdef _DEBUG
|
||||
m_setDevSwitchMsg_st_debug = std::make_pair(key, strJson);
|
||||
#endif
|
||||
DeviceSwitchCmd cmd;
|
||||
cmd = m_setDevSwitchMsg.getSetDevSwitch(key, strJson);
|
||||
if (cmd.id < 0) {
|
||||
LOG_F(WARNING, "parse device switch error:%s", strJson.c_str());
|
||||
}
|
||||
else
|
||||
{
|
||||
DevCmdExt devCmdExt;
|
||||
devCmdExt.id = cmd.id;
|
||||
devCmdExt.cmd = cmd.cmd;
|
||||
PowerManagerFsm::dispatch(devCmdExt);
|
||||
LOG_F(INFO, "set dev switch success");
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else if(key == m_taskStopMsg.key)
|
||||
{
|
||||
#ifdef _DEBUG
|
||||
m_taskStopMsg_st_debug = std::make_pair(key, strJson);
|
||||
#endif
|
||||
bool stop = m_taskStopMsg.getTaskStop(key, strJson);
|
||||
if (stop) {
|
||||
LOG_F(INFO, "task stop success");
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
LOG_F(WARNING, "task stop error:%s", strJson.c_str());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if(key == uDetect_xcVoltage_cmd::key)
|
||||
{
|
||||
uDetect_xcVoltage_cmd xcCmd;
|
||||
xcCmd.xcHighVoltageAdd_int32 = 0;
|
||||
xcCmd.xcLowVoltageAdd_int32 = 0;
|
||||
xcCmd.fromJsonString(strJson);
|
||||
SideSonarCmd sideSonarCmd;
|
||||
sideSonarCmd.xcHighVoltageAdd = xcCmd.xcHighVoltageAdd_int32;
|
||||
sideSonarCmd.xcLowVoltageAdd = xcCmd.xcLowVoltageAdd_int32;
|
||||
PowerManagerFsm::dispatch(sideSonarCmd);
|
||||
return true;
|
||||
}
|
||||
else if(key == uDetect_zdpVoltage_cmd::key)
|
||||
{
|
||||
uDetect_zdpVoltage_cmd zdpCmd;
|
||||
zdpCmd.fromJsonString(strJson);
|
||||
|
||||
DevCmdExt devCmdExt;
|
||||
devCmdExt.id = DeviceId::lowFreqSonar;
|
||||
devCmdExt.cmd = zdpCmd.zdpVoltageAdd_int32;
|
||||
PowerManagerFsm::dispatch(devCmdExt);
|
||||
LOG_F(INFO, "set dev switch success");
|
||||
return true;
|
||||
}
|
||||
else if(key == uDevice_thruster_st::key)
|
||||
{
|
||||
uDevice_thruster_st thrusterSt;
|
||||
thrusterSt.fromJsonString(strJson);
|
||||
m_pm->m_thrustRpm = thrusterSt.rpm_int16;
|
||||
if(thrusterSt.maxTorque_uint16 == 0)
|
||||
m_pm->m_thrustEnable = 0;
|
||||
else
|
||||
m_pm->m_thrustEnable = 1;
|
||||
return true;
|
||||
};
|
||||
LOG_F(WARNING, "Unknown key: %s", key.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
void UpperCommManager::processPeriodicTasks() {
|
||||
buildSystemReport();
|
||||
std::string strJson;
|
||||
//发送当前设备状态
|
||||
strJson = m_equStateMsg.buildMsg(m_pm->m_currentDriverState);
|
||||
m_pm->sendNotification(m_equStateMsg.key, strJson);
|
||||
//发送次级配电指令 修改后的代码
|
||||
strJson = m_secdistStateMsg.buildMsg(m_pm->m_subDisSysCmd,m_pm->m_subDisSysState, m_pm->m_subDisSysFault);
|
||||
m_pm->sendNotification(m_secdistStateMsg.key_cmd, strJson);
|
||||
//发送仪表电状态
|
||||
m_pm->sendNotification(m_equInsStateMsg.key,m_equInsStateMsg.buildMsg(m_pm->m_subDisSysState));
|
||||
#ifdef _DEBUG
|
||||
m_equInsStateMsg_fb_degub = std::make_pair(m_equInsStateMsg.key,m_equInsStateMsg.buildMsg(m_pm->m_subDisSysState));
|
||||
m_secdistStateMsg_cmd_debug = std::make_pair(m_secdistStateMsg.key_cmd,strJson);
|
||||
m_equStateMsg_fb_debug = std::make_pair(m_equStateMsg.key_cmd,m_equStateMsg.buildMsg(m_pm->m_currentDriverState));
|
||||
strJson = m_pm->m_driver.saveDriverTableToJson(&m_pm->m_subDisSysFault);
|
||||
m_pm->sendNotification("uPower_subDisFault_st",strJson);
|
||||
#endif
|
||||
}
|
||||
|
||||
void UpperCommManager::buildSystemReport() {
|
||||
m_pmStateMsg.state.workCondition = m_pm->workCondition;
|
||||
m_pmStateMsg.state.currentMod = m_pm->currentMod;
|
||||
m_pmStateMsg.state.powerState = m_pm->powerState;
|
||||
m_pmStateMsg.state.faultLevel = m_pm->faultLevel;
|
||||
m_pmStateMsg.state.faultCode = m_pm->faultCode;
|
||||
// cout << "m_pmStateMsg.state.faultCode.size():" << m_pmStateMsg.state.faultCode.size() << endl;
|
||||
m_pmStateMsg.state.soc = m_pm->soc;
|
||||
m_pmStateMsg.state.sustainableTime = m_pm->sustainableTime;
|
||||
// m_pmStateMsg.state.m_leakage = m_pm->m_leakage;
|
||||
m_pmStateMsg.state.m_leakage = m_pm->m_systemData->generateLeakageCode();
|
||||
m_pmStateMsg.state.m_faultNum = m_pm->m_faultNum;
|
||||
|
||||
m_pm->sendNotification(m_pmStateMsg.key, m_pmStateMsg.buildMsg(*(m_pm->m_systemData)));
|
||||
m_pm->sendNotification(m_fcsStateMsg.key, m_fcsStateMsg.buildMsg(*(m_pm->m_systemData)));
|
||||
m_pm->sendNotification(m_liBatStateMsg.key, m_liBatStateMsg.buildMsg(*(m_pm->m_systemData)));
|
||||
m_pm->sendNotification(m_disSysStateMsg.key, m_disSysStateMsg.buildMsg(*(m_pm->m_systemData),m_pm->m_currentDisBreakerState));
|
||||
m_pm->sendNotification(m_currentStateMsg.key, m_currentStateMsg.buildMsg(m_pm->m_pmCurrentState));
|
||||
|
||||
#ifdef _DEBUG
|
||||
m_pmStateMsg_fb_debug = std::make_pair(m_pmStateMsg.key, m_pmStateMsg.buildMsg(*(m_pm->m_systemData)));
|
||||
m_fcsStateMsg_st_debug = std::make_pair(m_fcsStateMsg.key, m_fcsStateMsg.buildMsg(*(m_pm->m_systemData)));
|
||||
m_liBatStateMsg_st_debug = std::make_pair(m_liBatStateMsg.key, m_liBatStateMsg.buildMsg(*(m_pm->m_systemData)));
|
||||
m_disSysStateMsg_st_debug = std::make_pair(m_disSysStateMsg.key, m_disSysStateMsg.buildMsg(*(m_pm->m_systemData),m_pm->m_currentDisBreakerState));
|
||||
m_currentStateMsg_st_debug = std::make_pair(m_currentStateMsg.key, m_currentStateMsg.buildMsg(m_pm->m_pmCurrentState));
|
||||
#endif
|
||||
}
|
||||
@@ -1,118 +0,0 @@
|
||||
#ifndef UPPER_COMM_MANAGER_H
|
||||
#define UPPER_COMM_MANAGER_H
|
||||
|
||||
#include "MOOS/libMOOS/Thirdparty/AppCasting/AppCastingMOOSApp.h"
|
||||
#include "pmSysvariable.h"
|
||||
#include "driver.h"
|
||||
#include "json/json.h"
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
#include "upmsg/uPower_equInsState.h"
|
||||
#include "upmsg/uDevice_secdistState.h"
|
||||
#include "upmsg/uPower_equState.h"
|
||||
#include "upmsg/uPower_disSysState.h"
|
||||
#include "upmsg/uPower_currentState_st.h"
|
||||
#include "upmsg/uPower_pmState.h"
|
||||
#include "upmsg/uPower_fcsState.h"
|
||||
#include "upmsg/uPower_liBatState.h"
|
||||
#include "upmsg/uDevice_depth.h"
|
||||
#include "upmsg/uExternComm_setOpCondition.h"
|
||||
#include "upmsg/uExternComm_setOpMode.h"
|
||||
#include "upmsg/uPlan_taskStart.h"
|
||||
#include "upmsg/uPlan_planStop.h"
|
||||
#include "upmsg/uExternComm_setDeviceSwitch.h"
|
||||
#include "upmsg/uExternComm_setPowerSystem.h"
|
||||
#include "upmsg/uPower_equState.h"
|
||||
#include "upmsg/uPower_sysState.h"
|
||||
#include "upmsg/uDetect_zdpVoltage_cmd.h"
|
||||
#include "upmsg/uDetect_xcVoltage_cmd.h"
|
||||
#include "upmsg/uDevice_thruster_st.h"
|
||||
|
||||
#define _DEBUG
|
||||
|
||||
using namespace std;
|
||||
#define VAR_TO_STR(var) #var
|
||||
//控制消息
|
||||
#define DB_TO_PM_MSCMD "uPower_sysState_cmd"
|
||||
#define DB_TO_PM_EQUIPMENTCMD "uPower_equState_cmd"
|
||||
|
||||
//决策消息
|
||||
#define DB_TO_PM_DEEPTH "uDevice_depth_st"
|
||||
// #define DB_TO_PM_MISSION "uPlan_taskStart_cmd"
|
||||
#define DB_TO_PM_TASKSTOP "uPlan_planStop_st"
|
||||
|
||||
//外部通信消息
|
||||
#define DB_TO_PM_SETOPCONDITION "uExternComm_setOpCondition_cmd"
|
||||
#define DB_TO_PM_SETOPMODE "uExternComm_setOpMode_cmd"
|
||||
#define DB_TO_PM_SETPMSYS "uExternComm_setPowerSystem_cmd"
|
||||
#define DB_TO_PM_SETDEVSWITCH "uExternComm_setDeviceSwitch_cmd"
|
||||
|
||||
class PowerManger; // 前向声明
|
||||
|
||||
class UpperCommManager {
|
||||
public:
|
||||
UpperCommManager(PowerManger* powerManager);
|
||||
~UpperCommManager(){};
|
||||
|
||||
// 周期调用
|
||||
void processPeriodicTasks();
|
||||
|
||||
// 处理上位机消息
|
||||
bool processUpperMsg(const std::string& key, const std::string& msg);
|
||||
|
||||
// 生成系统报告
|
||||
void buildSystemReport();
|
||||
|
||||
public:
|
||||
//定义上位机消息
|
||||
uPower_equInsStateMsg m_equInsStateMsg;
|
||||
uDevice_secdistStateMsg m_secdistStateMsg;
|
||||
uPower_equStateMsg m_equStateMsg;
|
||||
uPower_disSysStateMsg m_disSysStateMsg;
|
||||
uPower_currentStateMsg m_currentStateMsg;
|
||||
uPower_pmStateMsg m_pmStateMsg;
|
||||
uPower_fcsStateMsg m_fcsStateMsg;
|
||||
uPower_liBatStateMsg m_liBatStateMsg;
|
||||
|
||||
//上位机订阅消息
|
||||
uDevice_depthMsg m_depthMsg;
|
||||
uExternComm_setOpConditionMsg m_setOpConditionMsg;
|
||||
uExternComm_setOpModeMsg m_setOpModeMsg;
|
||||
uPlan_taskStartMsg m_taskStartMsg;
|
||||
uPlan_planStopMsg m_taskStopMsg;
|
||||
uExternComm_setDeviceSwitchMsg m_setDevSwitchMsg;
|
||||
uExternComm_setPowerSystemMsg m_setPMSysMsg;
|
||||
uPower_sysStateMsg m_sysStateMsg;
|
||||
private:
|
||||
PowerManger* m_pm;
|
||||
MSControlCmd m_msCmd;
|
||||
Driver m_driver;
|
||||
|
||||
#ifdef _DEBUG
|
||||
public:
|
||||
std::pair<string, string> m_equInsStateMsg_fb_degub;
|
||||
std::pair<string, string> m_secdistStateMsg_cmd_debug;
|
||||
std::pair<string, string> m_secdistStateMsg_fb_debug;
|
||||
|
||||
std::pair<string, string> m_equStateMsg_cmd_debug;
|
||||
std::pair<string, string> m_equStateMsg_fb_debug;
|
||||
std::pair<string, string> m_disSysStateMsg_st_debug;
|
||||
std::pair<string, string> m_currentStateMsg_st_debug;
|
||||
std::pair<string, string> m_pmStateMsg_fb_debug;
|
||||
std::pair<string, string> m_fcsStateMsg_st_debug;
|
||||
std::pair<string, string> m_liBatStateMsg_st_debug;
|
||||
|
||||
std::pair<string, string> m_depthMsg_st_debug;
|
||||
std::pair<string, string> m_setOpConditionMsg_st_debug;
|
||||
std::pair<string, string> m_setOpModeMsg_st_debug;
|
||||
std::pair<string, string> m_taskStartMsg_st_debug;
|
||||
std::pair<string, string> m_taskStopMsg_st_debug;
|
||||
std::pair<string, string> m_setDevSwitchMsg_st_debug;
|
||||
std::pair<string, string> m_setPMSysMsg_st_debug;
|
||||
std::pair<string, string> m_sysStateMsg_st_debug;
|
||||
#endif
|
||||
// bool parseControlCmdFromJson(MSControlCmd &cmd, const std::string &strJson);
|
||||
};
|
||||
|
||||
#endif // UPPER_COMM_MANAGER_H
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,138 +0,0 @@
|
||||
#ifndef DRIVER_H
|
||||
#define DRIVER_H
|
||||
#include <memory>
|
||||
#include "json/json.h"
|
||||
#include "iostream"
|
||||
#include <sstream>
|
||||
#include <vector>
|
||||
#include "pmSysvariable.h"
|
||||
|
||||
#define DRIVER_POWER_OFF 0x00
|
||||
#define DRIVER_FULL_POWER_ON 0x01
|
||||
#define DRIVER_INSTRUMENT_POWER_ON 0x02
|
||||
#define DRIVER_MOTIVE_POWER_ON 0x03
|
||||
#define DRIVER_STANDBY 0x04
|
||||
|
||||
using namespace std;
|
||||
struct DriverTable
|
||||
{
|
||||
unsigned char depth1;
|
||||
unsigned char depth2;
|
||||
unsigned char depth3;
|
||||
unsigned char overDeep1;
|
||||
unsigned char overDeep2;
|
||||
unsigned char ctd1;
|
||||
unsigned char ctd2;
|
||||
unsigned char soundVeloc;
|
||||
unsigned char commMast;
|
||||
unsigned char ins;
|
||||
unsigned char ntp;
|
||||
unsigned char inputWaterSensor1;
|
||||
unsigned char inputWaterSensor2;
|
||||
unsigned char inputWaterSensor3;
|
||||
//水声设备
|
||||
unsigned char singleBeamSonar1;
|
||||
unsigned char singleBeamSonar2;
|
||||
unsigned char singleBeamSonar3;
|
||||
unsigned char singleBeamSonar4;
|
||||
unsigned char singleBeamSonar5;
|
||||
unsigned char singleBeamSonar6;
|
||||
unsigned char singleBeamSonar7;
|
||||
unsigned char singleBeamSonar8;
|
||||
unsigned char forwardSonar;
|
||||
unsigned char DVL;
|
||||
unsigned char lowFreqSonar;
|
||||
unsigned char USBL;
|
||||
//执行机构
|
||||
unsigned char bowWaterInet1;
|
||||
unsigned char bowWaterInet2;
|
||||
unsigned char bowWaterInet3;
|
||||
unsigned char bowWaterInet4;
|
||||
unsigned char bowWaterInet5;
|
||||
unsigned char bowWaterInet6;
|
||||
unsigned char bowWaterInet7;
|
||||
unsigned char bowWaterInet8;
|
||||
unsigned char bowRudderDeploy;
|
||||
unsigned char bowRudderServo1;
|
||||
unsigned char bowRudderServo2;
|
||||
unsigned char bowCover1;
|
||||
unsigned char bowCover2;
|
||||
unsigned char bowCover3;
|
||||
unsigned char bowCover4;
|
||||
unsigned char bowCover5;
|
||||
unsigned char bowCover6;
|
||||
unsigned char waterInject;
|
||||
unsigned char mastLiftingServo;
|
||||
unsigned char buoyancyAdjust1;
|
||||
unsigned char buoyancyAdjust2;
|
||||
unsigned char buoyancyAdjust3;
|
||||
unsigned char buoyancyAdjust4;
|
||||
unsigned char buoyancyAdjust5;
|
||||
unsigned char sternRudderServo1;
|
||||
unsigned char sternRudderServo2;
|
||||
unsigned char sternRudderServo3;
|
||||
unsigned char sternRudderServo4;
|
||||
unsigned char thruster;
|
||||
unsigned char bowThrow;
|
||||
unsigned char sternThrow;
|
||||
//负载
|
||||
unsigned char photoSensor;
|
||||
unsigned char electSensor;
|
||||
unsigned char launchControler;
|
||||
unsigned char sideSonar;
|
||||
unsigned char buoyage;
|
||||
};
|
||||
|
||||
struct DriverCommand
|
||||
{
|
||||
int id;
|
||||
int cmd;
|
||||
};
|
||||
|
||||
|
||||
class Driver
|
||||
{
|
||||
public:
|
||||
Driver();
|
||||
~Driver();
|
||||
void setDebug(bool debug);
|
||||
|
||||
public:
|
||||
std::unique_ptr<DriverTable> currentDriverTable;
|
||||
std::unique_ptr<DriverTable> nextDriverTable;
|
||||
|
||||
//操作函数,操作指定设备
|
||||
void setDeviceState(DriverTable &driverTable, DeviceId::Type deviceId, unsigned char s);
|
||||
unsigned char getDeviceState(const DriverTable &driverTable, DeviceId::Type deviceId);
|
||||
|
||||
void getSTANDBYTable(DriverTable* driverTable);
|
||||
void getSHORE_BASED_READYable(DriverTable* driverTable);
|
||||
void getWATER_BASED_READYable(DriverTable* driverTable);
|
||||
void getCRUISE_MODEable(DriverTable* driverTable);
|
||||
void getHIGH_SPEED_MODEable(DriverTable* driverTable);
|
||||
void getASCEND_DESCENDable(DriverTable* driverTable);
|
||||
void getBUOYANCY_ADJUSTable(DriverTable* driverTable);
|
||||
void getUNDERWATER_RECONable(DriverTable* driverTable);
|
||||
void getSURFACE_RECONable(DriverTable* driverTable);
|
||||
void getDJ_MODEable(DriverTable* driverTable);
|
||||
|
||||
// void setDriverTable(DriverTable* driverTable, );
|
||||
|
||||
std::string getDriverTableJson();
|
||||
std::string getSubDisCmdJson(const DriverTable* driverTable);
|
||||
std::string getDriveStateJson(const DriverTable* driverTable);
|
||||
|
||||
std::string saveDriverTableToJson(const DriverTable* driverTable);
|
||||
int loadDriverTableFromJson(const std::string &strJson, DriverTable& table);
|
||||
vector<DriverCommand> loadDriverIdFromJson(const std::string &strJson);
|
||||
|
||||
int SafeReadUInt(const Json::Value& root, const std::string& key, unsigned char& value);
|
||||
|
||||
private:
|
||||
|
||||
bool debug;
|
||||
};
|
||||
|
||||
|
||||
|
||||
#endif // DRIVER_H
|
||||
@@ -1,125 +0,0 @@
|
||||
#ifndef FAULTCODE_H
|
||||
#define FAULTCODE_H
|
||||
|
||||
/**
|
||||
* @file faultCode.h
|
||||
* @brief 锂电池故障码定义及映射表
|
||||
*/
|
||||
|
||||
// 故障码映射表
|
||||
typedef struct {
|
||||
int id; // 序号
|
||||
int level; // 故障级别
|
||||
const uint8_t code; // 16进制故障码
|
||||
const char* desc; // 报警信息
|
||||
} FaultMap;
|
||||
|
||||
static const FaultMap batfaultMap[] = {
|
||||
//四级故障
|
||||
{1, 4, 0xC1, "MBMS绝缘故障"},
|
||||
{2, 4, 0xC2, "温度过高"},
|
||||
{3, 4, 0xC3, "MBMS预充失败"},
|
||||
{4, 4, 0xC4, "MBMS正主极继电器失效"},
|
||||
{5, 4, 0xC5, "MBMS负主极继电器失效"},
|
||||
{6, 4, 0xC6, "MBMS燃电充电正极继电器正极失效[仪器]"},
|
||||
{7, 4, 0xC7, "母线高压回路异常"},
|
||||
{8, 4, 0xC9, "MBMS电压测量异常"},
|
||||
{9, 4, 0xCA, "MBMS电流测量异常"},
|
||||
//三级故障
|
||||
{10, 3, 0x81, "MBMS绝缘故障3级"},
|
||||
{11, 3, 0x82, "温度过高3级"},
|
||||
{12, 3, 0x83, "温度过低3级"},
|
||||
{13, 3, 0x84, "MBMS总放电超功率3级"},
|
||||
{14, 3, 0x85, "MBMS总充电电流过大3级"},
|
||||
//二级故障
|
||||
{15, 1, 0x31, "BMS均衡模块故障2级"},
|
||||
{16, 2, 0x41, "MBMS绝缘故障2级"},
|
||||
{17, 2, 0x42, "MBMS总放电超功率2级"},
|
||||
{18, 2, 0x43, "电池包放电超功率2级"},
|
||||
{19, 2, 0x44, "MBMS总放电过流2级"},
|
||||
{20, 2, 0x45, "单包异常剔除2级"},
|
||||
{21, 2, 0x46, "单包没有电流2级"},
|
||||
{22, 2, 0x47, "自检有重复ID号2级"},
|
||||
{23, 2, 0x48, "电池包接入失败2级"},
|
||||
{24, 2, 0x49, "电池包充电电流过大2级"},
|
||||
{25, 2, 0x51, "电池包绝缘故障2级"},
|
||||
{26, 2, 0x52, "电池包温度过高2级"},
|
||||
{27, 2, 0x53, "电池包温度过低2级"},
|
||||
{28, 2, 0x54, "电池包单体电压不均衡2级"},
|
||||
{29, 2, 0x55, "电池包单体温度不均衡2级"},
|
||||
{30, 2, 0x56, "电池包过流2级"},
|
||||
{31, 2, 0x57, "电池包充电电流过大2级"},
|
||||
{32, 2, 0x58, "电池包单体电压过高2级"},
|
||||
{33, 2, 0x59, "电池包单体电压过低2级"},
|
||||
{34, 2, 0x5A, "电池包总电压过高2级"},
|
||||
{35, 2, 0x5B, "电池包总电压过低2级"},
|
||||
{36, 2, 0x5C, "电池包内部通讯故障2级"},
|
||||
{37, 2, 0x5D, "电池包初始化故障2级"},
|
||||
{38, 2, 0x62, "电池包高压回路连接异常2级"},
|
||||
{39, 2, 0x65, "电池包烟雾报警2级"},
|
||||
{40, 2, 0x72, "MBMS在线燃电充电超温2级"},
|
||||
//一级故障
|
||||
{41, 1, 0x01, "MBMS绝缘故障1级"},
|
||||
{42, 1, 0x02, "MBMS总放电超功率1级"},
|
||||
{43, 1, 0x11, "电池包绝缘故障1级"},
|
||||
{44, 1, 0x12, "电池包最高温度过高1级"},
|
||||
{45, 1, 0x13, "电池包最低温度过低1级"},
|
||||
{46, 1, 0x14, "电池包单体电压不均衡1级"},
|
||||
{47, 1, 0x15, "电池包单体温度不均衡1级"},
|
||||
{48, 1, 0x16, "电池包放电过流1级"},
|
||||
{49, 1, 0x17, "电池包充电电流过大1级"},
|
||||
{50, 1, 0x18, "电池包单体电压过高1级"},
|
||||
{51, 1, 0x19, "电池包单体电压过低1级"},
|
||||
{52, 1, 0x1A, "电池包总电压过高1级"},
|
||||
{53, 1, 0x1B, "电池包总电压过低1级"},
|
||||
{54, 1, 0x1D, "电池包烟雾报警1级"},
|
||||
};
|
||||
|
||||
static const FaultMap disfaultMap[] = {
|
||||
{1, 3, 1, "燃料电池断路器故障脱扣"},
|
||||
{2, 4, 2, "动力锂电池断路器故障脱扣"},
|
||||
{3, 4, 3, "推进电机断路器故障脱扣"},
|
||||
{4, 4, 4, "锂电池组仪表断路器故障脱扣"},
|
||||
{5, 4, 5, "DC/DC5模块断路器故障脱扣"},
|
||||
{6, 4, 6, "艏部高压配电箱断路器故障脱扣"},
|
||||
{7, 4, 7, "艉部FT装置4/5断路器故障脱扣"},
|
||||
{8, 4, 8, "艉舵开关1断路器故障脱扣"},
|
||||
{9, 4, 9, "艉舵开关2断路器故障脱扣"},
|
||||
{10, 4, 10, "FB预留断路器故障脱扣"},
|
||||
{11, 4, 11, "TYZ预留断路器故障脱扣"},
|
||||
{12, 4, 12, "预留断路器故障脱扣"},
|
||||
{13, 4, 13, "艏部FT装置1-3 断路器故障脱扣"},
|
||||
{14, 4, 14, "启闭机构断路器故障脱扣"},
|
||||
{15, 4, 15, "桅杆舵机控制箱断路器故障脱扣"},
|
||||
{16, 4, 16, "XCZ 断路器故障脱扣"},
|
||||
{17, 4, 17, "艏舵控制箱断路器故障脱扣"},
|
||||
{18, 4, 18, "敞水盖启动电缸断路器故障脱扣"},
|
||||
{19, 4, 19, "锂电池组(仪表)断路器故障脱扣"},
|
||||
{20, 4, 20, "艏部低压配电箱断路器故障脱扣"},
|
||||
{21, 4, 21, "UNIT4仪表DC48V断路器故障脱扣"},
|
||||
{22, 4, 22, "DC-DC1直流配电板断路器故障脱扣"},
|
||||
{23, 4, 23, "预留断路器故障脱扣"},
|
||||
{24, 4, 24, "预留断路器故障脱扣"},
|
||||
{25, 4, 25, "应急锂电池组2断路器"},
|
||||
{26, 4, 26, "UNIT1断路器故障脱扣"},
|
||||
{27, 4, 27, "UNIT2断路器故障脱扣"},
|
||||
{28, 4, 28, "UNIT3断路器故障脱扣"},
|
||||
{29, 4, 29, "UNIT5断路器故障脱扣"},
|
||||
{30, 4, 30, "艏部PZ装置断路器故障脱扣"},
|
||||
{31, 4, 31, "预留断路器故障脱扣"},
|
||||
{32, 4, 32, "预留断路器故障脱扣"},
|
||||
{33, 4, 33, "应急锂电池组1断路器故障脱扣"},
|
||||
{34, 4, 34, "动力母排绝缘低"},
|
||||
{35, 4, 35, "A汇流排绝缘低"},
|
||||
{36, 4, 36, "高压母线配电控制器仪表电源失电信号"},
|
||||
{37, 4, 37, "高压母线配电控制器应急电源失电信号"},
|
||||
{38, 4, 38, "高压汇流排A仪表电源失电信号"},
|
||||
{39, 4, 39, "高压汇流排A应急电源失电信号"},
|
||||
{40, 4, 40, "高压汇流排A仪表汇流排绝缘低"},
|
||||
{41, 4, 41, "高压汇流排B仪表电源失电信号"},
|
||||
{42, 4, 42, "高压汇流排B应急电源失电信号"},
|
||||
{43, 4, 43, "高压汇流排B仪表汇流排绝缘低"},
|
||||
{44, 4, 44, "仪表汇流排失电信号"},
|
||||
{45, 4, 45, "仪表汇流排浸水报警"}
|
||||
};
|
||||
#endif // FAULTCODE_H
|
||||
@@ -1,59 +0,0 @@
|
||||
#include "PowerManagerFsm.hpp"
|
||||
|
||||
void CruiseMode::entry() {
|
||||
PowerManagerFsm::entry();
|
||||
pm->workCondition = WorkCondition::CHANING;
|
||||
// pm->m_driver.getCRUISE_MODEable(&pm->m_subDisSysCmd);
|
||||
handleCuriseWork();
|
||||
//解除非必要动力电设备
|
||||
//1 解除启闭机构
|
||||
unsigned char cmd = 0;
|
||||
if(pm->m_currentDriverState.bowCover1 != 0 ||
|
||||
pm->m_currentDriverState.bowCover2 != 0 ||
|
||||
pm->m_currentDriverState.bowCover3 != 0 ||
|
||||
pm->m_currentDriverState.bowCover4 != 0 ||
|
||||
pm->m_currentDriverState.bowCover5 != 0 ||
|
||||
pm->m_currentDriverState.bowCover6 != 0)
|
||||
{
|
||||
pm->m_lowerCommManager->operate_HVA_actuatorCircuit_Breaker(0);
|
||||
MOOSPause(3);
|
||||
pm->m_driver.setDeviceState(pm->m_subDisSysCmd, DeviceId::bowCover1, (unsigned char)cmd);
|
||||
pm->m_driver.setDeviceState(pm->m_subDisSysCmd, DeviceId::bowCover2, (unsigned char)cmd);
|
||||
pm->m_driver.setDeviceState(pm->m_subDisSysCmd, DeviceId::bowCover3, (unsigned char)cmd);
|
||||
pm->m_driver.setDeviceState(pm->m_subDisSysCmd, DeviceId::bowCover4, (unsigned char)cmd);
|
||||
pm->m_driver.setDeviceState(pm->m_subDisSysCmd, DeviceId::bowCover5, (unsigned char)cmd);
|
||||
pm->m_driver.setDeviceState(pm->m_subDisSysCmd, DeviceId::bowCover6, (unsigned char)cmd);
|
||||
pm->m_upperCommManager->processPeriodicTasks();
|
||||
}
|
||||
|
||||
//2 解除敞水机构
|
||||
if(pm->m_currentDriverState.bowWaterInet1 != 0 ||
|
||||
pm->m_currentDriverState.bowWaterInet2 != 0 ||
|
||||
pm->m_currentDriverState.bowWaterInet3 != 0 ||
|
||||
pm->m_currentDriverState.bowWaterInet4 != 0 ||
|
||||
pm->m_currentDriverState.bowWaterInet5 != 0 ||
|
||||
pm->m_currentDriverState.bowWaterInet6 != 0 ||
|
||||
pm->m_currentDriverState.bowWaterInet7 != 0 ||
|
||||
pm->m_currentDriverState.bowWaterInet8 != 0)
|
||||
{
|
||||
pm->m_lowerCommManager->operate_HVA_openWaterCoverStartCylinderCircuit_Breaker(0);
|
||||
MOOSPause(3);
|
||||
pm->m_driver.setDeviceState(pm->m_subDisSysCmd, DeviceId::bowWaterInet1, (unsigned char)cmd);
|
||||
pm->m_driver.setDeviceState(pm->m_subDisSysCmd, DeviceId::bowWaterInet2, (unsigned char)cmd);
|
||||
pm->m_driver.setDeviceState(pm->m_subDisSysCmd, DeviceId::bowWaterInet3, (unsigned char)cmd);
|
||||
pm->m_driver.setDeviceState(pm->m_subDisSysCmd, DeviceId::bowWaterInet4, (unsigned char)cmd);
|
||||
pm->m_driver.setDeviceState(pm->m_subDisSysCmd, DeviceId::bowWaterInet5, (unsigned char)cmd);
|
||||
pm->m_driver.setDeviceState(pm->m_subDisSysCmd, DeviceId::bowWaterInet6, (unsigned char)cmd);
|
||||
pm->m_driver.setDeviceState(pm->m_subDisSysCmd, DeviceId::bowWaterInet7, (unsigned char)cmd);
|
||||
pm->m_driver.setDeviceState(pm->m_subDisSysCmd, DeviceId::bowWaterInet8, (unsigned char)cmd);
|
||||
}
|
||||
pm->workCondition = WorkCondition::CRUISE_MODE;
|
||||
LOG_F(INFO, "进入巡航模式");
|
||||
}
|
||||
|
||||
// CruiseMode实现
|
||||
void CruiseMode::react(MasterCommandEvent const &) {
|
||||
PowerManagerFsm::handelPowerCmd();
|
||||
PowerManagerFsm::handleModCmd();
|
||||
PowerManagerFsm::handleWorkCmd();
|
||||
}
|
||||
@@ -1,71 +0,0 @@
|
||||
#include "PowerManagerFsm.hpp"
|
||||
|
||||
|
||||
// DJMode实现
|
||||
void DJMode::react(MasterCommandEvent const &) {
|
||||
PowerManagerFsm::handelPowerCmd();
|
||||
PowerManagerFsm::handleModCmd();
|
||||
PowerManagerFsm::handleWorkCmd();
|
||||
}
|
||||
|
||||
void DJMode::entry() {
|
||||
PowerManagerFsm::entry();
|
||||
pm->workCondition = WorkCondition::CHANING;
|
||||
handleCuriseWork();
|
||||
//1 启动载荷装置
|
||||
pm->m_subDisSysCmd.launchControler = 1;
|
||||
//启动启闭机构和电缸
|
||||
unsigned char cmd = 1;
|
||||
//2.1 启闭机构
|
||||
pm->m_driver.setDeviceState(pm->m_subDisSysCmd, DeviceId::bowCover1, (unsigned char)cmd);
|
||||
pm->m_driver.setDeviceState(pm->m_subDisSysCmd, DeviceId::bowCover2, (unsigned char)cmd);
|
||||
pm->m_driver.setDeviceState(pm->m_subDisSysCmd, DeviceId::bowCover3, (unsigned char)cmd);
|
||||
pm->m_driver.setDeviceState(pm->m_subDisSysCmd, DeviceId::bowCover4, (unsigned char)cmd);
|
||||
pm->m_driver.setDeviceState(pm->m_subDisSysCmd, DeviceId::bowCover5, (unsigned char)cmd);
|
||||
pm->m_driver.setDeviceState(pm->m_subDisSysCmd, DeviceId::bowCover6, (unsigned char)cmd);
|
||||
pm->m_upperCommManager->processPeriodicTasks();
|
||||
MOOSPause(10);
|
||||
pm->m_lowerCommManager->operate_HVA_actuatorCircuit_Breaker(1);
|
||||
//2.2 敞水电缸
|
||||
pm->m_driver.setDeviceState(pm->m_subDisSysCmd, DeviceId::bowWaterInet1, (unsigned char)cmd);
|
||||
pm->m_driver.setDeviceState(pm->m_subDisSysCmd, DeviceId::bowWaterInet2, (unsigned char)cmd);
|
||||
pm->m_driver.setDeviceState(pm->m_subDisSysCmd, DeviceId::bowWaterInet3, (unsigned char)cmd);
|
||||
pm->m_driver.setDeviceState(pm->m_subDisSysCmd, DeviceId::bowWaterInet4, (unsigned char)cmd);
|
||||
pm->m_driver.setDeviceState(pm->m_subDisSysCmd, DeviceId::bowWaterInet5, (unsigned char)cmd);
|
||||
pm->m_driver.setDeviceState(pm->m_subDisSysCmd, DeviceId::bowWaterInet6, (unsigned char)cmd);
|
||||
pm->m_driver.setDeviceState(pm->m_subDisSysCmd, DeviceId::bowWaterInet7, (unsigned char)cmd);
|
||||
pm->m_driver.setDeviceState(pm->m_subDisSysCmd, DeviceId::bowWaterInet8, (unsigned char)cmd);
|
||||
pm->m_upperCommManager->processPeriodicTasks();
|
||||
MOOSPause(10);
|
||||
pm->m_lowerCommManager->operate_HVA_openWaterCoverStartCylinderCircuit_Breaker(1);
|
||||
pm->workCondition = WorkCondition::DJ_MODE;
|
||||
LOG_F(INFO, "进入DJ模式");
|
||||
}
|
||||
|
||||
|
||||
void DJMode::exit() {
|
||||
PowerManagerFsm::exit();
|
||||
//1 解除启闭机构
|
||||
unsigned char cmd = 0;
|
||||
pm->m_lowerCommManager->operate_HVA_actuatorCircuit_Breaker(0);
|
||||
MOOSPause(3);
|
||||
pm->m_driver.setDeviceState(pm->m_subDisSysCmd, DeviceId::bowCover1, (unsigned char)cmd);
|
||||
pm->m_driver.setDeviceState(pm->m_subDisSysCmd, DeviceId::bowCover2, (unsigned char)cmd);
|
||||
pm->m_driver.setDeviceState(pm->m_subDisSysCmd, DeviceId::bowCover3, (unsigned char)cmd);
|
||||
pm->m_driver.setDeviceState(pm->m_subDisSysCmd, DeviceId::bowCover4, (unsigned char)cmd);
|
||||
pm->m_driver.setDeviceState(pm->m_subDisSysCmd, DeviceId::bowCover5, (unsigned char)cmd);
|
||||
pm->m_driver.setDeviceState(pm->m_subDisSysCmd, DeviceId::bowCover6, (unsigned char)cmd);
|
||||
pm->m_upperCommManager->processPeriodicTasks();
|
||||
//2 解除敞水机构
|
||||
pm->m_lowerCommManager->operate_HVA_openWaterCoverStartCylinderCircuit_Breaker(0);
|
||||
MOOSPause(3);
|
||||
pm->m_driver.setDeviceState(pm->m_subDisSysCmd, DeviceId::bowWaterInet1, (unsigned char)cmd);
|
||||
pm->m_driver.setDeviceState(pm->m_subDisSysCmd, DeviceId::bowWaterInet2, (unsigned char)cmd);
|
||||
pm->m_driver.setDeviceState(pm->m_subDisSysCmd, DeviceId::bowWaterInet3, (unsigned char)cmd);
|
||||
pm->m_driver.setDeviceState(pm->m_subDisSysCmd, DeviceId::bowWaterInet4, (unsigned char)cmd);
|
||||
pm->m_driver.setDeviceState(pm->m_subDisSysCmd, DeviceId::bowWaterInet5, (unsigned char)cmd);
|
||||
pm->m_driver.setDeviceState(pm->m_subDisSysCmd, DeviceId::bowWaterInet6, (unsigned char)cmd);
|
||||
pm->m_driver.setDeviceState(pm->m_subDisSysCmd, DeviceId::bowWaterInet7, (unsigned char)cmd);
|
||||
pm->m_driver.setDeviceState(pm->m_subDisSysCmd, DeviceId::bowWaterInet8, (unsigned char)cmd);
|
||||
pm->m_upperCommManager->processPeriodicTasks();
|
||||
}
|
||||
@@ -1,20 +0,0 @@
|
||||
#include "PowerManagerFsm.hpp"
|
||||
|
||||
// FaultState实现
|
||||
void FaultState::entry() {
|
||||
PowerManagerFsm::entry();
|
||||
if(pm->m_missionState.type == TaskType::THROW_LOAD)
|
||||
{
|
||||
LOG_F(INFO, "检测到抛载");
|
||||
}
|
||||
}
|
||||
|
||||
void FaultState::react(FaultEvent const & e) {
|
||||
LOG_F(INFO, "FaultState 处理故障事件");
|
||||
}
|
||||
|
||||
void FaultState::react(MasterCommandEvent const &) {
|
||||
PowerManagerFsm::handelPowerCmd();
|
||||
PowerManagerFsm::handleModCmd();
|
||||
PowerManagerFsm::handleWorkCmd();
|
||||
}
|
||||
@@ -1,16 +0,0 @@
|
||||
#include "PowerManagerFsm.hpp"
|
||||
|
||||
// FloatAdjust实现
|
||||
void FloatAdjust::react(MasterCommandEvent const &) {
|
||||
PowerManagerFsm::handelPowerCmd();
|
||||
PowerManagerFsm::handleModCmd();
|
||||
PowerManagerFsm::handleWorkCmd();
|
||||
}
|
||||
|
||||
void FloatAdjust::entry() {
|
||||
PowerManagerFsm::entry();
|
||||
pm->workCondition = WorkCondition::CHANING;
|
||||
handleCuriseWork();
|
||||
pm->workCondition = WorkCondition::BUOYANCY_ADJUST;
|
||||
LOG_F(INFO, "进入浮调模式");
|
||||
}
|
||||
@@ -1,16 +0,0 @@
|
||||
#include "PowerManagerFsm.hpp"
|
||||
|
||||
void FloatDown::entry() {
|
||||
PowerManagerFsm::entry();
|
||||
pm->workCondition = WorkCondition::CHANING;
|
||||
handleCuriseWork();
|
||||
pm->workCondition = WorkCondition::ASCEND_DESCEND;
|
||||
LOG_F(INFO, "进入上浮下潜模式");
|
||||
}
|
||||
|
||||
// FloatDown实现
|
||||
void FloatDown::react(MasterCommandEvent const &) {
|
||||
PowerManagerFsm::handelPowerCmd();
|
||||
PowerManagerFsm::handleModCmd();
|
||||
PowerManagerFsm::handleWorkCmd();
|
||||
}
|
||||
@@ -1,16 +0,0 @@
|
||||
#include "PowerManagerFsm.hpp"
|
||||
|
||||
void HighSpeedMode::entry() {
|
||||
PowerManagerFsm::entry();
|
||||
pm->workCondition = WorkCondition::CHANING;
|
||||
handleCuriseWork();
|
||||
pm->workCondition = WorkCondition::HIGH_SPEED_MODE;
|
||||
LOG_F(INFO, "进入高速模式");
|
||||
}
|
||||
|
||||
// HighSpeedMode实现
|
||||
void HighSpeedMode::react(MasterCommandEvent const &) {
|
||||
PowerManagerFsm::handelPowerCmd();
|
||||
PowerManagerFsm::handleModCmd();
|
||||
PowerManagerFsm::handleWorkCmd();
|
||||
}
|
||||
@@ -1,10 +0,0 @@
|
||||
#include "PowerManagerFsm.hpp"
|
||||
|
||||
// InitState实现
|
||||
void InitState::entry() {
|
||||
PowerManagerFsm::entry();
|
||||
LOG_F(INFO, "进入初始化状态");
|
||||
pm->initControlCmd();
|
||||
pm->m_lowerCommManager->operate_hold();
|
||||
transit<StandbyState>();
|
||||
}
|
||||
@@ -1,90 +0,0 @@
|
||||
#include "PowerManagerFsm.hpp"
|
||||
|
||||
void Lifting::entry() {
|
||||
PowerManagerFsm::entry();
|
||||
pm->workCondition = WorkCondition::CHANING;
|
||||
//1. 关闭所有水声设备
|
||||
LOG_F(INFO,"前视声纳关机指令");
|
||||
pm->sendNotification("uExternComm_frontSonarControl_cmd","0");
|
||||
MOOSPause(10000);
|
||||
for(auto iter : underWterDevices)
|
||||
{
|
||||
pm->m_driver.setDeviceState(pm->m_subDisSysCmd, static_cast<DeviceId::Type>(iter), 0);
|
||||
}
|
||||
//2. 关闭动力电设备
|
||||
//2.1 断开所有艏部高压断路器
|
||||
pm->m_lowerCommManager->operate_HVA_actuatorCircuit_Breaker(0);
|
||||
MOOSPause(3);
|
||||
pm->m_lowerCommManager->operate_HVA_bowFTDevice123Circuit_Breaker(0);
|
||||
MOOSPause(3);
|
||||
pm->m_lowerCommManager->operate_HVA_bowRudderControlBoxCircuit_Breaker(0);
|
||||
MOOSPause(3);
|
||||
pm->m_lowerCommManager->operate_HVA_mastSteeringGearControlBoxCircuit_Breaker(0);
|
||||
MOOSPause(3);
|
||||
pm->m_lowerCommManager->operate_HVA_openWaterCoverStartCylinderCircuit_Breaker(0);
|
||||
MOOSPause(3);
|
||||
pm->m_lowerCommManager->operate_HVA_xczCircuit_Breaker(0);
|
||||
MOOSPause(3);
|
||||
//2.2 断开所有艉部高压设备断路器
|
||||
pm->m_lowerCommManager->operate_HV_propulsionMotor_Breaker(0);
|
||||
MOOSPause(3);
|
||||
pm->m_lowerCommManager->operate_HV_sternFt45_Breaker(0);
|
||||
MOOSPause(3);
|
||||
pm->m_lowerCommManager->operate_HV_sternRudder1_Breaker(0);
|
||||
MOOSPause(3);
|
||||
pm->m_lowerCommManager->operate_HV_sternRudder2_Breaker(0);
|
||||
MOOSPause(3);
|
||||
pm->m_lowerCommManager->operate_HV_fbReserved_Breaker(0);
|
||||
MOOSPause(3);
|
||||
pm->m_lowerCommManager->operate_HV_tyzReserved_Breaker(0);
|
||||
MOOSPause(3);
|
||||
pm->m_lowerCommManager->operate_HV_reserved_Breaker(0);
|
||||
MOOSPause(3);
|
||||
pm->m_lowerCommManager->operate_HV_dcDc5_Breaker(0);
|
||||
MOOSPause(3);
|
||||
pm->m_lowerCommManager->operate_HV_coolingSystem_Breaker(0);
|
||||
MOOSPause(3);
|
||||
|
||||
//2.5 断开动力电断路器
|
||||
pm->m_lowerCommManager->operate_HV_bowHighVoltageBox_Breaker(0);
|
||||
MOOSPause(3);
|
||||
pm->m_lowerCommManager->operate_HV_dcDc5_Breaker(0);
|
||||
MOOSPause(3);
|
||||
pm->m_lowerCommManager->operate_HV_coolingSystem_Breaker(0);
|
||||
MOOSPause(3);
|
||||
pm->m_lowerCommManager->operate_HV_dcDc5Module_Breaker(0);
|
||||
MOOSPause(3);
|
||||
pm->m_lowerCommManager->operate_HV_powerLithiumBattery_Breaker(0);
|
||||
//3. 关闭燃料电池
|
||||
//4. 关闭动力锂电池
|
||||
MOOSPause(3);
|
||||
{
|
||||
int count=0;
|
||||
while (!(pm->m_systemData->dyn_pos_relay_status == 0x02 && pm->m_systemData->dyn_neg_relay_status == 0x02))
|
||||
{
|
||||
LOG_F(INFO,"动力锂电池下电中...");
|
||||
MOOSPause(3);
|
||||
if(count>10)
|
||||
{
|
||||
LOG_F(INFO, "动力锂电池无下电反馈");
|
||||
break;
|
||||
}
|
||||
count++;
|
||||
}
|
||||
}
|
||||
LOG_F(INFO, "动力锂电池已下电");
|
||||
pm->workCondition = WorkCondition::LIFT_MODE;
|
||||
LOG_F(INFO, "WorkCondition %d", pm->workCondition);
|
||||
}
|
||||
|
||||
void Lifting::react(MasterCommandEvent const &) {
|
||||
PowerManagerFsm::handelPowerCmd();
|
||||
PowerManagerFsm::handleModCmd();
|
||||
PowerManagerFsm::handleWorkCmd();
|
||||
}
|
||||
|
||||
void Lifting::react(DevCmdExt const &e)
|
||||
{
|
||||
LOG_F(INFO, "DevCmdExt 执行");
|
||||
PowerManagerFsm::react(e);
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,300 +0,0 @@
|
||||
#ifndef POWER_MANAGER_FSM_HPP
|
||||
#define POWER_MANAGER_FSM_HPP
|
||||
#include "tinyfsm.hpp"
|
||||
#include "../logc/loguru.hpp"
|
||||
#include <iostream>
|
||||
#include <chrono> // 新增头文件
|
||||
#include <iomanip> // 新增头文件
|
||||
#include <ctime> // 新增头文件,用于localtime函数
|
||||
#include <cxxabi.h> // 新增头文件,用于demangle功能
|
||||
#include "../pmSysvariable.h"
|
||||
#include "../driver.h"
|
||||
#include "../PowerManger.h"
|
||||
#include "../upmsg/uExternComm_setThrustSpeed_cmd.h"
|
||||
|
||||
|
||||
#define OVER_DEPTH 0.1
|
||||
|
||||
// 前向声明
|
||||
class PowerManger;
|
||||
|
||||
enum class PowerSystemState {
|
||||
INIT,
|
||||
STANDBY,
|
||||
FAULT,
|
||||
};
|
||||
|
||||
//==================状态切换事件=============================
|
||||
struct InitEvent : tinyfsm::Event { };
|
||||
struct StandbyEvent : tinyfsm::Event { };
|
||||
struct TaskStopEvent : tinyfsm::Event { };
|
||||
struct TaskStartEvent : tinyfsm::Event {
|
||||
int type;
|
||||
bool enableBowRudder;
|
||||
bool enableBuoyancyAdjustment;
|
||||
TaskStartEvent() : type(0), enableBowRudder(false), enableBuoyancyAdjustment(false) {};
|
||||
TaskStartEvent(int type, bool bowRudder, bool buoyancyAdjustment) : type(type), enableBowRudder(bowRudder), enableBuoyancyAdjustment(buoyancyAdjustment) {};
|
||||
};
|
||||
//==================状态流程事件============================
|
||||
struct CycleTriggeredEvent : tinyfsm::Event {};
|
||||
struct MasterCommandEvent : tinyfsm::Event {};
|
||||
struct DeviceCmd : tinyfsm::Event {};
|
||||
struct DevCmdExt : tinyfsm::Event {
|
||||
int id;
|
||||
int cmd;
|
||||
DevCmdExt() : id(0), cmd(0) {};
|
||||
DevCmdExt(int id, int cmd) : id(id), cmd(cmd) {};
|
||||
};
|
||||
struct SideSonarCmd : tinyfsm::Event {
|
||||
int xcLowVoltageAdd;
|
||||
int xcHighVoltageAdd;
|
||||
SideSonarCmd() : xcLowVoltageAdd(0),xcHighVoltageAdd(0) {};
|
||||
SideSonarCmd(int xcLowVoltageAdd,int xcHighVoltageAdd) : xcLowVoltageAdd(xcLowVoltageAdd),xcHighVoltageAdd(xcHighVoltageAdd) {};
|
||||
};
|
||||
//==================测试事件================================
|
||||
struct TestEvent : tinyfsm::Event {
|
||||
std::string eventName;
|
||||
unsigned int type;
|
||||
unsigned int eventId;
|
||||
TestEvent() : eventName(""), eventId(0),type(0) {};
|
||||
TestEvent(std::string eventName, unsigned int type,unsigned int eventId) : eventName(eventName), eventId(eventId),type(type) {};
|
||||
};
|
||||
struct FaultEvent : tinyfsm::Event {
|
||||
unsigned int subDisSysFaultCode;
|
||||
unsigned int disSysFaultCode;
|
||||
unsigned int powerFaultCode;
|
||||
unsigned int fcsFaultCode;
|
||||
unsigned int ccsFaultCode;
|
||||
unsigned int injectionFaultCode;
|
||||
FaultEvent() : subDisSysFaultCode(0), disSysFaultCode(0), powerFaultCode(0), fcsFaultCode(0), ccsFaultCode(0),injectionFaultCode(0) {};
|
||||
FaultEvent(unsigned int subDisSysFaultCode,
|
||||
unsigned int disSysFaultCode,
|
||||
unsigned int powerFaultCode,
|
||||
unsigned int fcsFaultCode,
|
||||
unsigned int ccsFaultCode,
|
||||
unsigned int injectionFaultCode)
|
||||
: subDisSysFaultCode(subDisSysFaultCode),
|
||||
disSysFaultCode(disSysFaultCode),
|
||||
powerFaultCode(powerFaultCode),
|
||||
fcsFaultCode(fcsFaultCode),
|
||||
ccsFaultCode(ccsFaultCode),
|
||||
injectionFaultCode(injectionFaultCode) {};
|
||||
};
|
||||
|
||||
class PowerManagerFsm : public tinyfsm::Fsm<PowerManagerFsm> {
|
||||
protected:
|
||||
static PowerManger* pm;
|
||||
static DriverTable m_currentDriver;
|
||||
|
||||
public:
|
||||
static void init(PowerManger* powerManager) {
|
||||
pm = powerManager;
|
||||
}
|
||||
|
||||
virtual void react(tinyfsm::Event const &) { std::cout << "[ Reseve Envt ] " << "No Idear" << std::endl; }
|
||||
virtual void react(InitEvent const &) {};
|
||||
virtual void react(StandbyEvent const &) {};
|
||||
virtual void react(MasterCommandEvent const &) { LOG_F(INFO, "MasterCommandEvent");};
|
||||
// virtual void react(DeviceCmd const &);
|
||||
virtual void react(DevCmdExt const &e);
|
||||
virtual void react(TaskStartEvent const &e);
|
||||
virtual void react(FaultEvent const &e);
|
||||
virtual void react(TaskStopEvent const &e);
|
||||
virtual void react(CycleTriggeredEvent const &e);
|
||||
virtual void react(SideSonarCmd const &e);
|
||||
|
||||
|
||||
//测试事件
|
||||
virtual void react(TestEvent const &);
|
||||
|
||||
//======================操作函数=============================
|
||||
void handelPowerCmd();
|
||||
void handleModCmd();
|
||||
void handleWorkCmd();
|
||||
void handleDeviceCmd();
|
||||
|
||||
void handleCuriseWork();
|
||||
|
||||
void handleNoPowerDeviceCmd(int id , int cmd); // 非水声仪表设备
|
||||
void handleHydroacousticDeviceCmd(int id , int cmd); // 水声设备处理
|
||||
void handleBowRudderSystemCmd(int id, int cmd); // 艏舵设备处理
|
||||
void handleActuatorCmd(int id, int cmd); // 启闭机构处理
|
||||
void handleOpenWaterCmd(int id, int cmd); // 敞水机构处理
|
||||
void handleSternRudderCmd(int id, int cmd); // 艉舵设备处理
|
||||
void handlePropulsionMotorCmd(int id, int cmd); // 推进电机处理
|
||||
void handleBuoyancyAdjustmentCmd(int id, int cmd); // 浮调设备处理
|
||||
void handleFBSystemCmd(int id, int cmd); // FB设备处理
|
||||
void handleSideSonarCmd(int id, int cmd); // 舷侧设备处理
|
||||
void handleMastFoldingSystemCmd(int id, int cmd); // 桅杆设备处理
|
||||
|
||||
//获取仅仪表设备状态
|
||||
void getNoPowerDeviceStatus(DriverTable &s);
|
||||
void getBowRudderSystemStatus(DriverTable &s);
|
||||
void getActuatorStatus(DriverTable &s);
|
||||
void getSternRudderStatus(DriverTable &s);
|
||||
void getPropulsionMotorStatus(DriverTable &s);
|
||||
void getBuoyancyAdjustmentStatus(DriverTable &s);
|
||||
void getFBSystemCmdStatus(DriverTable &s);
|
||||
void getSideSonarStatus(DriverTable &s);
|
||||
void getMastFoldingSystem(DriverTable &s);
|
||||
void getOpenWaterStatus(DriverTable &s);
|
||||
|
||||
//故障处理
|
||||
void basicNavigationFault(FaultEvent const &e);
|
||||
void extendedNavigationFault(FaultEvent const &e);
|
||||
void obstacleAvoidanceFault(FaultEvent const &e);
|
||||
void buoyancyControlFault(FaultEvent const &e);
|
||||
void communicationSystemFault(FaultEvent const &e);
|
||||
void payloadSystemFault(FaultEvent const &e);
|
||||
void emergencySystemFault(FaultEvent const &e);
|
||||
void sensorSystemFault(FaultEvent const &e);
|
||||
|
||||
void basicNavigationFault();
|
||||
void extendedNavigationFault();
|
||||
void obstacleAvoidanceFault();
|
||||
void buoyancyControlFault();
|
||||
void communicationSystemFault();
|
||||
void payloadSystemFault();
|
||||
void emergencySystemFault();
|
||||
void sensorSystemFault();
|
||||
|
||||
// void handleFaultOfDisSys();
|
||||
// 状态机生命周期方法
|
||||
virtual void entry() {
|
||||
auto now = std::chrono::system_clock::now();
|
||||
auto now_time = std::chrono::system_clock::to_time_t(now);
|
||||
|
||||
int status = 0;
|
||||
char* demangled = abi::__cxa_demangle(typeid(*this).name(), nullptr, nullptr, &status);
|
||||
std::string typeName = (status == 0) ? demangled : typeid(*this).name();
|
||||
if (demangled) free(demangled);
|
||||
|
||||
std::cout << "\033[1;38;5;51m╭──────────────────────────────────────────────────────\n"
|
||||
<< "│ \033[1;38;5;226m⮞⮞⮞ \033[0;38;5;51m[" << std::put_time(std::localtime(&now_time), "%Y-%m-%d %H:%M:%S")
|
||||
<< "] \033[1;38;5;255m进入状态: \033[1;38;5;213m" << typeName << "\n"
|
||||
<< "│ \033[0m" << std::endl;
|
||||
|
||||
LOG_F(INFO, "进入状态: %s", typeName.c_str());
|
||||
}
|
||||
|
||||
virtual void exit() {
|
||||
auto now = std::chrono::system_clock::now();
|
||||
auto now_time = std::chrono::system_clock::to_time_t(now);
|
||||
|
||||
int status = 0;
|
||||
char* demangled = abi::__cxa_demangle(typeid(*this).name(), nullptr, nullptr, &status);
|
||||
std::string typeName = (status == 0) ? demangled : typeid(*this).name();
|
||||
if (demangled) free(demangled);
|
||||
|
||||
std::cout << "\033[1;38;5;203m│ \n"
|
||||
<< "│ \033[1;38;5;208m⮜⮜⮜ \033[0;38;5;203m[" << std::put_time(std::localtime(&now_time), "%Y-%m-%d %H:%M:%S")
|
||||
<< "] \033[1;38;5;255m离开状态: \033[1;38;5;213m" << typeName << "\n"
|
||||
<< "╰──────────────────────────────────────────────────────\033[0m" << std::endl;
|
||||
|
||||
LOG_F(INFO, "离开状态: %s", typeName.c_str());
|
||||
}
|
||||
};
|
||||
|
||||
// 初始化
|
||||
class InitState : public PowerManagerFsm {
|
||||
public:
|
||||
void entry() override;
|
||||
};
|
||||
|
||||
//待机状态
|
||||
class StandbyState : public PowerManagerFsm {
|
||||
public:
|
||||
void entry() override;
|
||||
void react(StandbyEvent const &) override;
|
||||
void react(DevCmdExt const &e) override;
|
||||
void react(MasterCommandEvent const &) override;
|
||||
};
|
||||
|
||||
// 岸基备航
|
||||
class ShoreBasedReady : public PowerManagerFsm {
|
||||
public:
|
||||
void entry() override;
|
||||
void react(MasterCommandEvent const &) override;
|
||||
private:
|
||||
};
|
||||
// 水中备航
|
||||
class WaterBasedReady : public PowerManagerFsm {
|
||||
public:
|
||||
void entry() override;
|
||||
void react(MasterCommandEvent const &) override;
|
||||
void react(DevCmdExt const &e) override;
|
||||
private:
|
||||
};
|
||||
// 巡航模式
|
||||
class CruiseMode : public PowerManagerFsm {
|
||||
public:
|
||||
void entry() override;
|
||||
void react(MasterCommandEvent const &) override;
|
||||
private:
|
||||
};
|
||||
// 上浮下潜
|
||||
class FloatDown : public PowerManagerFsm {
|
||||
public:
|
||||
void entry() override;
|
||||
void react(MasterCommandEvent const &) override;
|
||||
private:
|
||||
};
|
||||
// 高速模式
|
||||
class HighSpeedMode : public PowerManagerFsm {
|
||||
public:
|
||||
void entry() override;
|
||||
void react(MasterCommandEvent const &) override;
|
||||
private:
|
||||
};
|
||||
|
||||
// 浮调模式
|
||||
class FloatAdjust : public PowerManagerFsm {
|
||||
public:
|
||||
void entry() override;
|
||||
void react(MasterCommandEvent const &) override;
|
||||
private:
|
||||
};
|
||||
// 水下侦查
|
||||
class UnderwaterSurvey : public PowerManagerFsm {
|
||||
public:
|
||||
void entry() override;
|
||||
void react(MasterCommandEvent const &) override;
|
||||
private:
|
||||
};
|
||||
// 水面侦查
|
||||
class SurfaceSurvey : public PowerManagerFsm {
|
||||
public:
|
||||
void entry() override;
|
||||
void react(MasterCommandEvent const &) override;
|
||||
private:
|
||||
};
|
||||
// DJ模式
|
||||
class DJMode : public PowerManagerFsm {
|
||||
public:
|
||||
void entry() override;
|
||||
void react(MasterCommandEvent const &) override;
|
||||
void exit() override;
|
||||
private:
|
||||
};
|
||||
// 遥控工况
|
||||
class RemoteControl : public PowerManagerFsm {
|
||||
public:
|
||||
void entry() override;
|
||||
void react(MasterCommandEvent const &) override;
|
||||
private:
|
||||
};
|
||||
|
||||
class FaultState : public PowerManagerFsm {
|
||||
public:
|
||||
void entry() override;
|
||||
void react(FaultEvent const &);
|
||||
void react(MasterCommandEvent const &) override;
|
||||
};
|
||||
|
||||
class Lifting : public PowerManagerFsm {
|
||||
public:
|
||||
void entry() override;
|
||||
void react(MasterCommandEvent const &) override;
|
||||
};
|
||||
|
||||
#endif // POWER_MANAGER_FSM_HPP
|
||||
@@ -1,16 +0,0 @@
|
||||
#include "PowerManagerFsm.hpp"
|
||||
|
||||
// RemoteControl实现
|
||||
void RemoteControl::react(MasterCommandEvent const &){
|
||||
PowerManagerFsm::handelPowerCmd();
|
||||
PowerManagerFsm::handleModCmd();
|
||||
PowerManagerFsm::handleWorkCmd();
|
||||
}
|
||||
|
||||
void RemoteControl::entry() {
|
||||
PowerManagerFsm::entry();
|
||||
pm->workCondition = WorkCondition::REMOTE_CONTROL;
|
||||
LOG_F(INFO, "进入遥控工况");
|
||||
}
|
||||
|
||||
|
||||
@@ -1,92 +0,0 @@
|
||||
#include "PowerManagerFsm.hpp"
|
||||
|
||||
// ShoreBasedReady实现
|
||||
void ShoreBasedReady::react(MasterCommandEvent const &) {
|
||||
PowerManagerFsm::handelPowerCmd();
|
||||
PowerManagerFsm::handleModCmd();
|
||||
PowerManagerFsm::handleWorkCmd();
|
||||
}
|
||||
|
||||
void ShoreBasedReady::entry() {
|
||||
PowerManagerFsm::entry();
|
||||
pm->m_driver.getSHORE_BASED_READYable(&pm->m_subDisSysCmd);
|
||||
pm->workCondition = WorkCondition::CHANING;
|
||||
//依次接入执行机构动力电设备
|
||||
//1. 开启动力电
|
||||
//1.1 动力锂电池上电
|
||||
pm->m_CcuColCmd.powerBatCmd = BatteryCommand::Start;
|
||||
//1.2 闭合动力电断路器
|
||||
pm->m_lowerCommManager->operate_HV_powerLithiumBattery_Breaker(1);
|
||||
MOOSPause(100);
|
||||
pm->m_lowerCommManager->operate_HV_dcDc5Module_Breaker(1);
|
||||
MOOSPause(100);
|
||||
pm->m_lowerCommManager->operate_HV_dcDc5_Breaker(1);
|
||||
pm->m_lowerCommManager->operate_HV_coolingSystem_Breaker(1);
|
||||
MOOSPause(100);
|
||||
pm->m_lowerCommManager->operate_HV_bowHighVoltageBox_Breaker(1);
|
||||
MOOSPause(100);
|
||||
//2. 启动动力电设备
|
||||
unsigned char cmd = 1;
|
||||
//2.0 艉舵
|
||||
pm->m_driver.setDeviceState(pm->m_subDisSysCmd, DeviceId::sternRudderServo1, (unsigned char)cmd);
|
||||
pm->m_driver.setDeviceState(pm->m_subDisSysCmd, DeviceId::sternRudderServo2, (unsigned char)cmd);
|
||||
pm->m_upperCommManager->processPeriodicTasks();
|
||||
pm->m_lowerCommManager->operate_HV_sternRudder1_Breaker(1);
|
||||
pm->m_driver.setDeviceState(pm->m_subDisSysCmd, DeviceId::sternRudderServo3, (unsigned char)cmd);
|
||||
pm->m_driver.setDeviceState(pm->m_subDisSysCmd, DeviceId::sternRudderServo4, (unsigned char)cmd);
|
||||
pm->m_upperCommManager->processPeriodicTasks();
|
||||
pm->m_lowerCommManager->operate_HV_sternRudder2_Breaker(1);
|
||||
//2.1 启闭机构
|
||||
pm->m_driver.setDeviceState(pm->m_subDisSysCmd, DeviceId::bowCover1, (unsigned char)cmd);
|
||||
pm->m_driver.setDeviceState(pm->m_subDisSysCmd, DeviceId::bowCover2, (unsigned char)cmd);
|
||||
pm->m_driver.setDeviceState(pm->m_subDisSysCmd, DeviceId::bowCover3, (unsigned char)cmd);
|
||||
pm->m_driver.setDeviceState(pm->m_subDisSysCmd, DeviceId::bowCover4, (unsigned char)cmd);
|
||||
pm->m_driver.setDeviceState(pm->m_subDisSysCmd, DeviceId::bowCover5, (unsigned char)cmd);
|
||||
pm->m_driver.setDeviceState(pm->m_subDisSysCmd, DeviceId::bowCover6, (unsigned char)cmd);
|
||||
pm->m_upperCommManager->processPeriodicTasks();
|
||||
MOOSPause(100);
|
||||
pm->m_lowerCommManager->operate_HVA_actuatorCircuit_Breaker(1);
|
||||
//2.2 敞水电缸
|
||||
pm->m_driver.setDeviceState(pm->m_subDisSysCmd, DeviceId::bowWaterInet1, (unsigned char)cmd);
|
||||
pm->m_driver.setDeviceState(pm->m_subDisSysCmd, DeviceId::bowWaterInet2, (unsigned char)cmd);
|
||||
pm->m_driver.setDeviceState(pm->m_subDisSysCmd, DeviceId::bowWaterInet3, (unsigned char)cmd);
|
||||
pm->m_driver.setDeviceState(pm->m_subDisSysCmd, DeviceId::bowWaterInet4, (unsigned char)cmd);
|
||||
pm->m_driver.setDeviceState(pm->m_subDisSysCmd, DeviceId::bowWaterInet5, (unsigned char)cmd);
|
||||
pm->m_driver.setDeviceState(pm->m_subDisSysCmd, DeviceId::bowWaterInet6, (unsigned char)cmd);
|
||||
pm->m_driver.setDeviceState(pm->m_subDisSysCmd, DeviceId::bowWaterInet7, (unsigned char)cmd);
|
||||
pm->m_driver.setDeviceState(pm->m_subDisSysCmd, DeviceId::bowWaterInet8, (unsigned char)cmd);
|
||||
pm->m_upperCommManager->processPeriodicTasks();
|
||||
MOOSPause(100);
|
||||
pm->m_lowerCommManager->operate_HVA_openWaterCoverStartCylinderCircuit_Breaker(1);
|
||||
//2.3 艏舵
|
||||
pm->m_driver.setDeviceState(pm->m_subDisSysCmd, DeviceId::bowRudderDeploy, (unsigned char)cmd);
|
||||
pm->m_driver.setDeviceState(pm->m_subDisSysCmd, DeviceId::bowRudderServo1, (unsigned char)cmd);
|
||||
pm->m_upperCommManager->processPeriodicTasks();
|
||||
MOOSPause(100);
|
||||
pm->m_lowerCommManager->operate_HVA_bowRudderControlBoxCircuit_Breaker(1);
|
||||
//2.4 桅杆舵机
|
||||
pm->m_driver.setDeviceState(pm->m_subDisSysCmd, DeviceId::mastLiftingServo, (unsigned char)cmd);
|
||||
pm->m_upperCommManager->processPeriodicTasks();
|
||||
MOOSPause(100);
|
||||
pm->m_lowerCommManager->operate_HVA_mastSteeringGearControlBoxCircuit_Breaker(1);
|
||||
//2.5 艏部浮调机构
|
||||
pm->m_driver.setDeviceState(pm->m_subDisSysCmd, DeviceId::buoyancyAdjust1, (unsigned char)cmd);
|
||||
pm->m_driver.setDeviceState(pm->m_subDisSysCmd, DeviceId::buoyancyAdjust2, (unsigned char)cmd);
|
||||
pm->m_driver.setDeviceState(pm->m_subDisSysCmd, DeviceId::buoyancyAdjust3, (unsigned char)cmd);
|
||||
pm->m_upperCommManager->processPeriodicTasks();
|
||||
MOOSPause(100);
|
||||
pm->m_lowerCommManager->operate_HVA_bowFTDevice123Circuit_Breaker(1);
|
||||
//2.6 艉部浮调机构
|
||||
pm->m_driver.setDeviceState(pm->m_subDisSysCmd, DeviceId::buoyancyAdjust4, (unsigned char)cmd);
|
||||
pm->m_driver.setDeviceState(pm->m_subDisSysCmd, DeviceId::buoyancyAdjust5, (unsigned char)cmd);
|
||||
pm->m_upperCommManager->processPeriodicTasks();
|
||||
MOOSPause(100);
|
||||
pm->m_lowerCommManager->operate_HV_sternFt45_Breaker(1);
|
||||
//2.7 推进电机
|
||||
pm->m_driver.setDeviceState(pm->m_subDisSysCmd, DeviceId::thruster, (unsigned char)cmd);
|
||||
pm->m_upperCommManager->processPeriodicTasks();
|
||||
MOOSPause(100);
|
||||
pm->m_lowerCommManager->operate_HV_propulsionMotor_Breaker(1);
|
||||
pm->workCondition = WorkCondition::SHORE_BASED_READY;
|
||||
LOG_F(INFO, "进入岸基备航状态");
|
||||
}
|
||||
@@ -1,24 +0,0 @@
|
||||
#include "PowerManagerFsm.hpp"
|
||||
|
||||
// StandbyState实现
|
||||
void StandbyState::entry() {
|
||||
PowerManagerFsm::entry();
|
||||
pm->workCondition = WorkCondition::STANDBY;
|
||||
pm->m_driver.getSTANDBYTable(&pm->m_subDisSysCmd);
|
||||
pm->m_lowerCommManager->operate_hold();
|
||||
LOG_F(INFO, "WorkCondition %d", pm->workCondition);
|
||||
}
|
||||
void StandbyState::react(StandbyEvent const &) {
|
||||
transit<StandbyState>();
|
||||
}
|
||||
void StandbyState::react(MasterCommandEvent const &) {
|
||||
PowerManagerFsm::handelPowerCmd();
|
||||
PowerManagerFsm::handleModCmd();
|
||||
PowerManagerFsm::handleWorkCmd();
|
||||
}
|
||||
|
||||
void StandbyState::react(DevCmdExt const &e)
|
||||
{
|
||||
LOG_F(INFO, "DevCmdExt 执行");
|
||||
PowerManagerFsm::react(e);
|
||||
}
|
||||
@@ -1,16 +0,0 @@
|
||||
#include "PowerManagerFsm.hpp"
|
||||
|
||||
// SurfaceSurvey实现
|
||||
void SurfaceSurvey::react(MasterCommandEvent const &) {
|
||||
PowerManagerFsm::handelPowerCmd();
|
||||
PowerManagerFsm::handleModCmd();
|
||||
PowerManagerFsm::handleWorkCmd();
|
||||
}
|
||||
|
||||
void SurfaceSurvey::entry() {
|
||||
PowerManagerFsm::entry();
|
||||
pm->workCondition = WorkCondition::CHANING;
|
||||
handleCuriseWork();
|
||||
pm->workCondition = WorkCondition::SURFACE_RECON;
|
||||
LOG_F(INFO, "进入水面侦查模式");
|
||||
}
|
||||
@@ -1,17 +0,0 @@
|
||||
#include "PowerManagerFsm.hpp"
|
||||
|
||||
void UnderwaterSurvey::entry() {
|
||||
PowerManagerFsm::entry();
|
||||
pm->workCondition = WorkCondition::CHANING;
|
||||
handleCuriseWork();
|
||||
pm->workCondition = WorkCondition::UNDERWATER_RECON;
|
||||
LOG_F(INFO, "进入水下侦查模式");
|
||||
}
|
||||
|
||||
|
||||
// UnderwaterSurvey实现
|
||||
void UnderwaterSurvey::react(MasterCommandEvent const &) {
|
||||
PowerManagerFsm::handelPowerCmd();
|
||||
PowerManagerFsm::handleModCmd();
|
||||
PowerManagerFsm::handleWorkCmd();
|
||||
}
|
||||
@@ -1,62 +0,0 @@
|
||||
#include "PowerManagerFsm.hpp"
|
||||
|
||||
|
||||
void WaterBasedReady::entry() {
|
||||
PowerManagerFsm::entry();
|
||||
pm->workCondition = WorkCondition::CHANING;
|
||||
PowerManagerFsm::handleCuriseWork();
|
||||
//启动水声设备
|
||||
pm->m_driver.setDeviceState(pm->m_subDisSysCmd, DeviceId::DVL, (unsigned char)EquipmentCommand::ON);
|
||||
pm->m_driver.setDeviceState(pm->m_subDisSysCmd, DeviceId::USBL, (unsigned char)EquipmentCommand::ON);
|
||||
pm->m_upperCommManager->processPeriodicTasks();
|
||||
pm->workCondition = WorkCondition::WATER_BASED_READY;
|
||||
LOG_F(INFO, "进入水中备航状态");
|
||||
}
|
||||
|
||||
// WaterBasedReady实现
|
||||
void WaterBasedReady::react(MasterCommandEvent const &) {
|
||||
PowerManagerFsm::handelPowerCmd();
|
||||
PowerManagerFsm::handleModCmd();
|
||||
PowerManagerFsm::handleWorkCmd();
|
||||
}
|
||||
|
||||
void WaterBasedReady::react(DevCmdExt const &e)
|
||||
{
|
||||
int id = e.id;
|
||||
int cmd = e.cmd;
|
||||
if(underWterDevices.find(id) != underWterDevices.end())
|
||||
{
|
||||
if (pm->currentMod != PMMode::Debug)
|
||||
{
|
||||
if(pm->m_depth < OVER_DEPTH)
|
||||
{
|
||||
LOG_F(INFO, "水下设备操作上电保护 %d ", id);
|
||||
return;
|
||||
}
|
||||
}
|
||||
// 如果是前视声纳断电则先关机再断电
|
||||
if(id == DeviceId::forwardSonar)
|
||||
{
|
||||
if(cmd == 0)
|
||||
{
|
||||
LOG_F(INFO,"前视声纳关机指令");
|
||||
pm->sendNotification("uExternComm_frontSonarControl_cmd","0");
|
||||
MOOSPause(10000);
|
||||
}
|
||||
}
|
||||
LOG_F(INFO, "水声设备操作: %s,%d, %d", DeviceId::toString((DeviceId::Type)id), id, cmd);
|
||||
pm->m_driver.setDeviceState(pm->m_subDisSysCmd, (DeviceId::Type)id, (unsigned char)cmd);
|
||||
}
|
||||
else
|
||||
{
|
||||
if(pm->currentMod == PMMode::Normal)
|
||||
{
|
||||
LOG_F(INFO,"正常模式:操作禁止");
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
PowerManagerFsm::react(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,476 +0,0 @@
|
||||
#ifndef HTTP_SERVER_BATTERYOPERATION_H
|
||||
#define HTTP_SERVER_BATTERYOPERATION_H
|
||||
|
||||
#include <string>
|
||||
|
||||
const std::string BATTERY_OPERATION_HTML = R"(
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>电池操作</title>
|
||||
<link rel="stylesheet" href="/static/style.css">
|
||||
<style>
|
||||
:root {
|
||||
--primary-color: #2563eb;
|
||||
--primary-hover: #1d4ed8;
|
||||
--bg-color: #f8fafc;
|
||||
}
|
||||
|
||||
* {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
body {
|
||||
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
|
||||
background-color: var(--bg-color);
|
||||
color: #1a1a1a;
|
||||
}
|
||||
|
||||
.container {
|
||||
display: grid;
|
||||
grid-template-areas:
|
||||
"sidebar main-content";
|
||||
grid-template-columns: 220px 1fr;
|
||||
grid-template-rows: 1fr;
|
||||
min-height: 100vh;
|
||||
gap: 0;
|
||||
}
|
||||
|
||||
.header {
|
||||
grid-area: unset;
|
||||
background: white;
|
||||
padding: 0 0.5rem;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1);
|
||||
position: fixed;
|
||||
top: 0;
|
||||
right: 0;
|
||||
left: 220px;
|
||||
height: 36px;
|
||||
z-index: 10;
|
||||
}
|
||||
|
||||
.header h1 {
|
||||
font-size: 1.25rem;
|
||||
font-weight: 600;
|
||||
color: #1a1a1a;
|
||||
}
|
||||
|
||||
.sidebar {
|
||||
grid-area: sidebar;
|
||||
background: white;
|
||||
width: 220px;
|
||||
height: 100vh;
|
||||
position: fixed;
|
||||
left: 0;
|
||||
top: 0;
|
||||
padding: 0.5rem 0.25rem;
|
||||
box-shadow: 1px 0 3px rgba(0, 0, 0, 0.1);
|
||||
z-index: 20;
|
||||
}
|
||||
|
||||
.sidebar-menu {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.5rem;
|
||||
}
|
||||
|
||||
.sidebar-button {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 0.5rem 0.75rem;
|
||||
border-radius: 0.375rem;
|
||||
color: #4b5563;
|
||||
text-decoration: none;
|
||||
transition: all 0.2s ease;
|
||||
}
|
||||
|
||||
.sidebar-button:hover {
|
||||
background: var(--bg-color);
|
||||
color: var(--primary-color);
|
||||
}
|
||||
|
||||
.sidebar-icon {
|
||||
min-width: 1.5rem;
|
||||
margin-right: 1rem;
|
||||
font-size: 1.25rem;
|
||||
}
|
||||
|
||||
.main-content {
|
||||
grid-area: main-content;
|
||||
padding: 1px;
|
||||
margin-top: 36px;
|
||||
}
|
||||
|
||||
.control-panel {
|
||||
background: white;
|
||||
border-radius: 4px;
|
||||
padding: 20px;
|
||||
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
|
||||
margin: 20px;
|
||||
}
|
||||
|
||||
.panel-title {
|
||||
font-size: 1.2rem;
|
||||
font-weight: 600;
|
||||
color: #1a1a1a;
|
||||
margin-bottom: 16px;
|
||||
padding-bottom: 8px;
|
||||
border-bottom: 1px solid #e5e7eb;
|
||||
}
|
||||
|
||||
.control-group {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.control-label {
|
||||
display: block;
|
||||
margin-bottom: 8px;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.radio-group {
|
||||
display: flex;
|
||||
gap: 16px;
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
|
||||
.radio-option {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.select-control {
|
||||
width: 100%;
|
||||
padding: 8px 12px;
|
||||
border: 1px solid #d1d5db;
|
||||
border-radius: 4px;
|
||||
background-color: white;
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
|
||||
.slider-container {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
.slider {
|
||||
flex-grow: 1;
|
||||
height: 6px;
|
||||
-webkit-appearance: none;
|
||||
background: #d1d5db;
|
||||
border-radius: 3px;
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.slider::-webkit-slider-thumb {
|
||||
-webkit-appearance: none;
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
background: var(--primary-color);
|
||||
border-radius: 50%;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.slider-value {
|
||||
min-width: 50px;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.button-group {
|
||||
display: flex;
|
||||
gap: 12px;
|
||||
margin-top: 8px;
|
||||
}
|
||||
|
||||
.button {
|
||||
padding: 8px 16px;
|
||||
border: none;
|
||||
border-radius: 4px;
|
||||
background-color: #e5e7eb;
|
||||
color: #1a1a1a;
|
||||
font-weight: 500;
|
||||
cursor: pointer;
|
||||
transition: all 0.2s;
|
||||
}
|
||||
|
||||
.button:hover {
|
||||
background-color: #d1d5db;
|
||||
}
|
||||
|
||||
.button-secondary {
|
||||
background-color: #e5e7eb;
|
||||
color: #1a1a1a;
|
||||
}
|
||||
|
||||
.button-secondary:hover {
|
||||
background-color: #d1d5db;
|
||||
}
|
||||
|
||||
.button-active {
|
||||
background-color: var(--primary-color);
|
||||
color: white;
|
||||
}
|
||||
|
||||
.button-active:hover {
|
||||
background-color: var(--primary-hover);
|
||||
}
|
||||
|
||||
.form-submit {
|
||||
margin-top: 24px;
|
||||
width: 100%;
|
||||
padding: 12px;
|
||||
font-size: 1rem;
|
||||
}
|
||||
|
||||
.status-message {
|
||||
margin-top: 16px;
|
||||
padding: 12px;
|
||||
border-radius: 4px;
|
||||
background-color: #f0fdf4;
|
||||
color: #166534;
|
||||
display: none;
|
||||
}
|
||||
|
||||
.status-message.error {
|
||||
background-color: #fef2f2;
|
||||
color: #991b1b;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<div class="sidebar">
|
||||
<div class="sidebar-menu">
|
||||
<a href="/" class="sidebar-button">
|
||||
<span class="sidebar-icon">🏠</span>
|
||||
<span>系统主页</span>
|
||||
</a>
|
||||
<a href="/data" class="sidebar-button">
|
||||
<span class="sidebar-icon">📊</span>
|
||||
<span>系统数据</span>
|
||||
</a>
|
||||
<a href="/dashboard" class="sidebar-button">
|
||||
<span class="sidebar-icon">⚡</span>
|
||||
<span>配电操作</span>
|
||||
</a>
|
||||
<a href="/battery" class="sidebar-button">
|
||||
<span class="sidebar-icon">🔋</span>
|
||||
<span>电池操作</span>
|
||||
</a>
|
||||
<a href="/logs" class="sidebar-button">
|
||||
<span class="sidebar-icon">📝</span>
|
||||
<span>系统日志</span>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="header">
|
||||
<h1>电池操作系统</h1>
|
||||
</div>
|
||||
|
||||
<div class="main-content">
|
||||
<div class="control-panel">
|
||||
<div class="panel-title">燃料电池控制</div>
|
||||
|
||||
<form id="batteryForm" method="POST" action="/battery/control">
|
||||
<div class="control-group">
|
||||
<label class="control-label">燃料电池模式设定</label>
|
||||
<div class="radio-group">
|
||||
<label class="radio-option">
|
||||
<input type="radio" name="fuelCellMode" value="00H" checked>
|
||||
<span>无效</span>
|
||||
</label>
|
||||
<label class="radio-option">
|
||||
<input type="radio" name="fuelCellMode" value="01H">
|
||||
<span>调试</span>
|
||||
</label>
|
||||
<label class="radio-option">
|
||||
<input type="radio" name="fuelCellMode" value="02H">
|
||||
<span>自动</span>
|
||||
</label>
|
||||
<label class="radio-option">
|
||||
<input type="radio" name="fuelCellMode" value="03H">
|
||||
<span>补给</span>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="control-group">
|
||||
<label class="control-label">燃料电池指令</label>
|
||||
<select class="select-control" name="fuelCellCommand">
|
||||
<option value="00H">无效</option>
|
||||
<option value="01H">自检</option>
|
||||
<option value="02H">启动</option>
|
||||
<option value="03H">停机</option>
|
||||
<option value="04H">复位</option>
|
||||
<option value="05H">紧急停机</option>
|
||||
<option value="06H">补给</option>
|
||||
<option value="07H">制氢预热</option>
|
||||
<option value="08H">停机维护</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="control-group">
|
||||
<label class="control-label">燃料电池动力通路功率配置 (kW)</label>
|
||||
<div class="slider-container">
|
||||
<input type="range" class="slider" name="fuelCellPower" min="0" max="20" value="0" step="1">
|
||||
<span class="slider-value">0</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="panel-title">锂电池控制</div>
|
||||
|
||||
<div class="control-group">
|
||||
<label class="control-label">仪表锂电池启停指令</label>
|
||||
<div class="button-group">
|
||||
<button type="button" class="button button-active" data-command="instrumentBattery" data-value="00H">无效</button>
|
||||
<button type="button" class="button button-secondary" data-command="instrumentBattery" data-value="10H">启动</button>
|
||||
<button type="button" class="button button-secondary" data-command="instrumentBattery" data-value="20H">关闭</button>
|
||||
</div>
|
||||
<input type="hidden" name="instrumentBattery" value="00H">
|
||||
</div>
|
||||
|
||||
<div class="control-group">
|
||||
<label class="control-label">仪表锂电池允许充电</label>
|
||||
<div class="button-group">
|
||||
<button type="button" class="button button-secondary" data-command="instrumentBatteryCharge" data-value="0">允许</button>
|
||||
<button type="button" class="button button-active" data-command="instrumentBatteryCharge" data-value="48">禁止</button>
|
||||
</div>
|
||||
<input type="hidden" name="instrumentBatteryCharge" value="1">
|
||||
</div>
|
||||
|
||||
<div class="control-group">
|
||||
<label class="control-label">动力锂电池启停指令</label>
|
||||
<div class="button-group">
|
||||
<button type="button" class="button button-active" data-command="powerBattery" data-value="00H">无效</button>
|
||||
<button type="button" class="button button-secondary" data-command="powerBattery" data-value="10H">启动</button>
|
||||
<button type="button" class="button button-secondary" data-command="powerBattery" data-value="20H">关闭</button>
|
||||
</div>
|
||||
<input type="hidden" name="powerBattery" value="00H">
|
||||
</div>
|
||||
|
||||
<div class="control-group">
|
||||
<label class="control-label">动力锂电池电池功率配置值 (kW)</label>
|
||||
<div class="slider-container">
|
||||
<input type="range" class="slider" name="powerBatteryPower" min="0" max="400" value="0" step="10">
|
||||
<span class="slider-value">0</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="panel-title">主机状态</div>
|
||||
|
||||
<div class="control-group">
|
||||
<label class="control-label">主机状态指令</label>
|
||||
<div class="radio-group">
|
||||
<label class="radio-option">
|
||||
<input type="radio" name="hostStatus" value="AAH" checked>
|
||||
<span>运行</span>
|
||||
</label>
|
||||
<label class="radio-option">
|
||||
<input type="radio" name="hostStatus" value="FFH">
|
||||
<span>关机</span>
|
||||
</label>
|
||||
<label class="radio-option">
|
||||
<input type="radio" name="hostStatus" value="55H">
|
||||
<span>故障</span>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<button type="submit" class="button form-submit">提交配置</button>
|
||||
|
||||
<div id="statusMessage" class="status-message"></div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
// 更新滑块值显示
|
||||
document.querySelectorAll('.slider').forEach(slider => {
|
||||
const valueDisplay = slider.nextElementSibling;
|
||||
valueDisplay.textContent = slider.value;
|
||||
|
||||
slider.addEventListener('input', () => {
|
||||
valueDisplay.textContent = slider.value;
|
||||
});
|
||||
});
|
||||
|
||||
// 处理按钮组选择
|
||||
document.querySelectorAll('.button-group button').forEach(button => {
|
||||
button.addEventListener('click', () => {
|
||||
const group = button.closest('.button-group');
|
||||
const hiddenInput = group.nextElementSibling;
|
||||
const command = button.dataset.command;
|
||||
const value = button.dataset.value;
|
||||
|
||||
// 更新按钮样式
|
||||
group.querySelectorAll('button').forEach(btn => {
|
||||
btn.classList.remove('button-active');
|
||||
btn.classList.add('button-secondary');
|
||||
});
|
||||
button.classList.remove('button-secondary');
|
||||
button.classList.add('button-active');
|
||||
|
||||
// 更新隐藏输入值
|
||||
hiddenInput.value = value;
|
||||
});
|
||||
});
|
||||
|
||||
// 处理表单提交
|
||||
document.getElementById('batteryForm').addEventListener('submit', async (e) => {
|
||||
e.preventDefault();
|
||||
const form = e.target;
|
||||
const formData = new FormData(form);
|
||||
const statusMessage = document.getElementById('statusMessage');
|
||||
|
||||
try {
|
||||
// 将表单数据转换为URL编码格式
|
||||
const params = new URLSearchParams();
|
||||
for (const [key, value] of formData.entries()) {
|
||||
params.append(key, value);
|
||||
}
|
||||
|
||||
const response = await fetch(form.action, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/x-www-form-urlencoded'
|
||||
},
|
||||
body: params.toString()
|
||||
});
|
||||
|
||||
const result = await response.json();
|
||||
|
||||
if (result.success) {
|
||||
statusMessage.textContent = '配置提交成功';
|
||||
statusMessage.className = 'status-message';
|
||||
statusMessage.style.display = 'block';
|
||||
} else {
|
||||
statusMessage.textContent = result.message || '配置提交失败';
|
||||
statusMessage.className = 'status-message error';
|
||||
statusMessage.style.display = 'block';
|
||||
}
|
||||
} catch (error) {
|
||||
statusMessage.textContent = '网络错误: ' + error.message;
|
||||
statusMessage.className = 'status-message error';
|
||||
statusMessage.style.display = 'block';
|
||||
}
|
||||
|
||||
setTimeout(() => {
|
||||
statusMessage.style.display = 'none';
|
||||
}, 5000);
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
)";
|
||||
|
||||
#endif // HTTP_SERVER_BATTERYOPERATION_H
|
||||
@@ -1,580 +0,0 @@
|
||||
|
||||
#ifndef HTTP_SERVER_DASHBOARD_H
|
||||
#define HTTP_SERVER_DASHBOARD_H
|
||||
|
||||
#include <string>
|
||||
|
||||
const std::string DASHBOARD_HTML = R"row(
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>断路器控制面板</title>
|
||||
<style>
|
||||
body {
|
||||
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
|
||||
margin: 0;
|
||||
padding: 20px;
|
||||
background-color: #f8f9fa;
|
||||
}
|
||||
.container {
|
||||
display: flex;
|
||||
gap: 25px;
|
||||
max-width: 1400px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
.column {
|
||||
flex: 1;
|
||||
background: white;
|
||||
padding: 20px;
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 2px 10px rgba(0,0,0,0.1);
|
||||
transition: transform 0.2s;
|
||||
}
|
||||
.column:hover {
|
||||
transform: translateY(-2px);
|
||||
box-shadow: 0 4px 12px rgba(0,0,0,0.15);
|
||||
}
|
||||
.column-title {
|
||||
font-weight: 600;
|
||||
margin-bottom: 20px;
|
||||
text-align: center;
|
||||
font-size: 20px;
|
||||
color: #2c3e50;
|
||||
padding-bottom: 10px;
|
||||
border-bottom: 2px solid #eee;
|
||||
}
|
||||
.breaker {
|
||||
margin-bottom: 12px;
|
||||
padding: 10px 15px;
|
||||
background: #f8f9fa;
|
||||
border-radius: 6px;
|
||||
border-left: 4px solid #3498db;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 8px;
|
||||
}
|
||||
.breaker-name {
|
||||
font-weight: 600;
|
||||
font-size: 18px;
|
||||
color: #2c3e50;
|
||||
padding: 6px 10px;
|
||||
background-color: rgba(46, 204, 113, 0.1);
|
||||
border-radius: 4px;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
width: fit-content;
|
||||
}
|
||||
.breaker-controls {
|
||||
display: flex;
|
||||
gap: 10px;
|
||||
align-items: center;
|
||||
}
|
||||
button {
|
||||
padding: 8px 16px;
|
||||
min-width: 70px;
|
||||
cursor: pointer;
|
||||
border: none;
|
||||
border-radius: 4px;
|
||||
font-weight: 500;
|
||||
font-size: 14px;
|
||||
transition: all 0.2s;
|
||||
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
|
||||
}
|
||||
button:hover {
|
||||
opacity: 0.9;
|
||||
transform: translateY(-1px);
|
||||
}
|
||||
button:first-of-type {
|
||||
background-color: #2ecc71;
|
||||
color: white;
|
||||
}
|
||||
button:last-of-type {
|
||||
background-color: #e74c3c;
|
||||
color: white;
|
||||
}
|
||||
.status-message {
|
||||
margin-top: 8px;
|
||||
padding: 6px;
|
||||
font-size: 13px;
|
||||
border-radius: 3px;
|
||||
}
|
||||
.status-success {
|
||||
background-color: rgba(46, 204, 113, 0.1);
|
||||
color: #27ae60;
|
||||
}
|
||||
.status-error {
|
||||
background-color: rgba(231, 76, 60, 0.1);
|
||||
color: #c0392b;
|
||||
}
|
||||
.status-pending {
|
||||
background-color: rgba(241, 196, 15, 0.1);
|
||||
color: #f39c12;
|
||||
}
|
||||
.status-timer {
|
||||
font-size: 12px;
|
||||
color: #7f8c8d;
|
||||
margin-top: 4px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<div class="column">
|
||||
<div class="column-title">高压母线设备</div>
|
||||
<!-- 高压母线断路器列表 -->
|
||||
<div class="breaker">
|
||||
<div class="breaker-name">燃料电池断路器</div>
|
||||
<div class="breaker-controls">
|
||||
<button onclick="sendCommand('high_vol_bus', 'fuel_cell', 'close')">闭合</button>
|
||||
<button onclick="sendCommand('high_vol_bus', 'fuel_cell', 'open')">断开</button>
|
||||
</div>
|
||||
<div id="high_vol_bus-fuel_cell-status-message" class="status-message"></div>
|
||||
<div id="high_vol_bus-fuel_cell-timer" class="status-timer"></div>
|
||||
</div>
|
||||
<div class="breaker">
|
||||
<div class="breaker-name">动力锂电池断路器</div>
|
||||
<div class="breaker-controls">
|
||||
<button onclick="sendCommand('high_vol_bus', 'power_battery', 'close')">闭合</button>
|
||||
<button onclick="sendCommand('high_vol_bus', 'power_battery', 'open')">断开</button>
|
||||
</div>
|
||||
<div id="high_vol_bus-power_battery-status-message" class="status-message"></div>
|
||||
<div id="high_vol_bus-power_battery-timer" class="status-timer"></div>
|
||||
</div>
|
||||
<div class="breaker">
|
||||
<div class="breaker-name">推进电机断路器</div>
|
||||
<div class="breaker-controls">
|
||||
<button onclick="sendCommand('high_vol_bus', 'propulsion_motor', 'close')">闭合</button>
|
||||
<button onclick="sendCommand('high_vol_bus', 'propulsion_motor', 'open')">断开</button>
|
||||
</div>
|
||||
<div id="high_vol_bus-propulsion_motor-status-message" class="status-message"></div>
|
||||
<div id="high_vol_bus-propulsion_motor-timer" class="status-timer"></div>
|
||||
</div>
|
||||
<div class="breaker">
|
||||
<div class="breaker-name">锂电池组仪表断路器</div>
|
||||
<div class="breaker-controls">
|
||||
<button onclick="sendCommand('high_vol_bus', 'battery_meter', 'close')">闭合</button>
|
||||
<button onclick="sendCommand('high_vol_bus', 'battery_meter', 'open')">断开</button>
|
||||
</div>
|
||||
<div id="high_vol_bus-battery_meter-status-message" class="status-message"></div>
|
||||
<div id="high_vol_bus-battery_meter-timer" class="status-timer"></div>
|
||||
</div>
|
||||
<div class="breaker">
|
||||
<div class="breaker-name">DC/DC5模块断路器</div>
|
||||
<div class="breaker-controls">
|
||||
<button onclick="sendCommand('high_vol_bus', 'dcdc5', 'close')">闭合</button>
|
||||
<button onclick="sendCommand('high_vol_bus', 'dcdc5', 'open')">断开</button>
|
||||
</div>
|
||||
<div id="high_vol_bus-dcdc5-status-message" class="status-message"></div>
|
||||
<div id="high_vol_bus-dcdc5-timer" class="status-timer"></div>
|
||||
</div>
|
||||
<div class="breaker">
|
||||
<div class="breaker-name">艏部高压配电箱断路器</div>
|
||||
<div class="breaker-controls">
|
||||
<button onclick="sendCommand('high_vol_bus', 'bow_distribution', 'close')">闭合</button>
|
||||
<button onclick="sendCommand('high_vol_bus', 'bow_distribution', 'open')">断开</button>
|
||||
</div>
|
||||
<div id="high_vol_bus-bow_distribution-status-message" class="status-message"></div>
|
||||
<div id="high_vol_bus-bow_distribution-timer" class="status-timer"></div>
|
||||
</div>
|
||||
<div class="breaker">
|
||||
<div class="breaker-name">艉部FT装置4/5断路器</div>
|
||||
<div class="breaker-controls">
|
||||
<button onclick="sendCommand('high_vol_bus', 'stern_ft45', 'close')">闭合</button>
|
||||
<button onclick="sendCommand('high_vol_bus', 'stern_ft45', 'open')">断开</button>
|
||||
</div>
|
||||
<div id="high_vol_bus-stern_ft45-status-message" class="status-message"></div>
|
||||
<div id="high_vol_bus-stern_ft45-timer" class="status-timer"></div>
|
||||
</div>
|
||||
<div class="breaker">
|
||||
<div class="breaker-name">艉舵开关1断路器</div>
|
||||
<div class="breaker-controls">
|
||||
<button onclick="sendCommand('high_vol_bus', 'stern_rudder1', 'close')">闭合</button>
|
||||
<button onclick="sendCommand('high_vol_bus', 'stern_rudder1', 'open')">断开</button>
|
||||
</div>
|
||||
<div id="high_vol_bus-stern_rudder1-status-message" class="status-message"></div>
|
||||
<div id="high_vol_bus-stern_rudder1-timer" class="status-timer"></div>
|
||||
</div>
|
||||
<div class="breaker">
|
||||
<div class="breaker-name">艉舵开关2断路器</div>
|
||||
<div class="breaker-controls">
|
||||
<button onclick="sendCommand('high_vol_bus', 'stern_rudder2', 'close')">闭合</button>
|
||||
<button onclick="sendCommand('high_vol_bus', 'stern_rudder2', 'open')">断开</button>
|
||||
</div>
|
||||
<div id="high_vol_bus-stern_rudder2-status-message" class="status-message"></div>
|
||||
<div id="high_vol_bus-stern_rudder2-timer" class="status-timer"></div>
|
||||
</div>
|
||||
<div class="breaker">
|
||||
<div class="breaker-name">FB预留断路器</div>
|
||||
<div class="breaker-controls">
|
||||
<button onclick="sendCommand('high_vol_bus', 'fb_reserve', 'close')">闭合</button>
|
||||
<button onclick="sendCommand('high_vol_bus', 'fb_reserve', 'open')">断开</button>
|
||||
</div>
|
||||
<div id="high_vol_bus-fb_reserve-status-message" class="status-message"></div>
|
||||
<div id="high_vol_bus-fb_reserve-timer" class="status-timer"></div>
|
||||
</div>
|
||||
<div class="breaker">
|
||||
<div class="breaker-name">TYZ预留断路器</div>
|
||||
<div class="breaker-controls">
|
||||
<button onclick="sendCommand('high_vol_bus', 'tyz_reserve', 'close')">闭合</button>
|
||||
<button onclick="sendCommand('high_vol_bus', 'tyz_reserve', 'open')">断开</button>
|
||||
</div>
|
||||
<div id="high_vol_bus-tyz_reserve-status-message" class="status-message"></div>
|
||||
<div id="high_vol_bus-tyz_reserve-timer" class="status-timer"></div>
|
||||
</div>
|
||||
<div class="breaker">
|
||||
<div class="breaker-name">预留断路器</div>
|
||||
<div class="breaker-controls">
|
||||
<button onclick="sendCommand('high_vol_bus', 'reserve', 'close')">闭合</button>
|
||||
<button onclick="sendCommand('high_vol_bus', 'reserve', 'open')">断开</button>
|
||||
</div>
|
||||
<div id="high_vol_bus-reserve-status-message" class="status-message"></div>
|
||||
<div id="high_vol_bus-reserve-timer" class="status-timer"></div>
|
||||
</div>
|
||||
<div class="breaker">
|
||||
<div class="breaker-name">DC/DC5模块启动</div>
|
||||
<div class="breaker-controls">
|
||||
<button onclick="sendCommand('high_vol_bus', 'dcdc5_start', 'close')">启动</button>
|
||||
<button onclick="sendCommand('high_vol_bus', 'dcdc5_start', 'open')">停止</button>
|
||||
</div>
|
||||
<div id="high_vol_bus-dcdc5_start-status-message" class="status-message"></div>
|
||||
<div id="high_vol_bus-dcdc5_start-timer" class="status-timer"></div>
|
||||
</div>
|
||||
<div class="breaker">
|
||||
<div class="breaker-name">冷却系统启动</div>
|
||||
<div class="breaker-controls">
|
||||
<button onclick="sendCommand('high_vol_bus', 'cooling_system', 'close')">启动</button>
|
||||
<button onclick="sendCommand('high_vol_bus', 'cooling_system', 'open')">停止</button>
|
||||
</div>
|
||||
<div id="high_vol_bus-cooling_system-status-message" class="status-message"></div>
|
||||
<div id="high_vol_bus-cooling_system-timer" class="status-timer"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="column">
|
||||
<div class="column-title">艏高压设备</div>
|
||||
<!-- 艏高压断路器列表 -->
|
||||
<div class="breaker">
|
||||
<div class="breaker-name">艏部FT装置1-3断路器</div>
|
||||
<div class="breaker-controls">
|
||||
<button onclick="sendCommand('bow_high_vol', 'bow_ft1_3', 'close')">闭合</button>
|
||||
<button onclick="sendCommand('bow_high_vol', 'bow_ft1_3', 'open')">断开</button>
|
||||
</div>
|
||||
<div id="bow_high_vol-bow_ft1_3-status-message" class="status-message"></div>
|
||||
<div id="bow_high_vol-bow_ft1_3-timer" class="status-timer"></div>
|
||||
</div>
|
||||
<div class="breaker">
|
||||
<div class="breaker-name">启闭机构断路器</div>
|
||||
<div class="breaker-controls">
|
||||
<button onclick="sendCommand('bow_high_vol', 'opening_mechanism', 'close')">闭合</button>
|
||||
<button onclick="sendCommand('bow_high_vol', 'opening_mechanism', 'open')">断开</button>
|
||||
</div>
|
||||
<div id="bow_high_vol-opening_mechanism-status-message" class="status-message"></div>
|
||||
<div id="bow_high_vol-opening_mechanism-timer" class="status-timer"></div>
|
||||
</div>
|
||||
<div class="breaker">
|
||||
<div class="breaker-name">桅杆舵机控制箱断路器</div>
|
||||
<div class="breaker-controls">
|
||||
<button onclick="sendCommand('bow_high_vol', 'mast_steering', 'close')">闭合</button>
|
||||
<button onclick="sendCommand('bow_high_vol', 'mast_steering', 'open')">断开</button>
|
||||
</div>
|
||||
<div id="bow_high_vol-mast_steering-status-message" class="status-message"></div>
|
||||
<div id="bow_high_vol-mast_steering-timer" class="status-timer"></div>
|
||||
</div>
|
||||
<div class="breaker">
|
||||
<div class="breaker-name">XCZ断路器</div>
|
||||
<div class="breaker-controls">
|
||||
<button onclick="sendCommand('bow_high_vol', 'xcz', 'close')">闭合</button>
|
||||
<button onclick="sendCommand('bow_high_vol', 'xcz', 'open')">断开</button>
|
||||
</div>
|
||||
<div id="bow_high_vol-xcz-status-message" class="status-message"></div>
|
||||
<div id="bow_high_vol-xcz-timer" class="status-timer"></div>
|
||||
</div>
|
||||
<div class="breaker">
|
||||
<div class="breaker-name">艏舵控制箱断路器</div>
|
||||
<div class="breaker-controls">
|
||||
<button onclick="sendCommand('bow_high_vol', 'bow_rudder', 'close')">闭合</button>
|
||||
<button onclick="sendCommand('bow_high_vol', 'bow_rudder', 'open')">断开</button>
|
||||
</div>
|
||||
<div id="bow_high_vol-bow_rudder-status-message" class="status-message"></div>
|
||||
<div id="bow_high_vol-bow_rudder-timer" class="status-timer"></div>
|
||||
</div>
|
||||
<div class="breaker">
|
||||
<div class="breaker-name">敞水盖启动电缸断路器</div>
|
||||
<div class="breaker-controls">
|
||||
<button onclick="sendCommand('bow_high_vol', 'water_cover', 'close')">闭合</button>
|
||||
<button onclick="sendCommand('bow_high_vol', 'water_cover', 'open')">断开</button>
|
||||
</div>
|
||||
<div id="bow_high_vol-water_cover-status-message" class="status-message"></div>
|
||||
<div id="bow_high_vol-water_cover-timer" class="status-timer"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="column">
|
||||
<div class="column-title">仪表母线设备</div>
|
||||
<!-- 仪表母线断路器列表 -->
|
||||
<div class="breaker">
|
||||
<div class="breaker-name">锂电池组(仪表)断路器</div>
|
||||
<div class="breaker-controls">
|
||||
<button onclick="sendCommand('meter_bus', 'battery_meter', 'close')">闭合</button>
|
||||
<button onclick="sendCommand('meter_bus', 'battery_meter', 'open')">断开</button>
|
||||
</div>
|
||||
<div id="meter_bus-battery_meter-status-message" class="status-message"></div>
|
||||
<div id="meter_bus-battery_meter-timer" class="status-timer"></div>
|
||||
</div>
|
||||
<div class="breaker">
|
||||
<div class="breaker-name">艏部低压配电箱断路器</div>
|
||||
<div class="breaker-controls">
|
||||
<button onclick="sendCommand('meter_bus', 'bow_low_dist', 'close')">闭合</button>
|
||||
<button onclick="sendCommand('meter_bus', 'bow_low_dist', 'open')">断开</button>
|
||||
</div>
|
||||
<div id="meter_bus-bow_low_dist-status-message" class="status-message"></div>
|
||||
<div id="meter_bus-bow_low_dist-timer" class="status-timer"></div>
|
||||
</div>
|
||||
<div class="breaker">
|
||||
<div class="breaker-name">UNIT4仪表DC48V断路器</div>
|
||||
<div class="breaker-controls">
|
||||
<button onclick="sendCommand('meter_bus', 'unit4_dc48v', 'close')">闭合</button>
|
||||
<button onclick="sendCommand('meter_bus', 'unit4_dc48v', 'open')">断开</button>
|
||||
</div>
|
||||
<div id="meter_bus-unit4_dc48v-status-message" class="status-message"></div>
|
||||
<div id="meter_bus-unit4_dc48v-timer" class="status-timer"></div>
|
||||
</div>
|
||||
<div class="breaker">
|
||||
<div class="breaker-name">DC-C1直流配电板断路器</div>
|
||||
<div class="breaker-controls">
|
||||
<button onclick="sendCommand('meter_bus', 'dc_c1', 'close')">闭合</button>
|
||||
<button onclick="sendCommand('meter_bus', 'dc_c1', 'open')">断开</button>
|
||||
</div>
|
||||
<div id="meter_bus-dc_c1-status-message" class="status-message"></div>
|
||||
<div id="meter_bus-dc_c1-timer" class="status-timer"></div>
|
||||
</div>
|
||||
<div class="breaker">
|
||||
<div class="breaker-name">预留断路器1</div>
|
||||
<div class="breaker-controls">
|
||||
<button onclick="sendCommand('meter_bus', 'reserve1', 'close')">闭合</button>
|
||||
<button onclick="sendCommand('meter_bus', 'reserve1', 'open')">断开</button>
|
||||
</div>
|
||||
<div id="meter_bus-reserve1-status-message" class="status-message"></div>
|
||||
<div id="meter_bus-reserve1-timer" class="status-timer"></div>
|
||||
</div>
|
||||
<div class="breaker">
|
||||
<div class="breaker-name">预留断路器2</div>
|
||||
<div class="breaker-controls">
|
||||
<button onclick="sendCommand('meter_bus', 'reserve2', 'close')">闭合</button>
|
||||
<button onclick="sendCommand('meter_bus', 'reserve2', 'open')">断开</button>
|
||||
</div>
|
||||
<div id="meter_bus-reserve2-status-message" class="status-message"></div>
|
||||
<div id="meter_bus-reserve2-timer" class="status-timer"></div>
|
||||
</div>
|
||||
<div class="breaker">
|
||||
<div class="breaker-name">应急锂电池组2断路器</div>
|
||||
<div class="breaker-controls">
|
||||
<button onclick="sendCommand('meter_bus', 'emergency_battery2', 'close')">闭合</button>
|
||||
<button onclick="sendCommand('meter_bus', 'emergency_battery2', 'open')">断开</button>
|
||||
</div>
|
||||
<div id="meter_bus-emergency_battery2-status-message" class="status-message"></div>
|
||||
<div id="meter_bus-emergency_battery2-timer" class="status-timer"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="column">
|
||||
<div class="column-title">艏低压设备</div>
|
||||
<!-- 艏低压断路器列表 -->
|
||||
<div class="breaker">
|
||||
<div class="breaker-name">UNIT1断路器</div>
|
||||
<div class="breaker-controls">
|
||||
<button onclick="sendCommand('bow_low_vol', 'unit1', 'close')">闭合</button>
|
||||
<button onclick="sendCommand('bow_low_vol', 'unit1', 'open')">断开</button>
|
||||
</div>
|
||||
<div id="bow_low_vol-unit1-status-message" class="status-message"></div>
|
||||
<div id="bow_low_vol-unit1-timer" class="status-timer"></div>
|
||||
</div>
|
||||
<div class="breaker">
|
||||
<div class="breaker-name">UNIT2断路器</div>
|
||||
<div class="breaker-controls">
|
||||
<button onclick="sendCommand('bow_low_vol', 'unit2', 'close')">闭合</button>
|
||||
<button onclick="sendCommand('bow_low_vol', 'unit2', 'open')">断开</button>
|
||||
</div>
|
||||
<div id="bow_low_vol-unit2-status-message" class="status-message"></div>
|
||||
<div id="bow_low_vol-unit2-timer" class="status-timer"></div>
|
||||
</div>
|
||||
<div class="breaker">
|
||||
<div class="breaker-name">UNIT3断路器</div>
|
||||
<div class="breaker-controls">
|
||||
<button onclick="sendCommand('bow_low_vol', 'unit3', 'close')">闭合</button>
|
||||
<button onclick="sendCommand('bow_low_vol', 'unit3', 'open')">断开</button>
|
||||
</div>
|
||||
<div id="bow_low_vol-unit3-status-message" class="status-message"></div>
|
||||
<div id="bow_low_vol-unit3-timer" class="status-timer"></div>
|
||||
</div>
|
||||
<div class="breaker">
|
||||
<div class="breaker-name">UNIT5断路器</div>
|
||||
<div class="breaker-controls">
|
||||
<button onclick="sendCommand('bow_low_vol', 'unit5', 'close')">闭合</button>
|
||||
<button onclick="sendCommand('bow_low_vol', 'unit5', 'open')">断开</button>
|
||||
</div>
|
||||
<div id="bow_low_vol-unit5-status-message" class="status-message"></div>
|
||||
<div id="bow_low_vol-unit5-timer" class="status-timer"></div>
|
||||
</div>
|
||||
<div class="breaker">
|
||||
<div class="breaker-name">艏部PZ装置断路器</div>
|
||||
<div class="breaker-controls">
|
||||
<button onclick="sendCommand('bow_low_vol', 'bow_pz', 'close')">闭合</button>
|
||||
<button onclick="sendCommand('bow_low_vol', 'bow_pz', 'open')">断开</button>
|
||||
</div>
|
||||
<div id="bow_low_vol-bow_pz-status-message" class="status-message"></div>
|
||||
<div id="bow_low_vol-bow_pz-timer" class="status-timer"></div>
|
||||
</div>
|
||||
<div class="breaker">
|
||||
<div class="breaker-name">预留断路器1</div>
|
||||
<div class="breaker-controls">
|
||||
<button onclick="sendCommand('bow_low_vol', 'reserve1', 'close')">闭合</button>
|
||||
<button onclick="sendCommand('bow_low_vol', 'reserve1', 'open')">断开</button>
|
||||
</div>
|
||||
<div id="bow_low_vol-reserve1-status-message" class="status-message"></div>
|
||||
<div id="bow_low_vol-reserve1-timer" class="status-timer"></div>
|
||||
</div>
|
||||
<div class="breaker">
|
||||
<div class="breaker-name">预留断路器2</div>
|
||||
<div class="breaker-controls">
|
||||
<button onclick="sendCommand('bow_low_vol', 'reserve2', 'close')">闭合</button>
|
||||
<button onclick="sendCommand('bow_low_vol', 'reserve2', 'open')">断开</button>
|
||||
</div>
|
||||
<div id="bow_low_vol-reserve2-status-message" class="status-message"></div>
|
||||
<div id="bow_low_vol-reserve2-timer" class="status-timer"></div>
|
||||
</div>
|
||||
<div class="breaker">
|
||||
<div class="breaker-name">应急锂电池组1断路器</div>
|
||||
<div class="breaker-controls">
|
||||
<button onclick="sendCommand('bow_low_vol', 'emergency_battery1', 'close')">闭合</button>
|
||||
<button onclick="sendCommand('bow_low_vol', 'emergency_battery1', 'open')">断开</button>
|
||||
</div>
|
||||
<div id="bow_low_vol-emergency_battery1-status-message" class="status-message"></div>
|
||||
<div id="bow_low_vol-emergency_battery1-timer" class="status-timer"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
// 全局存储所有设备的计时器状态
|
||||
const deviceTimers = {};
|
||||
|
||||
function sendCommand(type, id, action, value) {
|
||||
const statusEl = document.getElementById(`${type}-${id}-status-message`);
|
||||
const timerEl = document.getElementById(`${type}-${id}-timer`);
|
||||
const buttons = document.querySelectorAll(`button[onclick*="sendCommand('${type}', '${id}'"]`);
|
||||
|
||||
// 检查是否已有计时器运行
|
||||
if (deviceTimers[`${type}-${id}`]) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 禁用按钮
|
||||
buttons.forEach(btn => {
|
||||
btn.disabled = true;
|
||||
btn.style.opacity = '0.6';
|
||||
btn.style.cursor = 'not-allowed';
|
||||
});
|
||||
|
||||
// 显示操作中状态
|
||||
if (statusEl) {
|
||||
statusEl.textContent = '操作中...';
|
||||
statusEl.className = 'status-message status-pending';
|
||||
}
|
||||
|
||||
// 启动5秒计时器
|
||||
if (timerEl) {
|
||||
let seconds = 8;
|
||||
timerEl.textContent = `等待反馈: ${seconds}秒`;
|
||||
timer = setInterval(() => {
|
||||
seconds--;
|
||||
if (seconds > 0) {
|
||||
timerEl.textContent = `等待反馈: ${seconds}秒`;
|
||||
} else {
|
||||
clearInterval(timer);
|
||||
timerEl.textContent = '';
|
||||
if (statusEl && statusEl.textContent === '操作中...') {
|
||||
statusEl.textContent = '操作超时: 未收到设备反馈';
|
||||
statusEl.className = 'status-message status-error';
|
||||
}
|
||||
}
|
||||
}, 1000);
|
||||
}
|
||||
|
||||
// 设置10秒超时
|
||||
const timeoutPromise = new Promise((_, reject) =>
|
||||
setTimeout(() => reject(new Error('请求超时')), 10000)
|
||||
);
|
||||
|
||||
// 存储计时器
|
||||
deviceTimers[`${type}-${id}`] = timer;
|
||||
|
||||
Promise.race([
|
||||
fetch('/control', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ device_type: type, device_id: id, action: action, value: value })
|
||||
}),
|
||||
timeoutPromise
|
||||
])
|
||||
.then(res => {
|
||||
// 立即清除计时器
|
||||
const timerEl = document.getElementById(`${type}-${id}-timer`);
|
||||
const buttons = document.querySelectorAll(`button[onclick*="sendCommand('${type}', '${id}'"]`);
|
||||
|
||||
if (timerEl) {
|
||||
clearInterval(deviceTimers[`${type}-${id}`]);
|
||||
delete deviceTimers[`${type}-${id}`];
|
||||
timerEl.textContent = '';
|
||||
}
|
||||
|
||||
// 恢复按钮状态
|
||||
buttons.forEach(btn => {
|
||||
btn.disabled = false;
|
||||
btn.style.opacity = '1';
|
||||
btn.style.cursor = 'pointer';
|
||||
});
|
||||
|
||||
return res.json();
|
||||
})
|
||||
.then(data => {
|
||||
const statusEl = document.getElementById(`${type}-${id}-status-message`);
|
||||
|
||||
if (statusEl) {
|
||||
statusEl.textContent = data.message || (data.success ? '操作成功' : '操作失败');
|
||||
statusEl.className = data.success ? 'status-message status-success' : 'status-message status-error';
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
const statusEl = document.getElementById(`${type}-${id}-status-message`);
|
||||
const timerEl = document.getElementById(`${type}-${id}-timer`);
|
||||
const buttons = document.querySelectorAll(`button[onclick*="sendCommand('${type}', '${id}'"]`);
|
||||
|
||||
if (timerEl) {
|
||||
clearInterval(deviceTimers[`${type}-${id}`]);
|
||||
delete deviceTimers[`${type}-${id}`];
|
||||
timerEl.textContent = '';
|
||||
}
|
||||
|
||||
// 恢复按钮状态
|
||||
buttons.forEach(btn => {
|
||||
btn.disabled = false;
|
||||
btn.style.opacity = '1';
|
||||
btn.style.cursor = 'pointer';
|
||||
});
|
||||
|
||||
if (statusEl) {
|
||||
if (error.message === '请求超时') {
|
||||
statusEl.textContent = '操作超时: 未收到设备反馈';
|
||||
} else {
|
||||
statusEl.textContent = '通信错误: ' + error.message;
|
||||
}
|
||||
statusEl.className = 'status-message status-error';
|
||||
}
|
||||
});
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
)row";
|
||||
#endif // HTTP_SERVER_DASHBOARD_H
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,466 +0,0 @@
|
||||
#ifndef HTTP_SERVER_DEBUGPAGE_H
|
||||
#define HTTP_SERVER_DEBUGPAGE_H
|
||||
|
||||
#include <string>
|
||||
|
||||
const std::string DEBUGPAGE_HTML = R"(
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Power Manager - 调试页面</title>
|
||||
<link rel="stylesheet" href="/static/style.css">
|
||||
<style>
|
||||
:root {
|
||||
--primary-color: #2563eb;
|
||||
--primary-hover: #1d4ed8;
|
||||
--bg-color: #f8fafc;
|
||||
--sidebar-width: 60px;
|
||||
--sidebar-expanded: 220px;
|
||||
--header-height: 36px;
|
||||
}
|
||||
|
||||
* {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
body {
|
||||
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
|
||||
background-color: var(--bg-color);
|
||||
color: #1a1a1a;
|
||||
}
|
||||
|
||||
.container {
|
||||
display: grid;
|
||||
grid-template-areas:
|
||||
"sidebar main-content";
|
||||
grid-template-columns: var(--sidebar-width) 1fr;
|
||||
grid-template-rows: 1fr;
|
||||
min-height: 100vh;
|
||||
gap: 0;
|
||||
}
|
||||
|
||||
.header {
|
||||
grid-area: unset;
|
||||
background: white;
|
||||
padding: 0 0.5rem;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1);
|
||||
position: fixed;
|
||||
top: 0;
|
||||
right: 0;
|
||||
left: var(--sidebar-width);
|
||||
height: var(--header-height);
|
||||
z-index: 10;
|
||||
}
|
||||
|
||||
.header h1 {
|
||||
font-size: 1.25rem;
|
||||
font-weight: 600;
|
||||
color: #1a1a1a;
|
||||
}
|
||||
|
||||
.sidebar {
|
||||
grid-area: sidebar;
|
||||
background: white;
|
||||
width: var(--sidebar-width);
|
||||
height: 100vh;
|
||||
position: fixed;
|
||||
left: 0;
|
||||
top: 0;
|
||||
padding: 0.5rem 0.25rem;
|
||||
transition: width 0.3s ease;
|
||||
box-shadow: 1px 0 3px rgba(0, 0, 0, 0.1);
|
||||
z-index: 20;
|
||||
}
|
||||
|
||||
.sidebar:hover {
|
||||
width: var(--sidebar-expanded);
|
||||
}
|
||||
|
||||
.sidebar-menu {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.5rem;
|
||||
}
|
||||
|
||||
.sidebar-button {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 0.5rem 0.75rem;
|
||||
border-radius: 0.375rem;
|
||||
color: #4b5563;
|
||||
text-decoration: none;
|
||||
transition: all 0.2s ease;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.sidebar-button:hover {
|
||||
background: var(--bg-color);
|
||||
color: var(--primary-color);
|
||||
}
|
||||
|
||||
.sidebar-icon {
|
||||
min-width: 1.5rem;
|
||||
margin-right: 1rem;
|
||||
font-size: 1.25rem;
|
||||
}
|
||||
|
||||
.main-content {
|
||||
grid-area: main-content;
|
||||
padding: 1px;
|
||||
margin-top: var(--header-height);
|
||||
}
|
||||
|
||||
.status-bar {
|
||||
position: fixed;
|
||||
top: 4px;
|
||||
right: 8px;
|
||||
background: white;
|
||||
padding: 4px 8px;
|
||||
border-radius: 4px;
|
||||
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
z-index: 15;
|
||||
}
|
||||
|
||||
.status-info {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
color: #4b5563;
|
||||
font-size: 0.875rem;
|
||||
}
|
||||
|
||||
.debug-panel {
|
||||
background: white;
|
||||
border-radius: 4px;
|
||||
padding: 16px;
|
||||
margin: 16px;
|
||||
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.panel-title {
|
||||
font-size: 1.25rem;
|
||||
font-weight: 600;
|
||||
color: #1a1a1a;
|
||||
margin-bottom: 16px;
|
||||
padding-bottom: 8px;
|
||||
border-bottom: 1px solid #e5e7eb;
|
||||
}
|
||||
|
||||
.debug-section {
|
||||
margin-bottom: 24px;
|
||||
}
|
||||
|
||||
.section-title {
|
||||
font-size: 1rem;
|
||||
font-weight: 600;
|
||||
color: #1a1a1a;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.message-cards {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr;
|
||||
gap: 12px;
|
||||
margin-top: 16px;
|
||||
max-width: 600px;
|
||||
padding: 0 16px;
|
||||
}
|
||||
|
||||
.message-card {
|
||||
width: 100%;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.message-card {
|
||||
background: white;
|
||||
border: 1px solid #e5e7eb;
|
||||
border-radius: 8px;
|
||||
overflow: hidden;
|
||||
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.card-header {
|
||||
padding: 12px 16px;
|
||||
background: #f3f4f6;
|
||||
border-bottom: 1px solid #e5e7eb;
|
||||
font-weight: 600;
|
||||
cursor: pointer;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.card-header:hover {
|
||||
background: #e5e7eb;
|
||||
}
|
||||
|
||||
.card-content {
|
||||
padding: 16px;
|
||||
}
|
||||
|
||||
.card-content pre {
|
||||
margin: 0;
|
||||
white-space: pre-wrap;
|
||||
font-family: monospace;
|
||||
max-height: 150px;
|
||||
overflow: hidden;
|
||||
transition: max-height 0.3s ease;
|
||||
}
|
||||
|
||||
.card-content pre.expanded {
|
||||
max-height: none;
|
||||
}
|
||||
|
||||
.toggle-button {
|
||||
background: none;
|
||||
border: none;
|
||||
color: #2563eb;
|
||||
cursor: pointer;
|
||||
font-size: 0.9em;
|
||||
padding: 4px 8px;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.toggle-button:hover {
|
||||
background: rgba(37, 99, 235, 0.1);
|
||||
}
|
||||
|
||||
.raw-data {
|
||||
font-family: monospace;
|
||||
white-space: pre-wrap;
|
||||
background-color: #f3f4f6;
|
||||
padding: 12px;
|
||||
border-radius: 4px;
|
||||
max-height: 300px;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.container {
|
||||
grid-template-columns: 1fr;
|
||||
grid-template-areas:
|
||||
"header"
|
||||
"main-content";
|
||||
}
|
||||
|
||||
.sidebar {
|
||||
transform: translateX(-100%);
|
||||
}
|
||||
|
||||
.header {
|
||||
left: 0;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<div class="sidebar">
|
||||
<div class="sidebar-menu">
|
||||
<a href="/" class="sidebar-button">
|
||||
<span class="sidebar-icon">🏠</span>
|
||||
<span>系统主页</span>
|
||||
</a>
|
||||
<a href="/debug" class="sidebar-button">
|
||||
<span class="sidebar-icon">🐞</span>
|
||||
<span>调试页面</span>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="header">
|
||||
<h1>Power Manager - 调试页面</h1>
|
||||
<div class="status-bar">
|
||||
<div class="status-info">
|
||||
<span id="wsStatus">🔴 WebSocket: 未连接</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="main-content">
|
||||
<div class="debug-panel">
|
||||
<div class="panel-title">系统调试信息</div>
|
||||
|
||||
<div class="debug-section">
|
||||
<div class="section-title">订阅消息</div>
|
||||
<div class="message-cards" id="subscribeDataTable">
|
||||
<!-- 订阅消息将通过JavaScript动态填充 -->
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="debug-section">
|
||||
<div class="section-title">发布消息</div>
|
||||
<div class="message-cards" id="publishDataTable">
|
||||
<!-- 发布消息将通过JavaScript动态填充 -->
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="debug-section">
|
||||
<div class="section-title">原始数据</div>
|
||||
<div class="raw-data" id="rawData">
|
||||
等待数据...
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
let ws = null;
|
||||
|
||||
function initWebSocket() {
|
||||
ws = new WebSocket('ws://' + window.location.host + '/ws/debug');
|
||||
|
||||
ws.onopen = () => {
|
||||
console.log('WebSocket调试连接已建立');
|
||||
updateStatus('🟢 WebSocket: 已连接');
|
||||
};
|
||||
|
||||
ws.onmessage = (event) => {
|
||||
try {
|
||||
const data = JSON.parse(event.data);
|
||||
console.log('收到调试数据:', data);
|
||||
document.getElementById('rawData').textContent = JSON.stringify(data, null, 2);
|
||||
|
||||
// 更新订阅消息表格
|
||||
const subscribeTable = document.getElementById('subscribeDataTable');
|
||||
const subscribeMessages = [
|
||||
'm_secdistStateMsg_fb_debug',
|
||||
'm_equStateMsg_cmd_debug',
|
||||
'm_depthMsg_st_debug',
|
||||
'm_setOpConditionMsg_st_debug',
|
||||
'm_setOpModeMsg_st_debug',
|
||||
'm_taskStartMsg_st_debug',
|
||||
'm_taskStopMsg_st_debug',
|
||||
'm_setDevSwitchMsg_st_debug',
|
||||
'm_setPMSysMsg_st_debug',
|
||||
'm_sysStateMsg_st_debug'
|
||||
];
|
||||
|
||||
subscribeMessages.forEach(msg => {
|
||||
if (data.debug && data.debug[msg] && data.debug[msg].name) {
|
||||
const msgName = data.debug[msg].name;
|
||||
const existingCard = Array.from(subscribeTable.children).find(card =>
|
||||
card.querySelector('.card-header').textContent === msgName
|
||||
);
|
||||
|
||||
if (existingCard) {
|
||||
existingCard.querySelector('pre').textContent = formatJsonContent(data.debug[msg].content || '无内容');
|
||||
} else if (msgName !== '未知消息') {
|
||||
addDebugRow(subscribeTable, data.debug[msg]);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// 更新发布消息表格
|
||||
const publishTable = document.getElementById('publishDataTable');
|
||||
const publishMessages = [
|
||||
'm_equInsStateMsg_fb_degub',
|
||||
'm_secdistStateMsg_cmd_debug',
|
||||
'm_equStateMsg_fb_debug',
|
||||
'm_disSysStateMsg_st_debug',
|
||||
'm_currentStateMsg_st_debug',
|
||||
'm_pmStateMsg_fb_debug',
|
||||
'm_fcsStateMsg_st_debug',
|
||||
'm_liBatStateMsg_st_debug'
|
||||
];
|
||||
|
||||
publishMessages.forEach(msg => {
|
||||
if (data.debug && data.debug[msg] && data.debug[msg].name) {
|
||||
const msgName = data.debug[msg].name;
|
||||
const existingCard = Array.from(publishTable.children).find(card =>
|
||||
card.querySelector('.card-header').textContent === msgName
|
||||
);
|
||||
|
||||
if (existingCard) {
|
||||
existingCard.querySelector('pre').textContent = formatJsonContent(data.debug[msg].content || '无内容');
|
||||
} else if (msgName !== '未知消息') {
|
||||
addDebugRow(publishTable, data.debug[msg]);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
} catch (e) {
|
||||
console.error('解析调试数据出错:', e);
|
||||
document.getElementById('rawData').textContent = '解析错误: ' + e.message + '\n\n原始数据:\n' + event.data;
|
||||
}
|
||||
};
|
||||
|
||||
ws.onclose = () => {
|
||||
console.log('WebSocket调试连接已关闭');
|
||||
updateStatus('🔴 WebSocket: 已断开');
|
||||
setTimeout(initWebSocket, 5000);
|
||||
};
|
||||
|
||||
ws.onerror = (error) => {
|
||||
console.error('WebSocket调试错误:', error);
|
||||
updateStatus('⚠️ WebSocket: 错误');
|
||||
};
|
||||
}
|
||||
|
||||
function updateStatus(status) {
|
||||
document.getElementById('wsStatus').textContent = status;
|
||||
}
|
||||
|
||||
function formatJsonContent(content) {
|
||||
try {
|
||||
const parsed = JSON.parse(content);
|
||||
return JSON.stringify(parsed, null, 2);
|
||||
} catch (e) {
|
||||
return content;
|
||||
}
|
||||
}
|
||||
|
||||
function addDebugRow(container, msgObj) {
|
||||
const card = document.createElement('div');
|
||||
card.className = 'message-card';
|
||||
|
||||
const header = document.createElement('div');
|
||||
header.className = 'card-header';
|
||||
header.textContent = msgObj.name || '未知消息';
|
||||
|
||||
const content = document.createElement('div');
|
||||
content.className = 'card-content';
|
||||
|
||||
const pre = document.createElement('pre');
|
||||
pre.textContent = formatJsonContent(msgObj.content || '无内容');
|
||||
|
||||
const toggleBtn = document.createElement('button');
|
||||
toggleBtn.className = 'toggle-button';
|
||||
toggleBtn.textContent = '展开';
|
||||
toggleBtn.onclick = function(e) {
|
||||
e.stopPropagation();
|
||||
pre.classList.toggle('expanded');
|
||||
this.textContent = pre.classList.contains('expanded') ? '收起' : '展开';
|
||||
};
|
||||
|
||||
header.onclick = function(e) {
|
||||
if(e.target !== toggleBtn) {
|
||||
pre.classList.toggle('expanded');
|
||||
toggleBtn.textContent = pre.classList.contains('expanded') ? '收起' : '展开';
|
||||
}
|
||||
};
|
||||
|
||||
content.appendChild(pre);
|
||||
content.appendChild(toggleBtn);
|
||||
card.appendChild(header);
|
||||
card.appendChild(content);
|
||||
container.appendChild(card);
|
||||
}
|
||||
|
||||
window.addEventListener('load', initWebSocket);
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
)";
|
||||
|
||||
#endif // HTTP_SERVER_DEBUGPAGE_H
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,90 +0,0 @@
|
||||
#ifndef HTTP_SERVER_H
|
||||
#define HTTP_SERVER_H
|
||||
#include "MOOS/libMOOS/Utils/MOOSThread.h"
|
||||
#include "mongoose.h"
|
||||
#include "../logc/loguru.hpp"
|
||||
#include "../systemData.h"
|
||||
#include <vector>
|
||||
#include <mutex>
|
||||
#include <unordered_map>
|
||||
#include <fstream>
|
||||
#include <deque>
|
||||
#include "../LowerCommManager.h"
|
||||
#include <string>
|
||||
#include <thread>
|
||||
#include <atomic>
|
||||
|
||||
class HttpServer {
|
||||
public:
|
||||
// 构造函数,传入PowerManger指针和端口号
|
||||
HttpServer(int port = 8000);
|
||||
|
||||
// 析构函数
|
||||
~HttpServer();
|
||||
|
||||
// 启动HTTP服务器线程
|
||||
void start();
|
||||
|
||||
// 停止HTTP服务器线程
|
||||
void stop();
|
||||
|
||||
// 检查服务器是否正在运行
|
||||
bool isRunning() const;
|
||||
|
||||
// 设置系统数据
|
||||
void setSystemData(SystemData* systemData){
|
||||
m_systemData = systemData;
|
||||
}
|
||||
void setLowerCommManager(LowerCommManager* lowerCommManager){
|
||||
m_lowerCommManager = lowerCommManager;
|
||||
}
|
||||
void setPowerManger(PowerManger* powerManger){
|
||||
m_powerManger = powerManger;
|
||||
}
|
||||
|
||||
// 推送系统数据到所有WebSocket客户端
|
||||
void pushSystemData();
|
||||
|
||||
// 监控日志文件变化并推送新内容
|
||||
void monitorLogFile();
|
||||
|
||||
// 处理日志请求
|
||||
void handleLogRequest(struct mg_connection* c, const std::string& msg);
|
||||
|
||||
// 读取日志文件
|
||||
std::vector<std::string> readLogFile(int page, int pageSize, const std::string& level, const std::string& search);
|
||||
|
||||
// 测试页面请求处理函数
|
||||
void handleTestPage(struct mg_connection* c, const std::string& msg);
|
||||
|
||||
private:
|
||||
// WebSocket事件处理函数
|
||||
void handleWebSocketEvent(struct mg_connection* c, int ev, void* ev_data, void* fn_data);
|
||||
|
||||
// 线程回调函数
|
||||
static bool serverThreadCB(void* pParam);
|
||||
bool serverThreadFunc();
|
||||
|
||||
// 后台系统数据
|
||||
SystemData *m_systemData = nullptr;
|
||||
LowerCommManager *m_lowerCommManager = nullptr;
|
||||
PowerManger *m_powerManger = nullptr;
|
||||
|
||||
struct mg_mgr mgr_; // Mongoose管理器
|
||||
int port_; // 监听端口
|
||||
bool running_; // 运行状态标志
|
||||
CMOOSThread m_ServerThread; // 服务器线程
|
||||
std::mutex ws_connections_mutex_; // WebSocket连接锁
|
||||
std::vector<mg_connection*> ws_connections_; // WebSocket连接列表
|
||||
std::unordered_map<mg_connection*, uint64_t> ws_last_io_time_; // 连接最后活动时间
|
||||
|
||||
// 日志文件相关
|
||||
std::string m_logFilePath = "pPowerManger.log";
|
||||
std::ifstream m_logFile;
|
||||
std::streampos m_lastLogPosition = 0;
|
||||
std::deque<std::string> m_logCache; // 缓存最近的日志
|
||||
static const size_t MAX_CACHE_SIZE = 1000; // 最大缓存条数
|
||||
|
||||
};
|
||||
|
||||
#endif // HTTP_SERVER_H
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,617 +0,0 @@
|
||||
#ifndef HTTP_SERVER_LOGPAGE_H
|
||||
#define HTTP_SERVER_LOGPAGE_H
|
||||
|
||||
#include <string>
|
||||
|
||||
const std::string LOG_PAGE_HTML = R"(
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>系统日志 - Power Manager</title>
|
||||
<style>
|
||||
:root {
|
||||
--primary-color: #2563eb;
|
||||
--primary-hover: #1d4ed8;
|
||||
--bg-color: #f8fafc;
|
||||
--sidebar-width: 60px;
|
||||
--sidebar-expanded: 220px;
|
||||
--header-height: 36px;
|
||||
}
|
||||
|
||||
* {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
body {
|
||||
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
|
||||
background-color: var(--bg-color);
|
||||
color: #1a1a1a;
|
||||
}
|
||||
|
||||
.container {
|
||||
display: grid;
|
||||
grid-template-areas: "sidebar main-content";
|
||||
grid-template-columns: var(--sidebar-width) 1fr;
|
||||
grid-template-rows: 1fr;
|
||||
min-height: 100vh;
|
||||
gap: 0;
|
||||
}
|
||||
|
||||
.header {
|
||||
grid-area: unset;
|
||||
background: white;
|
||||
padding: 0 0.5rem;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1);
|
||||
position: fixed;
|
||||
top: 0;
|
||||
right: 0;
|
||||
left: var(--sidebar-width);
|
||||
height: var(--header-height);
|
||||
z-index: 10;
|
||||
}
|
||||
|
||||
.header h1 {
|
||||
font-size: 1.25rem;
|
||||
font-weight: 600;
|
||||
color: #1a1a1a;
|
||||
}
|
||||
|
||||
.sidebar {
|
||||
grid-area: sidebar;
|
||||
background: white;
|
||||
width: var(--sidebar-width);
|
||||
height: 100vh;
|
||||
position: fixed;
|
||||
left: 0;
|
||||
top: 0;
|
||||
padding: 0.5rem 0.25rem;
|
||||
transition: width 0.3s ease;
|
||||
box-shadow: 1px 0 3px rgba(0, 0, 0, 0.1);
|
||||
z-index: 20;
|
||||
}
|
||||
|
||||
.sidebar:hover {
|
||||
width: var(--sidebar-expanded);
|
||||
}
|
||||
|
||||
.sidebar-menu {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.5rem;
|
||||
}
|
||||
|
||||
.sidebar-button {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 0.5rem 0.75rem;
|
||||
border-radius: 0.375rem;
|
||||
color: #4b5563;
|
||||
text-decoration: none;
|
||||
transition: all 0.2s ease;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.sidebar-button:hover {
|
||||
background: var(--bg-color);
|
||||
color: var(--primary-color);
|
||||
}
|
||||
|
||||
.sidebar-button.active {
|
||||
background: var(--primary-color);
|
||||
color: white;
|
||||
}
|
||||
|
||||
.sidebar-icon {
|
||||
min-width: 1.5rem;
|
||||
margin-right: 1rem;
|
||||
font-size: 1.25rem;
|
||||
}
|
||||
|
||||
.main-content {
|
||||
grid-area: main-content;
|
||||
padding: 1px;
|
||||
margin-top: var(--header-height);
|
||||
}
|
||||
|
||||
.log-panel {
|
||||
background: white;
|
||||
border-radius: 4px;
|
||||
padding: 6px;
|
||||
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
|
||||
height: calc(100vh - var(--header-height));
|
||||
overflow: hidden;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.log-controls {
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
padding: 4px;
|
||||
border-bottom: 1px solid #e5e7eb;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.log-button {
|
||||
padding: 4px 12px;
|
||||
border: 1px solid #e5e7eb;
|
||||
border-radius: 4px;
|
||||
background: white;
|
||||
color: #4b5563;
|
||||
cursor: pointer;
|
||||
font-size: 0.875rem;
|
||||
transition: all 0.2s;
|
||||
}
|
||||
|
||||
.log-button:hover {
|
||||
background: var(--bg-color);
|
||||
border-color: var(--primary-color);
|
||||
color: var(--primary-color);
|
||||
}
|
||||
|
||||
.log-filter {
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
align-items: center;
|
||||
margin-left: auto;
|
||||
}
|
||||
|
||||
.log-filter select, .log-filter input {
|
||||
padding: 4px 8px;
|
||||
border: 1px solid #e5e7eb;
|
||||
border-radius: 4px;
|
||||
font-size: 0.875rem;
|
||||
color: #4b5563;
|
||||
}
|
||||
|
||||
.log-filter input {
|
||||
width: 150px;
|
||||
}
|
||||
|
||||
.log-pagination {
|
||||
display: flex;
|
||||
gap: 4px;
|
||||
align-items: center;
|
||||
padding: 4px;
|
||||
border-top: 1px solid #e5e7eb;
|
||||
justify-content: space-between;
|
||||
font-size: 0.875rem;
|
||||
color: #4b5563;
|
||||
}
|
||||
|
||||
.page-info {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.page-size {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 4px;
|
||||
}
|
||||
|
||||
.page-size select {
|
||||
padding: 2px 4px;
|
||||
border: 1px solid #e5e7eb;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.page-nav {
|
||||
display: flex;
|
||||
gap: 4px;
|
||||
}
|
||||
|
||||
.page-nav button {
|
||||
padding: 2px 8px;
|
||||
border: 1px solid #e5e7eb;
|
||||
border-radius: 4px;
|
||||
background: white;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.page-nav button:disabled {
|
||||
opacity: 0.5;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
|
||||
.log-content {
|
||||
flex: 1;
|
||||
overflow: auto;
|
||||
padding: 8px;
|
||||
font-family: monospace;
|
||||
font-size: 0.875rem;
|
||||
line-height: 1.5;
|
||||
white-space: pre-wrap;
|
||||
background: #1a1a1a;
|
||||
color: #f8fafc;
|
||||
margin: 4px;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.log-entry {
|
||||
margin: 2px 0;
|
||||
padding: 2px 4px;
|
||||
border-radius: 2px;
|
||||
}
|
||||
|
||||
.log-entry:hover {
|
||||
background: rgba(255, 255, 255, 0.1);
|
||||
}
|
||||
|
||||
.log-entry.error {
|
||||
color: #f87171;
|
||||
}
|
||||
|
||||
.log-entry.warning {
|
||||
color: #fbbf24;
|
||||
}
|
||||
|
||||
.log-entry.info {
|
||||
color: #60a5fa;
|
||||
}
|
||||
|
||||
.status-bar {
|
||||
position: fixed;
|
||||
top: 4px;
|
||||
right: 8px;
|
||||
background: white;
|
||||
padding: 4px 8px;
|
||||
border-radius: 4px;
|
||||
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
z-index: 15;
|
||||
}
|
||||
|
||||
.status-info {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
color: #4b5563;
|
||||
font-size: 0.875rem;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<div class="sidebar">
|
||||
<div class="sidebar-menu">
|
||||
<a href="/" class="sidebar-button">
|
||||
<span class="sidebar-icon">🏠</span>
|
||||
<span>系统主页</span>
|
||||
</a>
|
||||
<a href="/data" class="sidebar-button">
|
||||
<span class="sidebar-icon">📊</span>
|
||||
<span>系统数据</span>
|
||||
</a>
|
||||
<a href="/dashboard" class="sidebar-button">
|
||||
<span class="sidebar-icon">⚡</span>
|
||||
<span>配电操作</span>
|
||||
</a>
|
||||
<a href="/logs" class="sidebar-button active">
|
||||
<span class="sidebar-icon">📝</span>
|
||||
<span>系统日志</span>
|
||||
</a>
|
||||
<a href="/testpage" class="sidebar-button">
|
||||
<span class="sidebar-icon">🧪</span>
|
||||
<span>测试页面</span>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="header">
|
||||
<h1>系统日志</h1>
|
||||
<div class="status-bar">
|
||||
<div class="status-info">
|
||||
<span>🟢 系统状态: <span id="systemStatus">运行中</span></span>
|
||||
<span>⚡ 应用频率: <span id="appFreq">0</span> Hz</span>
|
||||
<span>📡 通信频率: <span id="commFreq">0</span> Hz</span>
|
||||
<span>💻 CPU负载: <span id="cpuLoad">0</span>%</span>
|
||||
<span>⏱️ 迭代间隔: <span id="timeSinceIterate">0</span>ms</span>
|
||||
<span>🕒 更新时间: <time id="updateTime">2025-05-18 15:52</time></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="main-content">
|
||||
<div class="log-panel">
|
||||
<div class="log-controls">
|
||||
<button class="log-button" id="clearBtn">清空显示</button>
|
||||
<button class="log-button" id="scrollLockBtn">自动滚动</button>
|
||||
<button class="log-button" id="downloadBtn">下载日志</button>
|
||||
<div class="log-filter">
|
||||
<select id="logLevel">
|
||||
<option value="ALL">所有级别</option>
|
||||
<option value="ERROR">错误</option>
|
||||
<option value="WARNING">警告</option>
|
||||
<option value="INFO">信息</option>
|
||||
</select>
|
||||
<input type="text" id="searchInput" placeholder="搜索日志...">
|
||||
</div>
|
||||
</div>
|
||||
<div class="log-content" id="logContent"></div>
|
||||
<div class="log-pagination">
|
||||
<div class="page-size">
|
||||
每页显示:
|
||||
<select id="pageSize">
|
||||
<option value="100">100</option>
|
||||
<option value="200" selected>200</option>
|
||||
<option value="500">500</option>
|
||||
<option value="1000">1000</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="page-info">
|
||||
<span id="pageInfo">第 0/0 页</span>
|
||||
<div class="page-nav">
|
||||
<button id="firstPage">首页</button>
|
||||
<button id="prevPage">上一页</button>
|
||||
<button id="nextPage">下一页</button>
|
||||
<button id="lastPage">末页</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
let ws = null;
|
||||
let autoScroll = true;
|
||||
let logContent = document.getElementById('logContent');
|
||||
let currentPage = 1;
|
||||
let totalPages = 1;
|
||||
let pageSize = 200;
|
||||
let allLogs = [];
|
||||
let filteredLogs = [];
|
||||
let searchTimer = null;
|
||||
|
||||
function initWebSocket() {
|
||||
ws = new WebSocket('ws://' + window.location.host + '/ws');
|
||||
|
||||
ws.onopen = () => {
|
||||
console.log('WebSocket连接已建立');
|
||||
updateStatus('运行中', true);
|
||||
requestLogs();
|
||||
};
|
||||
|
||||
ws.onmessage = (event) => {
|
||||
const data = JSON.parse(event.data);
|
||||
if (data.type === 'log') {
|
||||
// 初始加载的日志数据
|
||||
allLogs = data.content;
|
||||
filterAndDisplayLogs();
|
||||
} else if (data.type === 'new_log') {
|
||||
// 新的日志条目
|
||||
if (Array.isArray(data.content)) {
|
||||
let shouldUpdate = false;
|
||||
data.content.forEach(log => {
|
||||
allLogs.push(log);
|
||||
if (shouldShowLog(log)) {
|
||||
filteredLogs.push(log);
|
||||
shouldUpdate = true;
|
||||
// 如果在最后一页或自动滚动模式下,直接添加到显示
|
||||
if (currentPage === totalPages || autoScroll) {
|
||||
appendLogEntry(log);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
if (shouldUpdate) {
|
||||
totalPages = Math.ceil(filteredLogs.length / pageSize);
|
||||
updatePagination();
|
||||
|
||||
// 如果开启了自动滚动,确保滚动到底部
|
||||
if (autoScroll) {
|
||||
logContent.scrollTop = logContent.scrollHeight;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (data.moosdb) {
|
||||
// 更新MOOSDB信息
|
||||
document.getElementById('appFreq').textContent = data.moosdb.appFreq.toFixed(2);
|
||||
document.getElementById('commFreq').textContent = data.moosdb.commFreq.toFixed(2);
|
||||
document.getElementById('cpuLoad').textContent = data.moosdb.cpuLoad.toFixed(1);
|
||||
document.getElementById('timeSinceIterate').textContent = data.moosdb.timeSinceIterate.toFixed(0);
|
||||
} else if (data.type === 'system_status') {
|
||||
updateStatus(data.status, true);
|
||||
}
|
||||
updateTime();
|
||||
};
|
||||
|
||||
ws.onclose = () => {
|
||||
console.log('WebSocket连接已关闭');
|
||||
updateStatus('已断开', false);
|
||||
// 增加重连延迟,避免快速重连
|
||||
setTimeout(() => {
|
||||
if (!ws || ws.readyState === WebSocket.CLOSED) {
|
||||
initWebSocket();
|
||||
}
|
||||
}, 2000);
|
||||
};
|
||||
|
||||
ws.onerror = (error) => {
|
||||
console.error('WebSocket错误:', error);
|
||||
updateStatus('错误', false);
|
||||
};
|
||||
}
|
||||
|
||||
function requestLogs() {
|
||||
ws.send(JSON.stringify({
|
||||
type: 'get_logs',
|
||||
page: currentPage,
|
||||
pageSize: pageSize,
|
||||
filter: {
|
||||
level: document.getElementById('logLevel').value,
|
||||
search: document.getElementById('searchInput').value
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
function shouldShowLog(logEntry) {
|
||||
const level = document.getElementById('logLevel').value;
|
||||
const search = document.getElementById('searchInput').value.toLowerCase();
|
||||
|
||||
if (level !== 'ALL') {
|
||||
if (!logEntry.includes(level)) return false;
|
||||
}
|
||||
|
||||
if (search && !logEntry.toLowerCase().includes(search)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
function filterAndDisplayLogs() {
|
||||
filteredLogs = allLogs.filter(shouldShowLog);
|
||||
totalPages = Math.ceil(filteredLogs.length / pageSize);
|
||||
displayCurrentPage();
|
||||
updatePagination();
|
||||
}
|
||||
|
||||
function displayCurrentPage() {
|
||||
logContent.innerHTML = '';
|
||||
const start = (currentPage - 1) * pageSize;
|
||||
const end = Math.min(start + pageSize, filteredLogs.length);
|
||||
|
||||
for (let i = start; i < end; i++) {
|
||||
appendLogEntry(filteredLogs[i]);
|
||||
}
|
||||
}
|
||||
|
||||
function updatePagination() {
|
||||
document.getElementById('pageInfo').textContent = `第 ${currentPage}/${totalPages} 页`;
|
||||
document.getElementById('firstPage').disabled = currentPage === 1;
|
||||
document.getElementById('prevPage').disabled = currentPage === 1;
|
||||
document.getElementById('nextPage').disabled = currentPage === totalPages;
|
||||
document.getElementById('lastPage').disabled = currentPage === totalPages;
|
||||
}
|
||||
|
||||
// 事件监听器
|
||||
document.getElementById('logLevel').addEventListener('change', () => {
|
||||
currentPage = 1;
|
||||
filterAndDisplayLogs();
|
||||
});
|
||||
|
||||
document.getElementById('searchInput').addEventListener('input', (e) => {
|
||||
clearTimeout(searchTimer);
|
||||
searchTimer = setTimeout(() => {
|
||||
currentPage = 1;
|
||||
filterAndDisplayLogs();
|
||||
}, 300);
|
||||
});
|
||||
|
||||
document.getElementById('pageSize').addEventListener('change', (e) => {
|
||||
pageSize = parseInt(e.target.value);
|
||||
currentPage = 1;
|
||||
filterAndDisplayLogs();
|
||||
});
|
||||
|
||||
document.getElementById('firstPage').addEventListener('click', () => {
|
||||
currentPage = 1;
|
||||
displayCurrentPage();
|
||||
updatePagination();
|
||||
});
|
||||
|
||||
document.getElementById('prevPage').addEventListener('click', () => {
|
||||
if (currentPage > 1) {
|
||||
currentPage--;
|
||||
displayCurrentPage();
|
||||
updatePagination();
|
||||
}
|
||||
});
|
||||
|
||||
document.getElementById('nextPage').addEventListener('click', () => {
|
||||
if (currentPage < totalPages) {
|
||||
currentPage++;
|
||||
displayCurrentPage();
|
||||
updatePagination();
|
||||
}
|
||||
});
|
||||
|
||||
document.getElementById('lastPage').addEventListener('click', () => {
|
||||
currentPage = totalPages;
|
||||
displayCurrentPage();
|
||||
updatePagination();
|
||||
});
|
||||
|
||||
function appendLogEntry(content) {
|
||||
const entry = document.createElement('div');
|
||||
entry.className = 'log-entry';
|
||||
|
||||
// 根据日志内容设置不同的样式
|
||||
if (content.includes('ERROR') || content.includes('ERR')) {
|
||||
entry.classList.add('error');
|
||||
} else if (content.includes('WARNING') || content.includes('WARN')) {
|
||||
entry.classList.add('warning');
|
||||
} else if (content.includes('INFO')) {
|
||||
entry.classList.add('info');
|
||||
}
|
||||
|
||||
entry.textContent = content;
|
||||
logContent.appendChild(entry);
|
||||
|
||||
// 只在自动滚动模式下滚动到底部
|
||||
if (autoScroll) {
|
||||
logContent.scrollTop = logContent.scrollHeight;
|
||||
}
|
||||
}
|
||||
|
||||
function updateStatus(status, isConnected) {
|
||||
const statusElement = document.querySelector('.status-info span:first-child');
|
||||
statusElement.innerHTML = `${isConnected ? '🟢' : '🔴'} 系统状态: ${status}`;
|
||||
}
|
||||
|
||||
function updateTime() {
|
||||
const now = new Date();
|
||||
const timeStr = now.toLocaleString('zh-CN', {
|
||||
year: 'numeric',
|
||||
month: '2-digit',
|
||||
day: '2-digit',
|
||||
hour: '2-digit',
|
||||
minute: '2-digit',
|
||||
second: '2-digit',
|
||||
hour12: false
|
||||
});
|
||||
document.getElementById('updateTime').textContent = timeStr;
|
||||
}
|
||||
|
||||
// 按钮事件处理
|
||||
document.getElementById('clearBtn').onclick = () => {
|
||||
logContent.innerHTML = '';
|
||||
};
|
||||
|
||||
document.getElementById('scrollLockBtn').onclick = function() {
|
||||
autoScroll = !autoScroll;
|
||||
this.textContent = autoScroll ? '自动滚动' : '已锁定';
|
||||
this.style.backgroundColor = autoScroll ? 'white' : '#e5e7eb';
|
||||
};
|
||||
|
||||
document.getElementById('downloadBtn').onclick = () => {
|
||||
const text = logContent.innerText;
|
||||
const blob = new Blob([text], { type: 'text/plain' });
|
||||
const url = URL.createObjectURL(blob);
|
||||
const a = document.createElement('a');
|
||||
a.href = url;
|
||||
a.download = `system_log_${new Date().toISOString().slice(0,19).replace(/[:-]/g, '')}.txt`;
|
||||
document.body.appendChild(a);
|
||||
a.click();
|
||||
document.body.removeChild(a);
|
||||
URL.revokeObjectURL(url);
|
||||
};
|
||||
|
||||
window.addEventListener('load', initWebSocket);
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
)";
|
||||
|
||||
#endif // HTTP_SERVER_LOGPAGE_H
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,458 +0,0 @@
|
||||
#ifndef HTTP_SERVER_TESTPAGE_H
|
||||
#define HTTP_SERVER_TESTPAGE_H
|
||||
|
||||
#include <string>
|
||||
|
||||
const std::string TESTPAGE_HTML = R"row(
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>测试页面</title>
|
||||
<link rel="stylesheet" href="/static/style.css">
|
||||
<style>
|
||||
:root {
|
||||
--primary-color: #2563eb;
|
||||
--primary-hover: #1d4ed8;
|
||||
--bg-color: #f8fafc;
|
||||
--sidebar-width: 60px;
|
||||
--sidebar-expanded: 220px;
|
||||
--header-height: 36px;
|
||||
}
|
||||
|
||||
* {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
body {
|
||||
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
|
||||
background-color: var(--bg-color);
|
||||
color: #1a1a1a;
|
||||
}
|
||||
|
||||
.container {
|
||||
display: grid;
|
||||
grid-template-areas:
|
||||
"sidebar main-content";
|
||||
grid-template-columns: var(--sidebar-width) 1fr;
|
||||
grid-template-rows: 1fr;
|
||||
min-height: 100vh;
|
||||
gap: 0;
|
||||
}
|
||||
|
||||
.header {
|
||||
grid-area: unset;
|
||||
background: white;
|
||||
padding: 0 0.5rem;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1);
|
||||
position: fixed;
|
||||
top: 0;
|
||||
right: 0;
|
||||
left: var(--sidebar-width);
|
||||
height: var(--header-height);
|
||||
z-index: 10;
|
||||
}
|
||||
|
||||
.header h1 {
|
||||
font-size: 1.25rem;
|
||||
font-weight: 600;
|
||||
color: #1a1a1a;
|
||||
}
|
||||
|
||||
.sidebar {
|
||||
grid-area: sidebar;
|
||||
background: white;
|
||||
width: var(--sidebar-width);
|
||||
height: 100vh;
|
||||
position: fixed;
|
||||
left: 0;
|
||||
top: 0;
|
||||
padding: 0.5rem 0.25rem;
|
||||
transition: width 0.3s ease;
|
||||
box-shadow: 1px 0 3px rgba(0, 0, 0, 0.1);
|
||||
z-index: 20;
|
||||
}
|
||||
|
||||
.sidebar:hover {
|
||||
width: var(--sidebar-expanded);
|
||||
}
|
||||
|
||||
.sidebar-menu {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.5rem;
|
||||
}
|
||||
|
||||
.sidebar-button {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 0.5rem 0.75rem;
|
||||
border-radius: 0.375rem;
|
||||
color: #4b5563;
|
||||
text-decoration: none;
|
||||
transition: all 0.2s ease;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.sidebar-button:hover {
|
||||
background: var(--bg-color);
|
||||
color: var(--primary-color);
|
||||
}
|
||||
|
||||
.sidebar-icon {
|
||||
min-width: 1.5rem;
|
||||
margin-right: 1rem;
|
||||
font-size: 1.25rem;
|
||||
}
|
||||
|
||||
.main-content {
|
||||
grid-area: main-content;
|
||||
padding: 1px;
|
||||
margin-top: var(--header-height);
|
||||
}
|
||||
|
||||
.status-bar {
|
||||
position: fixed;
|
||||
top: 4px;
|
||||
right: 8px;
|
||||
background: white;
|
||||
padding: 4px 8px;
|
||||
border-radius: 4px;
|
||||
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
z-index: 15;
|
||||
}
|
||||
|
||||
.status-info {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
color: #4b5563;
|
||||
font-size: 0.875rem;
|
||||
}
|
||||
|
||||
.data-panel {
|
||||
background: white;
|
||||
border-radius: 4px;
|
||||
padding: 16px;
|
||||
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
|
||||
height: calc(100vh - var(--header-height) + 3px);
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
.panel-title {
|
||||
font-size: 1rem;
|
||||
font-weight: 600;
|
||||
color: #1a1a1a;
|
||||
margin-bottom: 16px;
|
||||
padding-bottom: 8px;
|
||||
border-bottom: 1px solid #e5e7eb;
|
||||
}
|
||||
|
||||
.form-group {
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
.form-label {
|
||||
display: block;
|
||||
margin-bottom: 8px;
|
||||
font-weight: 500;
|
||||
color: #374151;
|
||||
}
|
||||
|
||||
.form-input {
|
||||
width: 100%;
|
||||
padding: 8px 12px;
|
||||
border: 1px solid #d1d5db;
|
||||
border-radius: 4px;
|
||||
font-size: 14px;
|
||||
transition: border-color 0.2s;
|
||||
}
|
||||
|
||||
.form-input:focus {
|
||||
outline: none;
|
||||
border-color: var(--primary-color);
|
||||
box-shadow: 0 0 0 2px rgba(37, 99, 235, 0.1);
|
||||
}
|
||||
|
||||
.btn {
|
||||
display: inline-block;
|
||||
padding: 8px 16px;
|
||||
background-color: var(--primary-color);
|
||||
color: white;
|
||||
border: none;
|
||||
border-radius: 4px;
|
||||
font-size: 14px;
|
||||
font-weight: 500;
|
||||
cursor: pointer;
|
||||
transition: background-color 0.2s;
|
||||
}
|
||||
|
||||
.btn:hover {
|
||||
background-color: var(--primary-hover);
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.container {
|
||||
grid-template-columns: 1fr;
|
||||
grid-template-areas:
|
||||
"header"
|
||||
"main-content";
|
||||
}
|
||||
|
||||
.sidebar {
|
||||
transform: translateX(-100%);
|
||||
}
|
||||
|
||||
.header {
|
||||
left: 0;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<div class="sidebar">
|
||||
<div class="sidebar-menu">
|
||||
<a href="/" class="sidebar-button">
|
||||
<span class="sidebar-icon">🏠</span>
|
||||
<span>系统主页</span>
|
||||
</a>
|
||||
<a href="/data" class="sidebar-button">
|
||||
<span class="sidebar-icon">📊</span>
|
||||
<span>系统数据</span>
|
||||
</a>
|
||||
<a href="/dashboard" class="sidebar-button">
|
||||
<span class="sidebar-icon">⚡</span>
|
||||
<span>配电操作</span>
|
||||
</a>
|
||||
<a href="/logs" class="sidebar-button">
|
||||
<span class="sidebar-icon">📝</span>
|
||||
<span>系统日志</span>
|
||||
</a>
|
||||
<a href="/testpage" class="sidebar-button">
|
||||
<span class="sidebar-icon">🧪</span>
|
||||
<span>测试页面</span>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="header">
|
||||
<h1>测试页面</h1>
|
||||
<div class="status-bar">
|
||||
<div class="status-info">
|
||||
<span>🟢 系统状态: <span id="systemStatus">运行中</span></span>
|
||||
<span>⚡ 应用频率: <span id="appFreq">0</span> Hz</span>
|
||||
<span>📡 通信频率: <span id="commFreq">0</span> Hz</span>
|
||||
<span>💻 CPU负载: <span id="cpuLoad">0</span>%</span>
|
||||
<span>⏱️ 迭代间隔: <span id="timeSinceIterate">0</span>ms</span>
|
||||
<span>🕒 更新时间: <time id="updateTime">2025-05-19 11:54</time></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="main-content">
|
||||
<div class="data-panel">
|
||||
<div class="panel-title">测试表单</div>
|
||||
<form id="testForm">
|
||||
<div class="form-section">
|
||||
<div class="panel-subtitle">测试类型/ID设置</div>
|
||||
<div class="form-group">
|
||||
<label for="type" class="form-label">类型</label>
|
||||
<input type="number" id="type" name="type" class="form-input" min="0" required>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="id" class="form-label">ID</label>
|
||||
<input type="number" id="id" name="id" class="form-input" min="0" required>
|
||||
</div>
|
||||
<button type="button" class="btn" onclick="submitTestForm()">提交类型/ID</button>
|
||||
</div>
|
||||
|
||||
<div class="form-section">
|
||||
<div class="panel-subtitle">MOOSDB测试消息设置</div>
|
||||
<div class="form-group">
|
||||
<label for="key" class="form-label">键(Key)</label>
|
||||
<input type="text" id="key" name="key" class="form-input" required>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="value" class="form-label">值(Value)</label>
|
||||
<input type="text" id="value" name="value" class="form-input" required>
|
||||
</div>
|
||||
<button type="button" class="btn" onclick="submitKeyValueForm()" style="background-color: #4f46e5;">提交键值对</button>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<style>
|
||||
.form-section {
|
||||
margin-bottom: 24px;
|
||||
padding: 16px;
|
||||
background: #f9fafb;
|
||||
border-radius: 8px;
|
||||
}
|
||||
.panel-subtitle {
|
||||
font-size: 0.9rem;
|
||||
font-weight: 600;
|
||||
color: #4b5563;
|
||||
margin-bottom: 12px;
|
||||
padding-bottom: 4px;
|
||||
border-bottom: 1px solid #e5e7eb;
|
||||
}
|
||||
</style>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
let ws = null;
|
||||
|
||||
function initWebSocket() {
|
||||
ws = new WebSocket('ws://' + window.location.host + '/ws');
|
||||
|
||||
ws.onopen = () => {
|
||||
console.log('WebSocket连接已建立');
|
||||
updateStatus('运行中', true);
|
||||
};
|
||||
|
||||
ws.onmessage = (event) => {
|
||||
const data = JSON.parse(event.data);
|
||||
console.log('收到系统数据:', data);
|
||||
|
||||
// 更新MOOSDB信息
|
||||
if (data.moosdb) {
|
||||
document.getElementById('appFreq').textContent = data.moosdb.appFreq.toFixed(2);
|
||||
document.getElementById('commFreq').textContent = data.moosdb.commFreq.toFixed(2);
|
||||
document.getElementById('cpuLoad').textContent = data.moosdb.cpuLoad.toFixed(1);
|
||||
document.getElementById('timeSinceIterate').textContent = data.moosdb.timeSinceIterate.toFixed(0);
|
||||
}
|
||||
|
||||
updateTime();
|
||||
};
|
||||
|
||||
ws.onclose = () => {
|
||||
console.log('WebSocket连接已关闭');
|
||||
updateStatus('已断开', false);
|
||||
setTimeout(initWebSocket, 5000);
|
||||
};
|
||||
|
||||
ws.onerror = (error) => {
|
||||
console.error('WebSocket错误:', error);
|
||||
updateStatus('错误', false);
|
||||
};
|
||||
}
|
||||
|
||||
function updateStatus(status, isConnected) {
|
||||
const statusElement = document.querySelector('.status-info span:first-child');
|
||||
statusElement.innerHTML = `${isConnected ? '🟢' : '🔴'} 系统状态: ${status}`;
|
||||
}
|
||||
|
||||
function updateTime() {
|
||||
const now = new Date();
|
||||
const timeStr = now.toLocaleString('zh-CN', {
|
||||
year: 'numeric',
|
||||
month: '2-digit',
|
||||
day: '2-digit',
|
||||
hour: '2-digit',
|
||||
minute: '2-digit',
|
||||
second: '2-digit',
|
||||
hour12: false
|
||||
});
|
||||
document.getElementById('updateTime').textContent = timeStr;
|
||||
}
|
||||
|
||||
function submitTestForm() {
|
||||
const form = document.getElementById('testForm');
|
||||
const typeValue = parseInt(form.type.value);
|
||||
const idValue = parseInt(form.id.value);
|
||||
|
||||
if (typeValue < 0 || idValue < 0) {
|
||||
alert('请输入非负整数');
|
||||
return;
|
||||
}
|
||||
|
||||
const formData = {
|
||||
type: typeValue,
|
||||
id: idValue
|
||||
};
|
||||
|
||||
sendFormData(formData);
|
||||
}
|
||||
|
||||
function submitKeyValueForm() {
|
||||
const key = document.getElementById('key').value.trim();
|
||||
const value = document.getElementById('value').value.trim();
|
||||
|
||||
if (!key || !value) {
|
||||
alert('请输入键和值');
|
||||
return;
|
||||
}
|
||||
|
||||
// 直接构造JSON对象,不通过form
|
||||
const payload = {
|
||||
key: key,
|
||||
value: value
|
||||
};
|
||||
|
||||
// 专门发送到MOOSDB测试消息接口
|
||||
fetch('/moosdb_test', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify(payload)
|
||||
})
|
||||
.then(response => {
|
||||
if (!response.ok) {
|
||||
throw new Error(`HTTP error! status: ${response.status}`);
|
||||
}
|
||||
return response.json();
|
||||
})
|
||||
.then(data => {
|
||||
if (data.success) {
|
||||
alert('MOOSDB测试消息提交成功: ' + data.message);
|
||||
} else {
|
||||
alert('MOOSDB测试消息提交失败: ' + data.error);
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('MOOSDB测试消息提交错误:', error);
|
||||
alert('MOOSDB测试消息提交过程中发生错误: ' + error.message);
|
||||
});
|
||||
}
|
||||
|
||||
function sendFormData(formData) {
|
||||
|
||||
fetch('/testpage', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify(formData)
|
||||
})
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
if (data.success) {
|
||||
alert('提交成功: ' + data.message);
|
||||
} else {
|
||||
alert('提交失败: ' + data.error);
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('提交错误:', error);
|
||||
alert('提交过程中发生错误');
|
||||
});
|
||||
}
|
||||
|
||||
window.addEventListener('load', initWebSocket);
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
)row";
|
||||
|
||||
#endif // HTTP_SERVER_TESTPAGE_H
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,9 +0,0 @@
|
||||
//SERVERHOST = 192.168.0.223
|
||||
//SERVERPORT = 9000
|
||||
ProcessConfig = pPowerManger
|
||||
{
|
||||
AppTick = 4
|
||||
CommsTick = 4
|
||||
log_level = INFO
|
||||
log_file = /path/to/your/logfile.log
|
||||
}
|
||||
@@ -1,964 +0,0 @@
|
||||
#ifndef PMSYSVARIABLE_H
|
||||
#define PMSYSVARIABLE_H
|
||||
|
||||
//宏定义
|
||||
#include<string>
|
||||
#include <map>
|
||||
#include <unordered_set>
|
||||
|
||||
#define BREAK_OFF 0xAA
|
||||
#define BREAK_ON 0x55
|
||||
#define BREAK_FALSE 0x5A
|
||||
|
||||
//消息结构体变量定义
|
||||
#pragma pack (1)
|
||||
typedef struct ccuState
|
||||
{
|
||||
uint8_t fc_mode; // 燃料电池系统运行模式:00H-无效, 01H-调试, 02H-自动, 03H-补给
|
||||
uint8_t fc_status; // 燃料电池状态:00H-无效, 01H-初始化, ..., 0DH-维护完成(详见协议)
|
||||
uint8_t fc_fault_level; // 燃料电池故障等级:00H-无故障, 10H-一级, 20H-二级, 30H-三级, 40H-四级
|
||||
|
||||
uint16_t output_power_limit; // 系统输出功率限制值,单位:W,范围:0~30000W
|
||||
uint16_t total_generation_time; // 系统累计发电时间,单位:0.1小时,最大值6553.5小时
|
||||
uint16_t total_generation_power; // 系统累计发电总功率,单位:W
|
||||
uint16_t fault_level_1; // 一级故障位,按位表示不同的故障项
|
||||
uint16_t fault_level_2; // 二级故障位
|
||||
uint16_t fault_level_3; // 三级故障位
|
||||
uint16_t fault_level_4; // 四级故障位
|
||||
|
||||
uint8_t hydrogen_capacity; // 储氢罐剩余容量百分比,单位:%,范围:0~100
|
||||
uint8_t liquid_oxygen_capacity; // 液氧罐剩余容量百分比,单位:%,范围:0~100
|
||||
|
||||
uint16_t palladium_temp; // 钯膜最高温度,单位:℃
|
||||
uint16_t main_pipe_pressure; // 主水路压力,单位:0.01kPa
|
||||
uint16_t aux_pipe_pressure; // 辅水路压力,单位:0.01kPa
|
||||
|
||||
uint16_t cabin_pressure1; // 舱室1压力,单位:0.01kPa
|
||||
uint16_t cabin_pressure2; // 舱室2压力,单位:0.01kPa
|
||||
uint16_t cabin_temp1; // 舱室1温度,单位:0.01℃
|
||||
uint16_t cabin_temp2; // 舱室2温度,单位:0.01℃
|
||||
uint16_t cabin_humidity1; // 舱室1湿度,单位:0.01%RH
|
||||
uint16_t cabin_humidity2; // 舱室2湿度,单位:0.01%RH
|
||||
|
||||
uint8_t flame_detector1; // 火焰探测器1状态:00H-无效, 01H-报警, 02H-故障
|
||||
uint8_t flame_detector2; // 火焰探测器2状态:00H-无效, 01H-报警, 02H-故障
|
||||
|
||||
uint16_t h2_concentration1; // 舱室H2浓度1,单位:0.01% LEL
|
||||
uint16_t h2_concentration2; // 舱室H2浓度2,单位:0.01% LEL
|
||||
uint16_t h2_concentration3; // 舱室H2浓度3,单位:0.01% LEL
|
||||
uint16_t o2_concentration1; // 舱室O2浓度1,单位:0.01% LEL
|
||||
uint16_t o2_concentration2; // 舱室O2浓度2,单位:0.01% LEL
|
||||
uint16_t ch3oh_concentration1; // 舱室甲醇气体浓度1,单位:0.01% LEL
|
||||
uint16_t ch3oh_concentration2; // 舱室甲醇气体浓度2,单位:0.01% LEL
|
||||
|
||||
uint16_t reserved1[2]; // 保留字段前2个元素
|
||||
uint16_t emergency_battery1_voltage; // 应急电池1总电压 [V]
|
||||
uint16_t emergency_battery1_current; // 应急电池1总电流 [A]
|
||||
uint16_t emergency_battery1_max_temp; // 应急电池1最高温度 [°C]
|
||||
uint16_t emergency_battery1_fault_word; // 应急电池1故障字
|
||||
uint16_t emergency_battery2_voltage; // 应急电池2总电压 [V]
|
||||
uint16_t emergency_battery2_current; // 应急电池2总电流 [A]
|
||||
uint16_t emergency_battery2_max_temp; // 应急电池2最高温度 [°C]
|
||||
uint16_t emergency_battery2_fault_word; // 应急电池2故障字
|
||||
|
||||
uint16_t cabin_ox_concentration; // 仪表舱内氧气浓度 [%]
|
||||
uint16_t cabin_temperature; // 仪表舱内温度 [°C]
|
||||
uint16_t cabin_humidity; // 仪表舱内湿度 [%RH]
|
||||
uint16_t cabin_pressure; // 仪表舱内大气压 [kPa]
|
||||
|
||||
uint16_t power_cabin_ox_concentration; // 动力舱内氧气浓度 [%]
|
||||
uint16_t power_cabin_temperature; // 动力舱内温度 [°C]
|
||||
uint16_t power_cabin_humidity; // 动力舱内湿度 [%RH]
|
||||
uint16_t power_cabin_pressure; // 动力舱内大气压 [kPa]
|
||||
uint8_t reserved2[1]; // 保留字段,地址范围54~55,共2个uint8_t,协议预留
|
||||
|
||||
uint8_t dyn_alarm_flag[6]; // 动力锂电池报警标志字数组,共6字节,按位表示各类报警
|
||||
uint8_t ins_alarm_flag[6]; // 仪表锂电池报警标志字数组,共6字节,按位表示各类报警
|
||||
|
||||
uint8_t ins_relay_status1; // 仪表电池继电器状态,高4位表示正极继电器,低4位表示充电继电器
|
||||
uint8_t ins_relay_status2; // 仪表电池预充继电器和负极继电器状态
|
||||
uint8_t dyn_relay_status1; // 动力电池正极与充电继电器状态
|
||||
uint8_t dyn_relay_status2; // 动力电池预充与负极继电器状态
|
||||
|
||||
uint16_t ins_max_discharge_power; // 仪表电池最大允许放电功率,单位:kW,精度0.05kW
|
||||
uint16_t dyn_max_discharge_power; // 动力电池最大允许放电功率,单位:kW,精度0.05kW
|
||||
|
||||
uint8_t ins_soc; // 仪表锂电池荷电状态SOC,范围:0~100
|
||||
uint8_t dyn_soc; // 动力锂电池荷电状态SOC,范围:0~100
|
||||
|
||||
uint16_t ins_total_energy; // 仪表电池总能量,单位:kWh
|
||||
uint16_t dyn_total_energy; // 动力电池总能量,单位:kWh
|
||||
|
||||
uint16_t ins_power_input; // 仪表电池输入功率,单位:kW
|
||||
uint16_t dyn_power_input; // 动力电池输入功率,单位:kW
|
||||
|
||||
uint8_t ins_charge_status; // 仪表电池充放电状态:00H-无效,10H-充电,20H-放电
|
||||
uint8_t dyn_charge_status; // 动力电池充放电状态:00H-无效,10H-充电,20H-放电
|
||||
|
||||
uint16_t ins_voltage_link; // 仪表电池LINK端电压,单位:0.01V
|
||||
uint16_t ins_voltage_pack; // 仪表电池PACK端电压,单位:0.01V
|
||||
uint16_t ins_current; // 仪表电池电流,单位:0.01A(正值放电)
|
||||
uint16_t ins_resistance_pos; // 仪表电池正极绝缘电阻,单位:kΩ
|
||||
uint16_t ins_resistance_neg; // 仪表电池负极绝缘电阻,单位:kΩ
|
||||
|
||||
uint16_t dyn_voltage_link; // 动力电池LINK端电压,单位:0.01V
|
||||
uint16_t dyn_voltage_pack; // 动力电池PACK端电压,单位:0.01V
|
||||
uint16_t dyn_current; // 动力电池电流,单位:0.01A(正值放电)
|
||||
uint16_t dyn_resistance_pos; // 动力电池正极绝缘电阻,单位:kΩ
|
||||
uint16_t dyn_resistance_neg; // 动力电池负极绝缘电阻,单位:kΩ
|
||||
|
||||
uint8_t ins_emergency_status; // 仪表电池紧急状态字,按位表示异常或告警状态
|
||||
uint8_t dyn_emergency_status; // 动力电池紧急状态字,按位表示异常或告警状态
|
||||
|
||||
uint8_t reserved3[2]; // 保留字节,协议预留
|
||||
|
||||
uint8_t ins_soc_threshold1; // 仪表电池1 SOC门限,范围:0~100
|
||||
uint8_t ins_soc_threshold2; // 仪表电池2 SOC门限,范围:0~100
|
||||
uint8_t ins_soc_threshold3; // 仪表电池3 SOC门限,范围:0~100
|
||||
uint8_t dyn_soc_threshold1; // 动力电池1 SOC门限,范围:0~100
|
||||
uint8_t dyn_soc_threshold2; // 动力电池2 SOC门限,范围:0~100
|
||||
uint8_t dyn_soc_threshold3; // 动力电池3 SOC门限,范围:0~100
|
||||
|
||||
uint8_t ins_power_limit1; // 仪表电池1功率限制值,单位:%
|
||||
uint8_t ins_power_limit2; // 仪表电池2功率限制值,单位:%
|
||||
uint8_t dyn_power_limit1; // 动力电池1功率限制值,单位:%
|
||||
uint8_t dyn_power_limit2; // 动力电池2功率限制值,单位:%
|
||||
|
||||
uint32_t device_online_flag1; // 设备在线状态标志1,byte0:低压配电板在线标志位 byte1:复合管控主机在线标志位 byte2:复合管控备机在线标志位
|
||||
uint32_t device_online_flag2; // 设备在线状态标志2,byte0:仪表锂电在线标志位 byte1:动力锂电在线标志位 byte2:燃电锂电在线标志位 byte3:高压配电板在线标志位
|
||||
|
||||
uint8_t dyn_charge_level; // 动力电池充电状态:01H-1级(不限), 02H-2级(限功率), 03H-3级(关闭)
|
||||
uint8_t dyn_water_leak_status; // 动力漏水状态:0XH-正常, 1XH-异常漏水
|
||||
uint8_t ins_water_leak_dcdc_status; // 仪表漏水状态与DCDC状态:低4位-漏水状态(0XH正常,1XH异常),高4位-DCDC状态(X0H正常,X1H故障)
|
||||
uint8_t reserved4;
|
||||
// uint32_t reserved4; // 保留字段,协议预留
|
||||
uint32_t heartbeat; // 主机心跳计数器或标志值
|
||||
} ccuState;
|
||||
|
||||
typedef struct {
|
||||
unsigned char insSocHold1;
|
||||
unsigned char insSocHold2;
|
||||
unsigned char insSocHold3;
|
||||
unsigned char fcuToInsLimit1;
|
||||
unsigned char fcuToinsLimit2;
|
||||
unsigned char powerSocHold1;
|
||||
unsigned char powerSocHold2;
|
||||
unsigned char powerSocHold3;
|
||||
unsigned char fcuToPowerLimit1;
|
||||
unsigned char fcuToPowerLimit2;
|
||||
}ccuSetParmCmd;
|
||||
|
||||
typedef struct {
|
||||
unsigned char fcmode;
|
||||
unsigned char fcuCmd;
|
||||
unsigned char fcuPowerEfficiency;
|
||||
unsigned char insChargeEnable;
|
||||
unsigned char insBatCmd;
|
||||
unsigned char powerBatCmd;
|
||||
unsigned short powerBatEfficiency;
|
||||
unsigned char heartbeat;
|
||||
unsigned char masterState;
|
||||
unsigned int paceholder1;
|
||||
unsigned int paceholder2;
|
||||
}ccuColCmd;
|
||||
|
||||
typedef struct disHighVolBusState
|
||||
{
|
||||
//断路器状态
|
||||
// 5: 燃料电池断路器
|
||||
unsigned char fuelCellCircuitBreaker;
|
||||
// 6: 动力锂电池断路器
|
||||
unsigned char powerLithiumBatteryCircuitBreaker;
|
||||
// 7: 推进电机断路器
|
||||
unsigned char propulsionMotorCircuitBreaker;
|
||||
// 8: 锂电池组仪表断路器
|
||||
unsigned char lithiumBatteryGroupInstrumentCircuitBreaker;
|
||||
// 9: DC/DC5模块断路器
|
||||
unsigned char dcDc5ModuleCircuitBreaker;
|
||||
// 10: 艏部高压配电箱断路器
|
||||
unsigned char bowHighVoltageDistributionBoxCircuitBreaker;
|
||||
// 11: 艉部FT装置4/5断路器
|
||||
unsigned char sternFTDevice45CircuitBreaker;
|
||||
|
||||
// 14: FB预留断路器
|
||||
unsigned char fbReservedCircuitBreaker;
|
||||
// 12: 艉舵开关1断路器
|
||||
unsigned char sternRudderSwitch1CircuitBreaker;
|
||||
// 13: 艉舵开关2断路器
|
||||
unsigned char sternRudderSwitch2CircuitBreaker;
|
||||
|
||||
// 15: TYZ预留断路器
|
||||
unsigned char tyzReservedCircuitBreaker;
|
||||
// 16: 预留断路器
|
||||
unsigned char reservedCircuitBreaker;
|
||||
// unsigned char busInsulationLow;
|
||||
// unsigned char busAInsulationHigh;
|
||||
// 17: DC/DC5故障字低
|
||||
// 0x00: 正常状态
|
||||
// Bit0: DC/DC模块过温关机
|
||||
// Bit1: 输出过流
|
||||
// Bit2: 输出过压
|
||||
// Bit3: 输出欠压
|
||||
// Bit4: 输入过压
|
||||
// Bit5: 输入欠压
|
||||
// Bit6: 输出短路保护
|
||||
// Bit7: 内部故障
|
||||
// 18: DC/DC5故障字高
|
||||
unsigned char dcDcFaultWord1;
|
||||
// 0x00: 正常状态
|
||||
// Bit0: 通讯故障报警
|
||||
// Bit1: 工作状态 1:启动,0:关闭
|
||||
// Bit2: 冷却泵1故障 冷却泵1故障 : 1故障, 0 正常
|
||||
// Bit3: 冷却泵2故障 冷却泵2故障 :1故障,0 正常
|
||||
// Bit4: 冷却水泄露
|
||||
// Bit5:冷却泵1运行状态 :1 运行,0 停止
|
||||
// Bit6:冷却泵2运行状态 :1 运行,0 停止
|
||||
unsigned char dcDcFaultWord2;
|
||||
// 19: 动力母排绝缘状态(0x55 正常,0xAA 绝缘低)
|
||||
unsigned char powerBusInsulationStatus;
|
||||
// 20: A汇流排绝缘状态(0x55 正常,0xAA 绝缘低)
|
||||
unsigned char aBusInsulationStatus;
|
||||
// 21: 仪表电源状态 (0x55 正常,0xAA 故障)
|
||||
unsigned char meterPowerLossSignal;
|
||||
// 22: 应急电源状态 (0x55 正常,0xAA 故障)
|
||||
unsigned char emergencyPowerLossSignal;
|
||||
// 22: dc/dc温度
|
||||
unsigned char dcDcTemperature;
|
||||
// 23: 动力汇流排电压
|
||||
unsigned short powerBusVoltage;
|
||||
// 24: DC/DC5模块电流
|
||||
unsigned short dcDc5ModuleCurrent;
|
||||
// 25: 动力汇流排电流
|
||||
unsigned short powerBusCurrent;
|
||||
// 26: A汇流排电压
|
||||
unsigned short busbarAVoltage;
|
||||
// 27: 推进电机控制箱电流
|
||||
unsigned short propulsionMotorControlBoxCurrent;
|
||||
// 28: A汇流排电流
|
||||
unsigned short busbarACurrent;
|
||||
// 29: 锂电池组(仪表)电流
|
||||
unsigned short lithiumBatteryGroupMeterCurrent;
|
||||
// 30: 艏部高压配电箱电流
|
||||
unsigned short bowHighVoltageDistributionBoxCurrent;
|
||||
// 31: 艉部FT装置4/5电流
|
||||
unsigned short sternFTDevice45Current;
|
||||
// 32: TYZ预留开关电流
|
||||
unsigned short tyzReservedSwitchCurrent;
|
||||
// 33: 艉舵开关1电流
|
||||
unsigned short sternRudderSwitch1Current;
|
||||
// 34: 预留电流
|
||||
unsigned short reservedCurrent1; // 改为 reservedCurrent1 以避免重名
|
||||
// 35: 艉舵开关2电流
|
||||
unsigned short sternRudderSwitch2Current;
|
||||
// 36: 预留电流2
|
||||
unsigned short reservedCurrent2; // 改为 reservedCurrent2 以避免重名
|
||||
// 37: FB预留电流
|
||||
unsigned short fbReservedSwitchCurrent;
|
||||
// 38: 预留电流3
|
||||
unsigned short reservedCurrent3; // 改为 reservedCurrent3 以避免重名
|
||||
// 39: 冷却水压力
|
||||
unsigned short coolWaterPressure;
|
||||
}disHighVolBusState;
|
||||
|
||||
typedef struct disHighAVolBusState
|
||||
{
|
||||
//5. 艏部FT装置1/2/3断路器
|
||||
unsigned char bowFTDevice123CircuitBreaker;
|
||||
//6. 启闭机构断路器
|
||||
unsigned char actuatorCircuitBreaker;
|
||||
//7. 桅杆舵机控制箱断路器
|
||||
unsigned char mastSteeringGearControlBoxCircuitBreaker;
|
||||
//8. XCZ断路器
|
||||
unsigned char xczCircuitBreaker;
|
||||
//9. 艏舵控制箱断路器
|
||||
unsigned char bowRudderControlBoxCircuitBreaker;
|
||||
//10. 敞水盖启动电缸断路器
|
||||
unsigned char openWaterCoverStartCylinderCircuitBreaker;
|
||||
//11. 仪表电源失电信号 (0x55 正常,0xAA 故障)
|
||||
unsigned char instrumentPowerFailureSignal;
|
||||
//12. 应急电源失电信号 (0x55 正常,0xAA 故障)
|
||||
unsigned char emergencyPowerFailureSignal;
|
||||
//13. 浸水报警
|
||||
// unsigned char busbarBInsulationStatus;
|
||||
unsigned char waterIngressionAlarm;
|
||||
//14. 汇流排B电压
|
||||
unsigned short busbarBVoltage;
|
||||
//15. 汇流排B电流
|
||||
unsigned short busbarBCurrent;
|
||||
//16. 艏部FT装置1/2/3电流
|
||||
unsigned short bowFTDevice123Current;
|
||||
//17. 启闭机构电流
|
||||
unsigned short actuatorCurrent;
|
||||
//18. 桅杆舵机控制箱电流
|
||||
unsigned short mastSteeringGearControlBoxCurrent;
|
||||
//19. XCZ电流
|
||||
unsigned short xczCurrent;
|
||||
//20. 艏舵控制箱电流
|
||||
unsigned short bowRudderControlBoxCurrent;
|
||||
//21. 敞水盖启动电缸电流
|
||||
unsigned short openWaterCoverStartCylinderCurrent;
|
||||
}disHighAVolBusState;
|
||||
|
||||
typedef struct disHighBVolBusState
|
||||
{
|
||||
//5. 锂电池组(仪表)断路器
|
||||
unsigned char lithiumBatteryGroupInstrumentCircuitBreaker;
|
||||
//6. 艏部低压配电箱断路器
|
||||
unsigned char bowLowVoltageDistributionBoxCircuitBreaker;
|
||||
//7. UNIT4仪表DC48V断路器
|
||||
unsigned char unit4InstrumentDC48VCircuitBreaker;
|
||||
//8. DC-C1直流配电板断路器
|
||||
unsigned char dcC1DCDistributionPanelCircuitBreaker;
|
||||
//9. 预留断路器1
|
||||
unsigned char reservedCircuitBreaker1; // 为了区分,添加了数字后缀
|
||||
//10. 预留断路器2
|
||||
unsigned char reservedCircuitBreaker2; // 为了区分,添加了数字后缀
|
||||
//11. 应急锂电池组2断路器
|
||||
unsigned char emergencyLithiumBatteryGroup2CircuitBreaker;
|
||||
//12. 仪表电源失电信号 (0x55 正常,0xAA 故障)
|
||||
unsigned char instrumentPowerFailureSignal;
|
||||
//13. 应急电源失电信号 (0x55 正常,0xAA 故障)
|
||||
unsigned char emergencyPowerFailureSignal;
|
||||
//14. 仪表汇流排绝缘低 (0x55 正常,0xAA 绝缘低)
|
||||
unsigned char instrumentBusbarInsulationLow;
|
||||
//15. 仪表母排电压
|
||||
unsigned short instrumentBusbarVoltage;
|
||||
//16. 艏部低压配电箱电流
|
||||
unsigned short bowLowVoltageDistributionBoxCurrent;
|
||||
//17. DC-C1(直流配电板1)仪表DC48V电流
|
||||
unsigned short dcC1InstrumentDC48VCurrent;
|
||||
//18. 预留电流
|
||||
unsigned short reservedCurrent1; // 为了区分,添加了数字后缀
|
||||
//19. 应急锂电池组2电流
|
||||
unsigned short emergencyLithiumBatteryGroup2Current;
|
||||
//20. 锂电池组(仪表)电流
|
||||
unsigned short lithiumBatteryGroupInstrumentCurrent;
|
||||
//21. UNIT4仪表DC48V电流
|
||||
unsigned short unit4InstrumentDC48VCurrent;
|
||||
//22. Ushort 预留电流
|
||||
unsigned short reservedCurrent2; // 为了区分,添加了数字后缀
|
||||
//23. 应急2汇流排电压
|
||||
unsigned short emergency2BusbarVoltage;
|
||||
//24. 复合能源管控系统应急DC48V电流
|
||||
unsigned short compositeEnergyManagementSystemEmergencyDC48VCurrent;
|
||||
//25. 燃料电池安全系统应急DC48V电流
|
||||
unsigned short fuelCellSecuritySystemEmergencyDC48VCurrent;
|
||||
//26. PLC控制电源电流
|
||||
unsigned short plcControlPowerCurrent;
|
||||
} disLowMainBusState;
|
||||
|
||||
typedef struct disLowBusState
|
||||
{
|
||||
//5. UNIT1断路器
|
||||
unsigned char unit1CircuitBreaker;
|
||||
//6. UNIT2断路器
|
||||
unsigned char unit2CircuitBreaker;
|
||||
//7. UNIT3断路器
|
||||
unsigned char unit3CircuitBreaker;
|
||||
//8. UNIT5断路器
|
||||
unsigned char unit5CircuitBreaker;
|
||||
//9. 艏部PZ装置断路器
|
||||
unsigned char bowPZDeviceCircuitBreaker;
|
||||
//10. 预留断路器1
|
||||
unsigned char reservedCircuitBreaker1; // 为了区分,添加了数字后缀
|
||||
//11. 预留断路器2
|
||||
unsigned char reservedCircuitBreaker2; // 为了区分,添加了数字后缀
|
||||
//12. 应急锂电池组1断路器
|
||||
unsigned char emergencyLithiumBatteryGroup1CircuitBreaker;
|
||||
//13. 仪表电源失电信号 (0x55 正常,0xAA 故障)
|
||||
unsigned char powerFailureSignal;
|
||||
//14. 应急电源失电信号 (0x55 正常,0xAA 故障)
|
||||
unsigned char emergencyPowerFailureSignal;
|
||||
//15. 浸水报警 (0x55 正常,0xAA 故障)
|
||||
unsigned char waterIngressionAlarm;
|
||||
//16. 仪表母排电压
|
||||
unsigned short instrumentBusbarVoltage;
|
||||
//17. 仪表母排电流
|
||||
unsigned short instrumentBusbarCurrent;
|
||||
//18. UNIT1电流
|
||||
unsigned short unit1Current;
|
||||
//19. UNIT2电流
|
||||
unsigned short unit2Current;
|
||||
//20. UNIT3电流
|
||||
unsigned short unit3Current;
|
||||
//21. UNIT5电流
|
||||
unsigned short unit5Current;
|
||||
//22. 艏部PZ装置电流
|
||||
unsigned short bowPZDeviceCurrent;
|
||||
//23. 应急锂电池组1电流
|
||||
unsigned short emergencyLithiumBatteryGroup1Current;
|
||||
//24. 应急1汇流排电压
|
||||
unsigned short emergency1BusbarVoltage;
|
||||
}disLowBusState;
|
||||
|
||||
typedef struct disHighVolBusCmd
|
||||
{
|
||||
// 5: 燃料电池断路器
|
||||
unsigned char fuelCellCircuitBreaker;
|
||||
// 6: 动力锂电池断路器
|
||||
unsigned char powerLithiumBatteryCircuitBreaker;
|
||||
// 7: 推进电机断路器
|
||||
unsigned char propulsionMotorCircuitBreaker;
|
||||
// 8: 锂电池组仪表断路器
|
||||
unsigned char lithiumBatteryGroupInstrumentCircuitBreaker;
|
||||
// 9: DC/DC5模块断路器
|
||||
unsigned char dcDc5ModuleCircuitBreaker;
|
||||
// 10: 艏部高压配电箱断路器
|
||||
unsigned char bowHighVoltageDistributionBoxCircuitBreaker;
|
||||
// 11: 艉部FT装置4/5断路器
|
||||
unsigned char sternFTDevice45CircuitBreaker;
|
||||
// // 12: 艉舵开关1断路器
|
||||
// unsigned char sternRudderSwitch1CircuitBreaker;
|
||||
// // 13: 艉舵开关2断路器
|
||||
// unsigned char sternRudderSwitch2CircuitBreaker;
|
||||
// // 14: FB预留断路器
|
||||
// unsigned char fbReservedCircuitBreaker;
|
||||
|
||||
// 12: FB预留断路器
|
||||
unsigned char fbReservedCircuitBreaker;
|
||||
// 13: 艉舵开关1断路器
|
||||
unsigned char sternRudderSwitch1CircuitBreaker;
|
||||
// 14: 艉舵开关2断路器
|
||||
unsigned char sternRudderSwitch2CircuitBreaker;
|
||||
|
||||
// 15: TYZ预留断路器
|
||||
unsigned char tyzReservedCircuitBreaker;
|
||||
// 16: 预留断路器
|
||||
unsigned char reservedCircuitBreaker;
|
||||
// 17: DC/DC5模块启动
|
||||
unsigned char dcdc5Module;
|
||||
// 18: 冷却系统启动
|
||||
unsigned char coolingSystem;
|
||||
// unsigned char inputWater;
|
||||
// unsigned char outputWater;
|
||||
}disHighVolBusCmd;
|
||||
|
||||
typedef struct disHighAVolBusCmd
|
||||
{
|
||||
//5. 艏部FT装置1/2/3断路器
|
||||
unsigned char bowFTDevice123CircuitBreaker;
|
||||
//6. 启闭机构断路器
|
||||
unsigned char actuatorCircuitBreaker;
|
||||
//7. 桅杆舵机控制箱断路器
|
||||
unsigned char mastSteeringGearControlBoxCircuitBreaker;
|
||||
//8. XCZ断路器
|
||||
unsigned char xczCircuitBreaker;
|
||||
//9. 艏舵控制箱断路器
|
||||
unsigned char bowRudderControlBoxCircuitBreaker;
|
||||
//10. 敞水盖启动电缸断路器
|
||||
unsigned char openWaterCoverStartCylinderCircuitBreaker;
|
||||
}disHighAVolBusCmd;
|
||||
|
||||
typedef struct disHighBVolBusCmd
|
||||
{
|
||||
//5. 锂电池组(仪表)断路器
|
||||
unsigned char lithiumBatteryGroupInstrumentCircuitBreaker;
|
||||
//6. 艏部低压配电箱断路器
|
||||
unsigned char bowLowVoltageDistributionBoxCircuitBreaker;
|
||||
//7. UNIT4仪表DC48V断路器
|
||||
unsigned char unit4InstrumentDC48VCircuitBreaker;
|
||||
//8. DC-C1直流配电板断路器
|
||||
unsigned char dcC1DCDistributionPanelCircuitBreaker;
|
||||
//9. 预留断路器1
|
||||
unsigned char reservedCircuitBreaker1; // 为了区分,添加了数字后缀
|
||||
//10. 预留断路器2
|
||||
unsigned char reservedCircuitBreaker2; // 为了区分,添加了数字后缀
|
||||
//11. 应急锂电池组2断路器
|
||||
unsigned char emergencyLithiumBatteryGroup2CircuitBreaker;
|
||||
}disLowMainBusCmd;
|
||||
|
||||
typedef struct disLowBusCmd
|
||||
{
|
||||
unsigned char unit1CircuitBreaker;
|
||||
unsigned char unit2CircuitBreaker;
|
||||
unsigned char unit3CircuitBreaker;
|
||||
unsigned char unit5CircuitBreaker;
|
||||
unsigned char bowPZDeviceCircuitBreaker;
|
||||
unsigned char reservedCircuitBreaker1; // 为了区分,添加了数字后缀
|
||||
unsigned char reservedCircuitBreaker2; // 为了区分,添加了数字后缀
|
||||
unsigned char emergencyLithiumBatteryGroup1CircuitBreaker;
|
||||
}disLowBusCmd;
|
||||
|
||||
#pragma pack (0)
|
||||
|
||||
//状态结构体定义
|
||||
typedef struct pmState
|
||||
{
|
||||
ccuState ccustate;
|
||||
disHighVolBusState bus1State;
|
||||
disHighAVolBusState bus2State;
|
||||
disLowMainBusState bus3State;
|
||||
disLowBusState bus4State;
|
||||
} PmState;
|
||||
|
||||
typedef struct disBus1Breaker
|
||||
{
|
||||
unsigned char fuelCellCircuitBreaker : 1;
|
||||
unsigned char powerLithiumBatteryCircuitBreaker : 1;
|
||||
unsigned char propulsionMotorCircuitBreaker : 1;
|
||||
unsigned char lithiumBatteryGroupInstrumentCircuitBreaker : 1;
|
||||
unsigned char dcDc5ModuleCircuitBreaker : 1;
|
||||
unsigned char bowHighVoltageDistributionBoxCircuitBreaker : 1;
|
||||
unsigned char sternFTDevice45CircuitBreaker : 1;
|
||||
unsigned char sternRudderSwitch1CircuitBreaker : 1;
|
||||
unsigned char sternRudderSwitch2CircuitBreaker : 1;
|
||||
unsigned char fbReservedCircuitBreaker : 1;
|
||||
unsigned char tyzReservedCircuitBreaker : 1;
|
||||
unsigned char reservedCircuitBreaker : 1;
|
||||
unsigned char dcdcmodel : 1;
|
||||
unsigned char coolingSystem : 1;
|
||||
unsigned short paceholder : 4;
|
||||
} disBus1Breaker;
|
||||
|
||||
|
||||
typedef struct disBus2Breaker
|
||||
{
|
||||
unsigned char bowFTDevice123CircuitBreaker : 1;
|
||||
unsigned char actuatorCircuitBreaker : 1;
|
||||
unsigned char mastSteeringGearControlBoxCircuitBreaker : 1;
|
||||
unsigned char xczCircuitBreaker : 1;
|
||||
unsigned char bowRudderControlBoxCircuitBreaker : 1;
|
||||
unsigned char openWaterCoverStartCylinderCircuitBreaker : 1;
|
||||
unsigned short paceholder : 10;
|
||||
/* data */
|
||||
} disBus2Breaker;
|
||||
|
||||
|
||||
typedef struct disBus3Breaker
|
||||
{
|
||||
unsigned char lithiumBatteryGroupInstrumentCircuitBreaker : 1;
|
||||
unsigned char bowLowVoltageDistributionBoxCircuitBreaker : 1;
|
||||
unsigned char unit4InstrumentDC48VCircuitBreaker : 1;
|
||||
unsigned char dcC1DCDistributionPanelCircuitBreaker : 1;
|
||||
unsigned char reservedCircuitBreaker1 : 1;
|
||||
unsigned char reservedCircuitBreaker2 : 1;
|
||||
unsigned char emergencyLithiumBatteryGroup2CircuitBreaker : 1;
|
||||
unsigned short paceholder : 9;
|
||||
/* data */
|
||||
} disBus3Breaker;
|
||||
|
||||
|
||||
typedef struct disBus4Breaker
|
||||
{
|
||||
unsigned char unit1CircuitBreaker : 1;
|
||||
unsigned char unit2CircuitBreaker : 1;
|
||||
unsigned char unit3CircuitBreaker : 1;
|
||||
unsigned char unit5CircuitBreaker : 1;
|
||||
unsigned char bowPZDeviceCircuitBreaker : 1;
|
||||
unsigned char reservedCircuitBreaker1 : 1; // 为了区分,添加了数字后缀
|
||||
unsigned char reservedCircuitBreaker2 : 1; // 为了区分,添加了数字后缀
|
||||
unsigned char emergencyLithiumBatteryGroup1CircuitBreaker : 1;
|
||||
unsigned short paceholder : 8;
|
||||
/* data */
|
||||
} disBus4Breaker;
|
||||
|
||||
typedef struct disSysBreakerList
|
||||
{
|
||||
disBus1Breaker bus1Breaker;
|
||||
disBus2Breaker bus2Breaker;
|
||||
disBus3Breaker bus3Breaker;
|
||||
disBus4Breaker bus4Breaker;
|
||||
} disSysBreaker;
|
||||
|
||||
typedef struct MSControlCmd
|
||||
{
|
||||
unsigned int powerCMD;
|
||||
unsigned int modCMD;
|
||||
unsigned int workCMD;
|
||||
}MSControlCmd;
|
||||
|
||||
|
||||
namespace FcuCommand {
|
||||
enum Type : unsigned char {
|
||||
SelfCheck = 0x01,
|
||||
Start = 0x02,
|
||||
Stop = 0x03,
|
||||
Reset = 0x04,
|
||||
EmergencyStop = 0x05,
|
||||
Supply = 0x06,
|
||||
WarmUp = 0x07,
|
||||
Maintenance = 0x08
|
||||
};
|
||||
}
|
||||
|
||||
enum class FcuState : unsigned char {
|
||||
//初始化
|
||||
Init = 0x01,
|
||||
//待机
|
||||
Standby = 0x02,
|
||||
//自检异常
|
||||
SelfCheckError = 0x03,
|
||||
//就绪
|
||||
Ready = 0x04,
|
||||
//启动
|
||||
Start = 0x05,
|
||||
//运行
|
||||
Running = 0x06,
|
||||
//停机
|
||||
Stop = 0x07,
|
||||
//故障
|
||||
Fault = 0x08,
|
||||
//补给
|
||||
Supply = 0x09,
|
||||
//预热
|
||||
WarmUp = 0x0A,
|
||||
//预热完成
|
||||
WarmUpComplete = 0x0B,
|
||||
//维护
|
||||
Maintenance = 0x0C,
|
||||
//维护完成
|
||||
MaintenanceComplete = 0x0D
|
||||
};
|
||||
|
||||
namespace BatteryCommand {
|
||||
enum Type : unsigned char {
|
||||
Start = 0x10,
|
||||
Stop = 0x20,
|
||||
Hold = 0x00
|
||||
};
|
||||
};
|
||||
|
||||
namespace PMMode {
|
||||
enum Type : unsigned char {
|
||||
Normal = 0,
|
||||
Test = 1,
|
||||
Debug = 2
|
||||
};
|
||||
};
|
||||
|
||||
//工况定义
|
||||
namespace WorkCondition {
|
||||
enum Type : unsigned char {
|
||||
CHANING = 0, // 工况切换中
|
||||
STANDBY = 1, // 待机工况
|
||||
SHORE_BASED_READY = 2, // 岸基备航
|
||||
WATER_BASED_READY = 3, // 水中备航
|
||||
REMOTE_CONTROL = 4, // 遥控工况
|
||||
CRUISE_MODE = 5, // 巡航模式
|
||||
HIGH_SPEED_MODE = 6, // 高速模式
|
||||
ASCEND_DESCEND = 7, // 上浮下潜
|
||||
BUOYANCY_ADJUST = 8, // 浮调模式
|
||||
UNDERWATER_RECON = 9, // 水下侦查
|
||||
SURFACE_RECON = 10, // 水面侦查
|
||||
DJ_MODE = 11, // DJ模式
|
||||
LIFT_MODE = 12 // 调试模式
|
||||
};
|
||||
};
|
||||
|
||||
namespace RunMode {
|
||||
enum Type : unsigned char {
|
||||
//正常模式
|
||||
Normal = 0,
|
||||
//测试模式
|
||||
Test = 1,
|
||||
//调试模式
|
||||
Debug = 2
|
||||
};
|
||||
};
|
||||
|
||||
namespace TaskType {
|
||||
enum Type : unsigned char {
|
||||
THROW_LOAD = 1, // 抛载
|
||||
FLOAT_UP = 2, // 运动上浮
|
||||
RECYCLE = 3, // 回收
|
||||
HOVER = 4, // 悬停
|
||||
SAT_COMM = 5, // 上浮通信
|
||||
SAT_CALIBRATE = 6, // 上浮校准
|
||||
TOUR = 7, // 游曳
|
||||
SAIL = 8, // 航行
|
||||
|
||||
EMER_SAT_COMM = 9, //紧急上浮通信
|
||||
EMER_SAIL = 10 //紧急航行
|
||||
};
|
||||
|
||||
inline const std::string toString(Type type) {
|
||||
static const std::map<Type, std::string> names = {
|
||||
{THROW_LOAD, "throwLoad"},
|
||||
{FLOAT_UP, "floatUp"},
|
||||
{RECYCLE, "recycle"},
|
||||
{HOVER, "hover"},
|
||||
{SAT_COMM, "satComm"},
|
||||
{SAT_CALIBRATE, "satCalibrate"},
|
||||
{TOUR, "tour"},
|
||||
{SAIL, "sail"},
|
||||
{EMER_SAT_COMM,"emerSatComm"},
|
||||
{EMER_SAIL,"emerSail"}
|
||||
};
|
||||
auto it = names.find(type);
|
||||
return it != names.end() ? it->second : "unknown";
|
||||
}
|
||||
inline Type fromString(const std::string& str) {
|
||||
static const std::map<std::string, Type> stringToEnum = {
|
||||
{"throwLoad", THROW_LOAD},
|
||||
{"floatUp", FLOAT_UP},
|
||||
{"recycle", RECYCLE},
|
||||
{"hover", HOVER},
|
||||
{"satComm", SAT_COMM},
|
||||
{"emerSatComm",SAT_COMM},
|
||||
{"satCalibrate",SAT_CALIBRATE},
|
||||
{"tour", TOUR},
|
||||
{"sail", SAIL},
|
||||
{"emerSatComm",EMER_SAT_COMM},
|
||||
{"emerSail",EMER_SAIL}
|
||||
};
|
||||
auto it = stringToEnum.find(str);
|
||||
return it != stringToEnum.end() ? it->second : static_cast<Type>(0); // 返回0表示无效类型
|
||||
}
|
||||
}
|
||||
|
||||
namespace EquipmentCommand {
|
||||
enum Type : unsigned char {
|
||||
OFF = 0, //断电
|
||||
ON = 1, //上电
|
||||
//仪表电上电
|
||||
METER_ON = 2,
|
||||
//动力电上电
|
||||
POWER_ON = 3,
|
||||
//仪表电断电
|
||||
METER_OFF = 4,
|
||||
//动力电断电
|
||||
POWER_OFF = 5,
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
struct MissionState
|
||||
{
|
||||
int type;
|
||||
bool enableBowRudder;
|
||||
bool enableBuoyancyAdjustment;
|
||||
};
|
||||
|
||||
struct DeviceSwitchCmd
|
||||
{
|
||||
int id;
|
||||
int cmd;
|
||||
};
|
||||
|
||||
namespace DeviceId {
|
||||
enum Type : unsigned char {
|
||||
singleBeamSonar1 = 0,
|
||||
singleBeamSonar2 = 1,
|
||||
singleBeamSonar3 = 2,
|
||||
singleBeamSonar4 = 3,
|
||||
singleBeamSonar5 = 4,
|
||||
singleBeamSonar6 = 5,
|
||||
singleBeamSonar7 = 6,
|
||||
singleBeamSonar8 = 7,
|
||||
forwardSonar = 8,
|
||||
bowCover1 = 9,
|
||||
bowCover2 = 10,
|
||||
bowCover3 = 11,
|
||||
bowCover4 = 12,
|
||||
bowCover5 = 13,
|
||||
bowCover6 = 14,
|
||||
bowRudderDeploy = 15,
|
||||
bowRudderServo1 = 16,
|
||||
bowRudderServo2 = 17,
|
||||
depth1 = 18,
|
||||
depth2 = 19,
|
||||
depth3 = 20,
|
||||
overDeep1 = 21,
|
||||
overDeep2 = 22,
|
||||
ctd1 = 23,
|
||||
ctd2 = 24,
|
||||
soundVeloc = 25,
|
||||
waterInject = 26,
|
||||
bowWaterInet1 = 27,
|
||||
bowWaterInet2 = 28,
|
||||
bowWaterInet3 = 29,
|
||||
bowWaterInet4 = 30,
|
||||
bowWaterInet5 = 31,
|
||||
bowWaterInet6 = 32,
|
||||
bowWaterInet7 = 33,
|
||||
bowWaterInet8 = 34,
|
||||
sideSonar = 35,
|
||||
lowFreqSonar = 36,
|
||||
launchControler = 37,
|
||||
photoSensor = 38,
|
||||
electSensor = 39,
|
||||
commMast = 40,
|
||||
mastLiftingServo = 41,
|
||||
USBL = 42,
|
||||
DVL = 43,
|
||||
buoyancyAdjust1 = 44,
|
||||
buoyancyAdjust2 = 45,
|
||||
buoyancyAdjust3 = 46,
|
||||
buoyancyAdjust4 = 47,
|
||||
buoyancyAdjust5 = 48,
|
||||
sternRudderServo1 = 49,
|
||||
sternRudderServo2 = 50,
|
||||
sternRudderServo3 = 51,
|
||||
sternRudderServo4 = 52,
|
||||
thruster = 53,
|
||||
bowThrow = 54,
|
||||
sternThrow = 55,
|
||||
buoyage = 56,
|
||||
ins = 57,
|
||||
ntp = 58,
|
||||
inputWaterSensor1 = 59,
|
||||
inputWaterSensor2 = 60,
|
||||
inputWaterSensor3 = 61,
|
||||
};
|
||||
inline const std::string toString(Type type) {
|
||||
static const std::map<Type, std::string> names = {
|
||||
{singleBeamSonar1, "singleBeamSonar1"},
|
||||
{singleBeamSonar2, "singleBeamSonar2"},
|
||||
{singleBeamSonar3, "singleBeamSonar3"},
|
||||
{singleBeamSonar4, "singleBeamSonar4"},
|
||||
{singleBeamSonar5, "singleBeamSonar5"},
|
||||
{singleBeamSonar6, "singleBeamSonar6"},
|
||||
{singleBeamSonar7, "singleBeamSonar7"},
|
||||
{singleBeamSonar8, "singleBeamSonar8"},
|
||||
{forwardSonar, "forwardSonar"},
|
||||
{bowCover1, "bowCover1"},
|
||||
{bowCover2, "bowCover2"},
|
||||
{bowCover3, "bowCover3"},
|
||||
{bowCover4, "bowCover4"},
|
||||
{bowCover5, "bowCover5"},
|
||||
{bowCover6, "bowCover6"},
|
||||
{bowRudderDeploy, "bowRudderDeploy"},
|
||||
{bowRudderServo1, "bowRudderServo1"},
|
||||
{bowRudderServo2, "bowRudderServo2"},
|
||||
{depth1, "depth1"},
|
||||
{depth2, "depth2"},
|
||||
{depth3, "depth3"},
|
||||
{overDeep1, "overDeep1"},
|
||||
{overDeep2, "overDeep2"},
|
||||
{ctd1, "ctd1"},
|
||||
{ctd2, "ctd2"},
|
||||
{soundVeloc, "soundVeloc"},
|
||||
{waterInject, "waterInject"},
|
||||
{bowWaterInet1, "bowWaterInet1"},
|
||||
{bowWaterInet2, "bowWaterInet2"},
|
||||
{bowWaterInet3, "bowWaterInet3"},
|
||||
{bowWaterInet4, "bowWaterInet4"},
|
||||
{bowWaterInet5, "bowWaterInet5"},
|
||||
{bowWaterInet6, "bowWaterInet6"},
|
||||
{bowWaterInet7, "bowWaterInet7"},
|
||||
{bowWaterInet8, "bowWaterInet8"},
|
||||
{sideSonar, "sideSonar"},
|
||||
{lowFreqSonar, "lowFreqSonar"},
|
||||
{launchControler, "launchControler"},
|
||||
{photoSensor, "photoSensor"},
|
||||
{electSensor, "electSensor"},
|
||||
{commMast, "commMast"},
|
||||
{mastLiftingServo, "mastLiftingServo"},
|
||||
{USBL, "USBL"},
|
||||
{DVL, "DVL"},
|
||||
{buoyancyAdjust1, "buoyancyAdjust1"},
|
||||
{buoyancyAdjust2, "buoyancyAdjust2"},
|
||||
{buoyancyAdjust3, "buoyancyAdjust3"},
|
||||
{buoyancyAdjust4, "buoyancyAdjust4"},
|
||||
{buoyancyAdjust5, "buoyancyAdjust5"},
|
||||
{sternRudderServo1, "sternRudderServo1"},
|
||||
{sternRudderServo2, "sternRudderServo2"},
|
||||
{sternRudderServo3, "sternRudderServo3"},
|
||||
{sternRudderServo4, "sternRudderServo4"},
|
||||
{thruster, "thruster"},
|
||||
{bowThrow, "bowThrow"},
|
||||
{sternThrow, "sternThrow"},
|
||||
{buoyage, "buoyage"},
|
||||
{ins, "ins"},
|
||||
{ntp, "ntp"},
|
||||
{inputWaterSensor1, "inputWaterSensor1"},
|
||||
{inputWaterSensor2, "inputWaterSensor2"},
|
||||
{inputWaterSensor3, "inputWaterSensor3"}
|
||||
};
|
||||
auto it = names.find(type);
|
||||
return it != names.end() ? it->second : "unknown";
|
||||
}
|
||||
}
|
||||
|
||||
// 设备类id存储
|
||||
static const std::unordered_set<int> underWterDevices = {
|
||||
DeviceId::singleBeamSonar1,
|
||||
DeviceId::singleBeamSonar2,
|
||||
DeviceId::singleBeamSonar3,
|
||||
DeviceId::singleBeamSonar4,
|
||||
DeviceId::singleBeamSonar5,
|
||||
DeviceId::singleBeamSonar6,
|
||||
DeviceId::singleBeamSonar7,
|
||||
DeviceId::singleBeamSonar8,
|
||||
DeviceId::forwardSonar,
|
||||
DeviceId::USBL,
|
||||
DeviceId::DVL,
|
||||
DeviceId::lowFreqSonar
|
||||
};
|
||||
static const std::unordered_set<int> noPowerDevices = {
|
||||
DeviceId::depth1,
|
||||
DeviceId::depth2,
|
||||
DeviceId::depth3,
|
||||
DeviceId::overDeep1,
|
||||
DeviceId::overDeep2,
|
||||
DeviceId::ctd1,
|
||||
DeviceId::ctd2,
|
||||
DeviceId::soundVeloc,
|
||||
DeviceId::waterInject,
|
||||
DeviceId::launchControler,
|
||||
DeviceId::photoSensor,
|
||||
DeviceId::electSensor,
|
||||
DeviceId::commMast,
|
||||
DeviceId::ntp,
|
||||
DeviceId::bowThrow,
|
||||
DeviceId::sternThrow,
|
||||
DeviceId::ins,
|
||||
DeviceId::inputWaterSensor1,
|
||||
DeviceId::inputWaterSensor2,
|
||||
DeviceId::inputWaterSensor3
|
||||
};
|
||||
namespace FaultEnable {
|
||||
enum Type : bool {
|
||||
BasicNavigationFault_1 = false, // 使能故障
|
||||
BasicNavigationFault_2 = false,
|
||||
BasicNavigationFault_3 = false,
|
||||
BasicNavigationFault_4 = false,
|
||||
BasicNavigationFault_5 = false,
|
||||
BasicNavigationFault_6 = false,
|
||||
BasicNavigationFault_7 = false,
|
||||
BasicNavigationFault_8 = false,
|
||||
BasicNavigationFault_9 = false,
|
||||
BasicNavigationFault_10 = false,
|
||||
|
||||
ExtendedNavigationFault_1 = false, // 使能故障
|
||||
ExtendedNavigationFault_2 = false,
|
||||
ExtendedNavigationFault_3 = false,
|
||||
ExtendedNavigationFault_4 = false,
|
||||
|
||||
ObstacleAvoidanceFault_1 = false, // 使能故障
|
||||
ObstacleAvoidanceFault_2 = false,
|
||||
ObstacleAvoidanceFault_3 = false,
|
||||
|
||||
BuoyancyControlFault_1 = false, // 使能故障
|
||||
BuoyancyControlFault_2 = false,
|
||||
BuoyancyControlFault_3 = false,
|
||||
BuoyancyControlFault_4 = false,
|
||||
|
||||
CommunicationSystemFault_1 = false, // 使能故障
|
||||
CommunicationSystemFault_2 = false,
|
||||
CommunicationSystemFault_3 = false,
|
||||
|
||||
PayloadSystemFault_1 = false, // 使能故障
|
||||
PayloadSystemFault_2 = false,
|
||||
PayloadSystemFault_3 = false,
|
||||
PayloadSystemFault_4 = false,
|
||||
PayloadSystemFault_5 = false,
|
||||
PayloadSystemFault_6 = false,
|
||||
PayloadSystemFault_7 = false,
|
||||
|
||||
EmergencySystemFault_1 = false, // 使能故障
|
||||
EmergencySystemFault_2 = false,
|
||||
EmergencySystemFault_3 = false,
|
||||
EmergencySystemFault_4 = false,
|
||||
EmergencySystemFault_5 = false,
|
||||
EmergencySystemFault_6 = false,
|
||||
|
||||
SensorSystemFault_1 = false, // 使能故障
|
||||
SensorSystemFault_2 = false,
|
||||
SensorSystemFault_3 = false,
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,36 +0,0 @@
|
||||
#ifndef SQLITE_H
|
||||
#define SQLITE_H
|
||||
#include "sqlite3.h"
|
||||
#include <string>
|
||||
#include "../pmSysvariable.h"
|
||||
|
||||
class SQLite
|
||||
{
|
||||
private:
|
||||
sqlite3* m_db;
|
||||
public:
|
||||
std::string m_dbPath;
|
||||
SQLite(const std::string& dbName);
|
||||
~SQLite();
|
||||
|
||||
//创建表
|
||||
bool createTable();
|
||||
bool createTable(const std::string& tableName, const std::string& columns);
|
||||
|
||||
// 插入数据函数
|
||||
bool insertData(ccuState data);
|
||||
bool insertData(disHighVolBusState data);
|
||||
bool insertData(disHighAVolBusState data);
|
||||
bool insertData(disLowMainBusState data);
|
||||
bool insertData(disLowBusState data);
|
||||
|
||||
//插入指令数据
|
||||
bool insertData(ccuColCmd cmd);
|
||||
bool insertData(disHighVolBusCmd cmd);
|
||||
bool insertData(disHighAVolBusCmd cmd);
|
||||
bool insertData(disLowMainBusCmd cmd);
|
||||
bool insertData(disLowBusCmd cmd);
|
||||
};
|
||||
|
||||
|
||||
#endif
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,719 +0,0 @@
|
||||
/*
|
||||
** 2006 June 7
|
||||
**
|
||||
** The author disclaims copyright to this source code. In place of
|
||||
** a legal notice, here is a blessing:
|
||||
**
|
||||
** May you do good and not evil.
|
||||
** May you find forgiveness for yourself and forgive others.
|
||||
** May you share freely, never taking more than you give.
|
||||
**
|
||||
*************************************************************************
|
||||
** This header file defines the SQLite interface for use by
|
||||
** shared libraries that want to be imported as extensions into
|
||||
** an SQLite instance. Shared libraries that intend to be loaded
|
||||
** as extensions by SQLite should #include this file instead of
|
||||
** sqlite3.h.
|
||||
*/
|
||||
#ifndef SQLITE3EXT_H
|
||||
#define SQLITE3EXT_H
|
||||
#include "sqlite3.h"
|
||||
|
||||
/*
|
||||
** The following structure holds pointers to all of the SQLite API
|
||||
** routines.
|
||||
**
|
||||
** WARNING: In order to maintain backwards compatibility, add new
|
||||
** interfaces to the end of this structure only. If you insert new
|
||||
** interfaces in the middle of this structure, then older different
|
||||
** versions of SQLite will not be able to load each other's shared
|
||||
** libraries!
|
||||
*/
|
||||
struct sqlite3_api_routines {
|
||||
void * (*aggregate_context)(sqlite3_context*,int nBytes);
|
||||
int (*aggregate_count)(sqlite3_context*);
|
||||
int (*bind_blob)(sqlite3_stmt*,int,const void*,int n,void(*)(void*));
|
||||
int (*bind_double)(sqlite3_stmt*,int,double);
|
||||
int (*bind_int)(sqlite3_stmt*,int,int);
|
||||
int (*bind_int64)(sqlite3_stmt*,int,sqlite_int64);
|
||||
int (*bind_null)(sqlite3_stmt*,int);
|
||||
int (*bind_parameter_count)(sqlite3_stmt*);
|
||||
int (*bind_parameter_index)(sqlite3_stmt*,const char*zName);
|
||||
const char * (*bind_parameter_name)(sqlite3_stmt*,int);
|
||||
int (*bind_text)(sqlite3_stmt*,int,const char*,int n,void(*)(void*));
|
||||
int (*bind_text16)(sqlite3_stmt*,int,const void*,int,void(*)(void*));
|
||||
int (*bind_value)(sqlite3_stmt*,int,const sqlite3_value*);
|
||||
int (*busy_handler)(sqlite3*,int(*)(void*,int),void*);
|
||||
int (*busy_timeout)(sqlite3*,int ms);
|
||||
int (*changes)(sqlite3*);
|
||||
int (*close)(sqlite3*);
|
||||
int (*collation_needed)(sqlite3*,void*,void(*)(void*,sqlite3*,
|
||||
int eTextRep,const char*));
|
||||
int (*collation_needed16)(sqlite3*,void*,void(*)(void*,sqlite3*,
|
||||
int eTextRep,const void*));
|
||||
const void * (*column_blob)(sqlite3_stmt*,int iCol);
|
||||
int (*column_bytes)(sqlite3_stmt*,int iCol);
|
||||
int (*column_bytes16)(sqlite3_stmt*,int iCol);
|
||||
int (*column_count)(sqlite3_stmt*pStmt);
|
||||
const char * (*column_database_name)(sqlite3_stmt*,int);
|
||||
const void * (*column_database_name16)(sqlite3_stmt*,int);
|
||||
const char * (*column_decltype)(sqlite3_stmt*,int i);
|
||||
const void * (*column_decltype16)(sqlite3_stmt*,int);
|
||||
double (*column_double)(sqlite3_stmt*,int iCol);
|
||||
int (*column_int)(sqlite3_stmt*,int iCol);
|
||||
sqlite_int64 (*column_int64)(sqlite3_stmt*,int iCol);
|
||||
const char * (*column_name)(sqlite3_stmt*,int);
|
||||
const void * (*column_name16)(sqlite3_stmt*,int);
|
||||
const char * (*column_origin_name)(sqlite3_stmt*,int);
|
||||
const void * (*column_origin_name16)(sqlite3_stmt*,int);
|
||||
const char * (*column_table_name)(sqlite3_stmt*,int);
|
||||
const void * (*column_table_name16)(sqlite3_stmt*,int);
|
||||
const unsigned char * (*column_text)(sqlite3_stmt*,int iCol);
|
||||
const void * (*column_text16)(sqlite3_stmt*,int iCol);
|
||||
int (*column_type)(sqlite3_stmt*,int iCol);
|
||||
sqlite3_value* (*column_value)(sqlite3_stmt*,int iCol);
|
||||
void * (*commit_hook)(sqlite3*,int(*)(void*),void*);
|
||||
int (*complete)(const char*sql);
|
||||
int (*complete16)(const void*sql);
|
||||
int (*create_collation)(sqlite3*,const char*,int,void*,
|
||||
int(*)(void*,int,const void*,int,const void*));
|
||||
int (*create_collation16)(sqlite3*,const void*,int,void*,
|
||||
int(*)(void*,int,const void*,int,const void*));
|
||||
int (*create_function)(sqlite3*,const char*,int,int,void*,
|
||||
void (*xFunc)(sqlite3_context*,int,sqlite3_value**),
|
||||
void (*xStep)(sqlite3_context*,int,sqlite3_value**),
|
||||
void (*xFinal)(sqlite3_context*));
|
||||
int (*create_function16)(sqlite3*,const void*,int,int,void*,
|
||||
void (*xFunc)(sqlite3_context*,int,sqlite3_value**),
|
||||
void (*xStep)(sqlite3_context*,int,sqlite3_value**),
|
||||
void (*xFinal)(sqlite3_context*));
|
||||
int (*create_module)(sqlite3*,const char*,const sqlite3_module*,void*);
|
||||
int (*data_count)(sqlite3_stmt*pStmt);
|
||||
sqlite3 * (*db_handle)(sqlite3_stmt*);
|
||||
int (*declare_vtab)(sqlite3*,const char*);
|
||||
int (*enable_shared_cache)(int);
|
||||
int (*errcode)(sqlite3*db);
|
||||
const char * (*errmsg)(sqlite3*);
|
||||
const void * (*errmsg16)(sqlite3*);
|
||||
int (*exec)(sqlite3*,const char*,sqlite3_callback,void*,char**);
|
||||
int (*expired)(sqlite3_stmt*);
|
||||
int (*finalize)(sqlite3_stmt*pStmt);
|
||||
void (*free)(void*);
|
||||
void (*free_table)(char**result);
|
||||
int (*get_autocommit)(sqlite3*);
|
||||
void * (*get_auxdata)(sqlite3_context*,int);
|
||||
int (*get_table)(sqlite3*,const char*,char***,int*,int*,char**);
|
||||
int (*global_recover)(void);
|
||||
void (*interruptx)(sqlite3*);
|
||||
sqlite_int64 (*last_insert_rowid)(sqlite3*);
|
||||
const char * (*libversion)(void);
|
||||
int (*libversion_number)(void);
|
||||
void *(*malloc)(int);
|
||||
char * (*mprintf)(const char*,...);
|
||||
int (*open)(const char*,sqlite3**);
|
||||
int (*open16)(const void*,sqlite3**);
|
||||
int (*prepare)(sqlite3*,const char*,int,sqlite3_stmt**,const char**);
|
||||
int (*prepare16)(sqlite3*,const void*,int,sqlite3_stmt**,const void**);
|
||||
void * (*profile)(sqlite3*,void(*)(void*,const char*,sqlite_uint64),void*);
|
||||
void (*progress_handler)(sqlite3*,int,int(*)(void*),void*);
|
||||
void *(*realloc)(void*,int);
|
||||
int (*reset)(sqlite3_stmt*pStmt);
|
||||
void (*result_blob)(sqlite3_context*,const void*,int,void(*)(void*));
|
||||
void (*result_double)(sqlite3_context*,double);
|
||||
void (*result_error)(sqlite3_context*,const char*,int);
|
||||
void (*result_error16)(sqlite3_context*,const void*,int);
|
||||
void (*result_int)(sqlite3_context*,int);
|
||||
void (*result_int64)(sqlite3_context*,sqlite_int64);
|
||||
void (*result_null)(sqlite3_context*);
|
||||
void (*result_text)(sqlite3_context*,const char*,int,void(*)(void*));
|
||||
void (*result_text16)(sqlite3_context*,const void*,int,void(*)(void*));
|
||||
void (*result_text16be)(sqlite3_context*,const void*,int,void(*)(void*));
|
||||
void (*result_text16le)(sqlite3_context*,const void*,int,void(*)(void*));
|
||||
void (*result_value)(sqlite3_context*,sqlite3_value*);
|
||||
void * (*rollback_hook)(sqlite3*,void(*)(void*),void*);
|
||||
int (*set_authorizer)(sqlite3*,int(*)(void*,int,const char*,const char*,
|
||||
const char*,const char*),void*);
|
||||
void (*set_auxdata)(sqlite3_context*,int,void*,void (*)(void*));
|
||||
char * (*xsnprintf)(int,char*,const char*,...);
|
||||
int (*step)(sqlite3_stmt*);
|
||||
int (*table_column_metadata)(sqlite3*,const char*,const char*,const char*,
|
||||
char const**,char const**,int*,int*,int*);
|
||||
void (*thread_cleanup)(void);
|
||||
int (*total_changes)(sqlite3*);
|
||||
void * (*trace)(sqlite3*,void(*xTrace)(void*,const char*),void*);
|
||||
int (*transfer_bindings)(sqlite3_stmt*,sqlite3_stmt*);
|
||||
void * (*update_hook)(sqlite3*,void(*)(void*,int ,char const*,char const*,
|
||||
sqlite_int64),void*);
|
||||
void * (*user_data)(sqlite3_context*);
|
||||
const void * (*value_blob)(sqlite3_value*);
|
||||
int (*value_bytes)(sqlite3_value*);
|
||||
int (*value_bytes16)(sqlite3_value*);
|
||||
double (*value_double)(sqlite3_value*);
|
||||
int (*value_int)(sqlite3_value*);
|
||||
sqlite_int64 (*value_int64)(sqlite3_value*);
|
||||
int (*value_numeric_type)(sqlite3_value*);
|
||||
const unsigned char * (*value_text)(sqlite3_value*);
|
||||
const void * (*value_text16)(sqlite3_value*);
|
||||
const void * (*value_text16be)(sqlite3_value*);
|
||||
const void * (*value_text16le)(sqlite3_value*);
|
||||
int (*value_type)(sqlite3_value*);
|
||||
char *(*vmprintf)(const char*,va_list);
|
||||
/* Added ??? */
|
||||
int (*overload_function)(sqlite3*, const char *zFuncName, int nArg);
|
||||
/* Added by 3.3.13 */
|
||||
int (*prepare_v2)(sqlite3*,const char*,int,sqlite3_stmt**,const char**);
|
||||
int (*prepare16_v2)(sqlite3*,const void*,int,sqlite3_stmt**,const void**);
|
||||
int (*clear_bindings)(sqlite3_stmt*);
|
||||
/* Added by 3.4.1 */
|
||||
int (*create_module_v2)(sqlite3*,const char*,const sqlite3_module*,void*,
|
||||
void (*xDestroy)(void *));
|
||||
/* Added by 3.5.0 */
|
||||
int (*bind_zeroblob)(sqlite3_stmt*,int,int);
|
||||
int (*blob_bytes)(sqlite3_blob*);
|
||||
int (*blob_close)(sqlite3_blob*);
|
||||
int (*blob_open)(sqlite3*,const char*,const char*,const char*,sqlite3_int64,
|
||||
int,sqlite3_blob**);
|
||||
int (*blob_read)(sqlite3_blob*,void*,int,int);
|
||||
int (*blob_write)(sqlite3_blob*,const void*,int,int);
|
||||
int (*create_collation_v2)(sqlite3*,const char*,int,void*,
|
||||
int(*)(void*,int,const void*,int,const void*),
|
||||
void(*)(void*));
|
||||
int (*file_control)(sqlite3*,const char*,int,void*);
|
||||
sqlite3_int64 (*memory_highwater)(int);
|
||||
sqlite3_int64 (*memory_used)(void);
|
||||
sqlite3_mutex *(*mutex_alloc)(int);
|
||||
void (*mutex_enter)(sqlite3_mutex*);
|
||||
void (*mutex_free)(sqlite3_mutex*);
|
||||
void (*mutex_leave)(sqlite3_mutex*);
|
||||
int (*mutex_try)(sqlite3_mutex*);
|
||||
int (*open_v2)(const char*,sqlite3**,int,const char*);
|
||||
int (*release_memory)(int);
|
||||
void (*result_error_nomem)(sqlite3_context*);
|
||||
void (*result_error_toobig)(sqlite3_context*);
|
||||
int (*sleep)(int);
|
||||
void (*soft_heap_limit)(int);
|
||||
sqlite3_vfs *(*vfs_find)(const char*);
|
||||
int (*vfs_register)(sqlite3_vfs*,int);
|
||||
int (*vfs_unregister)(sqlite3_vfs*);
|
||||
int (*xthreadsafe)(void);
|
||||
void (*result_zeroblob)(sqlite3_context*,int);
|
||||
void (*result_error_code)(sqlite3_context*,int);
|
||||
int (*test_control)(int, ...);
|
||||
void (*randomness)(int,void*);
|
||||
sqlite3 *(*context_db_handle)(sqlite3_context*);
|
||||
int (*extended_result_codes)(sqlite3*,int);
|
||||
int (*limit)(sqlite3*,int,int);
|
||||
sqlite3_stmt *(*next_stmt)(sqlite3*,sqlite3_stmt*);
|
||||
const char *(*sql)(sqlite3_stmt*);
|
||||
int (*status)(int,int*,int*,int);
|
||||
int (*backup_finish)(sqlite3_backup*);
|
||||
sqlite3_backup *(*backup_init)(sqlite3*,const char*,sqlite3*,const char*);
|
||||
int (*backup_pagecount)(sqlite3_backup*);
|
||||
int (*backup_remaining)(sqlite3_backup*);
|
||||
int (*backup_step)(sqlite3_backup*,int);
|
||||
const char *(*compileoption_get)(int);
|
||||
int (*compileoption_used)(const char*);
|
||||
int (*create_function_v2)(sqlite3*,const char*,int,int,void*,
|
||||
void (*xFunc)(sqlite3_context*,int,sqlite3_value**),
|
||||
void (*xStep)(sqlite3_context*,int,sqlite3_value**),
|
||||
void (*xFinal)(sqlite3_context*),
|
||||
void(*xDestroy)(void*));
|
||||
int (*db_config)(sqlite3*,int,...);
|
||||
sqlite3_mutex *(*db_mutex)(sqlite3*);
|
||||
int (*db_status)(sqlite3*,int,int*,int*,int);
|
||||
int (*extended_errcode)(sqlite3*);
|
||||
void (*log)(int,const char*,...);
|
||||
sqlite3_int64 (*soft_heap_limit64)(sqlite3_int64);
|
||||
const char *(*sourceid)(void);
|
||||
int (*stmt_status)(sqlite3_stmt*,int,int);
|
||||
int (*strnicmp)(const char*,const char*,int);
|
||||
int (*unlock_notify)(sqlite3*,void(*)(void**,int),void*);
|
||||
int (*wal_autocheckpoint)(sqlite3*,int);
|
||||
int (*wal_checkpoint)(sqlite3*,const char*);
|
||||
void *(*wal_hook)(sqlite3*,int(*)(void*,sqlite3*,const char*,int),void*);
|
||||
int (*blob_reopen)(sqlite3_blob*,sqlite3_int64);
|
||||
int (*vtab_config)(sqlite3*,int op,...);
|
||||
int (*vtab_on_conflict)(sqlite3*);
|
||||
/* Version 3.7.16 and later */
|
||||
int (*close_v2)(sqlite3*);
|
||||
const char *(*db_filename)(sqlite3*,const char*);
|
||||
int (*db_readonly)(sqlite3*,const char*);
|
||||
int (*db_release_memory)(sqlite3*);
|
||||
const char *(*errstr)(int);
|
||||
int (*stmt_busy)(sqlite3_stmt*);
|
||||
int (*stmt_readonly)(sqlite3_stmt*);
|
||||
int (*stricmp)(const char*,const char*);
|
||||
int (*uri_boolean)(const char*,const char*,int);
|
||||
sqlite3_int64 (*uri_int64)(const char*,const char*,sqlite3_int64);
|
||||
const char *(*uri_parameter)(const char*,const char*);
|
||||
char *(*xvsnprintf)(int,char*,const char*,va_list);
|
||||
int (*wal_checkpoint_v2)(sqlite3*,const char*,int,int*,int*);
|
||||
/* Version 3.8.7 and later */
|
||||
int (*auto_extension)(void(*)(void));
|
||||
int (*bind_blob64)(sqlite3_stmt*,int,const void*,sqlite3_uint64,
|
||||
void(*)(void*));
|
||||
int (*bind_text64)(sqlite3_stmt*,int,const char*,sqlite3_uint64,
|
||||
void(*)(void*),unsigned char);
|
||||
int (*cancel_auto_extension)(void(*)(void));
|
||||
int (*load_extension)(sqlite3*,const char*,const char*,char**);
|
||||
void *(*malloc64)(sqlite3_uint64);
|
||||
sqlite3_uint64 (*msize)(void*);
|
||||
void *(*realloc64)(void*,sqlite3_uint64);
|
||||
void (*reset_auto_extension)(void);
|
||||
void (*result_blob64)(sqlite3_context*,const void*,sqlite3_uint64,
|
||||
void(*)(void*));
|
||||
void (*result_text64)(sqlite3_context*,const char*,sqlite3_uint64,
|
||||
void(*)(void*), unsigned char);
|
||||
int (*strglob)(const char*,const char*);
|
||||
/* Version 3.8.11 and later */
|
||||
sqlite3_value *(*value_dup)(const sqlite3_value*);
|
||||
void (*value_free)(sqlite3_value*);
|
||||
int (*result_zeroblob64)(sqlite3_context*,sqlite3_uint64);
|
||||
int (*bind_zeroblob64)(sqlite3_stmt*, int, sqlite3_uint64);
|
||||
/* Version 3.9.0 and later */
|
||||
unsigned int (*value_subtype)(sqlite3_value*);
|
||||
void (*result_subtype)(sqlite3_context*,unsigned int);
|
||||
/* Version 3.10.0 and later */
|
||||
int (*status64)(int,sqlite3_int64*,sqlite3_int64*,int);
|
||||
int (*strlike)(const char*,const char*,unsigned int);
|
||||
int (*db_cacheflush)(sqlite3*);
|
||||
/* Version 3.12.0 and later */
|
||||
int (*system_errno)(sqlite3*);
|
||||
/* Version 3.14.0 and later */
|
||||
int (*trace_v2)(sqlite3*,unsigned,int(*)(unsigned,void*,void*,void*),void*);
|
||||
char *(*expanded_sql)(sqlite3_stmt*);
|
||||
/* Version 3.18.0 and later */
|
||||
void (*set_last_insert_rowid)(sqlite3*,sqlite3_int64);
|
||||
/* Version 3.20.0 and later */
|
||||
int (*prepare_v3)(sqlite3*,const char*,int,unsigned int,
|
||||
sqlite3_stmt**,const char**);
|
||||
int (*prepare16_v3)(sqlite3*,const void*,int,unsigned int,
|
||||
sqlite3_stmt**,const void**);
|
||||
int (*bind_pointer)(sqlite3_stmt*,int,void*,const char*,void(*)(void*));
|
||||
void (*result_pointer)(sqlite3_context*,void*,const char*,void(*)(void*));
|
||||
void *(*value_pointer)(sqlite3_value*,const char*);
|
||||
int (*vtab_nochange)(sqlite3_context*);
|
||||
int (*value_nochange)(sqlite3_value*);
|
||||
const char *(*vtab_collation)(sqlite3_index_info*,int);
|
||||
/* Version 3.24.0 and later */
|
||||
int (*keyword_count)(void);
|
||||
int (*keyword_name)(int,const char**,int*);
|
||||
int (*keyword_check)(const char*,int);
|
||||
sqlite3_str *(*str_new)(sqlite3*);
|
||||
char *(*str_finish)(sqlite3_str*);
|
||||
void (*str_appendf)(sqlite3_str*, const char *zFormat, ...);
|
||||
void (*str_vappendf)(sqlite3_str*, const char *zFormat, va_list);
|
||||
void (*str_append)(sqlite3_str*, const char *zIn, int N);
|
||||
void (*str_appendall)(sqlite3_str*, const char *zIn);
|
||||
void (*str_appendchar)(sqlite3_str*, int N, char C);
|
||||
void (*str_reset)(sqlite3_str*);
|
||||
int (*str_errcode)(sqlite3_str*);
|
||||
int (*str_length)(sqlite3_str*);
|
||||
char *(*str_value)(sqlite3_str*);
|
||||
/* Version 3.25.0 and later */
|
||||
int (*create_window_function)(sqlite3*,const char*,int,int,void*,
|
||||
void (*xStep)(sqlite3_context*,int,sqlite3_value**),
|
||||
void (*xFinal)(sqlite3_context*),
|
||||
void (*xValue)(sqlite3_context*),
|
||||
void (*xInv)(sqlite3_context*,int,sqlite3_value**),
|
||||
void(*xDestroy)(void*));
|
||||
/* Version 3.26.0 and later */
|
||||
const char *(*normalized_sql)(sqlite3_stmt*);
|
||||
/* Version 3.28.0 and later */
|
||||
int (*stmt_isexplain)(sqlite3_stmt*);
|
||||
int (*value_frombind)(sqlite3_value*);
|
||||
/* Version 3.30.0 and later */
|
||||
int (*drop_modules)(sqlite3*,const char**);
|
||||
/* Version 3.31.0 and later */
|
||||
sqlite3_int64 (*hard_heap_limit64)(sqlite3_int64);
|
||||
const char *(*uri_key)(const char*,int);
|
||||
const char *(*filename_database)(const char*);
|
||||
const char *(*filename_journal)(const char*);
|
||||
const char *(*filename_wal)(const char*);
|
||||
/* Version 3.32.0 and later */
|
||||
const char *(*create_filename)(const char*,const char*,const char*,
|
||||
int,const char**);
|
||||
void (*free_filename)(const char*);
|
||||
sqlite3_file *(*database_file_object)(const char*);
|
||||
/* Version 3.34.0 and later */
|
||||
int (*txn_state)(sqlite3*,const char*);
|
||||
/* Version 3.36.1 and later */
|
||||
sqlite3_int64 (*changes64)(sqlite3*);
|
||||
sqlite3_int64 (*total_changes64)(sqlite3*);
|
||||
/* Version 3.37.0 and later */
|
||||
int (*autovacuum_pages)(sqlite3*,
|
||||
unsigned int(*)(void*,const char*,unsigned int,unsigned int,unsigned int),
|
||||
void*, void(*)(void*));
|
||||
/* Version 3.38.0 and later */
|
||||
int (*error_offset)(sqlite3*);
|
||||
int (*vtab_rhs_value)(sqlite3_index_info*,int,sqlite3_value**);
|
||||
int (*vtab_distinct)(sqlite3_index_info*);
|
||||
int (*vtab_in)(sqlite3_index_info*,int,int);
|
||||
int (*vtab_in_first)(sqlite3_value*,sqlite3_value**);
|
||||
int (*vtab_in_next)(sqlite3_value*,sqlite3_value**);
|
||||
/* Version 3.39.0 and later */
|
||||
int (*deserialize)(sqlite3*,const char*,unsigned char*,
|
||||
sqlite3_int64,sqlite3_int64,unsigned);
|
||||
unsigned char *(*serialize)(sqlite3*,const char *,sqlite3_int64*,
|
||||
unsigned int);
|
||||
const char *(*db_name)(sqlite3*,int);
|
||||
/* Version 3.40.0 and later */
|
||||
int (*value_encoding)(sqlite3_value*);
|
||||
/* Version 3.41.0 and later */
|
||||
int (*is_interrupted)(sqlite3*);
|
||||
/* Version 3.43.0 and later */
|
||||
int (*stmt_explain)(sqlite3_stmt*,int);
|
||||
/* Version 3.44.0 and later */
|
||||
void *(*get_clientdata)(sqlite3*,const char*);
|
||||
int (*set_clientdata)(sqlite3*, const char*, void*, void(*)(void*));
|
||||
};
|
||||
|
||||
/*
|
||||
** This is the function signature used for all extension entry points. It
|
||||
** is also defined in the file "loadext.c".
|
||||
*/
|
||||
typedef int (*sqlite3_loadext_entry)(
|
||||
sqlite3 *db, /* Handle to the database. */
|
||||
char **pzErrMsg, /* Used to set error string on failure. */
|
||||
const sqlite3_api_routines *pThunk /* Extension API function pointers. */
|
||||
);
|
||||
|
||||
/*
|
||||
** The following macros redefine the API routines so that they are
|
||||
** redirected through the global sqlite3_api structure.
|
||||
**
|
||||
** This header file is also used by the loadext.c source file
|
||||
** (part of the main SQLite library - not an extension) so that
|
||||
** it can get access to the sqlite3_api_routines structure
|
||||
** definition. But the main library does not want to redefine
|
||||
** the API. So the redefinition macros are only valid if the
|
||||
** SQLITE_CORE macros is undefined.
|
||||
*/
|
||||
#if !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION)
|
||||
#define sqlite3_aggregate_context sqlite3_api->aggregate_context
|
||||
#ifndef SQLITE_OMIT_DEPRECATED
|
||||
#define sqlite3_aggregate_count sqlite3_api->aggregate_count
|
||||
#endif
|
||||
#define sqlite3_bind_blob sqlite3_api->bind_blob
|
||||
#define sqlite3_bind_double sqlite3_api->bind_double
|
||||
#define sqlite3_bind_int sqlite3_api->bind_int
|
||||
#define sqlite3_bind_int64 sqlite3_api->bind_int64
|
||||
#define sqlite3_bind_null sqlite3_api->bind_null
|
||||
#define sqlite3_bind_parameter_count sqlite3_api->bind_parameter_count
|
||||
#define sqlite3_bind_parameter_index sqlite3_api->bind_parameter_index
|
||||
#define sqlite3_bind_parameter_name sqlite3_api->bind_parameter_name
|
||||
#define sqlite3_bind_text sqlite3_api->bind_text
|
||||
#define sqlite3_bind_text16 sqlite3_api->bind_text16
|
||||
#define sqlite3_bind_value sqlite3_api->bind_value
|
||||
#define sqlite3_busy_handler sqlite3_api->busy_handler
|
||||
#define sqlite3_busy_timeout sqlite3_api->busy_timeout
|
||||
#define sqlite3_changes sqlite3_api->changes
|
||||
#define sqlite3_close sqlite3_api->close
|
||||
#define sqlite3_collation_needed sqlite3_api->collation_needed
|
||||
#define sqlite3_collation_needed16 sqlite3_api->collation_needed16
|
||||
#define sqlite3_column_blob sqlite3_api->column_blob
|
||||
#define sqlite3_column_bytes sqlite3_api->column_bytes
|
||||
#define sqlite3_column_bytes16 sqlite3_api->column_bytes16
|
||||
#define sqlite3_column_count sqlite3_api->column_count
|
||||
#define sqlite3_column_database_name sqlite3_api->column_database_name
|
||||
#define sqlite3_column_database_name16 sqlite3_api->column_database_name16
|
||||
#define sqlite3_column_decltype sqlite3_api->column_decltype
|
||||
#define sqlite3_column_decltype16 sqlite3_api->column_decltype16
|
||||
#define sqlite3_column_double sqlite3_api->column_double
|
||||
#define sqlite3_column_int sqlite3_api->column_int
|
||||
#define sqlite3_column_int64 sqlite3_api->column_int64
|
||||
#define sqlite3_column_name sqlite3_api->column_name
|
||||
#define sqlite3_column_name16 sqlite3_api->column_name16
|
||||
#define sqlite3_column_origin_name sqlite3_api->column_origin_name
|
||||
#define sqlite3_column_origin_name16 sqlite3_api->column_origin_name16
|
||||
#define sqlite3_column_table_name sqlite3_api->column_table_name
|
||||
#define sqlite3_column_table_name16 sqlite3_api->column_table_name16
|
||||
#define sqlite3_column_text sqlite3_api->column_text
|
||||
#define sqlite3_column_text16 sqlite3_api->column_text16
|
||||
#define sqlite3_column_type sqlite3_api->column_type
|
||||
#define sqlite3_column_value sqlite3_api->column_value
|
||||
#define sqlite3_commit_hook sqlite3_api->commit_hook
|
||||
#define sqlite3_complete sqlite3_api->complete
|
||||
#define sqlite3_complete16 sqlite3_api->complete16
|
||||
#define sqlite3_create_collation sqlite3_api->create_collation
|
||||
#define sqlite3_create_collation16 sqlite3_api->create_collation16
|
||||
#define sqlite3_create_function sqlite3_api->create_function
|
||||
#define sqlite3_create_function16 sqlite3_api->create_function16
|
||||
#define sqlite3_create_module sqlite3_api->create_module
|
||||
#define sqlite3_create_module_v2 sqlite3_api->create_module_v2
|
||||
#define sqlite3_data_count sqlite3_api->data_count
|
||||
#define sqlite3_db_handle sqlite3_api->db_handle
|
||||
#define sqlite3_declare_vtab sqlite3_api->declare_vtab
|
||||
#define sqlite3_enable_shared_cache sqlite3_api->enable_shared_cache
|
||||
#define sqlite3_errcode sqlite3_api->errcode
|
||||
#define sqlite3_errmsg sqlite3_api->errmsg
|
||||
#define sqlite3_errmsg16 sqlite3_api->errmsg16
|
||||
#define sqlite3_exec sqlite3_api->exec
|
||||
#ifndef SQLITE_OMIT_DEPRECATED
|
||||
#define sqlite3_expired sqlite3_api->expired
|
||||
#endif
|
||||
#define sqlite3_finalize sqlite3_api->finalize
|
||||
#define sqlite3_free sqlite3_api->free
|
||||
#define sqlite3_free_table sqlite3_api->free_table
|
||||
#define sqlite3_get_autocommit sqlite3_api->get_autocommit
|
||||
#define sqlite3_get_auxdata sqlite3_api->get_auxdata
|
||||
#define sqlite3_get_table sqlite3_api->get_table
|
||||
#ifndef SQLITE_OMIT_DEPRECATED
|
||||
#define sqlite3_global_recover sqlite3_api->global_recover
|
||||
#endif
|
||||
#define sqlite3_interrupt sqlite3_api->interruptx
|
||||
#define sqlite3_last_insert_rowid sqlite3_api->last_insert_rowid
|
||||
#define sqlite3_libversion sqlite3_api->libversion
|
||||
#define sqlite3_libversion_number sqlite3_api->libversion_number
|
||||
#define sqlite3_malloc sqlite3_api->malloc
|
||||
#define sqlite3_mprintf sqlite3_api->mprintf
|
||||
#define sqlite3_open sqlite3_api->open
|
||||
#define sqlite3_open16 sqlite3_api->open16
|
||||
#define sqlite3_prepare sqlite3_api->prepare
|
||||
#define sqlite3_prepare16 sqlite3_api->prepare16
|
||||
#define sqlite3_prepare_v2 sqlite3_api->prepare_v2
|
||||
#define sqlite3_prepare16_v2 sqlite3_api->prepare16_v2
|
||||
#define sqlite3_profile sqlite3_api->profile
|
||||
#define sqlite3_progress_handler sqlite3_api->progress_handler
|
||||
#define sqlite3_realloc sqlite3_api->realloc
|
||||
#define sqlite3_reset sqlite3_api->reset
|
||||
#define sqlite3_result_blob sqlite3_api->result_blob
|
||||
#define sqlite3_result_double sqlite3_api->result_double
|
||||
#define sqlite3_result_error sqlite3_api->result_error
|
||||
#define sqlite3_result_error16 sqlite3_api->result_error16
|
||||
#define sqlite3_result_int sqlite3_api->result_int
|
||||
#define sqlite3_result_int64 sqlite3_api->result_int64
|
||||
#define sqlite3_result_null sqlite3_api->result_null
|
||||
#define sqlite3_result_text sqlite3_api->result_text
|
||||
#define sqlite3_result_text16 sqlite3_api->result_text16
|
||||
#define sqlite3_result_text16be sqlite3_api->result_text16be
|
||||
#define sqlite3_result_text16le sqlite3_api->result_text16le
|
||||
#define sqlite3_result_value sqlite3_api->result_value
|
||||
#define sqlite3_rollback_hook sqlite3_api->rollback_hook
|
||||
#define sqlite3_set_authorizer sqlite3_api->set_authorizer
|
||||
#define sqlite3_set_auxdata sqlite3_api->set_auxdata
|
||||
#define sqlite3_snprintf sqlite3_api->xsnprintf
|
||||
#define sqlite3_step sqlite3_api->step
|
||||
#define sqlite3_table_column_metadata sqlite3_api->table_column_metadata
|
||||
#define sqlite3_thread_cleanup sqlite3_api->thread_cleanup
|
||||
#define sqlite3_total_changes sqlite3_api->total_changes
|
||||
#define sqlite3_trace sqlite3_api->trace
|
||||
#ifndef SQLITE_OMIT_DEPRECATED
|
||||
#define sqlite3_transfer_bindings sqlite3_api->transfer_bindings
|
||||
#endif
|
||||
#define sqlite3_update_hook sqlite3_api->update_hook
|
||||
#define sqlite3_user_data sqlite3_api->user_data
|
||||
#define sqlite3_value_blob sqlite3_api->value_blob
|
||||
#define sqlite3_value_bytes sqlite3_api->value_bytes
|
||||
#define sqlite3_value_bytes16 sqlite3_api->value_bytes16
|
||||
#define sqlite3_value_double sqlite3_api->value_double
|
||||
#define sqlite3_value_int sqlite3_api->value_int
|
||||
#define sqlite3_value_int64 sqlite3_api->value_int64
|
||||
#define sqlite3_value_numeric_type sqlite3_api->value_numeric_type
|
||||
#define sqlite3_value_text sqlite3_api->value_text
|
||||
#define sqlite3_value_text16 sqlite3_api->value_text16
|
||||
#define sqlite3_value_text16be sqlite3_api->value_text16be
|
||||
#define sqlite3_value_text16le sqlite3_api->value_text16le
|
||||
#define sqlite3_value_type sqlite3_api->value_type
|
||||
#define sqlite3_vmprintf sqlite3_api->vmprintf
|
||||
#define sqlite3_vsnprintf sqlite3_api->xvsnprintf
|
||||
#define sqlite3_overload_function sqlite3_api->overload_function
|
||||
#define sqlite3_prepare_v2 sqlite3_api->prepare_v2
|
||||
#define sqlite3_prepare16_v2 sqlite3_api->prepare16_v2
|
||||
#define sqlite3_clear_bindings sqlite3_api->clear_bindings
|
||||
#define sqlite3_bind_zeroblob sqlite3_api->bind_zeroblob
|
||||
#define sqlite3_blob_bytes sqlite3_api->blob_bytes
|
||||
#define sqlite3_blob_close sqlite3_api->blob_close
|
||||
#define sqlite3_blob_open sqlite3_api->blob_open
|
||||
#define sqlite3_blob_read sqlite3_api->blob_read
|
||||
#define sqlite3_blob_write sqlite3_api->blob_write
|
||||
#define sqlite3_create_collation_v2 sqlite3_api->create_collation_v2
|
||||
#define sqlite3_file_control sqlite3_api->file_control
|
||||
#define sqlite3_memory_highwater sqlite3_api->memory_highwater
|
||||
#define sqlite3_memory_used sqlite3_api->memory_used
|
||||
#define sqlite3_mutex_alloc sqlite3_api->mutex_alloc
|
||||
#define sqlite3_mutex_enter sqlite3_api->mutex_enter
|
||||
#define sqlite3_mutex_free sqlite3_api->mutex_free
|
||||
#define sqlite3_mutex_leave sqlite3_api->mutex_leave
|
||||
#define sqlite3_mutex_try sqlite3_api->mutex_try
|
||||
#define sqlite3_open_v2 sqlite3_api->open_v2
|
||||
#define sqlite3_release_memory sqlite3_api->release_memory
|
||||
#define sqlite3_result_error_nomem sqlite3_api->result_error_nomem
|
||||
#define sqlite3_result_error_toobig sqlite3_api->result_error_toobig
|
||||
#define sqlite3_sleep sqlite3_api->sleep
|
||||
#define sqlite3_soft_heap_limit sqlite3_api->soft_heap_limit
|
||||
#define sqlite3_vfs_find sqlite3_api->vfs_find
|
||||
#define sqlite3_vfs_register sqlite3_api->vfs_register
|
||||
#define sqlite3_vfs_unregister sqlite3_api->vfs_unregister
|
||||
#define sqlite3_threadsafe sqlite3_api->xthreadsafe
|
||||
#define sqlite3_result_zeroblob sqlite3_api->result_zeroblob
|
||||
#define sqlite3_result_error_code sqlite3_api->result_error_code
|
||||
#define sqlite3_test_control sqlite3_api->test_control
|
||||
#define sqlite3_randomness sqlite3_api->randomness
|
||||
#define sqlite3_context_db_handle sqlite3_api->context_db_handle
|
||||
#define sqlite3_extended_result_codes sqlite3_api->extended_result_codes
|
||||
#define sqlite3_limit sqlite3_api->limit
|
||||
#define sqlite3_next_stmt sqlite3_api->next_stmt
|
||||
#define sqlite3_sql sqlite3_api->sql
|
||||
#define sqlite3_status sqlite3_api->status
|
||||
#define sqlite3_backup_finish sqlite3_api->backup_finish
|
||||
#define sqlite3_backup_init sqlite3_api->backup_init
|
||||
#define sqlite3_backup_pagecount sqlite3_api->backup_pagecount
|
||||
#define sqlite3_backup_remaining sqlite3_api->backup_remaining
|
||||
#define sqlite3_backup_step sqlite3_api->backup_step
|
||||
#define sqlite3_compileoption_get sqlite3_api->compileoption_get
|
||||
#define sqlite3_compileoption_used sqlite3_api->compileoption_used
|
||||
#define sqlite3_create_function_v2 sqlite3_api->create_function_v2
|
||||
#define sqlite3_db_config sqlite3_api->db_config
|
||||
#define sqlite3_db_mutex sqlite3_api->db_mutex
|
||||
#define sqlite3_db_status sqlite3_api->db_status
|
||||
#define sqlite3_extended_errcode sqlite3_api->extended_errcode
|
||||
#define sqlite3_log sqlite3_api->log
|
||||
#define sqlite3_soft_heap_limit64 sqlite3_api->soft_heap_limit64
|
||||
#define sqlite3_sourceid sqlite3_api->sourceid
|
||||
#define sqlite3_stmt_status sqlite3_api->stmt_status
|
||||
#define sqlite3_strnicmp sqlite3_api->strnicmp
|
||||
#define sqlite3_unlock_notify sqlite3_api->unlock_notify
|
||||
#define sqlite3_wal_autocheckpoint sqlite3_api->wal_autocheckpoint
|
||||
#define sqlite3_wal_checkpoint sqlite3_api->wal_checkpoint
|
||||
#define sqlite3_wal_hook sqlite3_api->wal_hook
|
||||
#define sqlite3_blob_reopen sqlite3_api->blob_reopen
|
||||
#define sqlite3_vtab_config sqlite3_api->vtab_config
|
||||
#define sqlite3_vtab_on_conflict sqlite3_api->vtab_on_conflict
|
||||
/* Version 3.7.16 and later */
|
||||
#define sqlite3_close_v2 sqlite3_api->close_v2
|
||||
#define sqlite3_db_filename sqlite3_api->db_filename
|
||||
#define sqlite3_db_readonly sqlite3_api->db_readonly
|
||||
#define sqlite3_db_release_memory sqlite3_api->db_release_memory
|
||||
#define sqlite3_errstr sqlite3_api->errstr
|
||||
#define sqlite3_stmt_busy sqlite3_api->stmt_busy
|
||||
#define sqlite3_stmt_readonly sqlite3_api->stmt_readonly
|
||||
#define sqlite3_stricmp sqlite3_api->stricmp
|
||||
#define sqlite3_uri_boolean sqlite3_api->uri_boolean
|
||||
#define sqlite3_uri_int64 sqlite3_api->uri_int64
|
||||
#define sqlite3_uri_parameter sqlite3_api->uri_parameter
|
||||
#define sqlite3_uri_vsnprintf sqlite3_api->xvsnprintf
|
||||
#define sqlite3_wal_checkpoint_v2 sqlite3_api->wal_checkpoint_v2
|
||||
/* Version 3.8.7 and later */
|
||||
#define sqlite3_auto_extension sqlite3_api->auto_extension
|
||||
#define sqlite3_bind_blob64 sqlite3_api->bind_blob64
|
||||
#define sqlite3_bind_text64 sqlite3_api->bind_text64
|
||||
#define sqlite3_cancel_auto_extension sqlite3_api->cancel_auto_extension
|
||||
#define sqlite3_load_extension sqlite3_api->load_extension
|
||||
#define sqlite3_malloc64 sqlite3_api->malloc64
|
||||
#define sqlite3_msize sqlite3_api->msize
|
||||
#define sqlite3_realloc64 sqlite3_api->realloc64
|
||||
#define sqlite3_reset_auto_extension sqlite3_api->reset_auto_extension
|
||||
#define sqlite3_result_blob64 sqlite3_api->result_blob64
|
||||
#define sqlite3_result_text64 sqlite3_api->result_text64
|
||||
#define sqlite3_strglob sqlite3_api->strglob
|
||||
/* Version 3.8.11 and later */
|
||||
#define sqlite3_value_dup sqlite3_api->value_dup
|
||||
#define sqlite3_value_free sqlite3_api->value_free
|
||||
#define sqlite3_result_zeroblob64 sqlite3_api->result_zeroblob64
|
||||
#define sqlite3_bind_zeroblob64 sqlite3_api->bind_zeroblob64
|
||||
/* Version 3.9.0 and later */
|
||||
#define sqlite3_value_subtype sqlite3_api->value_subtype
|
||||
#define sqlite3_result_subtype sqlite3_api->result_subtype
|
||||
/* Version 3.10.0 and later */
|
||||
#define sqlite3_status64 sqlite3_api->status64
|
||||
#define sqlite3_strlike sqlite3_api->strlike
|
||||
#define sqlite3_db_cacheflush sqlite3_api->db_cacheflush
|
||||
/* Version 3.12.0 and later */
|
||||
#define sqlite3_system_errno sqlite3_api->system_errno
|
||||
/* Version 3.14.0 and later */
|
||||
#define sqlite3_trace_v2 sqlite3_api->trace_v2
|
||||
#define sqlite3_expanded_sql sqlite3_api->expanded_sql
|
||||
/* Version 3.18.0 and later */
|
||||
#define sqlite3_set_last_insert_rowid sqlite3_api->set_last_insert_rowid
|
||||
/* Version 3.20.0 and later */
|
||||
#define sqlite3_prepare_v3 sqlite3_api->prepare_v3
|
||||
#define sqlite3_prepare16_v3 sqlite3_api->prepare16_v3
|
||||
#define sqlite3_bind_pointer sqlite3_api->bind_pointer
|
||||
#define sqlite3_result_pointer sqlite3_api->result_pointer
|
||||
#define sqlite3_value_pointer sqlite3_api->value_pointer
|
||||
/* Version 3.22.0 and later */
|
||||
#define sqlite3_vtab_nochange sqlite3_api->vtab_nochange
|
||||
#define sqlite3_value_nochange sqlite3_api->value_nochange
|
||||
#define sqlite3_vtab_collation sqlite3_api->vtab_collation
|
||||
/* Version 3.24.0 and later */
|
||||
#define sqlite3_keyword_count sqlite3_api->keyword_count
|
||||
#define sqlite3_keyword_name sqlite3_api->keyword_name
|
||||
#define sqlite3_keyword_check sqlite3_api->keyword_check
|
||||
#define sqlite3_str_new sqlite3_api->str_new
|
||||
#define sqlite3_str_finish sqlite3_api->str_finish
|
||||
#define sqlite3_str_appendf sqlite3_api->str_appendf
|
||||
#define sqlite3_str_vappendf sqlite3_api->str_vappendf
|
||||
#define sqlite3_str_append sqlite3_api->str_append
|
||||
#define sqlite3_str_appendall sqlite3_api->str_appendall
|
||||
#define sqlite3_str_appendchar sqlite3_api->str_appendchar
|
||||
#define sqlite3_str_reset sqlite3_api->str_reset
|
||||
#define sqlite3_str_errcode sqlite3_api->str_errcode
|
||||
#define sqlite3_str_length sqlite3_api->str_length
|
||||
#define sqlite3_str_value sqlite3_api->str_value
|
||||
/* Version 3.25.0 and later */
|
||||
#define sqlite3_create_window_function sqlite3_api->create_window_function
|
||||
/* Version 3.26.0 and later */
|
||||
#define sqlite3_normalized_sql sqlite3_api->normalized_sql
|
||||
/* Version 3.28.0 and later */
|
||||
#define sqlite3_stmt_isexplain sqlite3_api->stmt_isexplain
|
||||
#define sqlite3_value_frombind sqlite3_api->value_frombind
|
||||
/* Version 3.30.0 and later */
|
||||
#define sqlite3_drop_modules sqlite3_api->drop_modules
|
||||
/* Version 3.31.0 and later */
|
||||
#define sqlite3_hard_heap_limit64 sqlite3_api->hard_heap_limit64
|
||||
#define sqlite3_uri_key sqlite3_api->uri_key
|
||||
#define sqlite3_filename_database sqlite3_api->filename_database
|
||||
#define sqlite3_filename_journal sqlite3_api->filename_journal
|
||||
#define sqlite3_filename_wal sqlite3_api->filename_wal
|
||||
/* Version 3.32.0 and later */
|
||||
#define sqlite3_create_filename sqlite3_api->create_filename
|
||||
#define sqlite3_free_filename sqlite3_api->free_filename
|
||||
#define sqlite3_database_file_object sqlite3_api->database_file_object
|
||||
/* Version 3.34.0 and later */
|
||||
#define sqlite3_txn_state sqlite3_api->txn_state
|
||||
/* Version 3.36.1 and later */
|
||||
#define sqlite3_changes64 sqlite3_api->changes64
|
||||
#define sqlite3_total_changes64 sqlite3_api->total_changes64
|
||||
/* Version 3.37.0 and later */
|
||||
#define sqlite3_autovacuum_pages sqlite3_api->autovacuum_pages
|
||||
/* Version 3.38.0 and later */
|
||||
#define sqlite3_error_offset sqlite3_api->error_offset
|
||||
#define sqlite3_vtab_rhs_value sqlite3_api->vtab_rhs_value
|
||||
#define sqlite3_vtab_distinct sqlite3_api->vtab_distinct
|
||||
#define sqlite3_vtab_in sqlite3_api->vtab_in
|
||||
#define sqlite3_vtab_in_first sqlite3_api->vtab_in_first
|
||||
#define sqlite3_vtab_in_next sqlite3_api->vtab_in_next
|
||||
/* Version 3.39.0 and later */
|
||||
#ifndef SQLITE_OMIT_DESERIALIZE
|
||||
#define sqlite3_deserialize sqlite3_api->deserialize
|
||||
#define sqlite3_serialize sqlite3_api->serialize
|
||||
#endif
|
||||
#define sqlite3_db_name sqlite3_api->db_name
|
||||
/* Version 3.40.0 and later */
|
||||
#define sqlite3_value_encoding sqlite3_api->value_encoding
|
||||
/* Version 3.41.0 and later */
|
||||
#define sqlite3_is_interrupted sqlite3_api->is_interrupted
|
||||
/* Version 3.43.0 and later */
|
||||
#define sqlite3_stmt_explain sqlite3_api->stmt_explain
|
||||
/* Version 3.44.0 and later */
|
||||
#define sqlite3_get_clientdata sqlite3_api->get_clientdata
|
||||
#define sqlite3_set_clientdata sqlite3_api->set_clientdata
|
||||
#endif /* !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION) */
|
||||
|
||||
#if !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION)
|
||||
/* This case when the file really is being compiled as a loadable
|
||||
** extension */
|
||||
# define SQLITE_EXTENSION_INIT1 const sqlite3_api_routines *sqlite3_api=0;
|
||||
# define SQLITE_EXTENSION_INIT2(v) sqlite3_api=v;
|
||||
# define SQLITE_EXTENSION_INIT3 \
|
||||
extern const sqlite3_api_routines *sqlite3_api;
|
||||
#else
|
||||
/* This case when the file is being statically linked into the
|
||||
** application */
|
||||
# define SQLITE_EXTENSION_INIT1 /*no-op*/
|
||||
# define SQLITE_EXTENSION_INIT2(v) (void)v; /* unused parameter */
|
||||
# define SQLITE_EXTENSION_INIT3 /*no-op*/
|
||||
#endif
|
||||
|
||||
#endif /* SQLITE3EXT_H */
|
||||
@@ -1,953 +0,0 @@
|
||||
#ifndef SYSTEMDATA_H
|
||||
#define SYSTEMDATA_H
|
||||
#include "pmSysvariable.h"
|
||||
#include "sqlit3/SQLite.h"
|
||||
#include <set>
|
||||
#include <mutex>
|
||||
#define DEBUFG
|
||||
class SystemData
|
||||
{
|
||||
private:
|
||||
SQLite* m_db;
|
||||
std::set<unsigned int> sysFaultCodes;
|
||||
mutable std::mutex sysFaultCodesMutex;
|
||||
public:
|
||||
/**
|
||||
* @brief 向系统故障码集合中插入一个故障码
|
||||
* @param faultCode 要插入的故障码
|
||||
*/
|
||||
void insertFaultCode(unsigned int faultCode) {
|
||||
std::lock_guard<std::mutex> lock(sysFaultCodesMutex);
|
||||
sysFaultCodes.insert(faultCode);
|
||||
}
|
||||
/**
|
||||
* @brief 从系统故障码集合中消除一个故障码
|
||||
* @param faultCode 要消除的故障码
|
||||
*/
|
||||
void eraseFaultCode(unsigned int faultCode) {
|
||||
std::lock_guard<std::mutex> lock(sysFaultCodesMutex);
|
||||
sysFaultCodes.erase(faultCode);
|
||||
}
|
||||
/**
|
||||
* @brief 获取系统当前的故障等级
|
||||
* @return uint8_t 故障等级,00H-无故障, 10H-一级, 20H-二级, 30H-三级, 40H-四级
|
||||
*/
|
||||
uint8_t getFaultCodeLevel() const {
|
||||
uint8_t maxLevel = 0;
|
||||
// 遍历 sysFaultCodes 集合中的每个故障码
|
||||
for (auto code : sysFaultCodes) {
|
||||
// 提取0xabcd中的b位 (右移8位后取低4位)
|
||||
uint8_t level = (code >> 8) & 0xF;
|
||||
if (level > maxLevel) {
|
||||
maxLevel = level;
|
||||
}
|
||||
}
|
||||
return maxLevel;
|
||||
}
|
||||
/**
|
||||
* @brief 获取系统当前的故障码集合
|
||||
* @return std::set<unsigned int>& 系统当前的故障码集合
|
||||
*/
|
||||
const std::set<unsigned int>& getFaultCode() const {
|
||||
return sysFaultCodes;
|
||||
}
|
||||
//燃料电池系统参数
|
||||
uint8_t fc_mode; // 燃料电池系统运行模式:00H-无效, 01H-调试, 02H-自动, 03H-补给
|
||||
uint8_t fc_status; // 燃料电池状态:00H-无效, 01H-初始化, ..., 0DH-维护完成
|
||||
uint8_t fc_fault_level; // 燃料电池故障等级:00H-无故障, 10H-一级, 20H-二级, 30H-三级, 40H-四级
|
||||
|
||||
//功率和时间参数
|
||||
float output_power_limit; // 系统输出功率限制值,单位:W
|
||||
float total_generation_time; // 系统累计发电时间,单位:0.1小时
|
||||
float total_generation_power; // 系统累计发电总功率,单位:W
|
||||
|
||||
//故障信息
|
||||
uint16_t fc_fault_level_1; // 一级故障位
|
||||
uint16_t fc_fault_level_2; // 二级故障位
|
||||
uint16_t fc_fault_level_3; // 三级故障位
|
||||
uint16_t fc_fault_level_4; // 四级故障位
|
||||
|
||||
//燃料容量
|
||||
float hydrogen_capacity; // 储氢罐剩余容量百分比,单位:%
|
||||
float liquid_oxygen_capacity; // 液氧罐剩余容量百分比,单位:%
|
||||
|
||||
//温度压力参数
|
||||
float palladium_temp; // 钯膜最高温度,单位:℃
|
||||
float main_pipe_pressure; // 主水路压力,单位:0.01kPa
|
||||
float aux_pipe_pressure; // 辅水路压力,单位:0.01kPa
|
||||
|
||||
//舱室环境参数
|
||||
float cabin_pressure1; // 舱室1压力,单位:0.01kPa
|
||||
float cabin_pressure2; // 舱室2压力,单位:0.01kPa
|
||||
float cabin_temp1; // 舱室1温度,单位:0.01℃
|
||||
float cabin_temp2; // 舱室2温度,单位:0.01℃
|
||||
float cabin_humidity1; // 舱室1湿度,单位:0.01%RH
|
||||
float cabin_humidity2; // 舱室2湿度,单位:0.01%RH
|
||||
|
||||
//火焰探测器
|
||||
uint8_t flame_detector1; // 火焰探测器1状态:00H-无效, 01H-报警, 02H-故障
|
||||
uint8_t flame_detector2; // 火焰探测器2状态:00H-无效, 01H-报警, 02H-故障
|
||||
|
||||
//气体浓度
|
||||
float h2_concentration1; // 舱室H2浓度1,单位:0.01% LEL
|
||||
float h2_concentration2; // 舱室H2浓度2,单位:0.01% LEL
|
||||
float h2_concentration3; // 舱室H2浓度3,单位:0.01% LEL
|
||||
float o2_concentration1; // 舱室O2浓度1,单位:0.01% LEL
|
||||
float o2_concentration2; // 舱室O2浓度2,单位:0.01% LEL
|
||||
float ch3oh_concentration1; // 舱室甲醇气体浓度1,单位:0.01% LEL
|
||||
float ch3oh_concentration2; // 舱室甲醇气体浓度2,单位:0.01% LEL
|
||||
|
||||
//保留字段
|
||||
float reserved1[10]; // 保留字段
|
||||
float cabin_ox_concentration; // 仪表舱内氧气浓度,单位:0.1%
|
||||
float cabin_temperature; // 仪表舱内温度,单位:0.1℃
|
||||
float cabin_humidity; // 仪表舱内湿度,单位:0.1%RH
|
||||
float cabin_pressure; // 仪表舱内大气压,单位:0.2kPa
|
||||
|
||||
//动力舱参数
|
||||
float power_cabin_ox_concentration; // 动力舱内氧气浓度,单位:0.1%
|
||||
float power_cabin_temperature; // 动力舱内温度,单位:0.1℃
|
||||
float power_cabin_humidity; // 动力舱内湿度,单位:0.1%RH
|
||||
float power_cabin_pressure; // 动力舱内大气压,单位:0.2kPa
|
||||
uint8_t reserved2[2]; // 保留字段
|
||||
|
||||
//电池报警标志
|
||||
uint8_t dyn_alarm_flag[6]; // 动力锂电池报警标志
|
||||
uint8_t ins_alarm_flag[6]; // 仪表锂电池报警标志
|
||||
|
||||
//继电器状态
|
||||
uint8_t ins_relay_status1; // 仪表电池继电器状态
|
||||
uint8_t ins_relay_status2; // 仪表电池预充继电器和负极继电器状态
|
||||
uint8_t dyn_relay_status1; // 动力电池正极与充电继电器状态
|
||||
uint8_t dyn_relay_status2; // 动力电池预充与负极继电器状态
|
||||
|
||||
//仪表电池继电器状态
|
||||
uint8_t ins_pos_relay_status; // 仪表电池正极继电器状态 (X0H:无效 X1H:接通 X2H:断开)
|
||||
uint8_t ins_charge_relay_status; // 仪表电池充电继电器状态 (0XH:无效 1XH:接通 2XH:断开)
|
||||
uint8_t ins_precharge_relay_status; // 仪表电池预充继电器状态 (X0H:无效 X1H:接通 X2H:断开)
|
||||
uint8_t ins_neg_relay_status; // 仪表电池负极继电器状态 (0XH:无效 1XH:接通 2XH:断开)
|
||||
|
||||
//动力电池继电器状态
|
||||
uint8_t dyn_pos_relay_status; // 动力电池正极继电器状态 (X0H:无效 X1H:接通 X2H:断开)
|
||||
uint8_t dyn_charge_relay_status; // 动力电池充电继电器状态 (0XH:无效 1XH:接通 2XH:断开)
|
||||
uint8_t dyn_precharge_relay_status; // 动力电池预充继电器状态 (X0H:无效 X1H:接通 X2H:断开)
|
||||
uint8_t dyn_neg_relay_status; // 动力电池负极继电器状态 (0XH:无效 1XH:接通 2XH:断开)
|
||||
|
||||
//电池功率参数
|
||||
float ins_max_discharge_power; // 仪表电池最大允许放电功率,单位:0.05kW
|
||||
float dyn_max_discharge_power; // 动力电池最大允许放电功率,单位:0.05kW
|
||||
|
||||
//电池SOC
|
||||
int ins_soc; // 仪表锂电池荷电状态SOC,范围:0~100
|
||||
int dyn_soc; // 动力锂电池荷电状态SOC,范围:0~100
|
||||
|
||||
//电池能量
|
||||
float ins_total_energy; // 仪表电池总能量,单位:0.1kWh
|
||||
float dyn_total_energy; // 动力电池总能量,单位:0.1kWh
|
||||
|
||||
//电池输入功率
|
||||
float ins_power_input; // 仪表电池输入功率,单位:0.1kW
|
||||
float dyn_power_input; // 动力电池输入功率,单位:0.1kW
|
||||
|
||||
//电池充放电状态
|
||||
uint8_t ins_charge_status; // 仪表电池充放电状态:00H-无效,10H-充电,20H-放电
|
||||
uint8_t dyn_charge_status; // 动力电池充放电状态:00H-无效,10H-充电,20H-放电
|
||||
|
||||
//电池电压电流
|
||||
float ins_voltage_link; // 仪表电池LINK端电压,单位:0.01V
|
||||
float ins_voltage_pack; // 仪表电池PACK端电压,单位:0.01V
|
||||
float ins_current; // 仪表电池电流,单位:0.01A
|
||||
float ins_resistance_pos; // 仪表电池正极绝缘电阻,单位:kΩ
|
||||
float ins_resistance_neg; // 仪表电池负极绝缘电阻,单位:kΩ
|
||||
float dyn_voltage_link; // 动力电池LINK端电压,单位:0.01V
|
||||
float dyn_voltage_pack; // 动力电池PACK端电压,单位:0.01V
|
||||
float dyn_current; // 动力电池电流,单位:0.05A
|
||||
float dyn_resistance_pos; // 动力电池正极绝缘电阻,单位:kΩ
|
||||
float dyn_resistance_neg; // 动力电池负极绝缘电阻,单位:kΩ
|
||||
|
||||
//紧急状态
|
||||
uint8_t ins_emergency_status; // 仪表电池紧急状态
|
||||
uint8_t dyn_emergency_status; // 动力电池紧急状态
|
||||
|
||||
//保留字段
|
||||
uint8_t reserved3[2]; // 保留字段
|
||||
float ins_soc_threshold1; // 仪表电池1 SOC门限
|
||||
float ins_soc_threshold2; // 仪表电池2 SOC门限
|
||||
float ins_soc_threshold3; // 仪表电池3 SOC门限
|
||||
float dyn_soc_threshold1; // 动力电池1 SOC门限
|
||||
float dyn_soc_threshold2; // 动力电池2 SOC门限
|
||||
float dyn_soc_threshold3; // 动力电池3 SOC门限
|
||||
float ins_power_limit1; // 仪表电池1功率限制值
|
||||
float ins_power_limit2; // 仪表电池2功率限制值
|
||||
float dyn_power_limit1; // 动力电池1功率限制值
|
||||
float dyn_power_limit2; // 动力电池2功率限制值
|
||||
|
||||
//设备在线状态
|
||||
uint32_t device_online_flag1; // 设备在线状态标志1
|
||||
uint32_t device_online_flag2; // 设备在线状态标志2
|
||||
|
||||
//其他锂电池状态
|
||||
uint8_t dyn_charge_level; // 动力电池充电状态:01H-1级(不限), 02H-2级(限功率), 03H-3级(关闭)
|
||||
uint8_t dyn_water_leak_status; // 动力漏水状态:0XH-正常, 1XH-异常漏水
|
||||
uint8_t ins_water_leak_dcdc_status; // 仪表漏水状态与DCDC状态:低4位-漏水状态(0XH正常,1XH异常),高4位-DCDC状态(X0H正常,X1H故障)
|
||||
uint8_t reserved4;
|
||||
|
||||
unsigned char water_leak_status_from_insbat; // 仪表漏水状态
|
||||
unsigned char water_leak_status_from_dynbat; // 动力漏水状态
|
||||
unsigned char dcdc_status_from_insbat; // 仪表DCDC状态
|
||||
|
||||
//保留字段
|
||||
// uint32_t reserved4; // 保留字段
|
||||
uint32_t heartbeat; // 主机心跳计数器
|
||||
|
||||
//锂电池故障字段
|
||||
unsigned char powfaultCode;
|
||||
unsigned char insfaultCode;
|
||||
|
||||
|
||||
//应急电池
|
||||
double emergency_battery1_voltage; // 应急电池1总电压 [V]
|
||||
double emergency_battery1_current; // 应急电池1总电流 [A]
|
||||
double emergency_battery1_max_temp; // 应急电池1最高温度 [°C]
|
||||
uint16_t emergency_battery1_fault_word; // 应急电池1故障字
|
||||
double emergency_battery2_voltage; // 应急电池2总电压 [V]
|
||||
double emergency_battery2_current; // 应急电池2总电流 [A]
|
||||
double emergency_battery2_max_temp; // 应急电池2最高温度 [°C]
|
||||
uint16_t emergency_battery2_fault_word; // 应急电池2故障字
|
||||
|
||||
// MOOSD 状态
|
||||
bool moosd_status;
|
||||
//配电系统状态
|
||||
//DC/DC状态字
|
||||
struct DcdcStatus
|
||||
{
|
||||
// DC/DC5故障字低
|
||||
union {
|
||||
unsigned char lowFaultWord;
|
||||
struct {
|
||||
bool overTemperatureShutdown : 1; // Bit0: DC/DC模块过温关机
|
||||
bool outputOverCurrent : 1; // Bit1: 输出过流
|
||||
bool outputOverVoltage : 1; // Bit2: 输出过压
|
||||
bool outputUnderVoltage : 1; // Bit3: 输出欠压
|
||||
bool inputOverVoltage : 1; // Bit4: 输入过压
|
||||
bool inputUnderVoltage : 1; // Bit5: 输入欠压
|
||||
bool outputShortCircuit : 1; // Bit6: 输出短路保护
|
||||
bool internalFault : 1; // Bit7: 内部故障
|
||||
};
|
||||
};
|
||||
// DC/DC5故障字高
|
||||
union {
|
||||
unsigned char highFaultWord;
|
||||
struct {
|
||||
bool communicationFault : 1; // Bit0: 通讯故障报警
|
||||
bool workingStatus : 1; // Bit1: 工作状态(1:启动, 0:关闭)
|
||||
bool coolingPump1Fault : 1; // Bit2: 冷却泵1故障
|
||||
bool coolingPump2Fault : 1; // Bit3: 冷却泵2故障
|
||||
bool coolingWaterLeak : 1; // Bit4: 冷却水泄露
|
||||
bool coolingPump1Running : 1; // Bit5: 冷却泵1运行状态
|
||||
bool coolingPump2Running : 1; // Bit6: 冷却泵2运行状态
|
||||
bool reserved : 1; // Bit7: 保留位
|
||||
};
|
||||
};
|
||||
|
||||
// 构造函数,初始化所有状态为正常
|
||||
DcdcStatus() : lowFaultWord(0x00), highFaultWord(0x00) {}
|
||||
} m_dcdcStatus;
|
||||
|
||||
|
||||
//动力母线状态
|
||||
struct POWER_BUS_STATUS
|
||||
{
|
||||
// 5: 燃料电池断路器 0 断开 1 闭合 2 故障
|
||||
unsigned char fuelCellCircuitBreaker;
|
||||
// 6: 动力锂电池断路器 0 断开 1 闭合 2 故障
|
||||
unsigned char powerLithiumBatteryCircuitBreaker;
|
||||
// 7: 推进电机断路器 0 断开 1 闭合 2 故障
|
||||
unsigned char propulsionMotorCircuitBreaker;
|
||||
// 8: 锂电池组仪表断路器 0 断开 1 闭合 2 故障
|
||||
unsigned char lithiumBatteryGroupInstrumentCircuitBreaker;
|
||||
// 9: DC/DC5模块断路器 0 断开 1 闭合 2 故障
|
||||
unsigned char dcDc5ModuleCircuitBreaker;
|
||||
// 10: 艏部高压配电箱断路器 0 断开 1 闭合 2 故障
|
||||
unsigned char bowHighVoltageDistributionBoxCircuitBreaker;
|
||||
// 11: 艉部FT装置4/5断路器 0 断开 1 闭合 2 故障
|
||||
unsigned char sternFTDevice45CircuitBreaker;
|
||||
// 12: 艉舵开关1断路器 0 断开 1 闭合 2 故障
|
||||
unsigned char sternRudderSwitch1CircuitBreaker;
|
||||
// 13: 艉舵开关2断路器 0 断开 1 闭合 2 故障
|
||||
unsigned char sternRudderSwitch2CircuitBreaker;
|
||||
// 14: FB预留断路器 0 断开 1 闭合 2 故障
|
||||
unsigned char fbReservedCircuitBreaker;
|
||||
// 15: TYZ预留断路器 0 断开 1 闭合 2 故障
|
||||
unsigned char tyzReservedCircuitBreaker;
|
||||
// 16: 预留断路器 0 断开 1 闭合 2 故障
|
||||
unsigned char reservedCircuitBreaker;
|
||||
// 17: DC/DC5模块状态 0 未运行;1 运行;2 DC/DC模块过温关机;3 输出过流;4 输出过压;5 输出欠压;6 输入过压;7 输入欠压;8 输出短路保护;9 内部故障
|
||||
unsigned char dcDcModuleStatus;
|
||||
// 18:冷却系统状态 0 未运行 1 运行 2 冷却泵1故障 3 冷却泵2故障 4 冷却水泄露
|
||||
unsigned char coolingSystemStatus;
|
||||
// 19: 动力母排绝缘状态 0 正常 1 绝缘低
|
||||
unsigned char powerBusInsulationStatus;
|
||||
// 20: A汇流排绝缘状态 0 正常 1 绝缘低
|
||||
unsigned char aBusInsulationStatus;
|
||||
// 21: 仪表电源状态 0 正常 1 故障
|
||||
unsigned char meterPowerLossSignal;
|
||||
// 22: 应急电源状态 0 正常 1 故障
|
||||
unsigned char emergencyPowerLossSignal;
|
||||
// 22: dc/dc温度
|
||||
float dcDcTemperature;
|
||||
// 23: 动力汇流排电压
|
||||
float powerBusVoltage;
|
||||
// 24: DC/DC5模块电流
|
||||
float dcDc5ModuleCurrent;
|
||||
// 25: 动力汇流排电流
|
||||
float powerBusCurrent;
|
||||
// 26: A汇流排电压
|
||||
float busbarAVoltage;
|
||||
// 27: 推进电机控制箱电流
|
||||
float propulsionMotorControlBoxCurrent;
|
||||
// 28: A汇流排电流
|
||||
float busbarACurrent;
|
||||
// 29: 锂电池组(仪表)电流
|
||||
float lithiumBatteryGroupMeterCurrent;
|
||||
// 30: 艏部高压配电箱电流
|
||||
float bowHighVoltageDistributionBoxCurrent;
|
||||
// 31: 艉部FT装置4/5电流
|
||||
float sternFTDevice45Current;
|
||||
// 32: TYZ预留开关电流
|
||||
float tyzReservedSwitchCurrent;
|
||||
// 33: 艉舵开关1电流
|
||||
float sternRudderSwitch1Current;
|
||||
// 34: 预留电流
|
||||
float reservedCurrent1; // 改为 reservedCurrent1 以避免重名
|
||||
// 35: 艉舵开关2电流
|
||||
float sternRudderSwitch2Current;
|
||||
// 36: 预留电流2
|
||||
float reservedCurrent2; // 改为 reservedCurrent2 以避免重名
|
||||
// 37: FB预留电流
|
||||
float fbReservedSwitchCurrent;
|
||||
// 38: 预留电流3
|
||||
float reservedCurrent3; // 改为 reservedCurrent3 以避免重名
|
||||
// 39: 冷却水压力
|
||||
float coolWaterPressure;
|
||||
}power_bus_status;
|
||||
|
||||
struct POWER_A_BUS_STATUS
|
||||
{
|
||||
//动力汇流排状态
|
||||
//5. 艏部FT装置1/2/3断路器 0 断开 1 闭合 2 故障
|
||||
unsigned char bowFTDevice123CircuitBreaker;
|
||||
//6. 启闭机构断路器 0 断开 1 闭合 2 故障
|
||||
unsigned char actuatorCircuitBreaker;
|
||||
//7. 桅杆舵机控制箱断路器 0 断开 1 闭合 2 故障
|
||||
unsigned char mastSteeringGearControlBoxCircuitBreaker;
|
||||
//8. XCZ断路器 0 断开 1 闭合 2 故障
|
||||
unsigned char xczCircuitBreaker;
|
||||
//9. 艏舵控制箱断路器 0 断开 1 闭合 2 故障
|
||||
unsigned char bowRudderControlBoxCircuitBreaker;
|
||||
//10. 敞水盖启动电缸断路器 0 断开 1 闭合 2 故障
|
||||
unsigned char openWaterCoverStartCylinderCircuitBreaker;
|
||||
//11. 仪表电源失电信号 0 正常 1 故障
|
||||
unsigned char instrumentPowerFailureSignal;
|
||||
//12. 应急电源失电信号 0 正常 1 故障
|
||||
unsigned char emergencyPowerFailureSignal;
|
||||
//13. 浸水报警 0 无 1 有
|
||||
unsigned char waterIngressionAlarm;
|
||||
//14. 汇流排B电压
|
||||
float busbarBVoltage;
|
||||
//15. 汇流排B电流
|
||||
float busbarBCurrent;
|
||||
//16. 艏部FT装置1/2/3电流
|
||||
float bowFTDevice123Current;
|
||||
//17. 启闭机构电流
|
||||
float actuatorCurrent;
|
||||
//18. 桅杆舵机控制箱电流
|
||||
float mastSteeringGearControlBoxCurrent;
|
||||
//19. XCZ电流
|
||||
float xczCurrent;
|
||||
//20. 艏舵控制箱电流
|
||||
float bowRudderControlBoxCurrent;
|
||||
//21. 敞水盖启动电缸电流
|
||||
float openWaterCoverStartCylinderCurrent;
|
||||
} power_a_bus_status;
|
||||
|
||||
//仪表主母线状态
|
||||
struct INSTRUMENT_MAIN_BUS_STATUS
|
||||
{
|
||||
//5. 锂电池组(仪表)断路器 0 断开 1 闭合 2 故障
|
||||
unsigned char lithiumBatteryGroupInstrumentCircuitBreaker;
|
||||
//6. 艏部低压配电箱断路器 0 断开 1 闭合 2 故障
|
||||
unsigned char bowLowVoltageDistributionBoxCircuitBreaker;
|
||||
//7. UNIT4仪表DC48V断路器 0 断开 1 闭合 2 故障
|
||||
unsigned char unit4InstrumentDC48VCircuitBreaker;
|
||||
//8. DC-C1直流配电板断路器 0 断开 1 闭合 2 故障
|
||||
unsigned char dcC1DCDistributionPanelCircuitBreaker;
|
||||
//9. 预留断路器1 0 断开 1 闭合 2 故障
|
||||
unsigned char reservedCircuitBreaker1; // 为了区分,添加了数字后缀
|
||||
//10. 预留断路器2 0 断开 1 闭合 2 故障
|
||||
unsigned char reservedCircuitBreaker2; // 为了区分,添加了数字后缀
|
||||
//11. 应急锂电池组2断路器 0 断开 1 闭合 2 故障
|
||||
unsigned char emergencyLithiumBatteryGroup2CircuitBreaker;
|
||||
//12. 仪表电源失电信号 0 正常 1 故障
|
||||
unsigned char instrumentPowerFailureSignal;
|
||||
//13. 应急电源失电信号 0 正常 1 故障
|
||||
unsigned char emergencyPowerFailureSignal;
|
||||
//14. 仪表汇流排绝缘低 0 正常 1 绝缘低
|
||||
unsigned char instrumentBusbarInsulationLow;
|
||||
//15. 仪表母排电压
|
||||
float instrumentBusbarVoltage;
|
||||
//16. 艏部低压配电箱电流
|
||||
float bowLowVoltageDistributionBoxCurrent;
|
||||
//17. DC-C1(直流配电板1)仪表DC48V电流
|
||||
float dcC1InstrumentDC48VCurrent;
|
||||
//18. 预留电流
|
||||
float reservedCurrent1; // 为了区分,添加了数字后缀
|
||||
//19. 应急锂电池组2电流
|
||||
float emergencyLithiumBatteryGroup2Current;
|
||||
//20. 锂电池组(仪表)电流
|
||||
float lithiumBatteryGroupInstrumentCurrent;
|
||||
//21. UNIT4仪表DC48V电流
|
||||
float unit4InstrumentDC48VCurrent;
|
||||
//22. Ushort 预留电流
|
||||
float reservedCurrent2; // 为了区分,添加了数字后缀
|
||||
//23. 应急2汇流排电压
|
||||
float emergency2BusbarVoltage;
|
||||
//24. 复合能源管控系统应急DC48V电流
|
||||
float compositeEnergyManagementSystemEmergencyDC48VCurrent;
|
||||
//25. 燃料电池安全系统应急DC48V电流
|
||||
float fuelCellSecuritySystemEmergencyDC48VCurrent;
|
||||
//26. PLC控制电源电流
|
||||
float plcControlPowerCurrent;
|
||||
} instrument_main_bus_status;
|
||||
|
||||
//仪表汇流排状态
|
||||
struct INSTRUMENT_BUS_STATUS
|
||||
{
|
||||
//5. UNIT1断路器 0 断开 1 闭合 2 故障
|
||||
unsigned char unit1CircuitBreaker;
|
||||
//6. UNIT2断路器 0 断开 1 闭合 2 故障
|
||||
unsigned char unit2CircuitBreaker;
|
||||
//7. UNIT3断路器 0 断开 1 闭合 2 故障
|
||||
unsigned char unit3CircuitBreaker;
|
||||
//8. UNIT5断路器 0 断开 1 闭合 2 故障
|
||||
unsigned char unit5CircuitBreaker;
|
||||
//9. 艏部PZ装置断路器 0 断开 1 闭合 2 故障
|
||||
unsigned char bowPZDeviceCircuitBreaker;
|
||||
//10. 预留断路器1 0 断开 1 闭合 2 故障
|
||||
unsigned char reservedCircuitBreaker1; // 为了区分,添加了数字后缀
|
||||
//11. 预留断路器2 0 断开 1 闭合 2 故障
|
||||
unsigned char reservedCircuitBreaker2; // 为了区分,添加了数字后缀
|
||||
//12. 应急锂电池组1断路器 0 断开 1 闭合 2 故障
|
||||
unsigned char emergencyLithiumBatteryGroup1CircuitBreaker;
|
||||
//13. 仪表电源失电信号 0 正常 1 故障
|
||||
unsigned char powerFailureSignal;
|
||||
//14. 应急电源失电信号 0 正常 1 故障
|
||||
unsigned char emergencyPowerFailureSignal;
|
||||
//15. 浸水报警 0 无 1 有
|
||||
unsigned char waterIngressionAlarm;
|
||||
//16. 仪表母排电压
|
||||
float instrumentBusbarVoltage;
|
||||
//17. 仪表母排电流
|
||||
float instrumentBusbarCurrent;
|
||||
//18. UNIT1电流
|
||||
float unit1Current;
|
||||
//19. UNIT2电流
|
||||
float unit2Current;
|
||||
//20. UNIT3电流
|
||||
float unit3Current;
|
||||
//21. UNIT5电流
|
||||
float unit5Current;
|
||||
//22. 艏部PZ装置电流
|
||||
float bowPZDeviceCurrent;
|
||||
//23. 应急锂电池组1电流
|
||||
float emergencyLithiumBatteryGroup1Current;
|
||||
//24. 应急1汇流排电压
|
||||
float emergency1BusbarVoltage;
|
||||
} instrument_bus_status;
|
||||
|
||||
struct COMMON_STATUS
|
||||
{
|
||||
//超时状态
|
||||
bool isTimeout;
|
||||
//最后更新时间
|
||||
double lastUpdateTime;
|
||||
};
|
||||
|
||||
struct DeviceCommonStatus
|
||||
{
|
||||
COMMON_STATUS ccu_status;
|
||||
COMMON_STATUS dis_hv_c1;
|
||||
COMMON_STATUS dis_hv_c2;
|
||||
COMMON_STATUS dis_lv_c1;
|
||||
COMMON_STATUS dis_lv_c2;
|
||||
} device_common_status;
|
||||
|
||||
struct DeviceOnlineStatus
|
||||
{
|
||||
//在线状态
|
||||
//0x00: 未上线
|
||||
//0x01: 在线
|
||||
//0x02: 上线后掉线
|
||||
uint8_t ins_online_state; //仪表锂电在线标志位
|
||||
uint8_t dyn_online_state; //动力锂电在线标志位
|
||||
uint8_t fuel_online_state; //燃电锂电在线标志位
|
||||
uint8_t high_voltage_online_state; //高压配电板在线标志位
|
||||
uint8_t low_voltage_online_state; //低压配电板在线标志位
|
||||
uint8_t composite_online_state; //复合管控主机在线标志位
|
||||
uint8_t composite_backup_online_state; //复合管控备机在线标志位
|
||||
} device_online_status;
|
||||
|
||||
enum LeakageStatus {
|
||||
LEAKAGE_BOW_EMERGENCY = 0, // 艏部应急漏水 (0x01)
|
||||
LEAKAGE_BOW_HIGH_VOLTAGE, // 艏高压漏水 (0x02)
|
||||
LEAKAGE_BOW_LOW_VOLTAGE, // 艏低压漏水 (0x04)
|
||||
LEAKAGE_FUEL_CELL, // 燃电舱漏水 (0x08)
|
||||
LEAKAGE_LI_BATTERY, // 锂电池舱漏水 (0x10)
|
||||
LEAKAGE_STERN_EMERGENCY, // 艉应急漏水 (0x20)
|
||||
LEAKAGE_FUEL_CELL_CABIN, // 燃料电池舱漏水 (0x40)
|
||||
LEAKAGE_BOW_EMERGENCY2 // 艏部应急漏水2 (0x80)
|
||||
};
|
||||
|
||||
unsigned char leakageCode = 0;
|
||||
bool leakStatus[8] = {false};
|
||||
|
||||
unsigned char generateLeakageCode() {
|
||||
unsigned char code = 0;
|
||||
if(leakStatus[LEAKAGE_BOW_EMERGENCY]) code |= 0x01;
|
||||
if(leakStatus[LEAKAGE_BOW_HIGH_VOLTAGE]) code |= 0x02;
|
||||
if(leakStatus[LEAKAGE_BOW_LOW_VOLTAGE]) code |= 0x04;
|
||||
if(leakStatus[LEAKAGE_FUEL_CELL]) code |= 0x08;
|
||||
if(leakStatus[LEAKAGE_LI_BATTERY]) code |= 0x10;
|
||||
if(leakStatus[LEAKAGE_STERN_EMERGENCY]) code |= 0x20;
|
||||
if(leakStatus[LEAKAGE_FUEL_CELL_CABIN]) code |= 0x40;
|
||||
if(leakStatus[LEAKAGE_BOW_EMERGENCY2]) code |= 0x80;
|
||||
return code;
|
||||
}
|
||||
public:
|
||||
SystemData(){
|
||||
//初始化变量全部为0
|
||||
memset(this, 0, sizeof(SystemData));
|
||||
disSysFaultCode.clear();
|
||||
sysFaultCodes.clear();
|
||||
};
|
||||
~SystemData(){};
|
||||
|
||||
void updateCommonStatus(double time_out=10){
|
||||
//更新时间
|
||||
double currentTime = MOOSTime();
|
||||
//判断是否超时
|
||||
device_common_status.ccu_status.isTimeout = abs(currentTime - device_common_status.ccu_status.lastUpdateTime) > time_out;
|
||||
device_common_status.dis_hv_c1.isTimeout = abs(currentTime - device_common_status.dis_hv_c1.lastUpdateTime) > time_out;
|
||||
device_common_status.dis_hv_c2.isTimeout = abs(currentTime - device_common_status.dis_hv_c2.lastUpdateTime) > time_out;
|
||||
device_common_status.dis_lv_c1.isTimeout = abs(currentTime - device_common_status.dis_lv_c1.lastUpdateTime) > time_out;
|
||||
device_common_status.dis_lv_c2.isTimeout = abs(currentTime - device_common_status.dis_lv_c2.lastUpdateTime) > time_out;
|
||||
};
|
||||
|
||||
void updateSystemData(ccuState data){
|
||||
|
||||
fc_mode = data.fc_mode;
|
||||
fc_status = data.fc_status;
|
||||
fc_fault_level = data.fc_fault_level;
|
||||
|
||||
//功率和时间参数
|
||||
output_power_limit = data.output_power_limit;
|
||||
total_generation_time = data.total_generation_time * 0.1;
|
||||
total_generation_power = data.total_generation_power;
|
||||
|
||||
//故障信息
|
||||
#ifdef DEBUG
|
||||
fc_fault_level_1 = data.fault_level_1;
|
||||
fc_fault_level_2 = data.fault_level_2;
|
||||
fc_fault_level_3 = data.fault_level_3;
|
||||
fc_fault_level_4 = data.fault_level_4;
|
||||
#endif
|
||||
|
||||
//燃料容量
|
||||
hydrogen_capacity = static_cast<int>(data.hydrogen_capacity);
|
||||
liquid_oxygen_capacity = static_cast<int>(data.liquid_oxygen_capacity);
|
||||
|
||||
//温度压力参数
|
||||
palladium_temp = data.palladium_temp;
|
||||
main_pipe_pressure = data.main_pipe_pressure * 0.01;
|
||||
aux_pipe_pressure = data.aux_pipe_pressure * 0.01;
|
||||
|
||||
//舱室环境参数
|
||||
cabin_pressure1 = data.cabin_pressure1 * 0.01;
|
||||
cabin_pressure2 = data.cabin_pressure2 * 0.01;
|
||||
cabin_temp1 = data.cabin_temp1 * 0.01;
|
||||
cabin_temp2 = data.cabin_temp2 * 0.01;
|
||||
cabin_humidity1 = data.cabin_humidity1 * 0.01;
|
||||
cabin_humidity2 = data.cabin_humidity2 * 0.01;
|
||||
|
||||
//火焰探测器
|
||||
flame_detector1 = data.flame_detector1;
|
||||
flame_detector2 = data.flame_detector2;
|
||||
|
||||
//气体浓度
|
||||
h2_concentration1 = data.h2_concentration1 * 0.01;
|
||||
h2_concentration2 = data.h2_concentration2 * 0.01;
|
||||
h2_concentration3 = data.h2_concentration3 * 0.01;
|
||||
o2_concentration1 = data.o2_concentration1 * 0.01;
|
||||
o2_concentration2 = data.o2_concentration2 * 0.01;
|
||||
ch3oh_concentration1 = data.ch3oh_concentration1 * 0.01;
|
||||
ch3oh_concentration2 = data.ch3oh_concentration2 * 0.01;
|
||||
|
||||
//保留字段
|
||||
for(int i=0; i<10; i++) {
|
||||
reserved1[i] = data.reserved1[i];
|
||||
}
|
||||
|
||||
//仪表舱参数
|
||||
cabin_ox_concentration = data.cabin_ox_concentration * 0.1;
|
||||
cabin_temperature = static_cast<int16_t>(data.cabin_temperature) * 0.1;
|
||||
cabin_humidity = data.cabin_humidity * 0.1;
|
||||
cabin_pressure = data.cabin_pressure * 0.2;
|
||||
|
||||
//动力舱参数
|
||||
power_cabin_ox_concentration = data.power_cabin_ox_concentration * 0.1;
|
||||
power_cabin_temperature = static_cast<int16_t>(data.power_cabin_temperature) * 0.1;
|
||||
power_cabin_humidity = data.power_cabin_humidity * 0.1;
|
||||
power_cabin_pressure = data.power_cabin_pressure * 0.2;
|
||||
|
||||
//电池报警标志
|
||||
for(int i=0; i<6; i++) {
|
||||
dyn_alarm_flag[i] = data.dyn_alarm_flag[i];
|
||||
ins_alarm_flag[i] = data.ins_alarm_flag[i];
|
||||
}
|
||||
|
||||
//继电器状态
|
||||
ins_relay_status1 = data.ins_relay_status1;
|
||||
ins_relay_status2 = data.ins_relay_status2;
|
||||
dyn_relay_status1 = data.dyn_relay_status1;
|
||||
dyn_relay_status2 = data.dyn_relay_status2;
|
||||
|
||||
//继电器状态
|
||||
ins_pos_relay_status = (data.ins_relay_status1 ) & 0x0F; // 取高4位作为正极继电器状态
|
||||
ins_charge_relay_status = ( data.ins_relay_status1 >> 4)& 0x0F; // 取低4位作为充电继电器状态
|
||||
ins_precharge_relay_status = (data.ins_relay_status2 ) & 0x0F; // 取高4位作为预充继电器状态
|
||||
ins_neg_relay_status = (data.ins_relay_status2 >> 4) & 0x0F; // 取低4位作为负极继电器状态
|
||||
|
||||
dyn_pos_relay_status = (data.dyn_relay_status1 ) & 0x0F; // 取高4位作为正极继电器状态
|
||||
dyn_charge_relay_status = (data.dyn_relay_status1 >> 4) & 0x0F; // 取低4位作为充电继电器状态
|
||||
dyn_precharge_relay_status = (data.dyn_relay_status2) & 0x0F; // 取高4位作为预充继电器状态
|
||||
dyn_neg_relay_status = (data.dyn_relay_status2 >> 4) & 0x0F; // 取低4位作为负极继电器状态
|
||||
|
||||
//电池功率参数
|
||||
ins_max_discharge_power = data.ins_max_discharge_power * 0.05;
|
||||
dyn_max_discharge_power = data.dyn_max_discharge_power * 0.05;
|
||||
|
||||
//电池SOC
|
||||
ins_soc = static_cast<int>(data.ins_soc);
|
||||
dyn_soc = static_cast<int>(data.dyn_soc);
|
||||
|
||||
//电池能量
|
||||
ins_total_energy = data.ins_total_energy * 0.1;
|
||||
dyn_total_energy = data.dyn_total_energy * 0.1;
|
||||
|
||||
//电池输入功率
|
||||
ins_power_input = data.ins_power_input ;
|
||||
dyn_power_input = data.dyn_power_input ;
|
||||
|
||||
//电池充放电状态
|
||||
ins_charge_status = data.ins_charge_status;
|
||||
dyn_charge_status = data.dyn_charge_status;
|
||||
|
||||
//电池电压电流
|
||||
ins_voltage_link = data.ins_voltage_link * 0.1;
|
||||
ins_voltage_pack = data.ins_voltage_pack * 0.1;
|
||||
ins_current = static_cast<int16_t>(data.ins_current) * 0.05;
|
||||
ins_resistance_pos = data.ins_resistance_pos;
|
||||
ins_resistance_neg = data.ins_resistance_neg;
|
||||
dyn_voltage_link = data.dyn_voltage_link * 0.1;
|
||||
dyn_voltage_pack = data.dyn_voltage_pack * 0.1;
|
||||
dyn_current = static_cast<int16_t>(data.dyn_current) * 0.05;
|
||||
dyn_resistance_pos = data.dyn_resistance_pos;
|
||||
dyn_resistance_neg = data.dyn_resistance_neg;
|
||||
|
||||
//紧急状态
|
||||
ins_emergency_status = data.ins_emergency_status;
|
||||
dyn_emergency_status = data.dyn_emergency_status;
|
||||
|
||||
//保留字段
|
||||
for(int i=0; i<2; i++) {
|
||||
reserved2[i] = data.reserved2[i];
|
||||
}
|
||||
|
||||
//SOC门限值
|
||||
ins_soc_threshold1 = data.ins_soc_threshold1;
|
||||
ins_soc_threshold2 = data.ins_soc_threshold2;
|
||||
ins_soc_threshold3 = data.ins_soc_threshold3;
|
||||
|
||||
//功率限制值
|
||||
ins_power_limit1 = data.ins_power_limit1;
|
||||
ins_power_limit2 = data.ins_power_limit2;
|
||||
|
||||
//设备在线状态
|
||||
device_online_flag1 = data.device_online_flag1;
|
||||
device_online_flag2 = data.device_online_flag2;
|
||||
|
||||
//更新设备在线状态
|
||||
device_online_status.ins_online_state = (data.device_online_flag1 >> 0) & 0xFF; // byte0:仪表锂电在线标志位
|
||||
device_online_status.dyn_online_state = (data.device_online_flag1 >> 8) & 0xFF; // byte1:动力锂电在线标志位
|
||||
device_online_status.fuel_online_state = (data.device_online_flag1 >> 16) & 0xFF; // byte2:燃电锂电在线标志位
|
||||
device_online_status.high_voltage_online_state = (data.device_online_flag1 >> 24) & 0xFF; // byte3:高压配电板在线标志位
|
||||
|
||||
device_online_status.low_voltage_online_state = (data.device_online_flag2 >> 0) & 0xFF; // byte0:低压配电板在线标志位
|
||||
device_online_status.composite_online_state = (data.device_online_flag2 >> 8) & 0xFF; // byte1:复合管控主机在线标志位
|
||||
device_online_status.composite_backup_online_state = (data.device_online_flag2 >> 16) & 0xFF; // byte2:复合管控备机在线标志位
|
||||
|
||||
// 更新锂电池其他状态
|
||||
dyn_water_leak_status = data.dyn_water_leak_status;
|
||||
ins_water_leak_dcdc_status = data.ins_water_leak_dcdc_status;
|
||||
|
||||
dyn_charge_level = data.dyn_charge_level; //01H:1级(不限)02H:2级(限功率)03H:3级(关闭)
|
||||
water_leak_status_from_insbat = ( data.ins_water_leak_dcdc_status >> 4) & 0x0F; // 00 正常,01 异常漏水
|
||||
water_leak_status_from_dynbat = (data.dyn_water_leak_status >> 4) & 0x0F; // 00 正常,01 异常漏水
|
||||
dcdc_status_from_insbat = (data.ins_water_leak_dcdc_status) & 0x0F; // 00 正常,01 故障
|
||||
//更新漏水状态
|
||||
if(water_leak_status_from_insbat == 0x01)
|
||||
{
|
||||
leakStatus[LEAKAGE_LI_BATTERY] = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
leakStatus[LEAKAGE_LI_BATTERY] = false;
|
||||
}
|
||||
if(water_leak_status_from_dynbat == 0x01)
|
||||
{
|
||||
leakStatus[LEAKAGE_LI_BATTERY] = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
leakStatus[LEAKAGE_LI_BATTERY] = false;
|
||||
}
|
||||
//应急电池
|
||||
emergency_battery1_voltage = data.emergency_battery1_voltage * 0.1;
|
||||
emergency_battery1_current = data.emergency_battery1_current * 0.05;
|
||||
emergency_battery1_max_temp = data.emergency_battery1_max_temp * 0.1;
|
||||
emergency_battery1_fault_word = data.emergency_battery1_fault_word;
|
||||
emergency_battery2_voltage = data.emergency_battery2_voltage * 0.1;
|
||||
emergency_battery2_current = data.emergency_battery2_current * 0.05;
|
||||
emergency_battery2_max_temp = data.emergency_battery2_max_temp * 0.1;
|
||||
emergency_battery2_fault_word = data.emergency_battery2_fault_word;
|
||||
//心跳计数器
|
||||
heartbeat = data.heartbeat;
|
||||
}
|
||||
std::set<unsigned int> disSysFaultCode;
|
||||
mutable std::mutex faultCodeMutex;
|
||||
void updateBreakerFault(unsigned char& breakerStatus, unsigned char rawStatus, unsigned int faultCode)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(faultCodeMutex);
|
||||
unsigned char newStatus = rawStatus == 0x55 ? 1 : (rawStatus == 0xAA ? 0 : 2);
|
||||
breakerStatus = newStatus; // 保证状态更新也是原子的
|
||||
|
||||
if(newStatus == 2) {
|
||||
disSysFaultCode.insert(faultCode);
|
||||
} else {
|
||||
disSysFaultCode.erase(faultCode);
|
||||
}
|
||||
}
|
||||
void updateBreakerFault(unsigned char& breakerStatus, unsigned char rawStatus)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(faultCodeMutex);
|
||||
unsigned char newStatus = rawStatus == 0x55 ? 1 : (rawStatus == 0xAA ? 0 : 2);
|
||||
breakerStatus = newStatus; // 保证状态更新也是原子的
|
||||
}
|
||||
void updateSystemData(disHighVolBusState data){
|
||||
updateBreakerFault(power_bus_status.fuelCellCircuitBreaker, data.fuelCellCircuitBreaker, 1);
|
||||
updateBreakerFault(power_bus_status.powerLithiumBatteryCircuitBreaker, data.powerLithiumBatteryCircuitBreaker, 2);
|
||||
updateBreakerFault(power_bus_status.propulsionMotorCircuitBreaker, data.propulsionMotorCircuitBreaker, 3);
|
||||
updateBreakerFault(power_bus_status.lithiumBatteryGroupInstrumentCircuitBreaker, data.lithiumBatteryGroupInstrumentCircuitBreaker, 4);
|
||||
updateBreakerFault(power_bus_status.dcDc5ModuleCircuitBreaker, data.dcDc5ModuleCircuitBreaker, 5);
|
||||
updateBreakerFault(power_bus_status.bowHighVoltageDistributionBoxCircuitBreaker, data.bowHighVoltageDistributionBoxCircuitBreaker, 6);
|
||||
updateBreakerFault(power_bus_status.sternFTDevice45CircuitBreaker, data.sternFTDevice45CircuitBreaker, 7);
|
||||
updateBreakerFault(power_bus_status.sternRudderSwitch1CircuitBreaker, data.sternRudderSwitch1CircuitBreaker, 8);
|
||||
updateBreakerFault(power_bus_status.sternRudderSwitch2CircuitBreaker, data.sternRudderSwitch2CircuitBreaker, 9);
|
||||
updateBreakerFault(power_bus_status.fbReservedCircuitBreaker, data.fbReservedCircuitBreaker);
|
||||
updateBreakerFault(power_bus_status.tyzReservedCircuitBreaker, data.tyzReservedCircuitBreaker);
|
||||
updateBreakerFault(power_bus_status.reservedCircuitBreaker, data.reservedCircuitBreaker);
|
||||
//模块状态
|
||||
power_bus_status.dcDcModuleStatus = data.dcDcFaultWord1;
|
||||
power_bus_status.coolingSystemStatus = data.dcDcFaultWord2;
|
||||
|
||||
m_dcdcStatus.lowFaultWord = data.dcDcFaultWord1;
|
||||
m_dcdcStatus.highFaultWord = data.dcDcFaultWord2;
|
||||
|
||||
//绝缘状态
|
||||
power_bus_status.powerBusInsulationStatus = data.powerBusInsulationStatus == 0x55 ? 0 : 1;
|
||||
// if(power_bus_status.powerBusInsulationStatus == 1) disSysFaultCode.insert(34); else disSysFaultCode.erase(34);
|
||||
|
||||
power_bus_status.aBusInsulationStatus = data.aBusInsulationStatus == 0x55 ? 0 : 1;
|
||||
// if(power_bus_status.aBusInsulationStatus == 1) disSysFaultCode.insert(35); else disSysFaultCode.erase(35);
|
||||
|
||||
//电源状态
|
||||
power_bus_status.meterPowerLossSignal = data.meterPowerLossSignal == 0x55 ? 0 : 1;
|
||||
// if(power_bus_status.meterPowerLossSignal == 1) disSysFaultCode.insert(36); else disSysFaultCode.erase(36);
|
||||
|
||||
power_bus_status.emergencyPowerLossSignal = data.emergencyPowerLossSignal == 0x55 ? 0 : 1;
|
||||
|
||||
// if(power_bus_status.emergencyPowerLossSignal == 1) disSysFaultCode.insert(37); else disSysFaultCode.erase(37);
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(faultCodeMutex);
|
||||
if(power_bus_status.emergencyPowerLossSignal == 1) disSysFaultCode.insert(37); else disSysFaultCode.erase(37);
|
||||
if(power_bus_status.meterPowerLossSignal == 1) disSysFaultCode.insert(36); else disSysFaultCode.erase(36);
|
||||
if(power_bus_status.aBusInsulationStatus == 1) disSysFaultCode.insert(35); else disSysFaultCode.erase(35);
|
||||
if(power_bus_status.powerBusInsulationStatus == 1) disSysFaultCode.insert(34); else disSysFaultCode.erase(34);
|
||||
}
|
||||
|
||||
//温度
|
||||
power_bus_status.dcDcTemperature = data.dcDcTemperature-40;
|
||||
|
||||
//电压电流参数
|
||||
power_bus_status.powerBusVoltage = data.powerBusVoltage * 0.1;
|
||||
power_bus_status.dcDc5ModuleCurrent = data.dcDc5ModuleCurrent * 0.1;
|
||||
power_bus_status.powerBusCurrent = data.powerBusCurrent * 0.1;
|
||||
power_bus_status.busbarAVoltage = data.busbarAVoltage * 0.1;
|
||||
power_bus_status.propulsionMotorControlBoxCurrent = data.propulsionMotorControlBoxCurrent * 0.1;
|
||||
power_bus_status.busbarACurrent = data.busbarACurrent * 0.1;
|
||||
power_bus_status.lithiumBatteryGroupMeterCurrent = data.lithiumBatteryGroupMeterCurrent * 0.1;
|
||||
power_bus_status.bowHighVoltageDistributionBoxCurrent = data.bowHighVoltageDistributionBoxCurrent * 0.1;
|
||||
power_bus_status.sternFTDevice45Current = data.sternFTDevice45Current * 0.1;
|
||||
power_bus_status.tyzReservedSwitchCurrent = data.tyzReservedSwitchCurrent * 0.1;
|
||||
power_bus_status.sternRudderSwitch1Current = data.sternRudderSwitch1Current * 0.1;
|
||||
power_bus_status.reservedCurrent1 = data.reservedCurrent1 * 0.1;
|
||||
power_bus_status.sternRudderSwitch2Current = data.sternRudderSwitch2Current * 0.1;
|
||||
power_bus_status.reservedCurrent2 = data.reservedCurrent2 * 0.1;
|
||||
power_bus_status.fbReservedSwitchCurrent = data.fbReservedSwitchCurrent * 0.1;
|
||||
power_bus_status.reservedCurrent3 = data.reservedCurrent3 * 0.1;
|
||||
|
||||
//冷却水压力
|
||||
power_bus_status.coolWaterPressure = data.coolWaterPressure * 0.1;
|
||||
};
|
||||
void updateSystemData(disHighAVolBusState data){
|
||||
//断路器状态 (0x55 1 0xAA 0 0x5A 2)
|
||||
updateBreakerFault(power_a_bus_status.bowFTDevice123CircuitBreaker, data.bowFTDevice123CircuitBreaker, 13);
|
||||
updateBreakerFault(power_a_bus_status.actuatorCircuitBreaker, data.actuatorCircuitBreaker, 14);
|
||||
updateBreakerFault(power_a_bus_status.mastSteeringGearControlBoxCircuitBreaker, data.mastSteeringGearControlBoxCircuitBreaker, 15);
|
||||
updateBreakerFault(power_a_bus_status.xczCircuitBreaker, data.xczCircuitBreaker, 16);
|
||||
updateBreakerFault(power_a_bus_status.bowRudderControlBoxCircuitBreaker, data.bowRudderControlBoxCircuitBreaker, 17);
|
||||
updateBreakerFault(power_a_bus_status.openWaterCoverStartCylinderCircuitBreaker, data.openWaterCoverStartCylinderCircuitBreaker, 18);
|
||||
|
||||
//电源状态
|
||||
power_a_bus_status.instrumentPowerFailureSignal = data.instrumentPowerFailureSignal == 0x55 ? 0 : 1;
|
||||
// if(power_a_bus_status.instrumentPowerFailureSignal == 1) disSysFaultCode.insert(38); else disSysFaultCode.erase(38);
|
||||
|
||||
power_a_bus_status.emergencyPowerFailureSignal = data.emergencyPowerFailureSignal == 0x55 ? 0 : 1;
|
||||
// if(power_a_bus_status.emergencyPowerFailureSignal == 1) disSysFaultCode.insert(39); else disSysFaultCode.erase(39);
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(faultCodeMutex);
|
||||
if(power_a_bus_status.emergencyPowerFailureSignal == 1) disSysFaultCode.insert(39); else disSysFaultCode.erase(39);
|
||||
if(power_a_bus_status.instrumentPowerFailureSignal == 1) disSysFaultCode.insert(38); else disSysFaultCode.erase(38);
|
||||
}
|
||||
|
||||
//浸水报警
|
||||
power_a_bus_status.waterIngressionAlarm = data.waterIngressionAlarm == 0x55 ? 0 : 1;
|
||||
//更新漏水状态
|
||||
if(power_a_bus_status.waterIngressionAlarm == 1)
|
||||
{
|
||||
leakStatus[LEAKAGE_BOW_HIGH_VOLTAGE] = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
leakStatus[LEAKAGE_BOW_HIGH_VOLTAGE] = false;
|
||||
}
|
||||
|
||||
|
||||
//电压电流参数
|
||||
power_a_bus_status.busbarBVoltage = data.busbarBVoltage * 0.1;
|
||||
power_a_bus_status.busbarBCurrent = data.busbarBCurrent * 0.1;
|
||||
power_a_bus_status.bowFTDevice123Current = data.bowFTDevice123Current * 0.1;
|
||||
power_a_bus_status.actuatorCurrent = data.actuatorCurrent * 0.1;
|
||||
power_a_bus_status.mastSteeringGearControlBoxCurrent = data.mastSteeringGearControlBoxCurrent * 0.1;
|
||||
power_a_bus_status.xczCurrent = data.xczCurrent * 0.1;
|
||||
power_a_bus_status.bowRudderControlBoxCurrent = data.bowRudderControlBoxCurrent * 0.1;
|
||||
power_a_bus_status.openWaterCoverStartCylinderCurrent = data.openWaterCoverStartCylinderCurrent * 0.1;
|
||||
};
|
||||
void updateSystemData(disLowMainBusState data){
|
||||
//断路器状态 (0x55 1 0xAA 0 0x5A 2)
|
||||
updateBreakerFault(instrument_main_bus_status.lithiumBatteryGroupInstrumentCircuitBreaker, data.lithiumBatteryGroupInstrumentCircuitBreaker, 19);
|
||||
updateBreakerFault(instrument_main_bus_status.bowLowVoltageDistributionBoxCircuitBreaker,data.bowLowVoltageDistributionBoxCircuitBreaker, 20);
|
||||
updateBreakerFault(instrument_main_bus_status.unit4InstrumentDC48VCircuitBreaker,data.unit4InstrumentDC48VCircuitBreaker, 21);
|
||||
updateBreakerFault(instrument_main_bus_status.dcC1DCDistributionPanelCircuitBreaker, data.dcC1DCDistributionPanelCircuitBreaker, 22);
|
||||
updateBreakerFault(instrument_main_bus_status.reservedCircuitBreaker1, data.reservedCircuitBreaker1);
|
||||
updateBreakerFault(instrument_main_bus_status.reservedCircuitBreaker2, data.reservedCircuitBreaker2);
|
||||
updateBreakerFault(instrument_main_bus_status.emergencyLithiumBatteryGroup2CircuitBreaker, data.emergencyLithiumBatteryGroup2CircuitBreaker, 25);
|
||||
|
||||
//电源状态
|
||||
instrument_main_bus_status.instrumentPowerFailureSignal = data.instrumentPowerFailureSignal == 0x55 ? 0 : 1;
|
||||
// if(instrument_main_bus_status.instrumentPowerFailureSignal == 1) disSysFaultCode.insert(40); else disSysFaultCode.erase(41);
|
||||
|
||||
instrument_main_bus_status.emergencyPowerFailureSignal = data.emergencyPowerFailureSignal == 0x55 ? 0 : 1;
|
||||
// if(instrument_main_bus_status.emergencyPowerFailureSignal == 1) disSysFaultCode.insert(41); else disSysFaultCode.erase(42);
|
||||
|
||||
//绝缘状态
|
||||
instrument_main_bus_status.instrumentBusbarInsulationLow = data.instrumentBusbarInsulationLow == 0x55 ? 0 : 1;
|
||||
// if(instrument_main_bus_status.instrumentBusbarInsulationLow == 1) disSysFaultCode.insert(42); else disSysFaultCode.erase(43);
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(faultCodeMutex);
|
||||
if(instrument_main_bus_status.instrumentPowerFailureSignal == 1) disSysFaultCode.insert(41); else disSysFaultCode.erase(41);
|
||||
if(instrument_main_bus_status.emergencyPowerFailureSignal == 1) disSysFaultCode.insert(42); else disSysFaultCode.erase(42);
|
||||
if(instrument_main_bus_status.instrumentBusbarInsulationLow == 1) disSysFaultCode.insert(43); else disSysFaultCode.erase(43);
|
||||
}
|
||||
|
||||
//电压电流参数
|
||||
instrument_main_bus_status.instrumentBusbarVoltage = data.instrumentBusbarVoltage * 0.1;
|
||||
instrument_main_bus_status.bowLowVoltageDistributionBoxCurrent = data.bowLowVoltageDistributionBoxCurrent * 0.1;
|
||||
instrument_main_bus_status.dcC1InstrumentDC48VCurrent = data.dcC1InstrumentDC48VCurrent * 0.1;
|
||||
instrument_main_bus_status.reservedCurrent1 = data.reservedCurrent1 * 0.1;
|
||||
instrument_main_bus_status.emergencyLithiumBatteryGroup2Current = data.emergencyLithiumBatteryGroup2Current * 0.1;
|
||||
instrument_main_bus_status.lithiumBatteryGroupInstrumentCurrent = data.lithiumBatteryGroupInstrumentCurrent * 0.1;
|
||||
instrument_main_bus_status.unit4InstrumentDC48VCurrent = data.unit4InstrumentDC48VCurrent * 0.1;
|
||||
instrument_main_bus_status.reservedCurrent2 = data.reservedCurrent2 * 0.1;
|
||||
instrument_main_bus_status.emergency2BusbarVoltage = data.emergency2BusbarVoltage * 0.1;
|
||||
instrument_main_bus_status.compositeEnergyManagementSystemEmergencyDC48VCurrent = data.compositeEnergyManagementSystemEmergencyDC48VCurrent * 0.1;
|
||||
instrument_main_bus_status.fuelCellSecuritySystemEmergencyDC48VCurrent = data.fuelCellSecuritySystemEmergencyDC48VCurrent * 0.1;
|
||||
instrument_main_bus_status.plcControlPowerCurrent = data.plcControlPowerCurrent * 0.1;
|
||||
}
|
||||
void updateSystemData(disLowBusState data){
|
||||
//断路器状态 (0x55 1 0xAA 0 0x5A 2)
|
||||
updateBreakerFault(instrument_bus_status.unit1CircuitBreaker, data.unit1CircuitBreaker, 26);
|
||||
updateBreakerFault(instrument_bus_status.unit2CircuitBreaker, data.unit2CircuitBreaker, 27);
|
||||
updateBreakerFault(instrument_bus_status.unit3CircuitBreaker, data.unit3CircuitBreaker, 28);
|
||||
updateBreakerFault(instrument_bus_status.unit5CircuitBreaker, data.unit5CircuitBreaker, 29);
|
||||
updateBreakerFault(instrument_bus_status.bowPZDeviceCircuitBreaker, data.bowPZDeviceCircuitBreaker);
|
||||
updateBreakerFault(instrument_bus_status.reservedCircuitBreaker1, data.reservedCircuitBreaker1);
|
||||
updateBreakerFault(instrument_bus_status.reservedCircuitBreaker2, data.reservedCircuitBreaker2);
|
||||
updateBreakerFault(instrument_bus_status.emergencyLithiumBatteryGroup1CircuitBreaker, data.emergencyLithiumBatteryGroup1CircuitBreaker, 33);
|
||||
|
||||
//电源状态
|
||||
instrument_bus_status.powerFailureSignal = data.powerFailureSignal == 0x55 ? 0 : 1;
|
||||
// if(instrument_bus_status.powerFailureSignal == 1) disSysFaultCode.insert(44); else disSysFaultCode.erase(44);
|
||||
|
||||
instrument_bus_status.emergencyPowerFailureSignal = data.emergencyPowerFailureSignal == 0x55 ? 0 : 1;
|
||||
// if(instrument_bus_status.emergencyPowerFailureSignal == 1) disSysFaultCode.insert(45); else disSysFaultCode.erase(45);
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(faultCodeMutex);
|
||||
if(instrument_bus_status.emergencyPowerFailureSignal == 1) disSysFaultCode.insert(45); else disSysFaultCode.erase(45);
|
||||
if(instrument_bus_status.powerFailureSignal == 1) disSysFaultCode.insert(44); else disSysFaultCode.erase(44);
|
||||
}
|
||||
|
||||
//浸水报警
|
||||
instrument_bus_status.waterIngressionAlarm = data.waterIngressionAlarm == 0x55 ? 0 : 1;
|
||||
//更新漏水状态
|
||||
if(instrument_bus_status.waterIngressionAlarm == 1)
|
||||
{
|
||||
leakStatus[LEAKAGE_BOW_LOW_VOLTAGE] = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
leakStatus[LEAKAGE_BOW_LOW_VOLTAGE] = false;
|
||||
}
|
||||
//电压电流参数
|
||||
instrument_bus_status.instrumentBusbarVoltage = data.instrumentBusbarVoltage * 0.1;
|
||||
instrument_bus_status.instrumentBusbarCurrent = data.instrumentBusbarCurrent * 0.1;
|
||||
instrument_bus_status.unit1Current = data.unit1Current * 0.1;
|
||||
instrument_bus_status.unit2Current = data.unit2Current * 0.1;
|
||||
instrument_bus_status.unit3Current = data.unit3Current * 0.1;
|
||||
instrument_bus_status.unit5Current = data.unit5Current * 0.1;
|
||||
instrument_bus_status.bowPZDeviceCurrent = data.bowPZDeviceCurrent * 0.1;
|
||||
instrument_bus_status.emergencyLithiumBatteryGroup1Current = data.emergencyLithiumBatteryGroup1Current * 0.1;
|
||||
instrument_bus_status.emergency1BusbarVoltage = data.emergency1BusbarVoltage * 0.1;
|
||||
}
|
||||
};
|
||||
#endif
|
||||
@@ -1,139 +0,0 @@
|
||||
#ifndef CCUUDPMSG__H
|
||||
#define CCUUDPMSG__H
|
||||
#include "../pmSysvariable.h"
|
||||
|
||||
#define CCU_UDPMSG_START1 0x20
|
||||
#define CCU_UDPMSG_START2 0x20
|
||||
|
||||
#define DIS_MSG_HEAD1 0x40
|
||||
#define DIS_MSG_HEAD2 0x40
|
||||
|
||||
#define CCU_CMD_ID 0x0040
|
||||
#define CCU_SET_PARM_ID 0x0041
|
||||
#define CCU_STATE_FB_ID 0x0051
|
||||
#define CCU_SET_PARM_FB_ID 0x0040
|
||||
|
||||
#define DIS_HVBUS_FB_ID 0x0005
|
||||
#define DIS_HVBUSA_FB_ID 0x0006
|
||||
#define DIS_HVBUSB_FB_ID 0x0007
|
||||
#define DIS_LVBUS_FB_ID 0x0008
|
||||
|
||||
#define DIS_HVBUS_CMD_ID 0x0001
|
||||
#define DIS_HVBUSA_CMD_ID 0x0002
|
||||
#define DIS_HVBUSB_CMD_ID 0x0003
|
||||
#define DIS_LVBUS_CMD_ID 0x0004
|
||||
|
||||
#define DIS_BREAKER_ON 0x55
|
||||
#define DIS_BREAKER_OFF 0xAA
|
||||
#define DIS_FAULTOFF 0x5A
|
||||
|
||||
typedef unsigned int Checksum;
|
||||
typedef unsigned char cChecksum;
|
||||
|
||||
#pragma pack (1)
|
||||
typedef struct {
|
||||
unsigned char start1;
|
||||
unsigned char start2;
|
||||
unsigned short id;
|
||||
unsigned short length;
|
||||
} m_header;
|
||||
|
||||
typedef struct {
|
||||
unsigned short year;
|
||||
unsigned char month;
|
||||
unsigned char day;
|
||||
unsigned char hour;
|
||||
unsigned char minute;
|
||||
unsigned char second;
|
||||
unsigned char milliseconds; //每10毫秒
|
||||
} m_date;
|
||||
// 复合管控器操作指令
|
||||
typedef struct {
|
||||
m_header header;
|
||||
m_date date;
|
||||
ccuColCmd cmd;
|
||||
Checksum checkCode;
|
||||
} msg_CcuColCmdMsg;
|
||||
|
||||
// 复合管控器参数设定指令
|
||||
typedef struct {
|
||||
m_header header;
|
||||
ccuSetParmCmd cmd;
|
||||
Checksum checkCode;
|
||||
} msg_CcuSetParmMsg;
|
||||
|
||||
// 配电指令
|
||||
typedef struct
|
||||
{
|
||||
m_header header;
|
||||
disHighVolBusCmd data;
|
||||
cChecksum checkCode;
|
||||
}msg_disHVBCmd;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
m_header header;
|
||||
disHighAVolBusCmd data;
|
||||
cChecksum checkCode;
|
||||
}msg_disHVBACmd;
|
||||
|
||||
typedef struct msg_disHVBBCmd
|
||||
{
|
||||
m_header header;
|
||||
disHighBVolBusCmd data;
|
||||
cChecksum checkCode;
|
||||
}msg_disLVMBCmd;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
m_header header;
|
||||
disLowBusCmd data;
|
||||
cChecksum checkCode;
|
||||
}msg_disLVBCmd;
|
||||
|
||||
|
||||
// 复合管控参数设定反馈指令
|
||||
typedef struct {
|
||||
m_header header;
|
||||
unsigned char flag;
|
||||
unsigned char failureCode;
|
||||
Checksum checkCode;
|
||||
} msg_CcuSetParmFbMsg;
|
||||
|
||||
// 复合管控状态反馈
|
||||
typedef struct {
|
||||
m_header header;
|
||||
ccuState data;
|
||||
Checksum checkCode;
|
||||
} msg_CcuStateFbMsg;
|
||||
|
||||
//高压母线配电反馈
|
||||
typedef struct {
|
||||
m_header header;
|
||||
disHighVolBusState data;
|
||||
cChecksum checkCode;
|
||||
} msg_disHighVolBusFbMsg;
|
||||
|
||||
// 高压母线A配电反馈
|
||||
typedef struct {
|
||||
m_header header;
|
||||
disHighAVolBusState data;
|
||||
cChecksum checkCode;
|
||||
} msg_disHighAVolBusFbMsg;
|
||||
|
||||
// 仪表母线配电反馈
|
||||
typedef struct {
|
||||
m_header header;
|
||||
disLowMainBusState data;
|
||||
cChecksum checkCode;
|
||||
} msg_disLowMainBusFbMsg;
|
||||
|
||||
//仪表汇流排配电反馈
|
||||
typedef struct {
|
||||
m_header header;
|
||||
disLowBusState data;
|
||||
cChecksum checkCode;
|
||||
} msg_disLowBusFbMsg;
|
||||
|
||||
#pragma pack ()
|
||||
#endif
|
||||
@@ -1,627 +0,0 @@
|
||||
#include "udpComm.h"
|
||||
#include <iostream>
|
||||
#include <memory>
|
||||
|
||||
udpComm::udpComm()
|
||||
{
|
||||
udpScoket = nullptr;
|
||||
ccuHost = "";
|
||||
ccuPort = 0;
|
||||
}
|
||||
|
||||
udpComm::~udpComm() {
|
||||
if (udpScoket) {
|
||||
delete udpScoket;
|
||||
udpScoket = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Checksum udpComm::calculateChecksum(const unsigned char* data, int size)
|
||||
{
|
||||
Checksum checksum = 0;
|
||||
int size_data = size - sizeof(Checksum);
|
||||
for (int i = 0; i < size_data; i++) {
|
||||
checksum += data[i];
|
||||
}
|
||||
return checksum;
|
||||
}
|
||||
Checksum udpComm::calculateChecksum(const unsigned char* data, int dataSize, int checkSize)
|
||||
{
|
||||
Checksum checksum = 0;
|
||||
int size_data = dataSize - checkSize;
|
||||
for (int i = 0; i < size_data; i++) {
|
||||
checksum += data[i];
|
||||
}
|
||||
return checksum;
|
||||
}
|
||||
bool udpComm::getMsgId(char *m,unsigned short &id)
|
||||
{
|
||||
m_header h;
|
||||
h = *reinterpret_cast<m_header *>(m);
|
||||
// 判断消息是否有效
|
||||
if (h.start1== DIS_MSG_HEAD1 && h.start2==DIS_MSG_HEAD2)
|
||||
{
|
||||
id = h.id;
|
||||
return true;
|
||||
}
|
||||
else if (h.start1==CCU_UDPMSG_START1 && h.start2==CCU_UDPMSG_START2)
|
||||
{
|
||||
id = h.id;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
// sError.push_back("Msg Header errar");
|
||||
// LOG_F(ERROR, "Msg Header errar start1: %d, start2: %d", h.start1, h.start2);
|
||||
return false;
|
||||
}
|
||||
bool udpComm::getMsgFromBuff(char *m, msg_CcuStateFbMsg &s) {
|
||||
Checksum sum;
|
||||
msg_CcuStateFbMsg *p;
|
||||
p = reinterpret_cast<msg_CcuStateFbMsg *>(m);
|
||||
sum = calculateChecksum((unsigned char*)m, sizeof(msg_CcuStateFbMsg));
|
||||
|
||||
if (sum != p->checkCode) {
|
||||
sError.push_back("CcuStat Msg Check error");
|
||||
return false;
|
||||
}
|
||||
s = *p;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool udpComm::getMsgFromBuff(char *m, msg_CcuSetParmFbMsg &s)
|
||||
{
|
||||
Checksum sum;
|
||||
msg_CcuSetParmFbMsg *p;
|
||||
p = reinterpret_cast<msg_CcuSetParmFbMsg *>(m);
|
||||
sum = calculateChecksum((unsigned char*)m, sizeof(msg_CcuSetParmFbMsg));
|
||||
|
||||
if (sum!= p->checkCode) {
|
||||
sError.push_back("CcuSetParm Msg Check error");
|
||||
return false;
|
||||
}
|
||||
|
||||
s = *p;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool udpComm::getMsgFromBuff(char *m, msg_disHighVolBusFbMsg &s)
|
||||
{
|
||||
cChecksum sum;
|
||||
msg_disHighVolBusFbMsg *p;
|
||||
p = reinterpret_cast<msg_disHighVolBusFbMsg *>(m);
|
||||
sum = calculateChecksum((unsigned char*)m, sizeof(msg_disHighVolBusFbMsg), sizeof(cChecksum)) & 0xFF;
|
||||
if (sum != p->checkCode) {
|
||||
sError.push_back("DisSys HVBus Msg Check error");
|
||||
LOG_F(ERROR, "DisSys HVBus Msg Check error sum: %d, source checkCode: %d", sum, p->checkCode);
|
||||
return false;
|
||||
}
|
||||
s = *p;
|
||||
// cout << s.data.busbarAVoltage << endl;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool udpComm::getMsgFromBuff(char *m, msg_disHighAVolBusFbMsg &s)
|
||||
{
|
||||
cChecksum sum;
|
||||
msg_disHighAVolBusFbMsg *p;
|
||||
p = reinterpret_cast<msg_disHighAVolBusFbMsg *>(m);
|
||||
sum = calculateChecksum((unsigned char*)m, sizeof(msg_disHighAVolBusFbMsg), sizeof(cChecksum)) & 0xFF;
|
||||
if (sum!= p->checkCode) {
|
||||
sError.push_back("DisSys HVABus Msg Check error");
|
||||
LOG_F(ERROR, "DisSys HVABus Msg Check error sum: %d, source checkCode: %d", sum, p->checkCode);
|
||||
return false;
|
||||
}
|
||||
s = *p;
|
||||
return true;
|
||||
}
|
||||
bool udpComm::getMsgFromBuff(char *m, msg_disLowMainBusFbMsg &s)
|
||||
{
|
||||
cChecksum sum;
|
||||
msg_disLowMainBusFbMsg *p;
|
||||
p = reinterpret_cast<msg_disLowMainBusFbMsg *>(m);
|
||||
sum = calculateChecksum((unsigned char*)m, sizeof(msg_disLowMainBusFbMsg), sizeof(cChecksum)) & 0xFF;
|
||||
if (sum!= p->checkCode) {
|
||||
sError.push_back("DisSys HVBBus Msg Check error");
|
||||
LOG_F(ERROR, "DisSys HVBBus Msg Check error sum: %d, source checkCode: %d", sum, p->checkCode);
|
||||
return false;
|
||||
}
|
||||
s = *p;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool udpComm::getMsgFromBuff(char *m, msg_disLowBusFbMsg &s)
|
||||
{
|
||||
cChecksum sum;
|
||||
msg_disLowBusFbMsg *p;
|
||||
p = reinterpret_cast<msg_disLowBusFbMsg *>(m);
|
||||
sum = calculateChecksum((unsigned char*)m, sizeof(msg_disLowBusFbMsg), sizeof(cChecksum)) & 0xFF;
|
||||
if (sum!= p->checkCode) {
|
||||
sError.push_back("DisSys LVBus Msg Check error");
|
||||
LOG_F(ERROR, "DisSys LVBus Msg Check error sum: %d, source checkCode: %d", sum, p->checkCode);
|
||||
return false;
|
||||
}
|
||||
s = *p;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool udpComm::pushMsgToQueue(unsigned char *m)
|
||||
{
|
||||
if(m==NULL)
|
||||
{
|
||||
// sError.push_back("pushMsgToQueue faile,Msg is NULL");
|
||||
LOG_F(ERROR, "pushMsgToQueue faile,Msg is NULL m: %p", m);
|
||||
return false;
|
||||
}
|
||||
|
||||
unsigned char* Buff = m;
|
||||
//消息头鉴定
|
||||
char *header = new char[sizeof(m_header)];
|
||||
unsigned short id;
|
||||
memcpy(header,Buff,sizeof(m_header));
|
||||
if(!getMsgId(header,id))
|
||||
{
|
||||
// sError.push_back("pushMsgToQueue faile,Msg ID error");
|
||||
// LOG_F(INFO, "pushMsgToQueue faile,Msg ID error header: %p", header);
|
||||
delete []header;
|
||||
return false;
|
||||
}
|
||||
delete []header;
|
||||
//输入消息
|
||||
switch (id)
|
||||
{
|
||||
case CCU_STATE_FB_ID: //CCU_STATE_FB 0x0051
|
||||
{
|
||||
msg_CcuStateFbMsg s;
|
||||
if(getMsgFromBuff((char *)Buff,s))
|
||||
{
|
||||
if(m_qReceiveCcuStateBuffer.size()<QUENUE_SIZE)
|
||||
{
|
||||
double time = MOOSTime();
|
||||
m_qReceiveCcuStateBuffer.push(std::make_pair(time, s));
|
||||
}
|
||||
else
|
||||
{
|
||||
// sError.push_back("pushMsgToQueue faile,CcuState buffer is full");
|
||||
LOG_F(INFO, "pushMsgToQueue faile,CcuState buffer is full");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case CCU_SET_PARM_FB_ID: //CCU_SET_PARM_FB 0x0040
|
||||
{
|
||||
msg_CcuSetParmFbMsg s;
|
||||
if(getMsgFromBuff((char *)Buff,s))
|
||||
{
|
||||
if(m_qReceiveCcuSetParmBuffer.size()<QUENUE_SIZE)
|
||||
{
|
||||
double time = MOOSTime();
|
||||
m_qReceiveCcuSetParmBuffer.push(std::make_pair(time, s));
|
||||
}
|
||||
else
|
||||
{
|
||||
// sError.push_back("pushMsgToQueue faile,CcuSetParm buffer is full");
|
||||
LOG_F(INFO, "pushMsgToQueue faile,CcuSetParm buffer is full");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case DIS_HVBUS_FB_ID: //DIS_HVBUS_FB 0x0020
|
||||
{
|
||||
msg_disHighVolBusFbMsg s;
|
||||
if(getMsgFromBuff((char *)Buff,s))
|
||||
{
|
||||
if(m_qReceiveDisHighVolBusBuffer.size()<QUENUE_SIZE)
|
||||
{
|
||||
double time = MOOSTime();
|
||||
m_qReceiveDisHighVolBusBuffer.push(std::make_pair(time, s));
|
||||
}
|
||||
else
|
||||
{
|
||||
// sError.push_back("pushMsgToQueue faile,DisSysHVBus buffer is full");
|
||||
LOG_F(INFO, "pushMsgToQueue faile,DisSysHVBus buffer is full");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case DIS_HVBUSA_FB_ID: //DIS_HVBUSA_FB 0x0006
|
||||
{
|
||||
msg_disHighAVolBusFbMsg s;
|
||||
if(getMsgFromBuff((char *)Buff,s))
|
||||
{
|
||||
if(m_qReceiveDisHighAVolBusBuffer.size()<QUENUE_SIZE)
|
||||
{
|
||||
double time = MOOSTime();
|
||||
m_qReceiveDisHighAVolBusBuffer.push(std::make_pair(time, s));
|
||||
}
|
||||
else
|
||||
{
|
||||
// sError.push_back("pushMsgToQueue faile,DisSysHVABus buffer is full");
|
||||
LOG_F(INFO, "pushMsgToQueue faile,DisSysHVABus buffer is full");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case DIS_HVBUSB_FB_ID: //DIS_HVBUSB_FB 0x0007
|
||||
{
|
||||
msg_disLowMainBusFbMsg s;
|
||||
if(getMsgFromBuff((char *)Buff,s))
|
||||
{
|
||||
if(m_qReceiveDisHighBVolBusBuffer.size()<QUENUE_SIZE)
|
||||
{
|
||||
double time = MOOSTime();
|
||||
m_qReceiveDisHighBVolBusBuffer.push(std::make_pair(time, s));
|
||||
}
|
||||
else
|
||||
{
|
||||
// sError.push_back("pushMsgToQueue faile,DisSysHVBBus buffer is full");
|
||||
LOG_F(INFO, "pushMsgToQueue faile,DisSysHVBBus buffer is full");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case DIS_LVBUS_FB_ID: //DIS_LVBUS_FB 0x0008
|
||||
{
|
||||
msg_disLowBusFbMsg s;
|
||||
if(getMsgFromBuff((char *)Buff,s))
|
||||
{
|
||||
if(m_qReceiveDisLowBusBuffer.size()<QUENUE_SIZE)
|
||||
{
|
||||
double time = MOOSTime();
|
||||
m_qReceiveDisLowBusBuffer.push(std::make_pair(time, s));
|
||||
}
|
||||
else
|
||||
{
|
||||
// sError.push_back("pushMsgToQueue faile,DisSysLVBus buffer is full");
|
||||
LOG_F(INFO, "pushMsgToQueue faile,DisSysLVBus buffer is full");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
bool udpComm::clearMsgQueue()
|
||||
{
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(m_mutexCcuState);
|
||||
while(!m_qReceiveCcuStateBuffer.empty())
|
||||
m_qReceiveCcuStateBuffer.pop();
|
||||
}
|
||||
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(m_mutexCcuSetParm);
|
||||
while(!m_qReceiveCcuSetParmBuffer.empty())
|
||||
m_qReceiveCcuSetParmBuffer.pop();
|
||||
}
|
||||
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(m_mutexDisHighVolBus);
|
||||
while(!m_qReceiveDisHighVolBusBuffer.empty())
|
||||
m_qReceiveDisHighVolBusBuffer.pop();
|
||||
}
|
||||
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(m_mutexDisHighAVolBus);
|
||||
while(!m_qReceiveDisHighAVolBusBuffer.empty())
|
||||
m_qReceiveDisHighAVolBusBuffer.pop();
|
||||
}
|
||||
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(m_mutexDisHighBVolBus);
|
||||
while(!m_qReceiveDisHighBVolBusBuffer.empty())
|
||||
m_qReceiveDisHighBVolBusBuffer.pop();
|
||||
}
|
||||
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(m_mutexDisLowBus);
|
||||
while(!m_qReceiveDisLowBusBuffer.empty())
|
||||
m_qReceiveDisLowBusBuffer.pop();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool udpComm::popMsgFormQueue(double &time,msg_CcuStateFbMsg &m)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(m_mutexCcuState);
|
||||
if(m_qReceiveCcuStateBuffer.empty())
|
||||
return false;
|
||||
time = m_qReceiveCcuStateBuffer.front().first;
|
||||
m = m_qReceiveCcuStateBuffer.front().second;
|
||||
m_qReceiveCcuStateBuffer.pop();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool udpComm::popMsgFormQueue(double &time,msg_CcuSetParmFbMsg &m)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(m_mutexCcuSetParm);
|
||||
if(m_qReceiveCcuSetParmBuffer.empty())
|
||||
return false;
|
||||
time = m_qReceiveCcuSetParmBuffer.front().first;
|
||||
m = m_qReceiveCcuSetParmBuffer.front().second;
|
||||
m_qReceiveCcuSetParmBuffer.pop();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool udpComm::popMsgFormQueue(double &time,msg_disHighVolBusFbMsg &m)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(m_mutexDisHighVolBus);
|
||||
if(m_qReceiveDisHighVolBusBuffer.empty())
|
||||
return false;
|
||||
time = m_qReceiveDisHighVolBusBuffer.front().first;
|
||||
m = m_qReceiveDisHighVolBusBuffer.front().second;
|
||||
m_qReceiveDisHighVolBusBuffer.pop();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool udpComm::popMsgFormQueue(double &time,msg_disHighAVolBusFbMsg &m)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(m_mutexDisHighAVolBus);
|
||||
if(m_qReceiveDisHighAVolBusBuffer.empty())
|
||||
return false;
|
||||
time = m_qReceiveDisHighAVolBusBuffer.front().first;
|
||||
m = m_qReceiveDisHighAVolBusBuffer.front().second;
|
||||
m_qReceiveDisHighAVolBusBuffer.pop();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool udpComm::popMsgFormQueue(double &time,msg_disLowMainBusFbMsg &m)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(m_mutexDisHighBVolBus);
|
||||
if(m_qReceiveDisHighBVolBusBuffer.empty())
|
||||
return false;
|
||||
time = m_qReceiveDisHighBVolBusBuffer.front().first;
|
||||
m = m_qReceiveDisHighBVolBusBuffer.front().second;
|
||||
m_qReceiveDisHighBVolBusBuffer.pop();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool udpComm::popMsgFormQueue(double &time,msg_disLowBusFbMsg &m)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(m_mutexDisLowBus);
|
||||
if(m_qReceiveDisLowBusBuffer.empty())
|
||||
return false;
|
||||
time = m_qReceiveDisLowBusBuffer.front().first;
|
||||
m = m_qReceiveDisLowBusBuffer.front().second;
|
||||
m_qReceiveDisLowBusBuffer.pop();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool udpComm::sendDisSysCmd(const disHighVolBusCmd cmd)
|
||||
{
|
||||
unsigned char* msgBuf;
|
||||
cChecksum cc;
|
||||
msg_disHVBCmd* msg = new msg_disHVBCmd;
|
||||
msg->header.id = DIS_HVBUS_CMD_ID;
|
||||
msg->header.start1 = DIS_MSG_HEAD1;
|
||||
msg->header.start2 = DIS_MSG_HEAD2;
|
||||
//TODO : 阈字节长度固定了,后续会修改
|
||||
msg->header.length = 18;
|
||||
// msg->header.length = sizeof(disHighVolBusCmd);
|
||||
msg->data = cmd;
|
||||
msgBuf = reinterpret_cast<unsigned char *>(msg);
|
||||
cc = calculateChecksum(msgBuf,sizeof(msg_disHVBCmd),sizeof(cChecksum));
|
||||
msg->checkCode = cc;
|
||||
try
|
||||
{
|
||||
sendMsg(msgBuf,sizeof(msg_disHVBCmd));
|
||||
}
|
||||
catch(const std::exception& e)
|
||||
{
|
||||
std::cerr << e.what() << '\n';
|
||||
}
|
||||
delete msg;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool udpComm::sendDisSysCmd(const disHighAVolBusCmd cmd)
|
||||
{
|
||||
unsigned char* msgBuf;
|
||||
cChecksum cc;
|
||||
msg_disHVBACmd* msg = new msg_disHVBACmd;
|
||||
msg->header.id = DIS_HVBUSA_CMD_ID;
|
||||
msg->header.start1 = DIS_MSG_HEAD1;
|
||||
msg->header.start2 = DIS_MSG_HEAD2;
|
||||
//TODO : 阈字节长度固定了,后续会修改
|
||||
msg->header.length = 6;
|
||||
// msg->header.length = sizeof(disHighAVolBusCmd);
|
||||
msg->data = cmd;
|
||||
msgBuf = reinterpret_cast<unsigned char *>(msg);
|
||||
cc = calculateChecksum(msgBuf,sizeof(msg_disHVBACmd),sizeof(cChecksum));
|
||||
msg->checkCode = cc;
|
||||
try
|
||||
{
|
||||
sendMsg(msgBuf,sizeof(msg_disHVBACmd));
|
||||
}
|
||||
catch(const std::exception& e)
|
||||
{
|
||||
std::cerr << e.what() << '\n';
|
||||
}
|
||||
delete msg;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool udpComm::sendDisSysCmd(const disHighBVolBusCmd cmd)
|
||||
{
|
||||
unsigned char* msgBuf;
|
||||
cChecksum cc;
|
||||
msg_disHVBBCmd* msg = new msg_disHVBBCmd;
|
||||
msg->header.id = DIS_HVBUSB_CMD_ID;
|
||||
msg->header.start1 = DIS_MSG_HEAD1;
|
||||
msg->header.start2 = DIS_MSG_HEAD2;
|
||||
//TODO : 阈字节长度固定了,后续会修改
|
||||
msg->header.length = 8;
|
||||
// msg->header.length = sizeof(disHighBVolBusCmd);
|
||||
msg->data = cmd;
|
||||
msgBuf = reinterpret_cast<unsigned char *>(msg);
|
||||
cc = calculateChecksum(msgBuf,sizeof(msg_disHVBBCmd),sizeof(cChecksum));
|
||||
msg->checkCode = cc;
|
||||
try
|
||||
{
|
||||
// cout << "=========" <<(int)sizeof(msg_disHVBBCmd) << endl;
|
||||
sendMsg(msgBuf,sizeof(msg_disHVBBCmd));
|
||||
}
|
||||
catch(const std::exception& e)
|
||||
{
|
||||
std::cerr << e.what() << '\n';
|
||||
}
|
||||
delete msg;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool udpComm::sendDisSysCmd(const disLowBusCmd cmd)
|
||||
{
|
||||
unsigned char* msgBuf;
|
||||
cChecksum cc;
|
||||
msg_disLVBCmd* msg = new msg_disLVBCmd;
|
||||
msg->header.id = DIS_LVBUS_CMD_ID;
|
||||
msg->header.start1 = DIS_MSG_HEAD1;
|
||||
msg->header.start2 = DIS_MSG_HEAD2;
|
||||
//TODO : 阈字节长度固定了,后续会修改
|
||||
msg->header.length = 8;
|
||||
// msg->header.length = sizeof(disLowBusCmd);
|
||||
msg->data = cmd;
|
||||
msgBuf = reinterpret_cast<unsigned char *>(msg);
|
||||
cc = calculateChecksum(msgBuf,sizeof(msg_disLVBCmd),sizeof(cChecksum));
|
||||
// msg->checkCode = static_cast<cChecksum>(cc & 0xFF);
|
||||
msg->checkCode = cc;
|
||||
cout << "cc======disLowBusCmd=============================" << (int) msg->checkCode << endl;
|
||||
try
|
||||
{
|
||||
sendMsg(msgBuf,sizeof(msg_disLVBCmd));
|
||||
}
|
||||
catch(const std::exception& e)
|
||||
{
|
||||
std::cerr << e.what() << '\n';
|
||||
}
|
||||
delete msg;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool udpComm::sendCcuColCmd(const ccuColCmd cmd)
|
||||
{
|
||||
unsigned char* msgBuf;
|
||||
Checksum cc;
|
||||
msg_CcuColCmdMsg* msg = new msg_CcuColCmdMsg();
|
||||
memset(msg, 0, sizeof(msg_CcuColCmdMsg)); // 初始化所有字段为0
|
||||
|
||||
msg->header.id = CCU_CMD_ID;
|
||||
msg->header.start1 = CCU_UDPMSG_START1;
|
||||
msg->header.start2 = CCU_UDPMSG_START2;
|
||||
msg->header.length = sizeof(ccuColCmd);
|
||||
|
||||
// 确保日期获取成功
|
||||
if(!getDate(msg->date.year,msg->date.month,msg->date.day,
|
||||
msg->date.hour,msg->date.minute,msg->date.second,msg->date.milliseconds)) {
|
||||
LOG_F(ERROR, "Failed to get current date/time");
|
||||
delete msg;
|
||||
return false;
|
||||
}
|
||||
|
||||
msg->cmd = cmd;
|
||||
msgBuf = reinterpret_cast<unsigned char *>(msg);
|
||||
cc = calculateChecksum(msgBuf,sizeof(msg_CcuColCmdMsg));
|
||||
msg->checkCode = static_cast<cChecksum>(cc & 0xFF);
|
||||
|
||||
bool sendResult = false;
|
||||
try {
|
||||
sendResult = sendMsg(msgBuf,sizeof(msg_CcuColCmdMsg));
|
||||
if (!sendResult) {
|
||||
LOG_F(ERROR, "Failed to send CCU command");
|
||||
}
|
||||
} catch (const std::exception& e) {
|
||||
LOG_F(ERROR, "Exception in sendCcuColCmd: %s", e.what());
|
||||
}
|
||||
|
||||
delete msg;
|
||||
return sendResult;
|
||||
}
|
||||
bool udpComm::sendCcuSetParmCmd(const ccuSetParmCmd cmd)
|
||||
{
|
||||
unsigned char* msgBuf;
|
||||
Checksum cc;
|
||||
msg_CcuSetParmMsg* msg = new msg_CcuSetParmMsg;
|
||||
msg->header.id = CCU_SET_PARM_ID;
|
||||
msg->header.start1 = CCU_UDPMSG_START1;
|
||||
msg->header.start2 = CCU_UDPMSG_START2;
|
||||
msg->header.length = sizeof(ccuSetParmCmd);
|
||||
msg->cmd = cmd;
|
||||
msgBuf = reinterpret_cast<unsigned char *>(msg);
|
||||
cc = calculateChecksum(msgBuf,sizeof(msg_CcuSetParmMsg));
|
||||
msg->checkCode = static_cast<cChecksum>(cc & 0xFF);
|
||||
try
|
||||
{
|
||||
sendMsg(msgBuf,sizeof(msg_CcuSetParmMsg));
|
||||
}
|
||||
catch(const std::exception& e)
|
||||
{
|
||||
std::cerr << e.what() << '\n';
|
||||
}
|
||||
delete msg;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool udpComm::getDate(unsigned short &year, unsigned char &month, unsigned char &day, unsigned char &hour, unsigned char &minute, unsigned char &second, unsigned char &milliseconds) {
|
||||
// 获取当前时间
|
||||
std::time_t now = std::time(nullptr);
|
||||
if (now == -1) {
|
||||
return false; // 获取时间失败
|
||||
}
|
||||
|
||||
// 转换为本地时间
|
||||
std::tm *localTime = std::localtime(&now);
|
||||
if (!localTime) {
|
||||
return false; // 转换失败
|
||||
}
|
||||
|
||||
// 获取年、月、日、时、分、秒
|
||||
year = localTime->tm_year + 1900; // tm_year 是从 1900 年开始的
|
||||
month = localTime->tm_mon + 1; // tm_mon 是从 0 开始的,0 对应 1 月
|
||||
day = localTime->tm_mday;
|
||||
hour = localTime->tm_hour;
|
||||
minute = localTime->tm_min;
|
||||
second = localTime->tm_sec;
|
||||
|
||||
// 获取毫秒,使用 std::chrono
|
||||
auto now_ms = std::chrono::system_clock::now();
|
||||
auto duration = now_ms.time_since_epoch();
|
||||
auto ms = std::chrono::duration_cast<std::chrono::milliseconds>(duration).count() % 1000; // 取毫秒部分
|
||||
ms = ms/10;
|
||||
milliseconds = static_cast<unsigned char>(ms);
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -1,108 +0,0 @@
|
||||
#ifndef UDPCOMM__H
|
||||
#define UDPCOMM__H
|
||||
#define UNIX
|
||||
|
||||
#include "ccuUdpMsg.h"
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <queue>
|
||||
#include <string.h>
|
||||
#include "MOOS/libMOOS/Utils/MOOSUtilityFunctions.h"
|
||||
#include "MOOS/libMOOS/Comms/XPCUdpSocket.h"
|
||||
#include <ctime>
|
||||
#include <mutex>
|
||||
#include <chrono>
|
||||
#include <iostream>
|
||||
#include <utility>
|
||||
#include "../logc/loguru.hpp"
|
||||
using namespace std;
|
||||
#define QUENUE_SIZE 100
|
||||
|
||||
class udpComm {
|
||||
public:
|
||||
udpComm();
|
||||
~udpComm();
|
||||
XPCUdpSocket *udpScoket;
|
||||
string ccuHost;
|
||||
long int ccuPort;
|
||||
|
||||
bool pushMsgToQueue(unsigned char *m);
|
||||
bool clearMsgQueue();
|
||||
|
||||
bool getMsgFromBuff(char *m, msg_CcuStateFbMsg &s);
|
||||
bool getMsgFromBuff(char *m, msg_CcuSetParmFbMsg &s);
|
||||
bool getMsgFromBuff(char *m, msg_disHighVolBusFbMsg &s);
|
||||
bool getMsgFromBuff(char *m, msg_disHighAVolBusFbMsg &s);
|
||||
bool getMsgFromBuff(char *m, msg_disLowMainBusFbMsg &s);
|
||||
bool getMsgFromBuff(char *m, msg_disLowBusFbMsg &s);
|
||||
|
||||
bool popMsgFormQueue(double &time,msg_CcuStateFbMsg &m);
|
||||
bool popMsgFormQueue(double &time,msg_CcuSetParmFbMsg &m);
|
||||
bool popMsgFormQueue(double &time,msg_disHighVolBusFbMsg &m);
|
||||
bool popMsgFormQueue(double &time,msg_disHighAVolBusFbMsg &m);
|
||||
bool popMsgFormQueue(double &time,msg_disLowMainBusFbMsg &m);
|
||||
bool popMsgFormQueue(double &time,msg_disLowBusFbMsg &m);
|
||||
|
||||
bool sendCcuColCmd(const ccuColCmd cmd);
|
||||
bool sendCcuSetParmCmd(const ccuSetParmCmd cmd);
|
||||
|
||||
bool sendDisSysCmd(const disHighVolBusCmd cmd);
|
||||
bool sendDisSysCmd(const disHighAVolBusCmd cmd);
|
||||
bool sendDisSysCmd(const disHighBVolBusCmd cmd);
|
||||
bool sendDisSysCmd(const disLowBusCmd cmd);
|
||||
bool sendMsg(const unsigned char* msg, unsigned int size) {
|
||||
if (!udpScoket) {
|
||||
LOG_F(ERROR, "UDP socket is null in sendMsg");
|
||||
return false;
|
||||
}
|
||||
if (!msg || size == 0) {
|
||||
LOG_F(ERROR, "Invalid message parameters in sendMsg");
|
||||
return false;
|
||||
}
|
||||
if (ccuHost.empty() || ccuPort <= 0) {
|
||||
LOG_F(ERROR, "Invalid CCU address: %s:%d", ccuHost.c_str(), ccuPort);
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
udpScoket->iSendMessageTo((void*)msg, size, ccuPort, ccuHost);
|
||||
return true;
|
||||
} catch (const XPCException& e) {
|
||||
LOG_F(ERROR, "XPCException in sendMsg");
|
||||
} catch (const std::exception& e) {
|
||||
LOG_F(ERROR, "Exception in sendMsg: %s", e.what());
|
||||
} catch (...) {
|
||||
LOG_F(ERROR, "Unknown exception in sendMsg");
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool getMsgId(char *m,unsigned short &id);
|
||||
Checksum calculateChecksum(const unsigned char* data, int size);
|
||||
Checksum calculateChecksum(const unsigned char* data, int dataSize, int checkSize);
|
||||
|
||||
bool getDate(unsigned short &year, unsigned char &month, unsigned char &day, unsigned char &hour, unsigned char &minute, unsigned char &second, unsigned char &milliseconds);
|
||||
|
||||
std::vector<std::string> sError;
|
||||
|
||||
|
||||
std::mutex m_mutexCcuState;
|
||||
std::mutex m_mutexCcuSetParm;
|
||||
std::mutex m_mutexDisHighVolBus;
|
||||
std::mutex m_mutexDisHighAVolBus;
|
||||
std::mutex m_mutexDisHighBVolBus;
|
||||
std::mutex m_mutexDisLowBus;
|
||||
// std::queue<msgWithTime> m_qReceiveCcuStateBuffer;
|
||||
std::queue<std::pair<double,msg_CcuStateFbMsg>> m_qReceiveCcuStateBuffer;
|
||||
std::queue<std::pair<double,msg_CcuSetParmFbMsg>> m_qReceiveCcuSetParmBuffer;
|
||||
std::queue<std::pair<double,msg_disHighVolBusFbMsg>> m_qReceiveDisHighVolBusBuffer;
|
||||
std::queue<std::pair<double,msg_disHighAVolBusFbMsg>> m_qReceiveDisHighAVolBusBuffer;
|
||||
std::queue<std::pair<double,msg_disLowMainBusFbMsg>> m_qReceiveDisHighBVolBusBuffer;
|
||||
std::queue<std::pair<double,msg_disLowBusFbMsg>> m_qReceiveDisLowBusBuffer;
|
||||
|
||||
private:
|
||||
msg_CcuColCmdMsg m_ccuColCmd;
|
||||
msg_CcuSetParmMsg m_ccuSetParmCmd;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -1,60 +0,0 @@
|
||||
/* json 格式 XC阵控制软件→复合能源管控系统
|
||||
{
|
||||
"xcLowVoltageAdd_int32 " : XX //命令类型:“无命令”0,“申请仪表上电”1,“申请仪表断电”2;类型:int
|
||||
"xcHighVoltageAdd_int32 " : XX, //命令类型:“无命令”0,“申请高压上电”1,“申请高压断电”2;类型:int
|
||||
}
|
||||
*/
|
||||
#ifndef UDETECT_XCVOLTAGE_CMD_H
|
||||
#define UDETECT_XCVOLTAGE_CMD_H
|
||||
#include "../logc/loguru.hpp"
|
||||
#include "json/json.h"
|
||||
#include <string>
|
||||
#include <memory>
|
||||
|
||||
class uDetect_xcVoltage_cmd
|
||||
{
|
||||
private:
|
||||
/* data */
|
||||
public:
|
||||
uDetect_xcVoltage_cmd(){};
|
||||
~uDetect_xcVoltage_cmd(){};
|
||||
|
||||
int xcLowVoltageAdd_int32;
|
||||
int xcHighVoltageAdd_int32;
|
||||
|
||||
static std::string key;
|
||||
|
||||
std::string toJsonString()
|
||||
{
|
||||
Json::Value j;
|
||||
j["xcLowVoltageAdd_int32"] = xcLowVoltageAdd_int32;
|
||||
j["xcHighVoltageAdd_int32"] = xcHighVoltageAdd_int32;
|
||||
|
||||
Json::StreamWriterBuilder builder;
|
||||
builder.settings_["indentation"] = "";
|
||||
return Json::writeString(builder, j);
|
||||
}
|
||||
bool fromJsonString(std::string jsonString)
|
||||
{
|
||||
Json::CharReaderBuilder readerBuilder;
|
||||
std::unique_ptr<Json::CharReader> reader(readerBuilder.newCharReader());
|
||||
Json::Value j;
|
||||
std::string errors;
|
||||
LOG_F(INFO, "jsonString: %s", jsonString.c_str());
|
||||
bool parsingSuccessful = reader->parse(jsonString.c_str(), jsonString.c_str() + jsonString.length(), &j, &errors);
|
||||
if (!parsingSuccessful) {
|
||||
LOG_F(ERROR, "Failed to parse JSON: %s", errors.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
if (j.isMember("xcLowVoltageAdd_int32") && j.isMember("xcHighVoltageAdd_int32")) {
|
||||
xcLowVoltageAdd_int32 = j["xcLowVoltageAdd_int32"].asInt();
|
||||
xcHighVoltageAdd_int32 = j["xcHighVoltageAdd_int32"].asInt();
|
||||
return true;
|
||||
}
|
||||
LOG_F(ERROR, "JSON does not contain required fields");
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -1,56 +0,0 @@
|
||||
/* json 格式 XC阵控制软件→复合能源管控系统
|
||||
{
|
||||
"zdpVoltageAdd_int32 " : XX //命令类型:“无命令”0,“申请仪表上电”1,“申请仪表断电”2;类型:int
|
||||
}
|
||||
*/
|
||||
#ifndef UDETECT_ZDPVOLTAGE_CMD_H
|
||||
#define UDETECT_ZDPVOLTAGE_CMD_H
|
||||
#include "../logc/loguru.hpp"
|
||||
#include "json/json.h"
|
||||
#include <string>
|
||||
#include <memory>
|
||||
|
||||
class uDetect_zdpVoltage_cmd
|
||||
{
|
||||
private:
|
||||
/* data */
|
||||
public:
|
||||
uDetect_zdpVoltage_cmd(){};
|
||||
~uDetect_zdpVoltage_cmd(){};
|
||||
|
||||
int zdpVoltageAdd_int32;
|
||||
|
||||
static std::string key;
|
||||
|
||||
std::string toJsonString()
|
||||
{
|
||||
Json::Value j;
|
||||
j["zdpVoltageAdd_int32"] = zdpVoltageAdd_int32;
|
||||
|
||||
Json::StreamWriterBuilder builder;
|
||||
builder.settings_["indentation"] = "";
|
||||
return Json::writeString(builder, j);
|
||||
}
|
||||
bool fromJsonString(std::string jsonString)
|
||||
{
|
||||
Json::CharReaderBuilder readerBuilder;
|
||||
std::unique_ptr<Json::CharReader> reader(readerBuilder.newCharReader());
|
||||
Json::Value j;
|
||||
std::string errors;
|
||||
LOG_F(INFO, "jsonString: %s", jsonString.c_str());
|
||||
bool parsingSuccessful = reader->parse(jsonString.c_str(), jsonString.c_str() + jsonString.length(), &j, &errors);
|
||||
if (!parsingSuccessful) {
|
||||
LOG_F(ERROR, "Failed to parse JSON: %s", errors.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
if (j.isMember("zdpVoltageAdd_int32")) {
|
||||
zdpVoltageAdd_int32 = j["zdpVoltageAdd_int32"].asInt();
|
||||
return true;
|
||||
}
|
||||
LOG_F(ERROR, "JSON does not contain required fields");
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -1,52 +0,0 @@
|
||||
//决策消息
|
||||
#ifndef UDEVICE_DEPTH_ST_H
|
||||
#define UDEVICE_DEPTH_ST_H
|
||||
#include <string>
|
||||
#include "../logc/loguru.hpp"
|
||||
#define DB_TO_PM_DEEPTH "uDevice_depth_st"
|
||||
class uDevice_depthMsg
|
||||
{
|
||||
private:
|
||||
|
||||
public:
|
||||
std::string key = "uDevice_depth_st";
|
||||
uDevice_depthMsg(/* args */){};
|
||||
~uDevice_depthMsg(){};
|
||||
int getDepth(const std::string& msgkey, const std::string& msg){
|
||||
if (msgkey != DB_TO_PM_DEEPTH)
|
||||
{
|
||||
LOG_F(WARNING, "消息类型错误 %s", msgkey.c_str());
|
||||
return 0;
|
||||
}
|
||||
int deepth;
|
||||
Json::Value root;
|
||||
Json::CharReaderBuilder builder;
|
||||
JSONCPP_STRING errs;
|
||||
|
||||
// 解析JSON字符串
|
||||
std::istringstream stream(msg);
|
||||
if (!Json::parseFromStream(builder, stream, &root, &errs)) {
|
||||
std::cerr << "JSON解析失败: " << errs << std::endl;
|
||||
LOG_F(WARNING, "JSON解析失败: %s", errs.c_str());
|
||||
return -1;
|
||||
}
|
||||
// 检查并读取深度数组
|
||||
if (root.isMember("value_array_int32") && root["value_array_int32"].isArray()) {
|
||||
const Json::Value& array = root["value_array_int32"];
|
||||
if (array.size() >= 3) {
|
||||
// 计算三个深度值的平均值
|
||||
deepth = (array[0].asInt() + array[1].asInt() + array[2].asInt()) / 3;
|
||||
} else {
|
||||
LOG_F(WARNING, "深度数组元素不足3个");
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
LOG_F(WARNING, "缺少或类型不匹配: value_array_int32");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return deepth;
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -1,531 +0,0 @@
|
||||
#ifndef UDEVICE_SECDISTSTATE_H
|
||||
#define UDEVICE_SECDISTSTATE_H
|
||||
#include <string>
|
||||
#include <json/json.h>
|
||||
#include "../driver.h"
|
||||
#include "../logc/loguru.hpp"
|
||||
#include <cstring>
|
||||
|
||||
class uDevice_secdistStateMsg
|
||||
{
|
||||
private:
|
||||
/* data */
|
||||
public:
|
||||
uDevice_secdistStateMsg(){};
|
||||
~uDevice_secdistStateMsg(){};
|
||||
std::string key_fb = "uDevice_secdistState_st";
|
||||
std::string key_cmd = "uPower_secdistState_cmd";
|
||||
|
||||
struct DeviceSecdistState
|
||||
{
|
||||
// UNIT1
|
||||
u_int8_t bowCover1;
|
||||
u_int8_t bowCover2;
|
||||
u_int8_t bowCover3;
|
||||
u_int8_t bowCover4;
|
||||
u_int8_t bowCover5;
|
||||
u_int8_t bowCover6;
|
||||
u_int8_t singleBeamSonar1;
|
||||
u_int8_t singleBeamSonar2;
|
||||
u_int8_t singleBeamSonar3;
|
||||
u_int8_t singleBeamSonar4;
|
||||
u_int8_t singleBeamSonar5;
|
||||
u_int8_t singleBeamSonar6;
|
||||
u_int8_t forwardSonar;
|
||||
u_int8_t depth3;
|
||||
u_int8_t soundVeloc;
|
||||
u_int8_t bowRudderServo;
|
||||
u_int8_t bowRudderDeploy;
|
||||
u_int8_t ctd1;
|
||||
u_int8_t waterInject;
|
||||
|
||||
// UNIT2
|
||||
u_int8_t sideSonar;
|
||||
u_int8_t bowWaterInet1;
|
||||
u_int8_t bowWaterInet2;
|
||||
u_int8_t bowWaterInet3;
|
||||
u_int8_t bowWaterInet4;
|
||||
u_int8_t bowWaterInet5;
|
||||
u_int8_t bowWaterInet6;
|
||||
u_int8_t bowWaterInet7;
|
||||
u_int8_t bowWaterInet8;
|
||||
u_int8_t launchControler;
|
||||
u_int8_t electSensor;
|
||||
u_int8_t lowFreqSonar;
|
||||
|
||||
// UNIT3
|
||||
u_int8_t buoyancyAdjust1;
|
||||
u_int8_t buoyancyAdjust2;
|
||||
u_int8_t buoyancyAdjust3;
|
||||
u_int8_t USBL;
|
||||
u_int8_t depth1;
|
||||
u_int8_t commDev;
|
||||
u_int8_t mastLiftingServo;
|
||||
u_int8_t DVL;
|
||||
u_int8_t ADCP;
|
||||
u_int8_t inOutLetWater1;
|
||||
u_int8_t inOutLetWater2;
|
||||
|
||||
// UNIT4
|
||||
u_int8_t singleBeamSonar7;
|
||||
u_int8_t singleBeamSonar8;
|
||||
u_int8_t buoyage;
|
||||
u_int8_t bowThrow;
|
||||
u_int8_t depth2;
|
||||
u_int8_t thruster;
|
||||
u_int8_t dragSonar;
|
||||
u_int8_t haulingMachine;
|
||||
u_int8_t buoyancyAdjust4;
|
||||
u_int8_t buoyancyAdjust5;
|
||||
u_int8_t sternRudderServo1;
|
||||
u_int8_t sternRudderServo2;
|
||||
u_int8_t sternRudderServo3;
|
||||
u_int8_t sternRudderServo4;
|
||||
u_int8_t ctd2;
|
||||
u_int8_t commDevStern;
|
||||
u_int8_t inOutLetWater3;
|
||||
|
||||
// UNIT5
|
||||
u_int8_t secINS;
|
||||
u_int8_t photoSensor;
|
||||
u_int8_t sternThrow;
|
||||
u_int8_t mainINS;
|
||||
} deviceSecdistState;
|
||||
|
||||
|
||||
|
||||
bool parseSecdistStateFromJson(DeviceSecdistState &state, const std::string &strJson){
|
||||
Json::Value root;
|
||||
Json::CharReaderBuilder readerBuilder;
|
||||
std::unique_ptr<Json::CharReader> reader(readerBuilder.newCharReader());
|
||||
std::string errors;
|
||||
|
||||
if(!reader->parse(strJson.c_str(), strJson.c_str() + strJson.length(), &root, &errors)){
|
||||
LOG_F(ERROR, "Failed to parse JSON: %s", errors.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
auto checkField = [&root](const std::string& field) -> bool {
|
||||
if(!root.isMember(field) || !root[field].isUInt()) {
|
||||
// std::cerr << "Missing or invalid field: " << field << std::endl;
|
||||
// LOG_F(ERROR, "Missing or invalid field: %s", field.c_str());
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
bool ok = true;
|
||||
|
||||
// UNIT1
|
||||
if(!checkField("bowCover1_uint8")) ok=false; state.bowCover1 = root["bowCover1_uint8"].asUInt();
|
||||
if(!checkField("bowCover2_uint8")) ok=false; state.bowCover2 = root["bowCover2_uint8"].asUInt();
|
||||
if(!checkField("bowCover3_uint8")) ok=false; state.bowCover3 = root["bowCover3_uint8"].asUInt();
|
||||
if(!checkField("bowCover4_uint8")) ok=false; state.bowCover4 = root["bowCover4_uint8"].asUInt();
|
||||
if(!checkField("bowCover5_uint8")) ok=false; state.bowCover5 = root["bowCover5_uint8"].asUInt();
|
||||
if(!checkField("bowCover6_uint8")) ok=false; state.bowCover6 = root["bowCover6_uint8"].asUInt();
|
||||
if(!checkField("singleBeamSonar1_uint8")) ok=false; state.singleBeamSonar1 = root["singleBeamSonar1_uint8"].asUInt();
|
||||
if(!checkField("singleBeamSonar2_uint8")) ok=false; state.singleBeamSonar2 = root["singleBeamSonar2_uint8"].asUInt();
|
||||
if(!checkField("singleBeamSonar3_uint8")) ok=false; state.singleBeamSonar3 = root["singleBeamSonar3_uint8"].asUInt();
|
||||
if(!checkField("singleBeamSonar4_uint8")) ok=false; state.singleBeamSonar4 = root["singleBeamSonar4_uint8"].asUInt();
|
||||
if(!checkField("singleBeamSonar5_uint8")) ok=false; state.singleBeamSonar5 = root["singleBeamSonar5_uint8"].asUInt();
|
||||
if(!checkField("singleBeamSonar6_uint8")) ok=false; state.singleBeamSonar6 = root["singleBeamSonar6_uint8"].asUInt();
|
||||
if(!checkField("forwardSonar_uint8")) ok=false; state.forwardSonar = root["forwardSonar_uint8"].asUInt();
|
||||
if(!checkField("depth3_uint8")) ok=false; state.depth3 = root["depth3_uint8"].asUInt();
|
||||
if(!checkField("soundVeloc_uint8")) ok=false; state.soundVeloc = root["soundVeloc_uint8"].asUInt();
|
||||
if(!checkField("bowRudderServo_uint8")) ok=false; state.bowRudderServo = root["bowRudderServo_uint8"].asUInt();
|
||||
if(!checkField("bowRudderDeploy_uint8")) ok=false; state.bowRudderDeploy = root["bowRudderDeploy_uint8"].asUInt();
|
||||
if(!checkField("ctd1_uint8")) ok=false; state.ctd1 = root["ctd1_uint8"].asUInt();
|
||||
if(!checkField("waterInject_uint8")) ok=false; state.waterInject = root["waterInject_uint8"].asUInt();
|
||||
|
||||
// UNIT2
|
||||
if(!checkField("sideSonar_uint8")) ok=false; state.sideSonar = root["sideSonar_uint8"].asUInt();
|
||||
if(!checkField("bowWaterInet1_uint8")) ok=false; state.bowWaterInet1 = root["bowWaterInet1_uint8"].asUInt();
|
||||
if(!checkField("bowWaterInet2_uint8")) ok=false; state.bowWaterInet2 = root["bowWaterInet2_uint8"].asUInt();
|
||||
if(!checkField("bowWaterInet3_uint8")) ok=false; state.bowWaterInet3 = root["bowWaterInet3_uint8"].asUInt();
|
||||
if(!checkField("bowWaterInet4_uint8")) ok=false; state.bowWaterInet4 = root["bowWaterInet4_uint8"].asUInt();
|
||||
if(!checkField("bowWaterInet5_uint8")) ok=false; state.bowWaterInet5 = root["bowWaterInet5_uint8"].asUInt();
|
||||
if(!checkField("bowWaterInet6_uint8")) ok=false; state.bowWaterInet6 = root["bowWaterInet6_uint8"].asUInt();
|
||||
if(!checkField("bowWaterInet7_uint8")) ok=false; state.bowWaterInet7 = root["bowWaterInet7_uint8"].asUInt();
|
||||
if(!checkField("bowWaterInet8_uint8")) ok=false; state.bowWaterInet8 = root["bowWaterInet8_uint8"].asUInt();
|
||||
if(!checkField("launchControler_uint8")) ok=false; state.launchControler = root["launchControler_uint8"].asUInt();
|
||||
if(!checkField("electSensor_uint8")) ok=false; state.electSensor = root["electSensor_uint8"].asUInt();
|
||||
if(!checkField("lowFreqSonar_uint8")) ok=false; state.lowFreqSonar = root["lowFreqSonar_uint8"].asUInt();
|
||||
|
||||
// UNIT3
|
||||
if(!checkField("buoyancyAdjust1_uint8")) ok=false; state.buoyancyAdjust1 = root["buoyancyAdjust1_uint8"].asUInt();
|
||||
if(!checkField("buoyancyAdjust2_uint8")) ok=false; state.buoyancyAdjust2 = root["buoyancyAdjust2_uint8"].asUInt();
|
||||
if(!checkField("buoyancyAdjust3_uint8")) ok=false; state.buoyancyAdjust3 = root["buoyancyAdjust3_uint8"].asUInt();
|
||||
if(!checkField("USBL_uint8")) ok=false; state.USBL = root["USBL_uint8"].asUInt();
|
||||
if(!checkField("depth1_uint8")) ok=false; state.depth1 = root["depth1_uint8"].asUInt();
|
||||
if(!checkField("commDev_uint8")) ok=false; state.commDev = root["commDev_uint8"].asUInt();
|
||||
if(!checkField("mastLiftingServo_uint8")) ok=false; state.mastLiftingServo = root["mastLiftingServo_uint8"].asUInt();
|
||||
if(!checkField("DVL_uint8")) ok=false; state.DVL = root["DVL_uint8"].asUInt();
|
||||
if(!checkField("ADCP_uint8")) ok=false; state.ADCP = root["ADCP_uint8"].asUInt();
|
||||
if(!checkField("inOutLetWater1_uint8")) ok=false; state.inOutLetWater1 = root["inOutLetWater1_uint8"].asUInt();
|
||||
if(!checkField("inOutLetWater2_uint8")) ok=false; state.inOutLetWater2 = root["inOutLetWater2_uint8"].asUInt();
|
||||
|
||||
// UNIT4
|
||||
if(!checkField("singleBeamSonar7_uint8")) ok=false; state.singleBeamSonar7 = root["singleBeamSonar7_uint8"].asUInt();
|
||||
if(!checkField("singleBeamSonar8_uint8")) ok=false; state.singleBeamSonar8 = root["singleBeamSonar8_uint8"].asUInt();
|
||||
if(!checkField("buoyage_uint8")) ok=false; state.buoyage = root["buoyage_uint8"].asUInt();
|
||||
if(!checkField("bowThrow_uint8")) ok=false; state.bowThrow = root["bowThrow_uint8"].asUInt();
|
||||
if(!checkField("depth2_uint8")) ok=false; state.depth2 = root["depth2_uint8"].asUInt();
|
||||
if(!checkField("thruster_uint8")) ok=false; state.thruster = root["thruster_uint8"].asUInt();
|
||||
if(!checkField("dragSonar_uint8")) ok=false; state.dragSonar = root["dragSonar_uint8"].asUInt();
|
||||
if(!checkField("haulingMachine_uint8")) ok=false; state.haulingMachine = root["haulingMachine_uint8"].asUInt();
|
||||
if(!checkField("buoyancyAdjust4_uint8")) ok=false; state.buoyancyAdjust4 = root["buoyancyAdjust4_uint8"].asUInt();
|
||||
if(!checkField("buoyancyAdjust5_uint8")) ok=false; state.buoyancyAdjust5 = root["buoyancyAdjust5_uint8"].asUInt();
|
||||
if(!checkField("sternRudderServo1_uint8")) ok=false; state.sternRudderServo1 = root["sternRudderServo1_uint8"].asUInt();
|
||||
if(!checkField("sternRudderServo2_uint8")) ok=false; state.sternRudderServo2 = root["sternRudderServo2_uint8"].asUInt();
|
||||
if(!checkField("sternRudderServo3_uint8")) ok=false; state.sternRudderServo3 = root["sternRudderServo3_uint8"].asUInt();
|
||||
if(!checkField("sternRudderServo4_uint8")) ok=false; state.sternRudderServo4 = root["sternRudderServo4_uint8"].asUInt();
|
||||
if(!checkField("ctd2_uint8")) ok=false; state.ctd2 = root["ctd2_uint8"].asUInt();
|
||||
if(!checkField("commDevStern_uint8")) ok=false; state.commDevStern = root["commDevStern_uint8"].asUInt();
|
||||
if(!checkField("inOutLetWater3_uint8")) ok=false; state.inOutLetWater3 = root["inOutLetWater3_uint8"].asUInt();
|
||||
|
||||
// UNIT5
|
||||
if(!checkField("secINS_uint8")) ok=false; state.secINS = root["secINS_uint8"].asUInt();
|
||||
if(!checkField("photoSensor_uint8")) ok=false; state.photoSensor = root["photoSensor_uint8"].asUInt();
|
||||
if(!checkField("sternThrow_uint8")) ok=false; state.sternThrow = root["sternThrow_uint8"].asUInt();
|
||||
if(!checkField("mainINS_uint8")) ok=false; state.mainINS = root["mainINS_uint8"].asUInt();
|
||||
|
||||
//不检查字段缺失
|
||||
ok = true;
|
||||
return ok;
|
||||
};
|
||||
std::string buildSecdistStateToJson(DeviceSecdistState &state){
|
||||
Json::Value root;
|
||||
|
||||
// UNIT1
|
||||
root["bowCover1_uint8"] = state.bowCover1;
|
||||
root["bowCover2_uint8"] = state.bowCover2;
|
||||
root["bowCover3_uint8"] = state.bowCover3;
|
||||
root["bowCover4_uint8"] = state.bowCover4;
|
||||
root["bowCover5_uint8"] = state.bowCover5;
|
||||
root["bowCover6_uint8"] = state.bowCover6;
|
||||
root["singleBeamSonar1_uint8"] = state.singleBeamSonar1;
|
||||
root["singleBeamSonar2_uint8"] = state.singleBeamSonar2;
|
||||
root["singleBeamSonar3_uint8"] = state.singleBeamSonar3;
|
||||
root["singleBeamSonar4_uint8"] = state.singleBeamSonar4;
|
||||
root["singleBeamSonar5_uint8"] = state.singleBeamSonar5;
|
||||
root["singleBeamSonar6_uint8"] = state.singleBeamSonar6;
|
||||
root["forwardSonar_uint8"] = state.forwardSonar;
|
||||
root["depth3_uint8"] = state.depth3;
|
||||
root["soundVeloc_uint8"] = state.soundVeloc;
|
||||
root["bowRudderServo_uint8"] = state.bowRudderServo;
|
||||
root["bowRudderDeploy_uint8"] = state.bowRudderDeploy;
|
||||
root["ctd1_uint8"] = state.ctd1;
|
||||
root["waterInject_uint8"] = state.waterInject;
|
||||
|
||||
// UNIT2
|
||||
root["sideSonar_uint8"] = state.sideSonar;
|
||||
root["bowWaterInet1_uint8"] = state.bowWaterInet1;
|
||||
root["bowWaterInet2_uint8"] = state.bowWaterInet2;
|
||||
root["bowWaterInet3_uint8"] = state.bowWaterInet3;
|
||||
root["bowWaterInet4_uint8"] = state.bowWaterInet4;
|
||||
root["bowWaterInet5_uint8"] = state.bowWaterInet5;
|
||||
root["bowWaterInet6_uint8"] = state.bowWaterInet6;
|
||||
root["bowWaterInet7_uint8"] = state.bowWaterInet7;
|
||||
root["bowWaterInet8_uint8"] = state.bowWaterInet8;
|
||||
root["launchControler_uint8"] = state.launchControler;
|
||||
root["electSensor_uint8"] = state.electSensor;
|
||||
root["lowFreqSonar_uint8"] = state.lowFreqSonar;
|
||||
|
||||
// UNIT3
|
||||
root["buoyancyAdjust1_uint8"] = state.buoyancyAdjust1;
|
||||
root["buoyancyAdjust2_uint8"] = state.buoyancyAdjust2;
|
||||
root["buoyancyAdjust3_uint8"] = state.buoyancyAdjust3;
|
||||
root["USBL_uint8"] = state.USBL;
|
||||
root["depth1_uint8"] = state.depth1;
|
||||
root["commDev_uint8"] = state.commDev;
|
||||
root["mastLiftingServo_uint8"] = state.mastLiftingServo;
|
||||
root["DVL_uint8"] = state.DVL;
|
||||
root["ADCP_uint8"] = state.ADCP;
|
||||
root["inOutLetWater1_uint8"] = state.inOutLetWater1;
|
||||
root["inOutLetWater2_uint8"] = state.inOutLetWater2;
|
||||
|
||||
// UNIT4
|
||||
root["singleBeamSonar7_uint8"] = state.singleBeamSonar7;
|
||||
root["singleBeamSonar8_uint8"] = state.singleBeamSonar8;
|
||||
root["buoyage_uint8"] = state.buoyage;
|
||||
root["bowThrow_uint8"] = state.bowThrow;
|
||||
root["depth2_uint8"] = state.depth2;
|
||||
root["thruster_uint8"] = state.thruster;
|
||||
root["dragSonar_uint8"] = state.dragSonar;
|
||||
root["haulingMachine_uint8"] = state.haulingMachine;
|
||||
root["buoyancyAdjust4_uint8"] = state.buoyancyAdjust4;
|
||||
root["buoyancyAdjust5_uint8"] = state.buoyancyAdjust5;
|
||||
root["sternRudderServo1_uint8"] = state.sternRudderServo1;
|
||||
root["sternRudderServo2_uint8"] = state.sternRudderServo2;
|
||||
root["sternRudderServo3_uint8"] = state.sternRudderServo3;
|
||||
root["sternRudderServo4_uint8"] = state.sternRudderServo4;
|
||||
root["ctd2_uint8"] = state.ctd2;
|
||||
root["commDevStern_uint8"] = state.commDevStern;
|
||||
root["inOutLetWater3_uint8"] = state.inOutLetWater3;
|
||||
|
||||
// UNIT5
|
||||
root["secINS_uint8"] = state.secINS;
|
||||
root["photoSensor_uint8"] = state.photoSensor;
|
||||
root["sternThrow_uint8"] = state.sternThrow;
|
||||
root["mainINS_uint8"] = state.mainINS;
|
||||
|
||||
Json::StreamWriterBuilder writerBuilder;
|
||||
writerBuilder.settings_["indentation"] = ""; // 紧凑格式,无缩进
|
||||
return Json::writeString(writerBuilder, root);
|
||||
};
|
||||
|
||||
bool converFromDriverTable(DeviceSecdistState &state,const DriverTable &driver){
|
||||
// UNIT1
|
||||
state.bowCover1 = driver.bowCover1;
|
||||
state.bowCover2 = driver.bowCover2;
|
||||
state.bowCover3 = driver.bowCover3;
|
||||
state.bowCover4 = driver.bowCover4;
|
||||
state.bowCover5 = driver.bowCover5;
|
||||
state.bowCover6 = driver.bowCover6;
|
||||
state.singleBeamSonar1 = driver.singleBeamSonar1;
|
||||
state.singleBeamSonar2 = driver.singleBeamSonar2;
|
||||
state.singleBeamSonar3 = driver.singleBeamSonar3;
|
||||
state.singleBeamSonar4 = driver.singleBeamSonar4;
|
||||
state.singleBeamSonar5 = driver.singleBeamSonar5;
|
||||
state.singleBeamSonar6 = driver.singleBeamSonar6;
|
||||
state.forwardSonar = driver.forwardSonar;
|
||||
state.depth3 = driver.depth3;
|
||||
state.soundVeloc = driver.soundVeloc;
|
||||
state.bowRudderServo = driver.bowRudderServo1;
|
||||
state.bowRudderDeploy = driver.bowRudderDeploy;
|
||||
state.ctd1 = driver.ctd1;
|
||||
state.waterInject = driver.waterInject;
|
||||
|
||||
// UNIT2
|
||||
state.sideSonar = driver.sideSonar;
|
||||
state.bowWaterInet1 = driver.bowWaterInet1;
|
||||
state.bowWaterInet2 = driver.bowWaterInet2;
|
||||
state.bowWaterInet3 = driver.bowWaterInet3;
|
||||
state.bowWaterInet4 = driver.bowWaterInet4;
|
||||
state.bowWaterInet5 = driver.bowWaterInet5;
|
||||
state.bowWaterInet6 = driver.bowWaterInet6;
|
||||
state.bowWaterInet7 = driver.bowWaterInet7;
|
||||
state.bowWaterInet8 = driver.bowWaterInet8;
|
||||
state.launchControler = driver.launchControler;
|
||||
state.electSensor = driver.electSensor;
|
||||
state.lowFreqSonar = driver.lowFreqSonar;
|
||||
|
||||
// UNIT3
|
||||
state.buoyancyAdjust1 = driver.buoyancyAdjust1;
|
||||
state.buoyancyAdjust2 = driver.buoyancyAdjust2;
|
||||
state.buoyancyAdjust3 = driver.buoyancyAdjust3;
|
||||
state.USBL = driver.USBL;
|
||||
state.depth1 = driver.depth1;
|
||||
state.commDev = driver.commMast;
|
||||
state.mastLiftingServo = driver.mastLiftingServo;
|
||||
state.DVL = driver.DVL;
|
||||
state.ADCP = driver.DVL; // Assuming ADCP is same as DVL
|
||||
//出入水传感器1、2共用一个继电器
|
||||
state.inOutLetWater1 = driver.inputWaterSensor1;
|
||||
state.inOutLetWater2 = driver.inputWaterSensor1;
|
||||
// state.inOutLetWater2 = driver.inputWaterSensor2;
|
||||
|
||||
// UNIT4
|
||||
state.singleBeamSonar7 = driver.singleBeamSonar7;
|
||||
state.singleBeamSonar8 = driver.singleBeamSonar8;
|
||||
state.buoyage = driver.buoyage;
|
||||
state.bowThrow = driver.bowThrow;
|
||||
state.depth2 = driver.depth2;
|
||||
state.thruster = driver.thruster;
|
||||
state.haulingMachine = 2; // No corresponding field in DriverTable
|
||||
state.buoyancyAdjust4 = driver.buoyancyAdjust4;
|
||||
state.buoyancyAdjust5 = driver.buoyancyAdjust5;
|
||||
state.sternRudderServo1 = driver.sternRudderServo1;
|
||||
state.sternRudderServo2 = driver.sternRudderServo2;
|
||||
state.sternRudderServo3 = driver.sternRudderServo3;
|
||||
state.sternRudderServo4 = driver.sternRudderServo4;
|
||||
state.ctd2 = driver.ctd2;
|
||||
state.commDevStern = 2; // No corresponding field in DriverTable
|
||||
state.inOutLetWater3 = driver.inputWaterSensor3;
|
||||
|
||||
// UNIT5
|
||||
state.secINS = driver.ins;
|
||||
state.photoSensor = driver.photoSensor;
|
||||
state.sternThrow = driver.sternThrow;
|
||||
state.mainINS = driver.ins;
|
||||
|
||||
// 未映射字段
|
||||
// driver.overDeep1
|
||||
// driver.overDeep2
|
||||
// driver.ntp
|
||||
state.dragSonar = 2; // Assuming dragSonar is same as lowFreqSonar
|
||||
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
bool converToDriverTable(const DeviceSecdistState &state, DriverTable &driver){
|
||||
// UNIT1
|
||||
driver.bowCover1 = state.bowCover1;
|
||||
driver.bowCover2 = state.bowCover2;
|
||||
driver.bowCover3 = state.bowCover3;
|
||||
driver.bowCover4 = state.bowCover4;
|
||||
driver.bowCover5 = state.bowCover5;
|
||||
driver.bowCover6 = state.bowCover6;
|
||||
driver.singleBeamSonar1 = state.singleBeamSonar1;
|
||||
driver.singleBeamSonar2 = state.singleBeamSonar2;
|
||||
driver.singleBeamSonar3 = state.singleBeamSonar3;
|
||||
driver.singleBeamSonar4 = state.singleBeamSonar4;
|
||||
driver.singleBeamSonar5 = state.singleBeamSonar5;
|
||||
driver.singleBeamSonar6 = state.singleBeamSonar6;
|
||||
driver.forwardSonar = state.forwardSonar;
|
||||
driver.depth3 = state.depth3;
|
||||
driver.soundVeloc = state.soundVeloc;
|
||||
driver.bowRudderServo1 = state.bowRudderServo;
|
||||
driver.bowRudderServo2 = state.bowRudderServo;
|
||||
driver.bowRudderDeploy = state.bowRudderDeploy;
|
||||
driver.ctd1 = state.ctd1;
|
||||
driver.waterInject = state.waterInject;
|
||||
|
||||
// UNIT2
|
||||
driver.sideSonar = state.sideSonar;
|
||||
driver.bowWaterInet1 = state.bowWaterInet1;
|
||||
driver.bowWaterInet2 = state.bowWaterInet2;
|
||||
driver.bowWaterInet3 = state.bowWaterInet3;
|
||||
driver.bowWaterInet4 = state.bowWaterInet4;
|
||||
driver.bowWaterInet5 = state.bowWaterInet5;
|
||||
driver.bowWaterInet6 = state.bowWaterInet6;
|
||||
driver.bowWaterInet7 = state.bowWaterInet7;
|
||||
driver.bowWaterInet8 = state.bowWaterInet8;
|
||||
driver.launchControler = state.launchControler;
|
||||
driver.electSensor = state.electSensor;
|
||||
driver.lowFreqSonar = state.lowFreqSonar;
|
||||
|
||||
// UNIT3
|
||||
driver.buoyancyAdjust1 = state.buoyancyAdjust1;
|
||||
driver.buoyancyAdjust2 = state.buoyancyAdjust2;
|
||||
driver.buoyancyAdjust3 = state.buoyancyAdjust3;
|
||||
driver.USBL = state.USBL;
|
||||
driver.depth1 = state.depth1;
|
||||
driver.commMast = state.commDev;
|
||||
driver.ntp = 1;
|
||||
driver.mastLiftingServo = state.mastLiftingServo;
|
||||
driver.DVL = state.DVL;
|
||||
driver.inputWaterSensor1 = state.inOutLetWater1;
|
||||
driver.inputWaterSensor2 = state.inOutLetWater2;
|
||||
driver.overDeep1 = (state.depth1 == 1) ? 1 : 0;
|
||||
driver.overDeep2 = (state.depth2 == 1 || state.depth3 == 1) ? 1 : 0;
|
||||
|
||||
// UNIT4
|
||||
driver.singleBeamSonar7 = state.singleBeamSonar7;
|
||||
driver.singleBeamSonar8 = state.singleBeamSonar8;
|
||||
driver.buoyage = state.buoyage;
|
||||
driver.bowThrow = state.bowThrow;
|
||||
driver.depth2 = state.depth2;
|
||||
driver.thruster = state.thruster;
|
||||
driver.buoyancyAdjust4 = state.buoyancyAdjust4;
|
||||
driver.buoyancyAdjust5 = state.buoyancyAdjust5;
|
||||
driver.sternRudderServo1 = state.sternRudderServo1;
|
||||
driver.sternRudderServo2 = state.sternRudderServo2;
|
||||
driver.sternRudderServo3 = state.sternRudderServo3;
|
||||
driver.sternRudderServo4 = state.sternRudderServo4;
|
||||
driver.ctd2 = state.ctd2;
|
||||
driver.inputWaterSensor3 = state.inOutLetWater3;
|
||||
|
||||
// UNIT5
|
||||
driver.ins = state.secINS | state.mainINS;
|
||||
driver.photoSensor = state.photoSensor;
|
||||
driver.sternThrow = state.sternThrow;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
std::string buildMsg(DriverTable &driver){
|
||||
DeviceSecdistState s;
|
||||
converFromDriverTable(s,driver);
|
||||
// std::cout << (int)s.depth1 << std::endl;
|
||||
// std::cout << buildSecdistStateToJson(s) << std::endl;
|
||||
return buildSecdistStateToJson(s);
|
||||
};
|
||||
|
||||
bool parseMsg(const std::string &strJson,DriverTable &driver){
|
||||
DeviceSecdistState s;
|
||||
if(!parseSecdistStateFromJson(s,strJson)){
|
||||
LOG_F(WARNING, "parseSecdistStateFromJson failed");
|
||||
return false;
|
||||
}
|
||||
converToDriverTable(s,driver);
|
||||
return true;
|
||||
};
|
||||
|
||||
std::string buildMsg(DriverTable driver, DriverTable driver_state){
|
||||
DeviceSecdistState s;
|
||||
DriverTable driverCopy = driver;
|
||||
for (size_t i = 0; i < sizeof(DriverTable); ++i) {
|
||||
unsigned char* driverCopyPtr = reinterpret_cast<unsigned char*>(&driverCopy) + i;
|
||||
unsigned char* statePtr = reinterpret_cast<unsigned char*>(&driver_state) + i;
|
||||
if (*driverCopyPtr == *statePtr) {
|
||||
*driverCopyPtr = 2;
|
||||
}
|
||||
}
|
||||
converFromDriverTable(s, driverCopy);
|
||||
// std::cout << (int)s.depth1 << std::endl;
|
||||
// std::cout << buildSecdistStateToJson(s) << std::endl;
|
||||
return buildSecdistStateToJson(s);
|
||||
};
|
||||
|
||||
std::string buildMsg(DriverTable driver, DriverTable driver_state, unsigned int nCheck){
|
||||
static size_t callCount = 0; // 静态变量,记录函数调用次数
|
||||
DeviceSecdistState s;
|
||||
DriverTable driverCopy = driver;
|
||||
if (nCheck > 0 && callCount % nCheck == 0)
|
||||
{
|
||||
for (size_t i = 0; i < sizeof(DriverTable); ++i) {
|
||||
unsigned char* driverCopyPtr = reinterpret_cast<unsigned char*>(&driverCopy) + i;
|
||||
unsigned char* statePtr = reinterpret_cast<unsigned char*>(&driver_state) + i;
|
||||
if (*driverCopyPtr == *statePtr) {
|
||||
*driverCopyPtr = 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
memset(&driverCopy, 2, sizeof(DriverTable));
|
||||
}
|
||||
callCount ++;
|
||||
converFromDriverTable(s, driverCopy);
|
||||
// std::cout << (int)s.depth1 << std::endl;
|
||||
// std::cout << buildSecdistStateToJson(s) << std::endl;
|
||||
return buildSecdistStateToJson(s);
|
||||
};
|
||||
|
||||
static DriverTable fault_state;
|
||||
std::string buildMsg(DriverTable driver, DriverTable driver_state, DriverTable &driver_fault_state){
|
||||
static size_t f_callCount = 0; // 静态变量,记录函数调用次数
|
||||
unsigned int nCheck = 10;
|
||||
DeviceSecdistState s;
|
||||
DriverTable driverCopy = driver;
|
||||
for (size_t i = 0; i < sizeof(DriverTable); ++i)
|
||||
{
|
||||
unsigned char* driverCopyPtr = reinterpret_cast<unsigned char*>(&driverCopy) + i;
|
||||
unsigned char* statePtr = reinterpret_cast<unsigned char*>(&driver_state) + i;
|
||||
unsigned char* faultStatePtr = reinterpret_cast<unsigned char*>(&driver_fault_state) + i;
|
||||
unsigned char* faultState = reinterpret_cast<unsigned char*>(&fault_state) + i;
|
||||
if (*driverCopyPtr == *statePtr)
|
||||
{
|
||||
*driverCopyPtr = 2;
|
||||
*faultStatePtr = 0;
|
||||
*faultState = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
*faultState = *faultState + 1;
|
||||
if(*faultState >= 5)
|
||||
{
|
||||
//只有开启失败才计入故障
|
||||
if(*driverCopyPtr == 1)
|
||||
*faultStatePtr = 1;
|
||||
*faultState = 5;
|
||||
}
|
||||
}
|
||||
}
|
||||
f_callCount ++;
|
||||
converFromDriverTable(s, driverCopy);
|
||||
return buildSecdistStateToJson(s);
|
||||
};
|
||||
};
|
||||
#endif
|
||||
@@ -1,124 +0,0 @@
|
||||
/*
|
||||
{
|
||||
"rpm int16": "xxx", // 实际转速,类型:int16_t
|
||||
"voltage_uint16": "xxx", // 电压,类型:uint16_t,单位 V
|
||||
"current_uint16": "xxx", // 电流,类型:uint16_t,单位 A
|
||||
"ctrlTemp_uint16": "xxx", // 控制器温度,类型:uint16_t,单位 °C
|
||||
"motorTemp_uint16": "xxx", // 电机温度,类型:uint16_t,单位 °C
|
||||
"motorTorque_uint16": "xxx", // 电机扭矩,类型:uint16_t,单位 N・m
|
||||
"maxTorque_uint16": "xxx", // 电机最大扭矩,类型:uint16_t,单位 N・m,电机使能时该字段非零,无使能地址报警,含使能整标标识字,00 无故障,按位常量零
|
||||
"error_int64": "xxx" // 见表 [1],类型:int64_t
|
||||
}
|
||||
*/
|
||||
#ifndef UDEVICE_THRUSTER_ST_H
|
||||
#define UDEVICE_THRUSTER_ST_H
|
||||
|
||||
#include "../logc/loguru.hpp"
|
||||
#include "json/json.h"
|
||||
#include <string>
|
||||
#include <memory>
|
||||
#include <sstream>
|
||||
|
||||
class uDevice_thruster_st
|
||||
{
|
||||
private:
|
||||
/* data */
|
||||
public:
|
||||
uDevice_thruster_st(){};
|
||||
~uDevice_thruster_st(){};
|
||||
|
||||
int16_t rpm_int16;
|
||||
uint16_t voltage_uint16;
|
||||
uint16_t current_uint16;
|
||||
uint16_t ctrlTemp_uint16;
|
||||
uint16_t motorTemp_uint16;
|
||||
uint16_t motorTorque_uint16;
|
||||
uint16_t maxTorque_uint16;
|
||||
int64_t error_int64;
|
||||
|
||||
static std::string key;
|
||||
|
||||
std::string toJsonString()
|
||||
{
|
||||
Json::Value j;
|
||||
j["rpm_int16"] = rpm_int16;
|
||||
j["voltage_uint16"] = voltage_uint16;
|
||||
j["current_uint16"] = current_uint16;
|
||||
j["ctrlTemp_uint16"] = ctrlTemp_uint16;
|
||||
j["motorTemp_uint16"] = motorTemp_uint16;
|
||||
j["motorTorque_uint16"] = motorTorque_uint16;
|
||||
j["maxTorque_uint16"] = maxTorque_uint16;
|
||||
j["error_int64"] = static_cast<Json::Int64>(error_int64);
|
||||
|
||||
Json::StreamWriterBuilder builder;
|
||||
builder.settings_["indentation"] = "";
|
||||
return Json::writeString(builder, j);
|
||||
}
|
||||
|
||||
bool fromJsonString(std::string jsonString)
|
||||
{
|
||||
Json::Value root;
|
||||
Json::CharReaderBuilder builder;
|
||||
JSONCPP_STRING errs;
|
||||
|
||||
// 解析JSON字符串
|
||||
std::istringstream stream(jsonString);
|
||||
if (!Json::parseFromStream(builder, stream, &root, &errs)) {
|
||||
LOG_F(WARNING, "JSON解析失败: %s", errs.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
// 提取rpm_int16
|
||||
if (root.isMember("rpm_int16") && root["rpm_int16"].isInt()) {
|
||||
rpm_int16 = root["rpm_int16"].asInt();
|
||||
// LOG_F(INFO, "rpm_int16: %d", rpm_int16);
|
||||
}
|
||||
|
||||
// 提取voltage_uint16
|
||||
if (root.isMember("voltage_uint16") && root["voltage_uint16"].isUInt()) {
|
||||
voltage_uint16 = root["voltage_uint16"].asUInt();
|
||||
// LOG_F(INFO, "voltage_uint16: %u", voltage_uint16);
|
||||
}
|
||||
|
||||
// 提取current_uint16
|
||||
if (root.isMember("current_uint16") && root["current_uint16"].isUInt()) {
|
||||
current_uint16 = root["current_uint16"].asUInt();
|
||||
// LOG_F(INFO, "current_uint16: %u", current_uint16);
|
||||
}
|
||||
|
||||
// 提取ctrlTemp_uint16
|
||||
if (root.isMember("ctrlTemp_uint16") && root["ctrlTemp_uint16"].isUInt()) {
|
||||
ctrlTemp_uint16 = root["ctrlTemp_uint16"].asUInt();
|
||||
// LOG_F(INFO, "ctrlTemp_uint16: %u", ctrlTemp_uint16);
|
||||
}
|
||||
|
||||
// 提取motorTemp_uint16
|
||||
if (root.isMember("motorTemp_uint16") && root["motorTemp_uint16"].isUInt()) {
|
||||
motorTemp_uint16 = root["motorTemp_uint16"].asUInt();
|
||||
// LOG_F(INFO, "motorTemp_uint16: %u", motorTemp_uint16);
|
||||
}
|
||||
|
||||
// 提取motorTorque_uint16
|
||||
if (root.isMember("motorTorque_uint16") && root["motorTorque_uint16"].isUInt()) {
|
||||
motorTorque_uint16 = root["motorTorque_uint16"].asUInt();
|
||||
// LOG_F(INFO, "motorTorque_uint16: %u", motorTorque_uint16);
|
||||
}
|
||||
|
||||
// 提取maxTorque_uint16
|
||||
if (root.isMember("maxTorque_uint16") && root["maxTorque_uint16"].isUInt()) {
|
||||
maxTorque_uint16 = root["maxTorque_uint16"].asUInt();
|
||||
// LOG_F(INFO, "maxTorque_uint16: %u", maxTorque_uint16);
|
||||
}
|
||||
|
||||
// 提取error_int64
|
||||
if (root.isMember("error_int64") && root["error_int64"].isInt64()) {
|
||||
error_int64 = root["error_int64"].asInt64();
|
||||
// LOG_F(INFO, "error_int64: %lld", error_int64);
|
||||
}
|
||||
|
||||
// LOG_F(INFO, "jsonString: %s", jsonString.c_str());
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -1,43 +0,0 @@
|
||||
#ifndef UEXTERNCOMM_SETDEVICESWITCH_CMD_H
|
||||
#define UEXTERNCOMM_SETDEVICESWITCH_CMD_H
|
||||
#include <string>
|
||||
|
||||
class uExternComm_setDeviceSwitchMsg
|
||||
{
|
||||
private:
|
||||
/* data */
|
||||
public:
|
||||
std::string key = "uExternComm_setDeviceSwitch_cmd";
|
||||
|
||||
uExternComm_setDeviceSwitchMsg(/* args */){};
|
||||
~uExternComm_setDeviceSwitchMsg(){};
|
||||
DeviceSwitchCmd getSetDevSwitch(const std::string& key, const std::string& msg)
|
||||
{
|
||||
Json::Value root;
|
||||
Json::CharReaderBuilder builder;
|
||||
JSONCPP_STRING errs;
|
||||
DeviceSwitchCmd cmd{};
|
||||
// 解析JSON字符串
|
||||
std::istringstream stream(msg);
|
||||
if (!Json::parseFromStream(builder, stream, &root, &errs)) {
|
||||
LOG_F(WARNING, "JSON解析失败: %s", errs.c_str());
|
||||
cmd.id = -1;
|
||||
}
|
||||
|
||||
// 检查并读取设备开关状态
|
||||
if (root.isMember("id_uint8") && root["id_uint8"].isUInt()) {
|
||||
cmd.id = root["id_uint8"].asUInt();
|
||||
} else {
|
||||
cmd.id = -1;
|
||||
LOG_F(WARNING, "缺少或类型不匹配: id_uint8");
|
||||
}
|
||||
if (root.isMember("cmd_uint8") && root["cmd_uint8"].isUInt()) {
|
||||
cmd.cmd = root["cmd_uint8"].asUInt();
|
||||
} else {
|
||||
LOG_F(WARNING, "缺少或类型不匹配: state_bool");
|
||||
}
|
||||
return cmd;
|
||||
};
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -1,43 +0,0 @@
|
||||
#ifndef UEXTERCOMM_SETOPCONDITION_CMD_H
|
||||
#define UEXTERCOMM_SETOPCONDITION_CMD_H
|
||||
#include <string>
|
||||
#include "../logc/loguru.hpp"
|
||||
#include "json/json.h"
|
||||
//外部通信消息
|
||||
#define DB_TO_PM_SETOPCONDITION "uExternComm_setOpCondition_cmd"
|
||||
|
||||
class uExternComm_setOpConditionMsg
|
||||
{
|
||||
private:
|
||||
/* data */
|
||||
public:
|
||||
std::string key = "uExternComm_setOpCondition_cmd";
|
||||
uExternComm_setOpConditionMsg(/* args */){};
|
||||
~uExternComm_setOpConditionMsg(){};
|
||||
|
||||
int getSetOpCondition(const std::string& key, const std::string& msg)
|
||||
{
|
||||
Json::Value root;
|
||||
Json::CharReaderBuilder builder;
|
||||
JSONCPP_STRING errs;
|
||||
|
||||
// 解析JSON字符串
|
||||
std::istringstream stream(msg);
|
||||
if (!Json::parseFromStream(builder, stream, &root, &errs)) {
|
||||
LOG_F(WARNING, "JSON解析失败: %s", errs.c_str());
|
||||
return -1;
|
||||
}
|
||||
|
||||
// 检查并读取操作条件
|
||||
if (root.isMember("state_uint8") && root["state_uint8"].isUInt()) {
|
||||
return root["state_uint8"].asUInt();
|
||||
LOG_F(INFO, "上位机指令:opCondition: %d", root["state_uint8"].asUInt());
|
||||
} else {
|
||||
LOG_F(WARNING, "缺少或类型不匹配: opCondition");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -1,46 +0,0 @@
|
||||
#ifndef UEXTERCOMM_SETOPMODE_CMD_H
|
||||
#define UEXTERCOMM_SETOPMODE_CMD_H
|
||||
#include <string>
|
||||
#include "../logc/loguru.hpp"
|
||||
|
||||
//外部通信消息
|
||||
#define DB_TO_PM_SETOPMODE "uExternComm_setOpMode_cmd"
|
||||
|
||||
class uExternComm_setOpModeMsg
|
||||
{
|
||||
private:
|
||||
/* data */
|
||||
public:
|
||||
std::string key = "uExternComm_setOpMode_cmd";
|
||||
uExternComm_setOpModeMsg(/* args */){};
|
||||
~uExternComm_setOpModeMsg(){};
|
||||
|
||||
int getSetOpMode(const std::string& msgkey, const std::string& msg){
|
||||
if (msgkey!= key)
|
||||
{
|
||||
LOG_F(WARNING, "消息类型错误 %s", msgkey.c_str());
|
||||
return 0;
|
||||
}
|
||||
Json::Value root;
|
||||
Json::CharReaderBuilder builder;
|
||||
JSONCPP_STRING errs;
|
||||
|
||||
// 解析JSON字符串
|
||||
std::istringstream stream(msg);
|
||||
if (!Json::parseFromStream(builder, stream, &root, &errs)) {
|
||||
LOG_F(WARNING, "JSON解析失败: %s", errs.c_str());
|
||||
return -1;
|
||||
}
|
||||
|
||||
// 检查并读取操作模式
|
||||
if (root.isMember("state_uint8") && root["state_uint8"].isUInt()) {
|
||||
return root["state_uint8"].asUInt();
|
||||
} else {
|
||||
LOG_F(WARNING, "缺少或类型不匹配: opMode");
|
||||
return -1;
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
#endif
|
||||
@@ -1,39 +0,0 @@
|
||||
#ifndef UEXTERNCONM_SETPMSYS_H
|
||||
#define UEXTERNCONM_SETPMSYS_H
|
||||
#include <string>
|
||||
#include "../logc/loguru.hpp"
|
||||
#define DB_TO_PM_SETPMSYS "uExternComm_setPowerSystem_cmd"
|
||||
class uExternComm_setPowerSystemMsg
|
||||
{
|
||||
private:
|
||||
|
||||
public:
|
||||
std::string key = "uExternComm_setPowerSystem_cmd";
|
||||
uExternComm_setPowerSystemMsg(/* args */){};
|
||||
~uExternComm_setPowerSystemMsg(){};
|
||||
|
||||
int getSetPMSys(const std::string& key, const std::string& msg)
|
||||
{
|
||||
Json::Value root;
|
||||
Json::CharReaderBuilder builder;
|
||||
JSONCPP_STRING errs;
|
||||
|
||||
// 解析JSON字符串
|
||||
std::istringstream stream(msg);
|
||||
if (!Json::parseFromStream(builder, stream, &root, &errs)) {
|
||||
std::cerr << "JSON解析失败: " << errs << std::endl;
|
||||
return -1;
|
||||
}
|
||||
|
||||
// 检查并读取电源系统设置
|
||||
if (root.isMember("powerCmd_uint8") && root["powerCmd_uint8"].isUInt()) {
|
||||
return root["powerCmd_uint8"].asUInt();
|
||||
} else {
|
||||
LOG_F(WARNING, "缺少或类型不匹配: powerCmd_uint8");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,70 +0,0 @@
|
||||
/*
|
||||
{
|
||||
"rpm_int16": "xx", // 期望转速;单位:rpm;类型 int16_t
|
||||
"enable_int16": "xx" // 使能指令,1 - 使能,0 - 去使能。类型 int16_t
|
||||
}
|
||||
*/
|
||||
#ifndef UEXTERNCOMM_SETTHRUSTSPEED_CMD_H
|
||||
#define UEXTERNCOMM_SETTHRUSTSPEED_CMD_H
|
||||
|
||||
#include "../logc/loguru.hpp"
|
||||
#include "json/json.h"
|
||||
#include <string>
|
||||
#include <memory>
|
||||
#include <sstream>
|
||||
|
||||
class uExternComm_setThrustSpeed_cmd
|
||||
{
|
||||
private:
|
||||
/* data */
|
||||
public:
|
||||
uExternComm_setThrustSpeed_cmd(){};
|
||||
~uExternComm_setThrustSpeed_cmd(){};
|
||||
|
||||
int16_t rpm_int16;
|
||||
int16_t enable_int16;
|
||||
|
||||
static std::string key;
|
||||
|
||||
std::string toJsonString()
|
||||
{
|
||||
Json::Value j;
|
||||
j["rpm_int16"] = rpm_int16;
|
||||
j["enable_int16"] = enable_int16;
|
||||
|
||||
Json::StreamWriterBuilder builder;
|
||||
builder.settings_["indentation"] = "";
|
||||
return Json::writeString(builder, j);
|
||||
}
|
||||
|
||||
bool fromJsonString(std::string jsonString)
|
||||
{
|
||||
Json::Value root;
|
||||
Json::CharReaderBuilder builder;
|
||||
JSONCPP_STRING errs;
|
||||
|
||||
// 解析JSON字符串
|
||||
std::istringstream stream(jsonString);
|
||||
if (!Json::parseFromStream(builder, stream, &root, &errs)) {
|
||||
LOG_F(WARNING, "JSON解析失败: %s", errs.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
// 提取rpm_int16
|
||||
if (root.isMember("rpm_int16") && root["rpm_int16"].isInt()) {
|
||||
rpm_int16 = root["rpm_int16"].asInt();
|
||||
// LOG_F(INFO, "rpm_int16: %d", rpm_int16);
|
||||
}
|
||||
|
||||
// 提取enable_int16
|
||||
if (root.isMember("enable_int16") && root["enable_int16"].isInt()) {
|
||||
enable_int16 = root["enable_int16"].asInt();
|
||||
// LOG_F(INFO, "enable_int16: %d", enable_int16);
|
||||
}
|
||||
|
||||
// LOG_F(INFO, "jsonString: %s", jsonString.c_str());
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -1,35 +0,0 @@
|
||||
#ifndef UPLAN_PLANSTOP_CMD_H
|
||||
#define UPLAN_PLANSTOP_CMD_H
|
||||
#include <string>
|
||||
#include "../logc/loguru.hpp"
|
||||
#define DB_TO_PM_TASKSTOP "uPlan_planStop_st"
|
||||
class uPlan_planStopMsg
|
||||
{
|
||||
private:
|
||||
/* data */
|
||||
public:
|
||||
std::string key = "uPlan_planStop_st";
|
||||
uPlan_planStopMsg(/* args */){};
|
||||
~uPlan_planStopMsg(){};
|
||||
bool getTaskStop(const std::string& key, const std::string& msg) {
|
||||
Json::Value root;
|
||||
Json::CharReaderBuilder builder;
|
||||
JSONCPP_STRING errs;
|
||||
|
||||
// 解析JSON字符串
|
||||
std::istringstream stream(msg);
|
||||
if (!Json::parseFromStream(builder, stream, &root, &errs)) {
|
||||
LOG_F(WARNING, "JSON解析失败: %s", errs.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
// 检查op_int32字段
|
||||
if (root.isMember("op_int32") && root["op_int32"].isInt()) {
|
||||
return root["op_int32"].asInt() == 1;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,55 +0,0 @@
|
||||
#ifndef UPPERCOMMMANAGER_H
|
||||
#define UPPERCOMMMANAGER_H
|
||||
#include <string>
|
||||
#include "../pmSysvariable.h"
|
||||
#include "../logc/loguru.hpp"
|
||||
//决策消息
|
||||
#define DB_TO_PM_MISSION "uPlan_taskStart_st"
|
||||
|
||||
class uPlan_taskStartMsg
|
||||
{
|
||||
private:
|
||||
/* data */
|
||||
public:
|
||||
std::string key = "uPlan_taskStart_st";
|
||||
uPlan_taskStartMsg(/* args */){};
|
||||
~uPlan_taskStartMsg(){};
|
||||
|
||||
MissionState getMission(const std::string& key, const std::string& msg) {
|
||||
MissionState mission{};
|
||||
Json::Value root;
|
||||
Json::CharReaderBuilder builder;
|
||||
JSONCPP_STRING errs;
|
||||
|
||||
// 解析JSON字符串
|
||||
std::istringstream stream(msg);
|
||||
if (!Json::parseFromStream(builder, stream, &root, &errs)) {
|
||||
std::cerr << "JSON解析失败: " << errs << std::endl;
|
||||
LOG_F(WARNING, "JSON解析失败: %s", errs.c_str());
|
||||
return mission;
|
||||
}
|
||||
|
||||
// 提取taskType_str
|
||||
if (root.isMember("taskType_str") && root["taskType_str"].isString()) {
|
||||
mission.type = TaskType::fromString(root["taskType_str"].asString());
|
||||
LOG_F(INFO, "taskType: %d", mission.type, root["taskType_str"].asString());
|
||||
}
|
||||
|
||||
// 提取balanceEnabled_bool
|
||||
if (root.isMember("balanceEnabled_bool") && root["balanceEnabled_bool"].isBool()) {
|
||||
mission.enableBuoyancyAdjustment = root["balanceEnabled_bool"].asBool();
|
||||
LOG_F(INFO, "balanceEnabled_bool: %d", mission.enableBuoyancyAdjustment);
|
||||
}
|
||||
|
||||
// 提取bowRudderUnfold_bool
|
||||
if (root.isMember("bowRudderUnfold_bool") && root["bowRudderUnfold_bool"].isBool()) {
|
||||
mission.enableBowRudder = root["bowRudderUnfold_bool"].asBool();
|
||||
LOG_F(INFO, "bowRudderUnfold_bool: %d", mission.enableBowRudder);
|
||||
}
|
||||
|
||||
|
||||
return mission;
|
||||
};
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -1,81 +0,0 @@
|
||||
#ifndef U_POWER_CURRENTSTATE_ST_H
|
||||
#define U_POWER_CURRENTSTATE_ST_H
|
||||
#include "../driver.h"
|
||||
#include "string"
|
||||
#include "json/json.h"
|
||||
#include <bitset>
|
||||
|
||||
class uPower_currentStateMsg
|
||||
{
|
||||
private:
|
||||
/* data */
|
||||
public:
|
||||
uPower_currentStateMsg() {
|
||||
memset(&state, 0, sizeof(state));
|
||||
};
|
||||
~uPower_currentStateMsg() {};
|
||||
std::string key = "uPower_currentState_st";
|
||||
|
||||
pmState state;
|
||||
std::string buildMsg(pmState state)
|
||||
{
|
||||
// 状态赋值
|
||||
Json::Value currentBusState;
|
||||
currentBusState["HVBpowerBusVol_uint16"] = state.bus1State.powerBusVoltage;
|
||||
currentBusState["HVBdcDc5Cur_uint16"] = state.bus1State.dcDc5ModuleCurrent;
|
||||
currentBusState["HVBpowerBusCur_uint16"] = state.bus1State.powerBusCurrent;
|
||||
currentBusState["HVBbusAVol_uint16"] = state.bus1State.busbarAVoltage;
|
||||
currentBusState["HVBmotorCur_uint16"] = state.bus1State.propulsionMotorControlBoxCurrent;
|
||||
currentBusState["HVBbusACur_uint16"] = state.bus1State.busbarACurrent;
|
||||
currentBusState["HVBbatGroupCur_uint16"] = state.bus1State.lithiumBatteryGroupMeterCurrent;
|
||||
currentBusState["HVBbowHVolDisBoxCur_uint16"] = state.bus1State.bowHighVoltageDistributionBoxCurrent;
|
||||
currentBusState["HVBFTDev45Cur_uint16"] = state.bus1State.sternFTDevice45Current;
|
||||
currentBusState["HVBtyzCur_uint16"] = state.bus1State.tyzReservedSwitchCurrent;
|
||||
currentBusState["HVBsternRud1Cur_uint16"] = state.bus1State.sternRudderSwitch1Current;
|
||||
currentBusState["HVBreservedCur1_uint16"] = state.bus1State.reservedCurrent1;
|
||||
currentBusState["HVBsternRud2Cur_uint16"] = state.bus1State.sternRudderSwitch2Current;
|
||||
currentBusState["HVBreservedCur2_uint16"] = state.bus1State.reservedCurrent2;
|
||||
currentBusState["HVBfbCur_uint16"] = state.bus1State.fbReservedSwitchCurrent;
|
||||
currentBusState["HVBreservedCur3_uint16"] = state.bus1State.reservedCurrent3;
|
||||
|
||||
currentBusState["HVABbusBVol_uint16"] = state.bus2State.busbarBVoltage;
|
||||
currentBusState["HVABbusBCur_uint16"] = state.bus2State.busbarBCurrent;
|
||||
currentBusState["HVABFTDev123Cur_uint16"] = state.bus2State.bowFTDevice123Current;
|
||||
currentBusState["HVABactCur_uint16"] = state.bus2State.actuatorCurrent;
|
||||
currentBusState["HVABmastSteGeaCur_uint16"] = state.bus2State.mastSteeringGearControlBoxCurrent;
|
||||
currentBusState["HVABxczCur_uint16"] = state.bus2State.xczCurrent;
|
||||
currentBusState["HVABbowRudCur_uint16"] = state.bus2State.bowRudderControlBoxCurrent;
|
||||
currentBusState["HVABopenWaterCur_uint16"] = state.bus2State.openWaterCoverStartCylinderCurrent;
|
||||
|
||||
currentBusState["HVBBinsBusVol_uint16"] = state.bus3State.instrumentBusbarVoltage;
|
||||
currentBusState["HVBBbowLowVolDisBoxCur_uint16"] = state.bus3State.bowLowVoltageDistributionBoxCurrent;
|
||||
currentBusState["HVBBdcC1InsCur_uint16"] = state.bus3State.dcC1InstrumentDC48VCurrent;
|
||||
currentBusState["HVBBreservedCur1_uint16"] = state.bus3State.reservedCurrent1;
|
||||
currentBusState["HVBBemerBatCur_uint16"] = state.bus3State.emergencyLithiumBatteryGroup2Current;
|
||||
currentBusState["HVBBbatInsCur_uint16"] = state.bus3State.lithiumBatteryGroupInstrumentCurrent;
|
||||
currentBusState["HVBBunit4Cur_uint16"] = state.bus3State.unit4InstrumentDC48VCurrent;
|
||||
currentBusState["HVBBreservedCur2_uint16"] = state.bus3State.reservedCurrent2;
|
||||
currentBusState["HVBBemer2BusVol_uint16"] = state.bus3State.emergency2BusbarVoltage;
|
||||
currentBusState["HVBBCCUCur_uint16"] = state.bus3State.compositeEnergyManagementSystemEmergencyDC48VCurrent;
|
||||
currentBusState["HVBBFCSSecurSysCur_uint16"] = state.bus3State.fuelCellSecuritySystemEmergencyDC48VCurrent;
|
||||
currentBusState["HVBBplcCur_uint16"] = state.bus3State.plcControlPowerCurrent;
|
||||
|
||||
currentBusState["LVBinsBusVol_uint16"] = state.bus4State.instrumentBusbarVoltage;
|
||||
currentBusState["LVBBinsBusCur_uint16"] = state.bus4State.instrumentBusbarCurrent;
|
||||
currentBusState["LVBBunit1Cur_uint16"] = state.bus4State.unit1Current;
|
||||
currentBusState["LVBBunit2Cur_uint16"] = state.bus4State.unit2Current;
|
||||
currentBusState["LVBBunit3Cur_uint16"] = state.bus4State.unit3Current;
|
||||
currentBusState["LVBBunit5Cur_uint16"] = state.bus4State.unit5Current;
|
||||
currentBusState["LVBBbowPZDevCur_uint16"] = state.bus4State.bowPZDeviceCurrent;
|
||||
currentBusState["LVBBemerBatCur_uint16"] = state.bus4State.emergencyLithiumBatteryGroup1Current;
|
||||
currentBusState["LVBBemerBusVol_uint16"] = state.bus4State.emergency1BusbarVoltage;
|
||||
|
||||
// 转化为json格式
|
||||
|
||||
Json::StreamWriterBuilder writerBuilder;
|
||||
writerBuilder.settings_["indentation"] = "";
|
||||
return Json::writeString(writerBuilder, currentBusState);
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -1,203 +0,0 @@
|
||||
#ifndef U_POWER_DISSYSSTATE_ST_H
|
||||
#define U_POWER_DISSYSSTATE_ST_H
|
||||
#include "../driver.h"
|
||||
#include "string"
|
||||
#include "json/json.h"
|
||||
#include <bitset>
|
||||
#include "../pmSysvariable.h"
|
||||
#include "../systemData.h"
|
||||
class uPower_disSysStateMsg
|
||||
{
|
||||
private:
|
||||
/* data */
|
||||
public:
|
||||
uPower_disSysStateMsg() {
|
||||
// state_of_bus_hv = {};
|
||||
// state_of_bus_hv_a = {};
|
||||
// state_of_bus_lv = {};
|
||||
// state_of_bus_lv_a = {};
|
||||
};
|
||||
~uPower_disSysStateMsg() {};
|
||||
std::string key = "uPower_disSysState_st";
|
||||
|
||||
struct state_of_bus_hv
|
||||
{
|
||||
// 使用 std::bitset 存储 16 位继电器状态
|
||||
std::bitset<16> relay_states;
|
||||
|
||||
// 燃料电池断路器
|
||||
void set_fuel_cell_breaker(bool state) { relay_states[0] = state; }
|
||||
// 动力锂电池断路器
|
||||
void set_power_lithium_battery_breaker(bool state) { relay_states[1] = state; }
|
||||
// 推进电机断路器
|
||||
void set_propulsion_motor_breaker(bool state) { relay_states[2] = state; }
|
||||
// 锂电池组仪表断路器
|
||||
void set_lithium_battery_meter_breaker(bool state) { relay_states[3] = state; }
|
||||
// DC/DC5模块断路器
|
||||
void set_dc_dc5_module_breaker(bool state) { relay_states[4] = state; }
|
||||
// 艏部高压配电箱断路器
|
||||
void set_bow_high_voltage_box_breaker(bool state) { relay_states[5] = state; }
|
||||
// 艉部FT装置4/5断路器
|
||||
void set_stern_ft_device_breaker(bool state) { relay_states[6] = state; }
|
||||
// 艉舵开关1断路器
|
||||
void set_stern_rudder_switch1_breaker(bool state) { relay_states[7] = state; }
|
||||
// 艉舵开关2断路器
|
||||
void set_stern_rudder_switch2_breaker(bool state) { relay_states[8] = state; }
|
||||
// FB预留断路器
|
||||
void set_fb_reserved_breaker(bool state) { relay_states[9] = state; }
|
||||
// TYZ预留断路器
|
||||
void set_tyz_reserved_breaker(bool state) { relay_states[10] = state; }
|
||||
// 预留断路器
|
||||
void set_reserved_breaker(bool state) { relay_states[11] = state; }
|
||||
// 初始化后 16 - 12 位为 0
|
||||
state_of_bus_hv() {
|
||||
relay_states.reset(12);
|
||||
relay_states.reset(13);
|
||||
relay_states.reset(14);
|
||||
relay_states.reset(15);
|
||||
}
|
||||
} m_state_of_bus_hv;
|
||||
|
||||
struct state_of_bus_hv_a
|
||||
{
|
||||
std::bitset<16> relay_states;
|
||||
// 艏部FT装置1 - 3 断路器
|
||||
void set_bow_ft_device_1_3_breaker(bool state) { relay_states[0] = state; }
|
||||
// 启闭机构断路器
|
||||
void set_opening_closing_mechanism_breaker(bool state) { relay_states[1] = state; }
|
||||
// 桅杆舵机控制箱断路器
|
||||
void set_mast_servo_control_box_breaker(bool state) { relay_states[2] = state; }
|
||||
// XCZ 断路器
|
||||
void set_xcz_breaker(bool state) { relay_states[3] = state; }
|
||||
// 艏舵控制箱断路器
|
||||
void set_bow_rudder_control_box_breaker(bool state) { relay_states[4] = state; }
|
||||
// 敞水盖启动电缸断路器
|
||||
void set_open_water_cover_actuator_breaker(bool state) { relay_states[5] = state; }
|
||||
// 初始化后 6 - 15 位为 0
|
||||
state_of_bus_hv_a() {
|
||||
for (int i = 6; i < 16; ++i) {
|
||||
relay_states.reset(i);
|
||||
}
|
||||
}
|
||||
}m_state_of_bus_hv_a;
|
||||
|
||||
struct state_of_bus_lv
|
||||
{
|
||||
std::bitset<16> relay_states;
|
||||
// 锂电池组(仪表)断路器
|
||||
void set_lithium_battery_group_meter_breaker(bool state) { relay_states[0] = state; }
|
||||
// 艏部低压配电箱断路器
|
||||
void set_bow_low_voltage_box_breaker(bool state) { relay_states[1] = state; }
|
||||
// UNIT4仪表DC48V断路器
|
||||
void set_unit4_meter_dc48v_breaker(bool state) { relay_states[2] = state; }
|
||||
// DC - C1直流配电板断路器
|
||||
void set_dc_c1_dc_distribution_board_breaker(bool state) { relay_states[3] = state; }
|
||||
// 预留断路器
|
||||
void set_reserved_breaker_1(bool state) { relay_states[4] = state; }
|
||||
// 预留断路器
|
||||
void set_reserved_breaker_2(bool state) { relay_states[5] = state; }
|
||||
// 应急锂电池组2断路器
|
||||
void set_emergency_lithium_battery_group_2_breaker(bool state) { relay_states[6] = state; }
|
||||
// 初始化后 7 - 15 位为 0
|
||||
state_of_bus_lv() {
|
||||
for (int i = 7; i < 16; ++i) {
|
||||
relay_states.reset(i);
|
||||
}
|
||||
}
|
||||
}m_state_of_bus_lv;
|
||||
|
||||
struct state_of_bus_lv_a
|
||||
{
|
||||
// 使用 std::bitset 存储 16 位继电器状态
|
||||
std::bitset<16> relay_states;
|
||||
// UNIT1断路器
|
||||
void set_unit1_breaker(bool state) { relay_states[0] = state; }
|
||||
// UNIT2断路器
|
||||
void set_unit2_breaker(bool state) { relay_states[1] = state; }
|
||||
// UNIT3断路器
|
||||
void set_unit3_breaker(bool state) { relay_states[2] = state; }
|
||||
// UNIT5断路器
|
||||
void set_unit5_breaker(bool state) { relay_states[3] = state; }
|
||||
// 艏部PZ装置断路器
|
||||
void set_bow_pz_device_breaker(bool state) { relay_states[4] = state; }
|
||||
// 预留断路器
|
||||
void set_reserved_breaker_1(bool state) { relay_states[5] = state; }
|
||||
// 预留断路器
|
||||
void set_reserved_breaker_2(bool state) { relay_states[6] = state; }
|
||||
// 应急锂电池组1断路器
|
||||
void set_emergency_lithium_battery_group_1_breaker(bool state) { relay_states[7] = state; }
|
||||
// 初始化后 8 - 15 位为 0
|
||||
state_of_bus_lv_a() {
|
||||
for (int i = 8; i < 16; ++i) {
|
||||
relay_states.reset(i);
|
||||
}
|
||||
}
|
||||
}m_state_of_bus_lv_a;
|
||||
|
||||
// std::string buildMsg(SystemData data,disSysBreakerList currentDisBreakerState)
|
||||
std::string buildMsg(const SystemData& data,disSysBreakerList currentDisBreakerState)
|
||||
{
|
||||
//构建配电系统状态报告
|
||||
Json::Value dis;
|
||||
// disBus1Breaker dis1 = currentDisBreakerState.bus1Breaker;
|
||||
m_state_of_bus_hv.set_fuel_cell_breaker((data.power_bus_status.fuelCellCircuitBreaker == 1));
|
||||
m_state_of_bus_hv.set_power_lithium_battery_breaker((data.power_bus_status.powerLithiumBatteryCircuitBreaker == 1));
|
||||
m_state_of_bus_hv.set_propulsion_motor_breaker((data.power_bus_status.propulsionMotorCircuitBreaker == 1));
|
||||
m_state_of_bus_hv.set_lithium_battery_meter_breaker((data.power_bus_status.lithiumBatteryGroupInstrumentCircuitBreaker == 1));
|
||||
m_state_of_bus_hv.set_dc_dc5_module_breaker((data.power_bus_status.dcDc5ModuleCircuitBreaker == 1));
|
||||
m_state_of_bus_hv.set_bow_high_voltage_box_breaker((data.power_bus_status.bowHighVoltageDistributionBoxCircuitBreaker == 1));
|
||||
m_state_of_bus_hv.set_stern_ft_device_breaker((data.power_bus_status.sternFTDevice45CircuitBreaker == 1));
|
||||
m_state_of_bus_hv.set_stern_rudder_switch1_breaker((data.power_bus_status.sternRudderSwitch1CircuitBreaker == 1));
|
||||
m_state_of_bus_hv.set_stern_rudder_switch2_breaker((data.power_bus_status.sternRudderSwitch2CircuitBreaker == 1));
|
||||
m_state_of_bus_hv.set_fb_reserved_breaker((data.power_bus_status.fbReservedCircuitBreaker == 1));
|
||||
m_state_of_bus_hv.set_tyz_reserved_breaker((data.power_bus_status.tyzReservedCircuitBreaker == 1));
|
||||
m_state_of_bus_hv.set_reserved_breaker((data.power_bus_status.reservedCircuitBreaker == 1));
|
||||
dis["HVolABusBreaker_uint16"] = m_state_of_bus_hv.relay_states.to_ulong();
|
||||
|
||||
|
||||
m_state_of_bus_hv_a.set_bow_ft_device_1_3_breaker((data.power_a_bus_status.bowFTDevice123CircuitBreaker == 1));
|
||||
m_state_of_bus_hv_a.set_opening_closing_mechanism_breaker((data.power_a_bus_status.actuatorCircuitBreaker == 1));
|
||||
m_state_of_bus_hv_a.set_mast_servo_control_box_breaker((data.power_a_bus_status.mastSteeringGearControlBoxCircuitBreaker == 1));
|
||||
m_state_of_bus_hv_a.set_xcz_breaker((data.power_a_bus_status.xczCircuitBreaker == 1));
|
||||
m_state_of_bus_hv_a.set_bow_rudder_control_box_breaker((data.power_a_bus_status.bowRudderControlBoxCircuitBreaker == 1));
|
||||
m_state_of_bus_hv_a.set_open_water_cover_actuator_breaker((data.power_a_bus_status.openWaterCoverStartCylinderCircuitBreaker == 1));
|
||||
dis["HVolBBusBreaker_uint16"] = m_state_of_bus_hv_a.relay_states.to_ulong();
|
||||
|
||||
m_state_of_bus_lv.set_bow_low_voltage_box_breaker((data.instrument_main_bus_status.bowLowVoltageDistributionBoxCircuitBreaker == 1));
|
||||
m_state_of_bus_lv.set_dc_c1_dc_distribution_board_breaker((data.instrument_main_bus_status.dcC1DCDistributionPanelCircuitBreaker == 1));
|
||||
m_state_of_bus_lv.set_unit4_meter_dc48v_breaker((data.instrument_main_bus_status.unit4InstrumentDC48VCircuitBreaker == 1));
|
||||
m_state_of_bus_lv.set_lithium_battery_group_meter_breaker((data.instrument_main_bus_status.lithiumBatteryGroupInstrumentCircuitBreaker == 1));
|
||||
m_state_of_bus_lv.set_emergency_lithium_battery_group_2_breaker((data.instrument_main_bus_status.emergencyLithiumBatteryGroup2CircuitBreaker == 1));
|
||||
m_state_of_bus_lv.set_reserved_breaker_1((data.instrument_main_bus_status.reservedCircuitBreaker1 == 1));
|
||||
m_state_of_bus_lv.set_reserved_breaker_2((data.instrument_main_bus_status.reservedCircuitBreaker2 == 1));
|
||||
dis["HVolBusBreaker_uint16"] = m_state_of_bus_lv.relay_states.to_ulong();
|
||||
|
||||
|
||||
m_state_of_bus_lv_a.set_unit1_breaker((data.instrument_bus_status.unit1CircuitBreaker == 1));
|
||||
m_state_of_bus_lv_a.set_unit2_breaker((data.instrument_bus_status.unit2CircuitBreaker == 1));
|
||||
m_state_of_bus_lv_a.set_unit3_breaker((data.instrument_bus_status.unit3CircuitBreaker == 1));
|
||||
m_state_of_bus_lv_a.set_unit5_breaker((data.instrument_bus_status.unit5CircuitBreaker == 1));
|
||||
m_state_of_bus_lv_a.set_bow_pz_device_breaker((data.instrument_bus_status.bowPZDeviceCircuitBreaker == 1));
|
||||
m_state_of_bus_lv_a.set_reserved_breaker_1((data.instrument_bus_status.reservedCircuitBreaker1 == 1));
|
||||
m_state_of_bus_lv_a.set_reserved_breaker_2((data.instrument_bus_status.reservedCircuitBreaker2 == 1));
|
||||
m_state_of_bus_lv_a.set_emergency_lithium_battery_group_1_breaker((data.instrument_bus_status.emergencyLithiumBatteryGroup1CircuitBreaker == 1));
|
||||
dis["LVolBusBreaker_uint16"] = m_state_of_bus_lv_a.relay_states.to_ulong();
|
||||
|
||||
//构建配电系统故障码
|
||||
Json::Value faultCodeDis_array = Json::Value(Json::arrayValue);
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(data.faultCodeMutex);
|
||||
for(auto val : data.disSysFaultCode)
|
||||
{
|
||||
faultCodeDis_array.append(val);
|
||||
}
|
||||
}
|
||||
dis["faultCode_array"] = faultCodeDis_array;
|
||||
|
||||
Json::StreamWriterBuilder writerBuilder;
|
||||
writerBuilder.settings_["indentation"] = "";
|
||||
return Json::writeString(writerBuilder, dis);
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -1,220 +0,0 @@
|
||||
#ifndef U_POWER_EQUINSSTATE_H
|
||||
#define U_POWER_EQUINSSTATE_H
|
||||
#include "../driver.h"
|
||||
#include "string"
|
||||
#include "json/json.h"
|
||||
#include <bitset>
|
||||
class uPower_equInsStateMsg
|
||||
{
|
||||
private:
|
||||
/* data */
|
||||
public:
|
||||
uPower_equInsStateMsg() {
|
||||
// 初始化成员变量
|
||||
//state全部初始化为0
|
||||
memset(&state, 0, sizeof(state));
|
||||
}; // 添加默认构造函数实现
|
||||
~uPower_equInsStateMsg() {}; // 添加析构函数实现
|
||||
std::string key = "uPower_equInsState_fb";
|
||||
|
||||
struct SensorState
|
||||
{
|
||||
unsigned int singleBeamSonar1 : 1; // 单波束声呐1
|
||||
unsigned int singleBeamSonar2 : 1; // 单波束声呐2
|
||||
unsigned int singleBeamSonar3 : 1; // 单波束声呐3
|
||||
unsigned int singleBeamSonar4 : 1; // 单波束声呐4
|
||||
unsigned int singleBeamSonar5 : 1; // 单波束声呐5
|
||||
unsigned int singleBeamSonar6 : 1; // 单波束声呐6
|
||||
unsigned int singleBeamSonar7 : 1; // 单波束声呐7
|
||||
unsigned int singleBeamSonar8 : 1; // 单波束声呐8
|
||||
unsigned int forwardSonar : 1; // 前视声呐
|
||||
unsigned int ctd1 : 1; // CTD1
|
||||
unsigned int ctd2 : 1; // CTD2
|
||||
unsigned int soundVelocityMeter : 1; // 声速仪
|
||||
unsigned int ntp : 1; // 深度计
|
||||
unsigned int depthMeter1 : 1; // 深度计1
|
||||
unsigned int depthMeter2 : 1; // 深度计2
|
||||
unsigned int depthMeter3 : 1; // 深度计3
|
||||
};
|
||||
struct ActuatorState
|
||||
{
|
||||
unsigned int openCloseMechanism1 : 1; // bit 0 启闭机构1
|
||||
unsigned int openCloseMechanism2 : 1; // bit 1 启闭机构2
|
||||
unsigned int openCloseMechanism3 : 1; // bit 2 启闭机构3
|
||||
unsigned int openCloseMechanism4 : 1; // bit 3 启闭机构4
|
||||
unsigned int openCloseMechanism5 : 1; // bit 4 启闭机构5
|
||||
unsigned int openCloseMechanism6 : 1; // bit 5 启闭机构6
|
||||
unsigned int reserved1 : 2; // bit 6-7 保留
|
||||
unsigned int openWaterMechanism1 : 1; // bit 8 敞水机构1
|
||||
unsigned int openWaterMechanism2 : 1; // bit 9 敞水机构2
|
||||
unsigned int openWaterMechanism3 : 1; // bit 10 敞水机构3
|
||||
unsigned int openWaterMechanism4 : 1; // bit 11 敞水机构4
|
||||
unsigned int openWaterMechanism5 : 1; // bit 12 敞水机构5
|
||||
unsigned int openWaterMechanism6 : 1; // bit 13 敞水机构6
|
||||
unsigned int openWaterMechanism7 : 1; // bit 14 敞水机构7
|
||||
unsigned int openWaterMechanism8 : 1; // bit 15 敞水机构8
|
||||
};
|
||||
|
||||
struct MotionState
|
||||
{
|
||||
unsigned int sternRudder1 : 1; // bit 0 艉部舵机1
|
||||
unsigned int sternRudder2 : 1; // bit 1 艉部舵机2
|
||||
unsigned int sternRudder3 : 1; // bit 2 艉部舵机3
|
||||
unsigned int sternRudder4 : 1; // bit 3 艉部舵机4
|
||||
unsigned int bowRudder : 1; // bit 4 艏舵电缸
|
||||
unsigned int waterInjection : 1; // bit 5 注水机构
|
||||
unsigned int propulsionMotor : 1; // bit 6 推进电机
|
||||
unsigned int buoyancyAdjust1 : 1; // bit 7 浮调机构(艏部)1
|
||||
unsigned int buoyancyAdjust2 : 1; // bit 8 浮调机构(艏部)2
|
||||
unsigned int buoyancyAdjust3 : 1; // bit 9 浮调机构(艏部)3
|
||||
unsigned int buoyancyAdjust4 : 1; // bit 10 浮调机构(艉部)4
|
||||
unsigned int buoyancyAdjust5 : 1; // bit 11 浮调机构(艉部)5
|
||||
unsigned int DVL : 1; // bit 12 DVL
|
||||
unsigned int INS : 1; // bit 13 惯导系统
|
||||
unsigned int bowRudderLeft : 1; // bit 14 艏舵左舵机
|
||||
unsigned int bowRudderRight : 1; // bit 15 艏右舵舵机
|
||||
};
|
||||
struct LoadcommState
|
||||
{
|
||||
unsigned int payloadControl : 1; // bit 0 载荷发控
|
||||
unsigned int optMast : 1; // bit 1 光电桅杆
|
||||
unsigned int emMast : 1; // bit 2 电磁桅杆
|
||||
unsigned int reserved1 : 1; // bit 3 保留
|
||||
unsigned int sideSonar : 1; // bit 4 舷侧声纳
|
||||
unsigned int towedSonar : 1; // bit 5 拖曳声纳
|
||||
unsigned int reserved2 : 2; // bit 6-7 保留
|
||||
unsigned int commMast : 1; // bit 8 通信桅杆
|
||||
unsigned int midLowFreqSonar : 1; // bit 9 中低频声呐
|
||||
unsigned int highFreqComm : 1; // bit 10 高频声通机
|
||||
unsigned int buoySystem : 1; // bit 11 浮标系统
|
||||
unsigned int commMastRudder : 1; // bit 12 通信桅杆舵机
|
||||
unsigned int optMastRudder : 1; // bit 13 光电桅杆舵机
|
||||
unsigned int emMastRudder : 1; // bit 14 电磁桅杆舵机
|
||||
unsigned int reserved3 : 1; // bit 15 保留
|
||||
};
|
||||
struct ThrowPowerState
|
||||
{
|
||||
unsigned int bowThrow : 1; // bit 0 艏部抛载
|
||||
unsigned int reserved1 : 7; // bit 1-7 保留
|
||||
unsigned int fuelCellController : 1; // bit 8 燃料电池控制器
|
||||
unsigned int instrumentPanel : 1; // bit 9 仪表配电板
|
||||
unsigned int powerPanel : 1; // bit 10 动力配电板
|
||||
unsigned int instrumentBattery : 1; // bit 11 仪表锂电池
|
||||
unsigned int powerBattery : 1; // bit 12 动力锂电
|
||||
unsigned int sternThrow : 1; // bit 13 艉部抛载
|
||||
unsigned int reserved2 : 2; // bit 14-15 保留
|
||||
};
|
||||
struct uPower_equInsState
|
||||
{
|
||||
SensorState sensorState;
|
||||
ActuatorState actuatorState;
|
||||
MotionState motionState;
|
||||
LoadcommState loadcommState;
|
||||
ThrowPowerState throwPowerState;
|
||||
} state;
|
||||
std::string buildMsg(DriverTable s)
|
||||
{
|
||||
// 按照协议格式填充数据
|
||||
|
||||
// 传感器状态赋值
|
||||
state.sensorState.singleBeamSonar1 = s.singleBeamSonar1;
|
||||
state.sensorState.singleBeamSonar2 = s.singleBeamSonar2;
|
||||
state.sensorState.singleBeamSonar3 = s.singleBeamSonar3;
|
||||
state.sensorState.singleBeamSonar4 = s.singleBeamSonar4;
|
||||
state.sensorState.singleBeamSonar5 = s.singleBeamSonar5;
|
||||
state.sensorState.singleBeamSonar6 = s.singleBeamSonar6;
|
||||
state.sensorState.singleBeamSonar7 = s.singleBeamSonar7;
|
||||
state.sensorState.singleBeamSonar8 = s.singleBeamSonar8;
|
||||
state.sensorState.forwardSonar = s.forwardSonar;
|
||||
state.sensorState.ctd1 = s.ctd1;
|
||||
state.sensorState.ctd2 = s.ctd2;
|
||||
state.sensorState.soundVelocityMeter = s.soundVeloc;
|
||||
state.sensorState.ntp = s.ntp;
|
||||
state.sensorState.depthMeter1 = s.depth1;
|
||||
state.sensorState.depthMeter2 = s.depth2;
|
||||
state.sensorState.depthMeter3 = s.depth3;
|
||||
|
||||
// 执行机构状态赋值
|
||||
state.actuatorState.openCloseMechanism1 = s.bowCover1;
|
||||
state.actuatorState.openCloseMechanism2 = s.bowCover2;
|
||||
state.actuatorState.openCloseMechanism3 = s.bowCover3;
|
||||
state.actuatorState.openCloseMechanism4 = s.bowCover4;
|
||||
state.actuatorState.openCloseMechanism5 = s.bowCover5;
|
||||
state.actuatorState.openCloseMechanism6 = s.bowCover6;
|
||||
state.actuatorState.openWaterMechanism1 = s.bowWaterInet1;
|
||||
state.actuatorState.openWaterMechanism2 = s.bowWaterInet2;
|
||||
state.actuatorState.openWaterMechanism3 = s.bowWaterInet3;
|
||||
state.actuatorState.openWaterMechanism4 = s.bowWaterInet4;
|
||||
state.actuatorState.openWaterMechanism5 = s.bowWaterInet5;
|
||||
state.actuatorState.openWaterMechanism6 = s.bowWaterInet6;
|
||||
state.actuatorState.openWaterMechanism7 = s.bowWaterInet7;
|
||||
state.actuatorState.openWaterMechanism8 = s.bowWaterInet8;
|
||||
|
||||
// 运动状态赋值
|
||||
state.motionState.sternRudder1 = s.sternRudderServo1;
|
||||
state.motionState.sternRudder2 = s.sternRudderServo2;
|
||||
state.motionState.sternRudder3 = s.sternRudderServo3;
|
||||
state.motionState.sternRudder4 = s.sternRudderServo4;
|
||||
|
||||
state.motionState.bowRudder = s.bowRudderDeploy;
|
||||
|
||||
state.motionState.waterInjection = s.waterInject;
|
||||
|
||||
state.motionState.propulsionMotor = s.thruster;
|
||||
state.motionState.buoyancyAdjust1 = s.buoyancyAdjust1;
|
||||
state.motionState.buoyancyAdjust2 = s.buoyancyAdjust2;
|
||||
state.motionState.buoyancyAdjust3 = s.buoyancyAdjust3;
|
||||
state.motionState.buoyancyAdjust4 = s.buoyancyAdjust4;
|
||||
state.motionState.buoyancyAdjust5 = s.buoyancyAdjust5;
|
||||
state.motionState.DVL = s.DVL;
|
||||
state.motionState.INS = s.ins;
|
||||
|
||||
state.motionState.bowRudderLeft = s.bowRudderServo1;
|
||||
state.motionState.bowRudderRight = s.bowRudderServo2;
|
||||
|
||||
// 负载通信状态赋值
|
||||
state.loadcommState.payloadControl = s.launchControler;
|
||||
state.loadcommState.sideSonar = s.sideSonar;
|
||||
state.loadcommState.optMast = s.photoSensor;
|
||||
state.loadcommState.emMast = s.electSensor;
|
||||
state.loadcommState.buoySystem = s.buoyage;
|
||||
state.loadcommState.commMastRudder = s.mastLiftingServo;
|
||||
state.loadcommState.optMastRudder = s.mastLiftingServo;
|
||||
state.loadcommState.emMastRudder = s.mastLiftingServo;
|
||||
state.loadcommState.highFreqComm = s.USBL;
|
||||
state.loadcommState.midLowFreqSonar = s.lowFreqSonar;
|
||||
state.loadcommState.commMast = s.commMast;
|
||||
state.loadcommState.towedSonar = 0; //拖曳声纳未安装,默认为0
|
||||
|
||||
// 抛载和电源状态赋值
|
||||
state.throwPowerState.bowThrow = s.bowThrow; // 艏部抛载
|
||||
state.throwPowerState.sternThrow = s.sternThrow; // 艉部抛载
|
||||
state.throwPowerState.fuelCellController = 1; // 燃料电池控制器 默认开启
|
||||
state.throwPowerState.instrumentPanel = 1; // 仪表配电板 默认开启
|
||||
state.throwPowerState.powerPanel = 1; // 动力配电板 默认开启
|
||||
state.throwPowerState.instrumentBattery = 1; // 仪表锂电池 默认开启
|
||||
state.throwPowerState.powerBattery = 1; // 动力锂电 默认开启
|
||||
|
||||
// 转化为json格式
|
||||
Json::Value root;
|
||||
root["sensor_int16"] = *reinterpret_cast<uint16_t*>(&state.sensorState);
|
||||
root["actuator_int16"] = *reinterpret_cast<uint16_t*>(&state.actuatorState);
|
||||
root["motion_int16"] = *reinterpret_cast<uint16_t*>(&state.motionState);
|
||||
root["loadcomm_int16"] = *reinterpret_cast<uint16_t*>(&state.loadcommState);
|
||||
root["throwpower_int16"] = *reinterpret_cast<uint16_t*>(&state.throwPowerState);
|
||||
|
||||
//以二进制形式打印
|
||||
// std::cout << "sensor_int16: " << std::bitset<16>(*reinterpret_cast<uint16_t*>(&state.sensorState)) << std::endl;
|
||||
// std::cout << "actuator_int16: " << std::bitset<16>(*reinterpret_cast<uint16_t*>(&state.actuatorState)) << std::endl;
|
||||
// std::cout << "motion_int16: " << std::bitset<16>(*reinterpret_cast<uint16_t*>(&state.motionState)) << std::endl;
|
||||
// std::cout << "loadcomm_int16: " << std::bitset<16>(*reinterpret_cast<uint16_t*>(&state.loadcommState)) << std::endl;
|
||||
// std::cout << "throwpower_int16: " << std::bitset<16>(*reinterpret_cast<uint16_t*>(&state.throwPowerState)) << std::endl;
|
||||
|
||||
// 返回json字符串
|
||||
Json::StreamWriterBuilder writerBuilder;
|
||||
writerBuilder.settings_["indentation"] = ""; // 紧凑格式,无缩进
|
||||
return Json::writeString(writerBuilder, root);
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user