1. 优化了cpp_json的内容,使其更modern
2. 稍微优化了一下系统配置类 3. 增加了系统版本号,便于区分系统版本,方便OTA 4. 重写OTA的逻辑,完成了Cpp的OTA封装,测试通过
This commit is contained in:
@@ -9,27 +9,27 @@
|
||||
*/
|
||||
|
||||
/**
|
||||
* 如何使用:
|
||||
std::string text = R"({"name":"Misaki","age":18,"skills":["C++","RISC-V"]})";
|
||||
auto j = cppjson::Json::parse(text);
|
||||
std::cout << "name = " << j["name"].asString() << '\n';
|
||||
j["skills"].append(cppjson::Json("Go"));
|
||||
std::cout << j.dumpPretty() << '\n';
|
||||
* 如何使用:\n
|
||||
std::string text = R"({"name":"Misaki","age":18,"skills":["C++","RISC-V"]})"; \n
|
||||
auto j = cppjson::Json::parse(text);\n
|
||||
std::cout << "name = " << j["name"].asString() << '\n';\n
|
||||
j["skills"].append(cppjson::Json("Go"));\n
|
||||
std::cout << j.dumpPretty() << '\n';\n
|
||||
|
||||
or:
|
||||
Json j = Json::object();
|
||||
j.set("name", Json("misaki"))
|
||||
.set("age", Json(24))
|
||||
.set("vip", Json(true))
|
||||
.set("list", Json::array()
|
||||
.append(Json(1))
|
||||
.append(Json("hello")));
|
||||
or:\n
|
||||
Json j = Json::object();\n
|
||||
j.set("name", Json("misaki"))\n
|
||||
.set("age", Json(24))\n
|
||||
.set("vip", Json(true))\n
|
||||
.set("list", Json::array()\n
|
||||
.append(Json(1))\n
|
||||
.append(Json("hello")));\n
|
||||
|
||||
std::cout << j.dumpPretty() << "\n";
|
||||
std::cout << j.dumpPretty() << "\n";\n
|
||||
|
||||
Json j2 = j["list"];
|
||||
for (auto& v : j2) std::cout << v.dump() << " ";
|
||||
std::cout << "\n";
|
||||
Json j2 = j["list"];\n
|
||||
for (auto& v : j2) std::cout << v.dump() << " ";\n
|
||||
std::cout << "\n";\n
|
||||
*/
|
||||
|
||||
// cpp_json.hpp
|
||||
@@ -53,8 +53,14 @@ class Json {
|
||||
public:
|
||||
enum Type { Null, Bool, Number, String, ArrayType, ObjectType };
|
||||
|
||||
/*-------- 构造 ------------------------------------------------*/
|
||||
// 构造
|
||||
Json() noexcept : ptr_(nullptr), owner_(false) {}
|
||||
|
||||
// 支持所有整型(包括 int32_t / uint64_t 等 typedef)
|
||||
template <typename T,
|
||||
std::enable_if_t<std::is_integral_v<T>, int> = 0>
|
||||
explicit Json(T v) noexcept
|
||||
: ptr_(cJSON_CreateNumber(static_cast<double>(v))), owner_(true) {}
|
||||
explicit Json(std::nullptr_t) noexcept : Json() {}
|
||||
explicit Json(bool v) : ptr_(cJSON_CreateBool(v)), owner_(true) {}
|
||||
explicit Json(int v) : ptr_(cJSON_CreateNumber(v)), owner_(true) {}
|
||||
@@ -63,11 +69,11 @@ public:
|
||||
explicit Json(const std::string& v):ptr_(cJSON_CreateString(v.c_str())), owner_(true) {}
|
||||
explicit Json(const Array& arr); // 类外实现
|
||||
explicit Json(const Object& obj); // 类外实现
|
||||
/* 接管原始指针,owner=true 会负责 delete */
|
||||
// 接管原始指针,owner=true 会负责 delete,切记不要接管后再在外部cJSON_Delete
|
||||
explicit Json(cJSON* raw, bool owner = true) noexcept
|
||||
: ptr_(raw), owner_(owner) {}
|
||||
|
||||
/*-------- 拷贝/移动 -------------------------------------------*/
|
||||
// 拷贝/移动
|
||||
Json(const Json& rhs)
|
||||
: ptr_(rhs.ptr_ ? cJSON_Duplicate(rhs.ptr_, 1) : nullptr), owner_(true) {}
|
||||
Json(Json&& rhs) noexcept
|
||||
@@ -75,7 +81,7 @@ public:
|
||||
Json& operator=(Json rhs) noexcept { swap(rhs); return *this; }
|
||||
~Json() { reset(); }
|
||||
|
||||
/*-------- 工厂 ------------------------------------------------*/
|
||||
// 工厂
|
||||
static Json parse(const std::string& text) {
|
||||
cJSON* p = cJSON_Parse(text.c_str());
|
||||
if (!p) throw std::runtime_error("cppjson::parse failed");
|
||||
@@ -84,7 +90,7 @@ public:
|
||||
static Json array() { return Json(cJSON_CreateArray(), true); }
|
||||
static Json object() { return Json(cJSON_CreateObject(), true); }
|
||||
|
||||
/*-------- 序列化 ----------------------------------------------*/
|
||||
// 序列化
|
||||
[[nodiscard]] std::string dump() const {
|
||||
if (!ptr_) return "null";
|
||||
char* s = cJSON_PrintUnformatted(ptr_);
|
||||
@@ -100,7 +106,7 @@ public:
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*-------- 类型查询 --------------------------------------------*/
|
||||
// 类型查询
|
||||
[[nodiscard]] Type type() const noexcept {
|
||||
if (!ptr_) return Null;
|
||||
switch (ptr_->type & 0xFF) {
|
||||
@@ -120,13 +126,13 @@ public:
|
||||
[[nodiscard]] bool isArray() const noexcept { return type() == ArrayType; }
|
||||
[[nodiscard]] bool isObject() const noexcept { return type() == ObjectType; }
|
||||
|
||||
/*-------- 取值 ------------------------------------------------*/
|
||||
// 取值
|
||||
[[nodiscard]] bool asBool() const { if (!isBool()) throw std::runtime_error("not bool"); return cJSON_IsTrue(ptr_); }
|
||||
[[nodiscard]] int asInt() const { if (!isNumber()) throw std::runtime_error("not number"); return static_cast<int>(ptr_->valueint); }
|
||||
[[nodiscard]] double asDouble() const { if (!isNumber()) throw std::runtime_error("not number"); return ptr_->valuedouble; }
|
||||
[[nodiscard]] std::string asString() const { if (!isString()) throw std::runtime_error("not string"); return ptr_->valuestring; }
|
||||
|
||||
/*-------- 数组/对象接口 ---------------------------------------*/
|
||||
// 数组/对象接口
|
||||
[[nodiscard]] size_t size() const {
|
||||
if (isArray() || isObject()) return cJSON_GetArraySize(ptr_);
|
||||
return 0;
|
||||
@@ -152,7 +158,7 @@ public:
|
||||
return *this;
|
||||
}
|
||||
|
||||
/*-------- 迭代器(只读)---------------------------------------*/
|
||||
// 迭代器(只读)
|
||||
template <bool IsConst>
|
||||
struct iterator_impl {
|
||||
using iterator_category = std::forward_iterator_tag;
|
||||
@@ -194,7 +200,7 @@ private:
|
||||
};
|
||||
|
||||
|
||||
/*================ 类外实现:Array / Object 构造 =================*/
|
||||
// 类外实现:Array / Object 构造
|
||||
inline Json::Json(const Array& arr)
|
||||
: ptr_(cJSON_CreateArray()), owner_(true) {
|
||||
for (const auto& v : arr) append(v);
|
||||
|
||||
@@ -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()
|
||||
@@ -10,6 +10,7 @@
|
||||
#include <esp_efuse_table.h>
|
||||
#include <sstream>
|
||||
#include <iomanip>
|
||||
#include <algorithm>
|
||||
|
||||
static const char *TAG = "ToolsClass";
|
||||
|
||||
@@ -39,4 +40,31 @@ std::string ToolsClass::getChipMAC() {
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
// 1. 去掉 mac 中的冒号
|
||||
// 2. 拼接 chipID
|
||||
// 3. 取前 24 字符并转大写
|
||||
std::string ToolsClass::GenerateSN(const std::string& mac, const std::string& chipID)
|
||||
{
|
||||
// 1. 去掉 MAC 里的冒号
|
||||
std::string plainMac;
|
||||
plainMac.reserve(mac.size());
|
||||
for (char ch : mac)
|
||||
if (ch != ':') plainMac.push_back(ch);
|
||||
|
||||
// 2. 拼接
|
||||
std::string raw = plainMac + chipID;
|
||||
|
||||
// 3. 取前 24 位并转大写
|
||||
if (raw.size() > 24) raw.resize(24);
|
||||
std::transform(raw.begin(), raw.end(), raw.begin(),
|
||||
[](unsigned char c){ return std::toupper(c); });
|
||||
return raw;
|
||||
}
|
||||
|
||||
std::string ToolsClass::device_version = "Beta0.3";
|
||||
std::string ToolsClass::getDeviceVersion() {
|
||||
return device_version;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -12,20 +12,36 @@ class ToolsClass {
|
||||
public:
|
||||
/**
|
||||
* 获取当前时间
|
||||
* @return
|
||||
* @return 当前时间
|
||||
*/
|
||||
static std::string getCurrentTime();
|
||||
|
||||
/**
|
||||
* 获取esp32s3的芯片序列号
|
||||
* @return
|
||||
* @return 芯片序列号
|
||||
*/
|
||||
static std::string getChipSerialNumber();
|
||||
|
||||
/**
|
||||
* 获取esp32s3的MAC地址
|
||||
* @return
|
||||
* @return MAC地址
|
||||
*/
|
||||
static std::string getChipMAC();
|
||||
|
||||
|
||||
/**
|
||||
* 生成SN码
|
||||
* @param mac mac地址
|
||||
* @param chipID 芯片ID
|
||||
* @return 生成的SN码
|
||||
*/
|
||||
static std::string GenerateSN(const std::string& mac, const std::string& chipID);
|
||||
|
||||
/**
|
||||
* 获取设备版本
|
||||
* @return 设备版本
|
||||
*/
|
||||
static std::string getDeviceVersion();
|
||||
static std::string device_version; // 设备版本
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user