smallin/my-storage

1.0.1

Latest
uploaded 1 week ago
Storage component(支持struct结构化存储)

readme

# 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));
}
```

Links

Supports all targets

License: Apache 2.0

To add this component to your project, run:

idf.py add-dependency "smallin/my-storage^1.0.1"

download archive

Stats

  • Archive size
    Archive size ~ 11.52 KB
  • Downloaded in total
    Downloaded in total 0 times
  • Downloaded this version
    This version: 0 times

Badge

smallin/my-storage version: 1.0.1
|