1. 优化了cpp_json的内容,使其更modern

2. 稍微优化了一下系统配置类
3. 增加了系统版本号,便于区分系统版本,方便OTA
4. 重写OTA的逻辑,完成了Cpp的OTA封装,测试通过
This commit is contained in:
Misaki
2025-09-24 04:01:23 +08:00
parent 6c4749ba0c
commit a47e20cb64
18 changed files with 908 additions and 458 deletions
@@ -3,3 +3,7 @@
//
#include "sys_conf_singleton.h"
// 静态成员变量定义
SysConfJson* SysConfJson::instance = nullptr;
std::mutex SysConfJson::instanceMutex;
@@ -13,16 +13,16 @@
#include <fstream>
#include <mutex>
static constexpr char kSysConfPartName[] = "sys_conf";
template <const char* PartitionLabel>
class SysConfJson {
public:
static SysConfJson& instance() {
static SysConfJson inst;
return inst;
static SysConfJson* getInstance() {
std::lock_guard<std::mutex> lock(instanceMutex);
if (instance == nullptr) {
instance = new SysConfJson();
return instance;
}
return instance;
}
/* 把 sn 持久化到 <mount>/sn.json,成功返回 true */
bool saveSN(const std::string& sn)
{
@@ -30,7 +30,6 @@ public:
doc.set("sn", cppjson::Json(sn)); // {"sn":"xxxxxx"}
return write("sn", doc); // 实际文件 = <mount>/sn.json
}
/* 读取 sn,如果文件/字段不存在返回空串(绝不抛异常) */
std::string loadSN()
{
@@ -39,14 +38,12 @@ public:
cppjson::Json snNode = j["sn"];
return snNode.isString() ? snNode.asString() : "";
}
/* 直接覆盖写,无 tmp */
bool write(const char* key, const cppjson::Json& j) {
const std::string path = buildPath(key);
const std::string txt = j.dump();
return writeRaw(path, txt);
}
/* 读 */
cppjson::Json read(const char* key) const {
std::string content;
@@ -58,13 +55,11 @@ public:
return {};
}
}
/* 删文件 */
bool remove(const char* key) const {
const std::string path = buildPath(key);
return ::unlink(path.c_str()) == 0;
}
/* 列文件 */
[[nodiscard]] std::vector<std::string> ls() const {
std::vector<std::string> names;
@@ -78,35 +73,24 @@ public:
::closedir(dir);
return names;
}
/* 格式化 */
[[nodiscard]] bool format() const {
ESP_LOGW(TAG, "format <%s>", PartitionLabel);
return esp_vfs_fat_spiflash_format_rw_wl(kMount, PartitionLabel) == ESP_OK;
ESP_LOGW(TAG, "format <%s>", kSysConfPartName);
return esp_vfs_fat_spiflash_format_rw_wl(kMount, kSysConfPartName) == ESP_OK;
}
/* 禁止拷贝 */
SysConfJson(const SysConfJson&) = delete;
SysConfJson& operator=(const SysConfJson&) = delete;
private:
constexpr static const char* TAG = "SysConfJson";
constexpr static const char* kMount = "/sys_conf";
wl_handle_t wl_ = WL_INVALID_HANDLE;
bool mounted_ = false;
static constexpr const char* kFileName = "sys_conf.json";
std::mutex mtx_;
SysConfJson() { mount(); }
~SysConfJson() { unmount(); }
void mount() {
esp_vfs_fat_mount_config_t cfg = {
.format_if_mount_failed = true,
.format_if_mount_failed = true, // 如果 FAT 分区无法挂载,并且此参数为 true,则创建分区表并格式化文件系统。
.max_files = 8,
.allocation_unit_size = CONFIG_WL_SECTOR_SIZE
.allocation_unit_size = CONFIG_WL_SECTOR_SIZE,
};
esp_err_t err = esp_vfs_fat_spiflash_mount_rw_wl(kMount, PartitionLabel, &cfg, &wl_);
esp_err_t err = esp_vfs_fat_spiflash_mount_rw_wl(kMount, kSysConfPartName, &cfg, &wl_);
if (err != ESP_OK) {
ESP_LOGE(TAG, "mount fail <%s>", esp_err_to_name(err));
return;
@@ -114,14 +98,12 @@ private:
mounted_ = true;
ESP_LOGI(TAG, "FAT mounted at %s", kMount);
}
void unmount() {
if (!mounted_) return;
esp_vfs_fat_spiflash_unmount_rw_wl(kMount, wl_);
wl_ = WL_INVALID_HANDLE;
mounted_ = false;
}
bool writeRaw(const std::string& path, const std::string& txt) {
FILE* f = std::fopen(path.c_str(), "wb");
if (!f) return false;
@@ -129,7 +111,6 @@ private:
std::fclose(f);
return ok;
}
bool readRaw(const char* key, std::string& out) const {
const std::string path = buildPath(key);
FILE* f = std::fopen(path.c_str(), "rb");
@@ -146,6 +127,15 @@ private:
std::string buildPath(const char* key) const {
return std::string(kMount) + "/" + key;
}
private:
constexpr static const char* TAG = "SysConfJson";
constexpr static const char* kMount = "/sys_conf";
static constexpr char kSysConfPartName[] = "sys_conf";
wl_handle_t wl_ = WL_INVALID_HANDLE;
bool mounted_ = false;
static constexpr const char* kFileName = "sys_conf.json";
static SysConfJson* instance; // 单例实例
static std::mutex instanceMutex; // 单例锁
};
#define SYS_CONF_JSON() SysConfJson<kSysConfPartName>::instance()