241 lines
8.3 KiB
C++
241 lines
8.3 KiB
C++
#pragma once
|
|
#include <algorithm>
|
|
#include <cctype>
|
|
#include <fstream>
|
|
#include <iostream>
|
|
#include <map>
|
|
#include <memory>
|
|
#include <mutex>
|
|
#include <sstream>
|
|
#include <string>
|
|
#include <vector>
|
|
|
|
#include "INIReader.h"
|
|
|
|
// ------------------------
|
|
// 线程安全配置管理单例类
|
|
// ------------------------
|
|
class ConfigManager
|
|
{
|
|
public:
|
|
// 获取单例
|
|
static ConfigManager& instance()
|
|
{
|
|
static ConfigManager inst;
|
|
return inst;
|
|
}
|
|
|
|
// 加载 INI 文件
|
|
bool load(const std::string& path)
|
|
{
|
|
std::lock_guard<std::mutex> lock(mtx);
|
|
file_path = path;
|
|
|
|
auto r = std::make_unique<INIReader>(path);
|
|
if (r->ParseError() < 0)
|
|
{
|
|
std::cerr << "Can't load config file: " << path << ", will create default on save\n";
|
|
reader.reset();
|
|
buildMapFromReader(); // 用 schema 默认值初始化
|
|
return false;
|
|
}
|
|
|
|
reader = std::move(r);
|
|
buildMapFromReader();
|
|
return true;
|
|
}
|
|
|
|
// ==================== Vehicle ====================
|
|
std::string getVin() { return getValue("vehicle", "vin", "LSV1234567890KUNL"); }
|
|
std::string getVehicleId() { return getValue("vehicle", "vehicle_id", "V010001"); }
|
|
void setVin(const std::string& vin) { setValue("vehicle", "vin", vin); }
|
|
void setVehicleId(const std::string& vid) { setValue("vehicle", "vehicle_id", vid); }
|
|
|
|
// ==================== Cloud ====================
|
|
std::string getDeviceNo() { return getValue("cloud", "device_no", "KL001"); }
|
|
std::string getPlatformIp() { return getValue("cloud", "platform_ip", "192.168.1.100"); }
|
|
int getPlatformPort() { return getInt("cloud", "platform_port", 8888); }
|
|
std::string getMqttIp() { return getValue("cloud", "mqtt_ip", "192.168.1.101"); }
|
|
int getMqttPort() { return getInt("cloud", "mqtt_port", 1883); }
|
|
// ✅ 新增
|
|
std::string getMqttUsername() { return getValue("cloud", "mqtt_username", ""); }
|
|
std::string getMqttPassword() { return getValue("cloud", "mqtt_password", ""); }
|
|
int getHeartbeatInterval() { return getInt("cloud", "heartbeat_interval", 60); }
|
|
|
|
void setDeviceNo(const std::string& v) { setValue("cloud", "device_no", v); }
|
|
void setPlatformIp(const std::string& v) { setValue("cloud", "platform_ip", v); }
|
|
void setPlatformPort(int v) { setValue("cloud", "platform_port", std::to_string(v)); }
|
|
void setMqttIp(const std::string& v) { setValue("cloud", "mqtt_ip", v); }
|
|
void setMqttPort(int v) { setValue("cloud", "mqtt_port", std::to_string(v)); }
|
|
// ✅ 新增
|
|
void setMqttUsername(const std::string& v) { setValue("cloud", "mqtt_username", v); }
|
|
void setMqttPassword(const std::string& v) { setValue("cloud", "mqtt_password", v); }
|
|
void setHeartbeatInterval(int interval) { setValue("cloud", "heartbeat_interval", std::to_string(interval)); }
|
|
|
|
// ==================== Cockpit ====================
|
|
std::string getCockpitId() { return getValue("cockpit", "cockpit_id", "C010001"); }
|
|
std::string getCockpitMqttIp() { return getValue("cockpit", "mqtt_ip", "192.168.1.110"); }
|
|
int getCockpitMqttPort() { return getInt("cockpit", "mqtt_port", 1883); }
|
|
|
|
void setCockpitId(const std::string& v) { setValue("cockpit", "cockpit_id", v); }
|
|
void setCockpitMqttIp(const std::string& v) { setValue("cockpit", "mqtt_ip", v); }
|
|
void setCockpitMqttPort(int v) { setValue("cockpit", "mqtt_port", std::to_string(v)); }
|
|
|
|
// ==================== Serial ====================
|
|
std::string getSerialDev() { return getValue("serial", "dev_name", "/dev/ttyUSB3"); }
|
|
int getSerialBaudrate() { return getInt("serial", "baudrate", 115200); }
|
|
|
|
void setSerialDev(const std::string& v) { setValue("serial", "dev_name", v); }
|
|
void setSerialBaudrate(int v) { setValue("serial", "baudrate", std::to_string(v)); }
|
|
|
|
// ==================== TBox ====================
|
|
int getLoginSeq() { return getInt("tbox", "login_seq", 1); }
|
|
std::string getLoginSeqDate() { return getValue("tbox", "login_seq_date", "000000"); }
|
|
|
|
void setLoginSeq(int v) { setValue("tbox", "login_seq", std::to_string(v)); }
|
|
void setLoginSeqDate(const std::string& v) { setValue("tbox", "login_seq_date", v); }
|
|
|
|
// 保存当前内存 map 到文件
|
|
bool save()
|
|
{
|
|
std::lock_guard<std::mutex> lock(mtx);
|
|
std::ofstream ofs(file_path);
|
|
if (!ofs.is_open()) return false;
|
|
|
|
for (const auto& [section, items] : schema)
|
|
{
|
|
ofs << "[" << section << "]\n";
|
|
for (const auto& item : items)
|
|
{
|
|
ofs << item.key << "=" << getValueUnlocked(section, item.key, item.default_value) << "\n";
|
|
}
|
|
ofs << "\n";
|
|
}
|
|
return true;
|
|
}
|
|
|
|
private:
|
|
ConfigManager() = default;
|
|
~ConfigManager() = default;
|
|
ConfigManager(const ConfigManager&) = delete;
|
|
ConfigManager& operator=(const ConfigManager&) = delete;
|
|
|
|
struct ConfigItem
|
|
{
|
|
std::string key;
|
|
std::string default_value;
|
|
};
|
|
|
|
const std::vector<std::pair<std::string, std::vector<ConfigItem>>> schema = {
|
|
{"vehicle",
|
|
{
|
|
{"vin", "LSV1234567890KUNL"},
|
|
{"vehicle_id", "V010001"},
|
|
}},
|
|
{"cloud",
|
|
{
|
|
{"device_no", "KL001"},
|
|
{"platform_ip", "192.168.1.100"},
|
|
{"platform_port", "8888"},
|
|
{"mqtt_ip", "192.168.1.101"},
|
|
{"mqtt_port", "1883"},
|
|
{"mqtt_username", ""}, // ✅ 新增
|
|
{"mqtt_password", ""}, // ✅ 新增
|
|
{"heartbeat_interval", "60"},
|
|
}},
|
|
{"cockpit",
|
|
{
|
|
{"cockpit_id", "C010001"},
|
|
{"mqtt_ip", "192.168.1.110"},
|
|
{"mqtt_port", "1883"},
|
|
}},
|
|
{"serial",
|
|
{
|
|
{"dev_name", "/dev/ttyUSB3"},
|
|
{"baudrate", "115200"},
|
|
}},
|
|
{"tbox",
|
|
{
|
|
{"login_seq", "1"},
|
|
{"login_seq_date", "000000"},
|
|
}},
|
|
};
|
|
|
|
std::unique_ptr<INIReader> reader;
|
|
std::string file_path;
|
|
std::map<std::string, std::map<std::string, std::string>> sections;
|
|
std::mutex mtx; // 多线程保护
|
|
|
|
// 根据 INIReader 初始化 map
|
|
void buildMapFromReader()
|
|
{
|
|
sections.clear();
|
|
|
|
for (const auto& [section, items] : schema)
|
|
{
|
|
for (const auto& item : items)
|
|
{
|
|
if (reader) { sections[section][item.key] = reader->Get(section, item.key, item.default_value); }
|
|
else
|
|
{
|
|
sections[section][item.key] = item.default_value;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
int getInt(const std::string& section, const std::string& key, int def)
|
|
{
|
|
std::string v = getValue(section, key, std::to_string(def));
|
|
try
|
|
{
|
|
size_t idx = 0;
|
|
int result = std::stoi(v, &idx);
|
|
if (idx != v.size()) throw std::invalid_argument("trailing chars");
|
|
return result;
|
|
}
|
|
catch (...)
|
|
{
|
|
// 自动纠错 + 修复配置
|
|
setValue(section, key, std::to_string(def));
|
|
return def;
|
|
}
|
|
}
|
|
|
|
bool getBool(const std::string& section, const std::string& key, bool def)
|
|
{
|
|
std::string v = getValue(section, key, def ? "1" : "0");
|
|
std::string lv = v;
|
|
std::transform(lv.begin(), lv.end(), lv.begin(), [](unsigned char c) { return std::tolower(c); });
|
|
if (lv == "1" || lv == "true" || lv == "yes") return true;
|
|
if (lv == "0" || lv == "false" || lv == "no") return false;
|
|
|
|
setValue(section, key, def ? "1" : "0");
|
|
return def;
|
|
}
|
|
|
|
std::string getValueUnlocked(const std::string& section, const std::string& key, const std::string& def)
|
|
{
|
|
auto& sec = sections[section];
|
|
auto it = sec.find(key);
|
|
if (it != sec.end()) return it->second;
|
|
|
|
sec[key] = def;
|
|
return def;
|
|
}
|
|
|
|
// 从 map 获取值
|
|
std::string getValue(const std::string& section, const std::string& key, const std::string& def)
|
|
{
|
|
std::lock_guard<std::mutex> lock(mtx);
|
|
return getValueUnlocked(section, key, def);
|
|
}
|
|
|
|
// 写入 map
|
|
void setValue(const std::string& section, const std::string& key, const std::string& value)
|
|
{
|
|
std::lock_guard<std::mutex> lock(mtx);
|
|
sections[section][key] = value;
|
|
}
|
|
};
|