- 新增 msg_log 原始帧表,RX/TX 双向记录原始字节与校验结果 - SQLite 封装改为描述符驱动的泛化 insert,删除 10 个手写 SQL - 新增 ccuSetParmCmd/ccuSetParmFb 表,补齐 CCU 参数设定反馈落库 - 错误防崩溃:统一加锁、fail-open 降级、损坏自动重建、析构顺序修复 - WAL/迁移/预编译语句路径,数据库路径支持 mission 配置 dbpath - 清理未使用的 shell.c/sqlite3ext.h/SQLite.zip
997 lines
39 KiB
C++
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;
|
|
}
|