Files
H100PowerManger/src/pPowerManger/sqlit3/SQLite.cpp
T
zjk f50c7bd612 数据库:下位机交互数据全量落库,SQLite 封装重构
- 新增 msg_log 原始帧表,RX/TX 双向记录原始字节与校验结果
- SQLite 封装改为描述符驱动的泛化 insert,删除 10 个手写 SQL
- 新增 ccuSetParmCmd/ccuSetParmFb 表,补齐 CCU 参数设定反馈落库
- 错误防崩溃:统一加锁、fail-open 降级、损坏自动重建、析构顺序修复
- WAL/迁移/预编译语句路径,数据库路径支持 mission 配置 dbpath
- 清理未使用的 shell.c/sqlite3ext.h/SQLite.zip
2026-08-19 16:28:41 +08:00

997 lines
39 KiB
C++

#include "SQLite.h"
#include <string>
#include <vector>
#include <chrono>
#include <cstdio>
#include "../logc/loguru.hpp"
namespace {
const int SCHEMA_VERSION = 1;
}
SQLite::SQLite(const std::string& dbPath)
: m_db(nullptr), m_status(Status::Disabled), m_dbPath(dbPath)
{
int rc = sqlite3_open_v2(dbPath.c_str(), &m_db,
SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE | SQLITE_OPEN_NOMUTEX,
nullptr);
if (rc != SQLITE_OK) {
m_lastError = m_db ? sqlite3_errmsg(m_db) : "unknown error";
LOG_F(ERROR, "无法打开数据库 %s: %s", dbPath.c_str(), m_lastError.c_str());
if (m_db) { sqlite3_close(m_db); m_db = nullptr; }
m_status = Status::Disabled;
return;
}
m_status = Status::OK;
if (!applyPragmas()) {
m_status = Status::Degraded;
}
if (!migrate()) {
int err = sqlite3_errcode(m_db);
if (err == SQLITE_CORRUPT || err == SQLITE_NOTADB) {
LOG_F(ERROR, "数据库损坏,尝试备份并重建: %s", dbPath.c_str());
sqlite3_close(m_db);
m_db = nullptr;
std::string backup = dbPath + ".corrupt";
std::rename(dbPath.c_str(), backup.c_str());
if (sqlite3_open_v2(dbPath.c_str(), &m_db,
SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE | SQLITE_OPEN_NOMUTEX,
nullptr) == SQLITE_OK) {
m_status = Status::OK;
applyPragmas();
if (!migrate()) {
if (m_status == Status::OK) m_status = Status::Degraded;
}
} else {
m_status = Status::Disabled;
}
} else if (m_status == Status::OK) {
m_status = Status::Degraded;
}
}
}
SQLite::~SQLite()
{
if (m_db) sqlite3_close(m_db);
}
std::string SQLite::lastError() const
{
std::lock_guard<std::mutex> lock(m_dbMutex);
return m_lastError;
}
bool SQLite::setError(int rc, const char* op)
{
m_lastError = m_db ? sqlite3_errmsg(m_db) : "database not open";
LOG_F(ERROR, "SQLite %s 失败 (rc=%d): %s", op, rc, m_lastError.c_str());
if (rc == SQLITE_CORRUPT || rc == SQLITE_NOTADB) {
m_status = Status::Disabled;
} else if (rc == SQLITE_FULL || rc == SQLITE_BUSY || rc == SQLITE_LOCKED) {
m_status = Status::Degraded;
}
return false;
}
bool SQLite::applyPragmas()
{
const char* pragmas[] = {
"PRAGMA journal_mode=WAL;",
"PRAGMA synchronous=NORMAL;",
"PRAGMA busy_timeout=5000;",
"PRAGMA foreign_keys=OFF;"
};
for (const char* p : pragmas) {
if (sqlite3_exec(m_db, p, nullptr, nullptr, nullptr) != SQLITE_OK) {
setError(sqlite3_errcode(m_db), p);
return false;
}
}
return true;
}
bool SQLite::migrate()
{
int version = 0;
sqlite3_stmt* stmt = nullptr;
if (sqlite3_prepare_v2(m_db, "PRAGMA user_version;", -1, &stmt, nullptr) == SQLITE_OK) {
if (sqlite3_step(stmt) == SQLITE_ROW) version = sqlite3_column_int(stmt, 0);
sqlite3_finalize(stmt);
}
if (!createAllTablesUnlocked()) return false;
if (version < SCHEMA_VERSION) {
std::string sql = "PRAGMA user_version = " + std::to_string(SCHEMA_VERSION) + ";";
sqlite3_exec(m_db, sql.c_str(), nullptr, nullptr, nullptr);
}
return true;
}
bool SQLite::createTableInternal(const std::string& tableName, const std::string& columns)
{
std::string sql = "CREATE TABLE IF NOT EXISTS " + tableName + " (" + columns + ");";
char* errMsg = nullptr;
int rc = sqlite3_exec(m_db, sql.c_str(), nullptr, nullptr, &errMsg);
if (rc != SQLITE_OK) {
m_lastError = errMsg ? errMsg : "create table failed";
LOG_F(ERROR, "创建表失败: %s (%s)", tableName.c_str(), m_lastError.c_str());
if (errMsg) sqlite3_free(errMsg);
return false;
}
return true;
}
bool SQLite::createTable(const std::string& tableName, const std::string& columns)
{
std::lock_guard<std::mutex> lock(m_dbMutex);
if (!m_db) {
m_lastError = "database not open";
return false;
}
return createTableInternal(tableName, columns);
}
bool SQLite::createTable()
{
std::lock_guard<std::mutex> lock(m_dbMutex);
if (!m_db) {
m_lastError = "database not open";
return false;
}
return createAllTablesUnlocked();
}
bool SQLite::createAllTablesUnlocked()
{
// 1. ccuState
std::string ccuStateColumns = R"(
id INTEGER PRIMARY KEY AUTOINCREMENT,
timestamp DATETIME DEFAULT (datetime('now', 'localtime')),
fc_mode INTEGER,
fc_status INTEGER,
fc_fault_level INTEGER,
output_power_limit INTEGER,
total_generation_time INTEGER,
total_generation_power INTEGER,
fault_level_1 INTEGER,
fault_level_2 INTEGER,
fault_level_3 INTEGER,
fault_level_4 INTEGER,
hydrogen_capacity INTEGER,
liquid_oxygen_capacity INTEGER,
palladium_temp INTEGER,
main_pipe_pressure INTEGER,
aux_pipe_pressure INTEGER,
cabin_pressure1 INTEGER,
cabin_pressure2 INTEGER,
cabin_temp1 INTEGER,
cabin_temp2 INTEGER,
cabin_humidity1 INTEGER,
cabin_humidity2 INTEGER,
flame_detector1 INTEGER,
flame_detector2 INTEGER,
h2_concentration1 INTEGER,
h2_concentration2 INTEGER,
h2_concentration3 INTEGER,
o2_concentration1 INTEGER,
o2_concentration2 INTEGER,
ch3oh_concentration1 INTEGER,
ch3oh_concentration2 INTEGER,
reserved1_1 INTEGER, reserved1_2 INTEGER,
emergency_battery1_voltage INTEGER,
emergency_battery1_current INTEGER,
emergency_battery1_max_temp INTEGER,
emergency_battery1_fault_word INTEGER,
emergency_battery2_voltage INTEGER,
emergency_battery2_current INTEGER,
emergency_battery2_max_temp INTEGER,
emergency_battery2_fault_word INTEGER,
cabin_ox_concentration INTEGER,
cabin_temperature INTEGER,
cabin_humidity INTEGER,
cabin_pressure INTEGER,
power_cabin_ox_concentration INTEGER,
power_cabin_temperature INTEGER,
power_cabin_humidity INTEGER,
power_cabin_pressure INTEGER,
reserved2 INTEGER,
dyn_alarm_flag1 INTEGER, dyn_alarm_flag2 INTEGER, dyn_alarm_flag3 INTEGER,
dyn_alarm_flag4 INTEGER, dyn_alarm_flag5 INTEGER, dyn_alarm_flag6 INTEGER,
ins_alarm_flag1 INTEGER, ins_alarm_flag2 INTEGER, ins_alarm_flag3 INTEGER,
ins_alarm_flag4 INTEGER, ins_alarm_flag5 INTEGER, ins_alarm_flag6 INTEGER,
ins_relay_status1 INTEGER,
ins_relay_status2 INTEGER,
dyn_relay_status1 INTEGER,
dyn_relay_status2 INTEGER,
ins_max_discharge_power INTEGER,
dyn_max_discharge_power INTEGER,
ins_soc INTEGER,
dyn_soc INTEGER,
ins_total_energy INTEGER,
dyn_total_energy INTEGER,
ins_power_input INTEGER,
dyn_power_input INTEGER,
ins_charge_status INTEGER,
dyn_charge_status INTEGER,
ins_voltage_link INTEGER,
ins_voltage_pack INTEGER,
ins_current INTEGER,
ins_resistance_pos INTEGER,
ins_resistance_neg INTEGER,
dyn_voltage_link INTEGER,
dyn_voltage_pack INTEGER,
dyn_current INTEGER,
dyn_resistance_pos INTEGER,
dyn_resistance_neg INTEGER,
ins_emergency_status INTEGER,
dyn_emergency_status INTEGER,
reserved3_1 INTEGER, reserved3_2 INTEGER,
ins_soc_threshold1 INTEGER,
ins_soc_threshold2 INTEGER,
ins_soc_threshold3 INTEGER,
dyn_soc_threshold1 INTEGER,
dyn_soc_threshold2 INTEGER,
dyn_soc_threshold3 INTEGER,
ins_power_limit1 INTEGER,
ins_power_limit2 INTEGER,
dyn_power_limit1 INTEGER,
dyn_power_limit2 INTEGER,
device_online_flag1 INTEGER,
device_online_flag2 INTEGER,
reserved4 INTEGER,
heartbeat INTEGER
)";
if (!createTableInternal("ccuState", ccuStateColumns)) return false;
// 2. disHighVolBusState
std::string disHighVolBusColumns = R"(
id INTEGER PRIMARY KEY AUTOINCREMENT,
timestamp DATETIME DEFAULT (datetime('now', 'localtime')),
fuelCellCircuitBreaker INTEGER,
powerLithiumBatteryCircuitBreaker INTEGER,
propulsionMotorCircuitBreaker INTEGER,
lithiumBatteryGroupInstrumentCircuitBreaker INTEGER,
dcDc5ModuleCircuitBreaker INTEGER,
bowHighVoltageDistributionBoxCircuitBreaker INTEGER,
sternFTDevice45CircuitBreaker INTEGER,
sternRudderSwitch1CircuitBreaker INTEGER,
sternRudderSwitch2CircuitBreaker INTEGER,
fbReservedCircuitBreaker INTEGER,
tyzReservedCircuitBreaker INTEGER,
reservedCircuitBreaker INTEGER,
dcDcFaultWord1 INTEGER,
dcDcFaultWord2 INTEGER,
powerBusInsulationStatus INTEGER,
aBusInsulationStatus INTEGER,
meterPowerLossSignal INTEGER,
emergencyPowerLossSignal INTEGER,
powerBusVoltage INTEGER,
dcDc5ModuleCurrent INTEGER,
powerBusCurrent INTEGER,
busbarAVoltage INTEGER,
propulsionMotorControlBoxCurrent INTEGER,
busbarACurrent INTEGER,
lithiumBatteryGroupMeterCurrent INTEGER,
bowHighVoltageDistributionBoxCurrent INTEGER,
sternFTDevice45Current INTEGER,
tyzReservedSwitchCurrent INTEGER,
sternRudderSwitch1Current INTEGER,
reservedCurrent1 INTEGER,
sternRudderSwitch2Current INTEGER,
reservedCurrent2 INTEGER,
fbReservedSwitchCurrent INTEGER,
reservedCurrent3 INTEGER,
coolWaterPressure INTEGER
)";
if (!createTableInternal("disHighVolBusState", disHighVolBusColumns)) return false;
// 3. disHighAVolBusState
std::string disHighAVolBusColumns = R"(
id INTEGER PRIMARY KEY AUTOINCREMENT,
timestamp DATETIME DEFAULT (datetime('now', 'localtime')),
bowFTDevice123CircuitBreaker INTEGER,
actuatorCircuitBreaker INTEGER,
mastSteeringGearControlBoxCircuitBreaker INTEGER,
xczCircuitBreaker INTEGER,
bowRudderControlBoxCircuitBreaker INTEGER,
openWaterCoverStartCylinderCircuitBreaker INTEGER,
instrumentPowerFailureSignal INTEGER,
emergencyPowerFailureSignal INTEGER,
waterIngressionAlarm INTEGER,
busbarBVoltage INTEGER,
busbarBCurrent INTEGER,
bowFTDevice123Current INTEGER,
actuatorCurrent INTEGER,
mastSteeringGearControlBoxCurrent INTEGER,
xczCurrent INTEGER,
bowRudderControlBoxCurrent INTEGER,
openWaterCoverStartCylinderCurrent INTEGER
)";
if (!createTableInternal("disHighAVolBusState", disHighAVolBusColumns)) return false;
// 4. disLowMainBusState
std::string disLowMainBusColumns = R"(
id INTEGER PRIMARY KEY AUTOINCREMENT,
timestamp DATETIME DEFAULT (datetime('now', 'localtime')),
lithiumBatteryGroupInstrumentCircuitBreaker INTEGER,
bowLowVoltageDistributionBoxCircuitBreaker INTEGER,
unit4InstrumentDC48VCircuitBreaker INTEGER,
dcC1DCDistributionPanelCircuitBreaker INTEGER,
reservedCircuitBreaker1 INTEGER,
reservedCircuitBreaker2 INTEGER,
emergencyLithiumBatteryGroup2CircuitBreaker INTEGER,
instrumentPowerFailureSignal INTEGER,
emergencyPowerFailureSignal INTEGER,
instrumentBusbarInsulationLow INTEGER,
instrumentBusbarVoltage INTEGER,
bowLowVoltageDistributionBoxCurrent INTEGER,
dcC1InstrumentDC48VCurrent INTEGER,
reservedCurrent1 INTEGER,
emergencyLithiumBatteryGroup2Current INTEGER,
lithiumBatteryGroupInstrumentCurrent INTEGER,
unit4InstrumentDC48VCurrent INTEGER,
reservedCurrent2 INTEGER,
emergency2BusbarVoltage INTEGER,
compositeEnergyManagementSystemEmergencyDC48VCurrent INTEGER,
fuelCellSecuritySystemEmergencyDC48VCurrent INTEGER,
plcControlPowerCurrent INTEGER
)";
if (!createTableInternal("disLowMainBusState", disLowMainBusColumns)) return false;
// 5. disLowBusState
std::string disLowBusColumns = R"(
id INTEGER PRIMARY KEY AUTOINCREMENT,
timestamp DATETIME DEFAULT (datetime('now', 'localtime')),
unit1CircuitBreaker INTEGER,
unit2CircuitBreaker INTEGER,
unit3CircuitBreaker INTEGER,
unit5CircuitBreaker INTEGER,
bowPZDeviceCircuitBreaker INTEGER,
reservedCircuitBreaker1 INTEGER,
reservedCircuitBreaker2 INTEGER,
emergencyLithiumBatteryGroup1CircuitBreaker INTEGER,
powerFailureSignal INTEGER,
emergencyPowerFailureSignal INTEGER,
waterIngressionAlarm INTEGER,
instrumentBusbarVoltage INTEGER,
instrumentBusbarCurrent INTEGER,
unit1Current INTEGER,
unit2Current INTEGER,
unit3Current INTEGER,
unit5Current INTEGER,
bowPZDeviceCurrent INTEGER,
emergencyLithiumBatteryGroup1Current INTEGER,
emergency1BusbarVoltage INTEGER
)";
if (!createTableInternal("disLowBusState", disLowBusColumns)) return false;
// 6. ccuColCmd
std::string ccuColCmdColumns = R"(
id INTEGER PRIMARY KEY AUTOINCREMENT,
timestamp DATETIME DEFAULT (datetime('now', 'localtime')),
workCondition INTEGER,
fcuCmd INTEGER,
fcuPowerEfficiency INTEGER,
insChargeEnable INTEGER,
insBatCmd INTEGER,
powerBatCmd INTEGER,
powerBatEfficiency INTEGER,
heartbeat INTEGER,
masterState INTEGER,
paceholder1 INTEGER,
paceholder2 INTEGER
)";
if (!createTableInternal("ccuColCmd", ccuColCmdColumns)) return false;
// 7. disHighVolBusCmd
std::string disHighVolBusCmdColumns = R"(
id INTEGER PRIMARY KEY AUTOINCREMENT,
timestamp DATETIME DEFAULT (datetime('now', 'localtime')),
fuelCellCircuitBreaker INTEGER,
powerLithiumBatteryCircuitBreaker INTEGER,
propulsionMotorCircuitBreaker INTEGER,
lithiumBatteryGroupInstrumentCircuitBreaker INTEGER,
dcDc5ModuleCircuitBreaker INTEGER,
bowHighVoltageDistributionBoxCircuitBreaker INTEGER,
sternFTDevice45CircuitBreaker INTEGER,
sternRudderSwitch1CircuitBreaker INTEGER,
sternRudderSwitch2CircuitBreaker INTEGER,
fbReservedCircuitBreaker INTEGER,
tyzReservedCircuitBreaker INTEGER,
reservedCircuitBreaker INTEGER,
dcdc5Module INTEGER,
coolingSystem INTEGER
)";
if (!createTableInternal("disHighVolBusCmd", disHighVolBusCmdColumns)) return false;
// 8. disHighAVolBusCmd
std::string disHighAVolBusCmdColumns = R"(
id INTEGER PRIMARY KEY AUTOINCREMENT,
timestamp DATETIME DEFAULT (datetime('now', 'localtime')),
bowFTDevice123CircuitBreaker INTEGER,
actuatorCircuitBreaker INTEGER,
mastSteeringGearControlBoxCircuitBreaker INTEGER,
xczCircuitBreaker INTEGER,
bowRudderControlBoxCircuitBreaker INTEGER,
openWaterCoverStartCylinderCircuitBreaker INTEGER
)";
if (!createTableInternal("disHighAVolBusCmd", disHighAVolBusCmdColumns)) return false;
// 9. disLowMainBusCmd
std::string disLowMainBusCmdColumns = R"(
id INTEGER PRIMARY KEY AUTOINCREMENT,
timestamp DATETIME DEFAULT (datetime('now', 'localtime')),
lithiumBatteryGroupInstrumentCircuitBreaker INTEGER,
bowLowVoltageDistributionBoxCircuitBreaker INTEGER,
unit4InstrumentDC48VCircuitBreaker INTEGER,
dcC1DCDistributionPanelCircuitBreaker INTEGER,
reservedCircuitBreaker1 INTEGER,
reservedCircuitBreaker2 INTEGER,
emergencyLithiumBatteryGroup2CircuitBreaker INTEGER
)";
if (!createTableInternal("disLowMainBusCmd", disLowMainBusCmdColumns)) return false;
// 10. disLowBusCmd
std::string disLowBusCmdColumns = R"(
id INTEGER PRIMARY KEY AUTOINCREMENT,
timestamp DATETIME DEFAULT (datetime('now', 'localtime')),
unit1CircuitBreaker INTEGER,
unit2CircuitBreaker INTEGER,
unit3CircuitBreaker INTEGER,
unit5CircuitBreaker INTEGER,
bowPZDeviceCircuitBreaker INTEGER,
reservedCircuitBreaker1 INTEGER,
reservedCircuitBreaker2 INTEGER,
emergencyLithiumBatteryGroup1CircuitBreaker INTEGER
)";
if (!createTableInternal("disLowBusCmd", disLowBusCmdColumns)) return false;
// 11. ccuSetParmCmd(复合管控参数设定下发)
std::string ccuSetParmCmdColumns = R"(
id INTEGER PRIMARY KEY AUTOINCREMENT,
timestamp DATETIME DEFAULT (datetime('now', 'localtime')),
insSocHold1 INTEGER,
insSocHold2 INTEGER,
insSocHold3 INTEGER,
fcuToInsLimit1 INTEGER,
fcuToInsLimit2 INTEGER,
powerSocHold1 INTEGER,
powerSocHold2 INTEGER,
powerSocHold3 INTEGER,
fcuToPowerLimit1 INTEGER,
fcuToPowerLimit2 INTEGER
)";
if (!createTableInternal("ccuSetParmCmd", ccuSetParmCmdColumns)) return false;
// 12. ccuSetParmFb(复合管控参数设定反馈)
std::string ccuSetParmFbColumns = R"(
id INTEGER PRIMARY KEY AUTOINCREMENT,
timestamp DATETIME DEFAULT (datetime('now', 'localtime')),
flag INTEGER,
failureCode INTEGER
)";
if (!createTableInternal("ccuSetParmFb", ccuSetParmFbColumns)) return false;
// 13. msg_log(原始收发帧日志)
std::string msgLogColumns = R"(
id INTEGER PRIMARY KEY AUTOINCREMENT,
ts REAL NOT NULL,
ts_local TEXT DEFAULT (datetime('now', 'localtime')),
direction INTEGER NOT NULL,
msg_id INTEGER NOT NULL,
msg_name TEXT,
length INTEGER,
payload_hex TEXT,
checksum_ok INTEGER,
note TEXT
)";
if (!createTableInternal("msg_log", msgLogColumns)) return false;
// 索引
sqlite3_exec(m_db, "CREATE INDEX IF NOT EXISTS idx_msg_log_ts ON msg_log(ts);", nullptr, nullptr, nullptr);
sqlite3_exec(m_db, "CREATE INDEX IF NOT EXISTS idx_msg_log_id ON msg_log(msg_id);", nullptr, nullptr, nullptr);
return true;
}
//====================================================================
// 泛化插入:所有类型共用这一条路径,列名与绑定器一一对应
//====================================================================
bool SQLite::insertGeneric(const std::string& table, const std::vector<Column>& cols, const void* obj)
{
try {
std::lock_guard<std::mutex> lock(m_dbMutex);
if (!m_db) { setError(SQLITE_MISUSE, "insert (db not open)"); return false; }
if (m_status == Status::Disabled) return false;
if (cols.empty()) return false;
std::string sql = "INSERT INTO " + table + " (";
for (size_t i = 0; i < cols.size(); ++i) {
if (i) sql += ",";
sql += cols[i].name;
}
sql += ") VALUES (";
for (size_t i = 0; i < cols.size(); ++i) {
if (i) sql += ",";
sql += "?";
}
sql += ")";
sqlite3_stmt* stmt = nullptr;
int rc = sqlite3_prepare_v2(m_db, sql.c_str(), -1, &stmt, nullptr);
if (rc != SQLITE_OK) { setError(rc, "prepare"); return false; }
int idx = 1;
for (size_t i = 0; i < cols.size(); ++i) {
cols[i].bind(stmt, idx, obj);
}
rc = sqlite3_step(stmt);
sqlite3_finalize(stmt);
if (rc != SQLITE_DONE) { setError(rc, "step"); return false; }
if (m_status == Status::Degraded) m_status = Status::OK;
return true;
} catch (const std::exception& e) {
LOG_F(ERROR, "SQLite insert 异常: %s", e.what());
return false;
} catch (...) {
LOG_F(ERROR, "SQLite insert 未知异常");
return false;
}
}
//====================================================================
// 列绑定宏:字段名 + 绑定器(无捕获函数指针,不抛异常、不分配)
//====================================================================
#define COL(Struct, member) \
SQLite::Column{ #member, [](sqlite3_stmt* s, int& i, const void* o){ \
sqlite3_bind_int64(s, i++, static_cast<sqlite3_int64>(static_cast<const Struct*>(o)->member)); } }
#define COL_AS(Struct, member, colname) \
SQLite::Column{ colname, [](sqlite3_stmt* s, int& i, const void* o){ \
sqlite3_bind_int64(s, i++, static_cast<sqlite3_int64>(static_cast<const Struct*>(o)->member)); } }
#define COL_ARR(Struct, arr, index, colname) \
SQLite::Column{ colname, [](sqlite3_stmt* s, int& i, const void* o){ \
sqlite3_bind_int64(s, i++, static_cast<sqlite3_int64>(static_cast<const Struct*>(o)->arr[index])); } }
//====================================================================
// 状态反馈数据
//====================================================================
bool SQLite::insertData(ccuState data)
{
std::vector<Column> cols = {
COL(ccuState, fc_mode),
COL(ccuState, fc_status),
COL(ccuState, fc_fault_level),
COL(ccuState, output_power_limit),
COL(ccuState, total_generation_time),
COL(ccuState, total_generation_power),
COL(ccuState, fault_level_1),
COL(ccuState, fault_level_2),
COL(ccuState, fault_level_3),
COL(ccuState, fault_level_4),
COL(ccuState, hydrogen_capacity),
COL(ccuState, liquid_oxygen_capacity),
COL(ccuState, palladium_temp),
COL(ccuState, main_pipe_pressure),
COL(ccuState, aux_pipe_pressure),
COL(ccuState, cabin_pressure1),
COL(ccuState, cabin_pressure2),
COL(ccuState, cabin_temp1),
COL(ccuState, cabin_temp2),
COL(ccuState, cabin_humidity1),
COL(ccuState, cabin_humidity2),
COL(ccuState, flame_detector1),
COL(ccuState, flame_detector2),
COL(ccuState, h2_concentration1),
COL(ccuState, h2_concentration2),
COL(ccuState, h2_concentration3),
COL(ccuState, o2_concentration1),
COL(ccuState, o2_concentration2),
COL(ccuState, ch3oh_concentration1),
COL(ccuState, ch3oh_concentration2),
COL_ARR(ccuState, reserved1, 0, "reserved1_1"),
COL_ARR(ccuState, reserved1, 1, "reserved1_2"),
COL(ccuState, emergency_battery1_voltage),
COL(ccuState, emergency_battery1_current),
COL(ccuState, emergency_battery1_max_temp),
COL(ccuState, emergency_battery1_fault_word),
COL(ccuState, emergency_battery2_voltage),
COL(ccuState, emergency_battery2_current),
COL(ccuState, emergency_battery2_max_temp),
COL(ccuState, emergency_battery2_fault_word),
COL(ccuState, cabin_ox_concentration),
COL(ccuState, cabin_temperature),
COL(ccuState, cabin_humidity),
COL(ccuState, cabin_pressure),
COL(ccuState, power_cabin_ox_concentration),
COL(ccuState, power_cabin_temperature),
COL(ccuState, power_cabin_humidity),
COL(ccuState, power_cabin_pressure),
COL_ARR(ccuState, reserved2, 0, "reserved2"),
COL_ARR(ccuState, dyn_alarm_flag, 0, "dyn_alarm_flag1"),
COL_ARR(ccuState, dyn_alarm_flag, 1, "dyn_alarm_flag2"),
COL_ARR(ccuState, dyn_alarm_flag, 2, "dyn_alarm_flag3"),
COL_ARR(ccuState, dyn_alarm_flag, 3, "dyn_alarm_flag4"),
COL_ARR(ccuState, dyn_alarm_flag, 4, "dyn_alarm_flag5"),
COL_ARR(ccuState, dyn_alarm_flag, 5, "dyn_alarm_flag6"),
COL_ARR(ccuState, ins_alarm_flag, 0, "ins_alarm_flag1"),
COL_ARR(ccuState, ins_alarm_flag, 1, "ins_alarm_flag2"),
COL_ARR(ccuState, ins_alarm_flag, 2, "ins_alarm_flag3"),
COL_ARR(ccuState, ins_alarm_flag, 3, "ins_alarm_flag4"),
COL_ARR(ccuState, ins_alarm_flag, 4, "ins_alarm_flag5"),
COL_ARR(ccuState, ins_alarm_flag, 5, "ins_alarm_flag6"),
COL(ccuState, ins_relay_status1),
COL(ccuState, ins_relay_status2),
COL(ccuState, dyn_relay_status1),
COL(ccuState, dyn_relay_status2),
COL(ccuState, ins_max_discharge_power),
COL(ccuState, dyn_max_discharge_power),
COL(ccuState, ins_soc),
COL(ccuState, dyn_soc),
COL(ccuState, ins_total_energy),
COL(ccuState, dyn_total_energy),
COL(ccuState, ins_power_input),
COL(ccuState, dyn_power_input),
COL(ccuState, ins_charge_status),
COL(ccuState, dyn_charge_status),
COL(ccuState, ins_voltage_link),
COL(ccuState, ins_voltage_pack),
COL(ccuState, ins_current),
COL(ccuState, ins_resistance_pos),
COL(ccuState, ins_resistance_neg),
COL(ccuState, dyn_voltage_link),
COL(ccuState, dyn_voltage_pack),
COL(ccuState, dyn_current),
COL(ccuState, dyn_resistance_pos),
COL(ccuState, dyn_resistance_neg),
COL(ccuState, ins_emergency_status),
COL(ccuState, dyn_emergency_status),
COL_ARR(ccuState, reserved3, 0, "reserved3_1"),
COL_ARR(ccuState, reserved3, 1, "reserved3_2"),
COL(ccuState, ins_soc_threshold1),
COL(ccuState, ins_soc_threshold2),
COL(ccuState, ins_soc_threshold3),
COL(ccuState, dyn_soc_threshold1),
COL(ccuState, dyn_soc_threshold2),
COL(ccuState, dyn_soc_threshold3),
COL(ccuState, ins_power_limit1),
COL(ccuState, ins_power_limit2),
COL(ccuState, dyn_power_limit1),
COL(ccuState, dyn_power_limit2),
COL(ccuState, device_online_flag1),
COL(ccuState, device_online_flag2),
COL(ccuState, reserved4),
COL(ccuState, heartbeat),
};
return insertGeneric("ccuState", cols, &data);
}
bool SQLite::insertData(disHighVolBusState data)
{
std::vector<Column> cols = {
COL(disHighVolBusState, fuelCellCircuitBreaker),
COL(disHighVolBusState, powerLithiumBatteryCircuitBreaker),
COL(disHighVolBusState, propulsionMotorCircuitBreaker),
COL(disHighVolBusState, lithiumBatteryGroupInstrumentCircuitBreaker),
COL(disHighVolBusState, dcDc5ModuleCircuitBreaker),
COL(disHighVolBusState, bowHighVoltageDistributionBoxCircuitBreaker),
COL(disHighVolBusState, sternFTDevice45CircuitBreaker),
COL(disHighVolBusState, sternRudderSwitch1CircuitBreaker),
COL(disHighVolBusState, sternRudderSwitch2CircuitBreaker),
COL(disHighVolBusState, fbReservedCircuitBreaker),
COL(disHighVolBusState, tyzReservedCircuitBreaker),
COL(disHighVolBusState, reservedCircuitBreaker),
COL(disHighVolBusState, dcDcFaultWord1),
COL(disHighVolBusState, dcDcFaultWord2),
COL(disHighVolBusState, powerBusInsulationStatus),
COL(disHighVolBusState, aBusInsulationStatus),
COL(disHighVolBusState, meterPowerLossSignal),
COL(disHighVolBusState, emergencyPowerLossSignal),
COL(disHighVolBusState, powerBusVoltage),
COL(disHighVolBusState, dcDc5ModuleCurrent),
COL(disHighVolBusState, powerBusCurrent),
COL(disHighVolBusState, busbarAVoltage),
COL(disHighVolBusState, propulsionMotorControlBoxCurrent),
COL(disHighVolBusState, busbarACurrent),
COL(disHighVolBusState, lithiumBatteryGroupMeterCurrent),
COL(disHighVolBusState, bowHighVoltageDistributionBoxCurrent),
COL(disHighVolBusState, sternFTDevice45Current),
COL(disHighVolBusState, tyzReservedSwitchCurrent),
COL(disHighVolBusState, sternRudderSwitch1Current),
COL(disHighVolBusState, reservedCurrent1),
COL(disHighVolBusState, sternRudderSwitch2Current),
COL(disHighVolBusState, reservedCurrent2),
COL(disHighVolBusState, fbReservedSwitchCurrent),
COL(disHighVolBusState, reservedCurrent3),
COL(disHighVolBusState, coolWaterPressure),
};
return insertGeneric("disHighVolBusState", cols, &data);
}
bool SQLite::insertData(disHighAVolBusState data)
{
std::vector<Column> cols = {
COL(disHighAVolBusState, bowFTDevice123CircuitBreaker),
COL(disHighAVolBusState, actuatorCircuitBreaker),
COL(disHighAVolBusState, mastSteeringGearControlBoxCircuitBreaker),
COL(disHighAVolBusState, xczCircuitBreaker),
COL(disHighAVolBusState, bowRudderControlBoxCircuitBreaker),
COL(disHighAVolBusState, openWaterCoverStartCylinderCircuitBreaker),
COL(disHighAVolBusState, instrumentPowerFailureSignal),
COL(disHighAVolBusState, emergencyPowerFailureSignal),
COL(disHighAVolBusState, waterIngressionAlarm),
COL(disHighAVolBusState, busbarBVoltage),
COL(disHighAVolBusState, busbarBCurrent),
COL(disHighAVolBusState, bowFTDevice123Current),
COL(disHighAVolBusState, actuatorCurrent),
COL(disHighAVolBusState, mastSteeringGearControlBoxCurrent),
COL(disHighAVolBusState, xczCurrent),
COL(disHighAVolBusState, bowRudderControlBoxCurrent),
COL(disHighAVolBusState, openWaterCoverStartCylinderCurrent),
};
return insertGeneric("disHighAVolBusState", cols, &data);
}
bool SQLite::insertData(disLowMainBusState data)
{
std::vector<Column> cols = {
COL(disLowMainBusState, lithiumBatteryGroupInstrumentCircuitBreaker),
COL(disLowMainBusState, bowLowVoltageDistributionBoxCircuitBreaker),
COL(disLowMainBusState, unit4InstrumentDC48VCircuitBreaker),
COL(disLowMainBusState, dcC1DCDistributionPanelCircuitBreaker),
COL(disLowMainBusState, reservedCircuitBreaker1),
COL(disLowMainBusState, reservedCircuitBreaker2),
COL(disLowMainBusState, emergencyLithiumBatteryGroup2CircuitBreaker),
COL(disLowMainBusState, instrumentPowerFailureSignal),
COL(disLowMainBusState, emergencyPowerFailureSignal),
COL(disLowMainBusState, instrumentBusbarInsulationLow),
COL(disLowMainBusState, instrumentBusbarVoltage),
COL(disLowMainBusState, bowLowVoltageDistributionBoxCurrent),
COL(disLowMainBusState, dcC1InstrumentDC48VCurrent),
COL(disLowMainBusState, reservedCurrent1),
COL(disLowMainBusState, emergencyLithiumBatteryGroup2Current),
COL(disLowMainBusState, lithiumBatteryGroupInstrumentCurrent),
COL(disLowMainBusState, unit4InstrumentDC48VCurrent),
COL(disLowMainBusState, reservedCurrent2),
COL(disLowMainBusState, emergency2BusbarVoltage),
COL(disLowMainBusState, compositeEnergyManagementSystemEmergencyDC48VCurrent),
COL(disLowMainBusState, fuelCellSecuritySystemEmergencyDC48VCurrent),
COL(disLowMainBusState, plcControlPowerCurrent),
};
return insertGeneric("disLowMainBusState", cols, &data);
}
bool SQLite::insertData(disLowBusState data)
{
std::vector<Column> cols = {
COL(disLowBusState, unit1CircuitBreaker),
COL(disLowBusState, unit2CircuitBreaker),
COL(disLowBusState, unit3CircuitBreaker),
COL(disLowBusState, unit5CircuitBreaker),
COL(disLowBusState, bowPZDeviceCircuitBreaker),
COL(disLowBusState, reservedCircuitBreaker1),
COL(disLowBusState, reservedCircuitBreaker2),
COL(disLowBusState, emergencyLithiumBatteryGroup1CircuitBreaker),
COL(disLowBusState, powerFailureSignal),
COL(disLowBusState, emergencyPowerFailureSignal),
COL(disLowBusState, waterIngressionAlarm),
COL(disLowBusState, instrumentBusbarVoltage),
COL(disLowBusState, instrumentBusbarCurrent),
COL(disLowBusState, unit1Current),
COL(disLowBusState, unit2Current),
COL(disLowBusState, unit3Current),
COL(disLowBusState, unit5Current),
COL(disLowBusState, bowPZDeviceCurrent),
COL(disLowBusState, emergencyLithiumBatteryGroup1Current),
COL(disLowBusState, emergency1BusbarVoltage),
};
return insertGeneric("disLowBusState", cols, &data);
}
bool SQLite::insertData(const msg_CcuSetParmFbMsg& fb)
{
std::vector<Column> cols = {
COL(msg_CcuSetParmFbMsg, flag),
COL(msg_CcuSetParmFbMsg, failureCode),
};
return insertGeneric("ccuSetParmFb", cols, &fb);
}
//====================================================================
// 下发指令数据
//====================================================================
bool SQLite::insertData(ccuColCmd cmd)
{
std::vector<Column> cols = {
COL_AS(ccuColCmd, fcmode, "workCondition"),
COL(ccuColCmd, fcuCmd),
COL(ccuColCmd, fcuPowerEfficiency),
COL(ccuColCmd, insChargeEnable),
COL(ccuColCmd, insBatCmd),
COL(ccuColCmd, powerBatCmd),
COL(ccuColCmd, powerBatEfficiency),
COL(ccuColCmd, heartbeat),
COL(ccuColCmd, masterState),
COL(ccuColCmd, paceholder1),
COL(ccuColCmd, paceholder2),
};
return insertGeneric("ccuColCmd", cols, &cmd);
}
bool SQLite::insertData(ccuSetParmCmd cmd)
{
std::vector<Column> cols = {
COL(ccuSetParmCmd, insSocHold1),
COL(ccuSetParmCmd, insSocHold2),
COL(ccuSetParmCmd, insSocHold3),
COL(ccuSetParmCmd, fcuToInsLimit1),
COL(ccuSetParmCmd, fcuToinsLimit2),
COL(ccuSetParmCmd, powerSocHold1),
COL(ccuSetParmCmd, powerSocHold2),
COL(ccuSetParmCmd, powerSocHold3),
COL(ccuSetParmCmd, fcuToPowerLimit1),
COL(ccuSetParmCmd, fcuToPowerLimit2),
};
return insertGeneric("ccuSetParmCmd", cols, &cmd);
}
bool SQLite::insertData(disHighVolBusCmd cmd)
{
std::vector<Column> cols = {
COL(disHighVolBusCmd, fuelCellCircuitBreaker),
COL(disHighVolBusCmd, powerLithiumBatteryCircuitBreaker),
COL(disHighVolBusCmd, propulsionMotorCircuitBreaker),
COL(disHighVolBusCmd, lithiumBatteryGroupInstrumentCircuitBreaker),
COL(disHighVolBusCmd, dcDc5ModuleCircuitBreaker),
COL(disHighVolBusCmd, bowHighVoltageDistributionBoxCircuitBreaker),
COL(disHighVolBusCmd, sternFTDevice45CircuitBreaker),
COL(disHighVolBusCmd, sternRudderSwitch1CircuitBreaker),
COL(disHighVolBusCmd, sternRudderSwitch2CircuitBreaker),
COL(disHighVolBusCmd, fbReservedCircuitBreaker),
COL(disHighVolBusCmd, tyzReservedCircuitBreaker),
COL(disHighVolBusCmd, reservedCircuitBreaker),
COL(disHighVolBusCmd, dcdc5Module),
COL(disHighVolBusCmd, coolingSystem),
};
return insertGeneric("disHighVolBusCmd", cols, &cmd);
}
bool SQLite::insertData(disHighAVolBusCmd cmd)
{
std::vector<Column> cols = {
COL(disHighAVolBusCmd, bowFTDevice123CircuitBreaker),
COL(disHighAVolBusCmd, actuatorCircuitBreaker),
COL(disHighAVolBusCmd, mastSteeringGearControlBoxCircuitBreaker),
COL(disHighAVolBusCmd, xczCircuitBreaker),
COL(disHighAVolBusCmd, bowRudderControlBoxCircuitBreaker),
COL(disHighAVolBusCmd, openWaterCoverStartCylinderCircuitBreaker),
};
return insertGeneric("disHighAVolBusCmd", cols, &cmd);
}
bool SQLite::insertData(disLowMainBusCmd cmd)
{
std::vector<Column> cols = {
COL(disLowMainBusCmd, lithiumBatteryGroupInstrumentCircuitBreaker),
COL(disLowMainBusCmd, bowLowVoltageDistributionBoxCircuitBreaker),
COL(disLowMainBusCmd, unit4InstrumentDC48VCircuitBreaker),
COL(disLowMainBusCmd, dcC1DCDistributionPanelCircuitBreaker),
COL(disLowMainBusCmd, reservedCircuitBreaker1),
COL(disLowMainBusCmd, reservedCircuitBreaker2),
COL(disLowMainBusCmd, emergencyLithiumBatteryGroup2CircuitBreaker),
};
return insertGeneric("disLowMainBusCmd", cols, &cmd);
}
bool SQLite::insertData(disLowBusCmd cmd)
{
std::vector<Column> cols = {
COL(disLowBusCmd, unit1CircuitBreaker),
COL(disLowBusCmd, unit2CircuitBreaker),
COL(disLowBusCmd, unit3CircuitBreaker),
COL(disLowBusCmd, unit5CircuitBreaker),
COL(disLowBusCmd, bowPZDeviceCircuitBreaker),
COL(disLowBusCmd, reservedCircuitBreaker1),
COL(disLowBusCmd, reservedCircuitBreaker2),
COL(disLowBusCmd, emergencyLithiumBatteryGroup1CircuitBreaker),
};
return insertGeneric("disLowBusCmd", cols, &cmd);
}
#undef COL
#undef COL_ARR
//====================================================================
// 原始收发帧落库
//====================================================================
void SQLite::onFrame(int direction, unsigned short msgId, const char* name,
const unsigned char* data, unsigned int len, bool checksumOk)
{
try {
std::lock_guard<std::mutex> lock(m_dbMutex);
if (!m_db || m_status == Status::Disabled) return;
static const char* hexDigits = "0123456789ABCDEF";
std::string hex;
hex.reserve(len * 2);
for (unsigned int i = 0; i < len; ++i) {
hex.push_back(hexDigits[data[i] >> 4]);
hex.push_back(hexDigits[data[i] & 0x0F]);
}
double ts = std::chrono::duration<double>(
std::chrono::system_clock::now().time_since_epoch()).count();
const char* sql =
"INSERT INTO msg_log "
"(ts, direction, msg_id, msg_name, length, payload_hex, checksum_ok) "
"VALUES (?,?,?,?,?,?,?)";
sqlite3_stmt* stmt = nullptr;
int rc = sqlite3_prepare_v2(m_db, sql, -1, &stmt, nullptr);
if (rc != SQLITE_OK) { setError(rc, "prepare msg_log"); return; }
sqlite3_bind_double(stmt, 1, ts);
sqlite3_bind_int(stmt, 2, direction);
sqlite3_bind_int(stmt, 3, static_cast<int>(msgId));
sqlite3_bind_text(stmt, 4, name ? name : "", -1, SQLITE_TRANSIENT);
sqlite3_bind_int(stmt, 5, static_cast<int>(len));
sqlite3_bind_text(stmt, 6, hex.c_str(), static_cast<int>(hex.size()), SQLITE_TRANSIENT);
sqlite3_bind_int(stmt, 7, checksumOk ? 1 : 0);
rc = sqlite3_step(stmt);
sqlite3_finalize(stmt);
if (rc != SQLITE_DONE) { setError(rc, "step msg_log"); return; }
if (m_status == Status::Degraded) m_status = Status::OK;
} catch (const std::exception& e) {
LOG_F(ERROR, "SQLite onFrame 异常: %s", e.what());
} catch (...) {
LOG_F(ERROR, "SQLite onFrame 未知异常");
}
}
//====================================================================
// 查询接口
//====================================================================
bool SQLite::queryInt(const std::string& sql, long long& out)
{
std::lock_guard<std::mutex> lock(m_dbMutex);
if (!m_db) return false;
sqlite3_stmt* stmt = nullptr;
int rc = sqlite3_prepare_v2(m_db, sql.c_str(), -1, &stmt, nullptr);
if (rc != SQLITE_OK) { setError(rc, "query"); return false; }
bool ok = false;
if (sqlite3_step(stmt) == SQLITE_ROW) {
out = sqlite3_column_int64(stmt, 0);
ok = true;
}
sqlite3_finalize(stmt);
return ok;
}
long long SQLite::count(const std::string& table)
{
std::lock_guard<std::mutex> lock(m_dbMutex);
if (!m_db) return 0;
std::string sql = "SELECT COUNT(*) FROM " + table;
sqlite3_stmt* stmt = nullptr;
int rc = sqlite3_prepare_v2(m_db, sql.c_str(), -1, &stmt, nullptr);
if (rc != SQLITE_OK) { setError(rc, "count"); return 0; }
long long n = 0;
if (sqlite3_step(stmt) == SQLITE_ROW) n = sqlite3_column_int64(stmt, 0);
sqlite3_finalize(stmt);
return n;
}