# MyStorage组件
一个一级结构化数据存储组件(暂不支持数组),目前支持常规数据、string;
## 使用要求
1. 提供默认构造函数;
2. 适当给予较大的分区;
## 存储特点
```cpp
using FieldBytes = int16_t; // 结构体中字段字节数
using FieldCount = uint16_t; // 用户结构体字段数量
enum FieldType {
kNormal_1, // 1字节常规数据,如char、int8_t
kNormal_2,
kNormal_4,
kNormal_8,
kString, // std::string字符串
kArray_Char, // char[]字符串
kArray_Blob, // 字节数组,如int8_t[]
kUnsupport
};
struct StructMetaData {
FieldBytes bytes; // 字段所占字节数
size_t offset; // 字段相对头部偏移
};
struct StructMeta {
FieldCount field_count; // 字段数量
FieldBytes total_bytes; // 结构总字节数
std::vector<StructMetaData> data; // 字段数据
};
```
1. 使用名字空间为"storage";
2. 字段元信息:由用户定义与组件定义2部分组合完成,受NVS键字段串最长15个字符影响(不包括结束字符\0),用户定义部(prefix)分限制为8个字符(结构体长度小于100个元素时)。
1. 存储位图:prefix+"bitmap",后续可能会扩展为+"bitmap#"
2. 字段数据:prefix+"-mlen"
3. 字段总字节数:prefix+"-byte"
4. 第i字段字节数、偏移:prefix+"-mfby#"、prefix+"-mfof#"
3. 具体数据存储:prefix + "-" + bitmap_index + "-" + field_index
## plan to do
1. 使用Kconfig定义预定的名字空间、字段等信息;
2. 是否有必要增加修改指定字段API
### 数组支持,当前仅支持char[]数组和其他
1. 如何增加数组的支持?----数组,使用blob进行存储,还要存储其长度
2. 如何支持指针?---string其实是指针,其指向了一段内存,但它是自己管理内存的,而普通指针需要手动管理内存。。。。
## 使用示例
```cpp
#include "sdkconfig.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_log.h"
#include "my_nvs.hpp"
#include "my_storage.h"
#define TAG "main"
using RunCount = int32_t;
enum CronPeriod {
YEARLY, // 每年
MONTHLY, // 每月
DAILY, // 每日
HOURLY, // 每时
MINUTE, // 每分钟
WEEKLY, // 每周
CUSTOM // 自定义
};
struct CronTask {
bool has_run = false; // 已运行标志(防多次触发)
CronPeriod period_type; // 重复类型
time_t period = 0; // 重复周期
RunCount count_left = 0; // 剩余执行次数
RunCount execution_count = 0; // 执行次数
// time_t scheduled_time = 0; // 计划运行时刻
// std::string callback_key; // 回调函数
// std::string callback_arg; // 回调函数参数
std::string name; // 任务名称
// 暂不支持数组类型。。。后续可能会考虑支持
};
extern "C" void app_main(void)
{
// 实例化一个存储存储CronTask结构的储存类:其存储时键名前缀为Task,注册每个字段的元信息
MyStorage<CronTask> storage("Task", DECLARE_META(CronTask,
FIELD(CronTask, has_run),
FIELD(CronTask, period_type),
FIELD(CronTask, period),
FIELD(CronTask, count_left),
FIELD(CronTask, execution_count),
// FIELD(CronTask, scheduled_time),
// FIELD(CronTask, callback_key),
// FIELD(CronTask, callback_arg),
FIELD(CronTask, name)
));
storage.SetPrintf([](const CronTask& t){
ESP_LOGW(TAG, "Task name=%s, period=%lu", t.name.c_str(), t.period);
});
CronTask t1, t2, t3, t4;
t1.name = "t1";
t2.name = "t2";
t3.name = "t3";
t4.name = "t4";
t1.period = 1;
t2.period = 2;
t3.period = 3;
t4.period = 4;
ESP_LOGW(TAG, "\nClear() Method");
ESP_LOGI(TAG, "storage used=%d", storage.GetUsed());
// 添加到存储中
storage.Clear();
ESP_LOGI(TAG, "storage has been clear, used=%d", storage.GetUsed());
vTaskDelay(pdMS_TO_TICKS(3000));
ESP_LOGW(TAG, "\nWrite() Method");
for (int i = 0; i < 8; i++) {
storage.Write(t1);
storage.Write(t2);
storage.Write(t3);
storage.Write(t4);
ESP_LOGI(TAG, "write round %d", i);
}
ESP_LOGI(TAG, "%d tasks has ben saved to nvs.", storage.GetUsed());
vTaskDelay(pdMS_TO_TICKS(3000));
ESP_LOGW(TAG, "\nRead() Method");
CronTask t, x;
storage.Read([](const CronTask& t){
return t.name == "t3";
}, t);
ESP_LOGI(TAG, "Read Task name=t3, Task name:%s, period:%lu", t.name.c_str(), t.period);
vTaskDelay(pdMS_TO_TICKS(3000));
ESP_LOGW(TAG, "\nModify() Method");
storage.Modify([](CronTask& t){
if (t.name == "t3") {
t.period = 1024;
return true;
}
return false;});
storage.Read([](const CronTask& t){
return t.name == "t3";
}, x);
ESP_LOGI(TAG, "(Modifyed)Read Task name=t3, Task name:%s, period:%lu", x.name.c_str(), x.period);
vTaskDelay(pdMS_TO_TICKS(3000));
ESP_LOGW(TAG, "\nDel() and Find() Method");
ESP_LOGI(TAG, "Clear all the task name=t2");
storage.Del([](const CronTask& t){
return t.name == "t2";
}, false);
ESP_LOGI(TAG, "used=%d", storage.GetUsed());
ESP_LOGI(TAG, "Search task name=t2, %s", storage.Find([](CronTask t){ return t.name == "t2"; }) ? "find" : "unfind");
vTaskDelay(pdMS_TO_TICKS(3000));
ESP_LOGW(TAG, "\nUpsert() Method");
ESP_LOGI(TAG, "Upsert the task name=t1 and t2");
ESP_LOGI(TAG, "Upsert an exist item name=t1, storage used=%d", storage.GetUsed());
CronTask k1, k2;
k1.name = "exist";
k1.period = 33;
storage.Upsert([](CronTask& t){
return t.name == "t1";
}, k1);
ESP_LOGI(TAG, "Upsert exit over, storage used=%d", storage.GetUsed());
k2.name = "un exist";
k2.period = 44;
storage.Upsert([](CronTask& t){
return t.name == "none exist";
}, k2);
ESP_LOGI(TAG, "Upsert none exist over, storage used=%d", storage.GetUsed());
vTaskDelay(pdMS_TO_TICKS(3000));
}
```
idf.py add-dependency "smallin/my-storage^1.0.1"