Просмотр исходного кода

Merge pull request #1 from Guozhanxin/main

the first version
guo 5 лет назад
Родитель
Сommit
791bb24593
10 измененных файлов с 2360 добавлено и 0 удалено
  1. 260 0
      README.md
  2. 11 0
      SConscript
  3. 99 0
      inc/lpm.h
  4. 287 0
      src/lpm.c
  5. 110 0
      src/lpm_dev.c
  6. 204 0
      src/lpm_dev_blk.c
  7. 15 0
      src/lpm_dev_nand.c
  8. 830 0
      src/lpm_partition.c
  9. 496 0
      src/x_mem.c
  10. 48 0
      src/x_mem.h

+ 260 - 0
README.md

@@ -1,2 +1,262 @@
 # LPM
+
 逻辑分区管理(Logical partition management),支持动态创建、删除、查找、读写物理存储设备上的逻辑分区。
+
+## LPM 使用说明
+### LPM 初始化
+
+初始化 API 是一定要执行的,确保 LPM 初始化后能正确的管理 block 设备。
+
+#### 1. LPM 初始化
+```lpm_init(void);``` 
+
+上电初始化首先要执行的函数,用于初始化 **lpm** 链表
+
+#### 2. LPM 管理 BLOCK 设备
+```int lpm_dev_blk_append(struct rt_device *dev)``` 
+
+把 **block_dev** 交由 **lpm** 管理
+
+#### 3. LPM 查找被管理的 BLOCK 设备
+```struct lpm_dev *lpm_dev_find(const char *dev_name)```
+
+可以查找到 **block_dev** 是否被 **lpm** 管理
+
+### LPM API
+
+LPM 组件提供了API 可供用户动态调用
+
+#### 1. 查找分区
+
+```struct lpm_partition *lpm_partition_find(const char *dev_name, const char *name)``` 
+
+查找当前 block 设备上的 分区信息
+
+| 参数     | 描述                                                |
+| -------- | --------------------------------------------------- |
+| dev_name | block 设备的名字,可以通过 list_device 查看到的名字 |
+| name     | 分区的名字                                          |
+| return   | 返回分区的指针                                      |
+
+#### 2. 创建分区
+
+```struct lpm_partition *lpm_partition_create(const char *dev_name, const char *name, uint32_t size)``` 
+
+在当前 block 设备上创建一个分区
+
+| 参数     | 描述                                                |
+| -------- | --------------------------------------------------- |
+| dev_name | block 设备的名字,可以通过 list_device 查看到的名字 |
+| name     | 分区的名字                                          |
+| return   | 返回分区的指针                                      |
+
+#### 3. 删除分区
+
+```int lpm_partition_delete(const char *dev_name, const char *name)``` 
+
+删除当前 block 设备上的分区
+
+| 参数     | 描述                                                |
+| -------- | --------------------------------------------------- |
+| dev_name | block 设备的名字,可以通过 list_device 查看到的名字 |
+| name     | 分区的名字                                          |
+| return   | 返回分区的指针                                      |
+
+#### 4. 删除所有分区
+
+```int lpm_partition_delete_all(const char *dev_name)``` 
+
+删除当前 block 设备上的所有分区
+
+| 参数     | 描述                                                |
+| -------- | --------------------------------------------------- |
+| dev_name | block 设备的名字,可以通过 list_device 查看到的名字 |
+| return   | 返回分区的指针                                      |
+
+#### 5. 创建 block 设备
+
+```struct rt_device *lpm_blk_device_create(const char *dev_name, const char *parition_name)```
+
+在 lpm 分区上创建一个 block 设备,新的 block 设备名是就是传递进去的分区名
+
+| 参数     | 描述                                                |
+| -------- | --------------------------------------------------- |
+| dev_name | block 设备的名字,可以通过 list_device 查看到的名字 |
+| name     | 分区的名字                                          |
+| return   | 返回新的 block 设备的指针                           |
+
+#### 6. 分区读数据
+
+```int lpm_partition_read(const struct lpm_partition *part, uint32_t sector_no, uint8_t *buf, size_t size)``` 
+
+对分区进行读操作。
+
+| 参数      | 描述                 |
+| --------- | -------------------- |
+| part      | 分区的名字           |
+| sector_no | 开始读的 sector      |
+| buf       | 读数据的缓冲区       |
+| size      | 读数据的长度         |
+| return    | 返回读取到数据的长度 |
+
+#### 7. 分区写数据
+
+```int lpm_partition_write(const struct lpm_partition *part, uint32_t sector_no, const uint8_t *buf, size_t size)``` 
+
+对分区进行写操作。
+
+| 参数      | 描述             |
+| --------- | ---------------- |
+| part      | 分区的名字       |
+| sector_no | 开始读的 sector  |
+| buf       | 写数据的缓冲区   |
+| size      | 写数据的长度     |
+| return    | 返回写数据的长度 |
+
+#### 8. 分区擦除
+
+```int lpm_partition_erase(const struct lpm_partition *part, uint32_t block_no, size_t num)``` 
+
+擦除分区。
+
+| 参数     | 描述              |
+| -------- | ----------------- |
+| part     | 分区的名字        |
+| block_no | 开始擦的 block    |
+| num      | 擦除的 block 数量 |
+| return   | 返回结果          |
+
+#### 9. 分区全部擦除
+
+```int lpm_partition_erase_all(const struct lpm_partition *part)``` 
+
+擦除分区上的所有数据。
+
+| 参数     | 描述              |
+| -------- | ----------------- |
+| part     | 分区的名字        |
+| return   | 返回结果          |
+
+#### 10. 打印分区信息
+
+```int lpm_dump_partition(void)``` 
+
+打印所有的分区信息。
+
+```
+==================== LPM partition table ============================
+|  dev_name  |  par_name  |  block_size  |   offset   |   length   |
+---------------------------------------------------------------------
+|  norflash  |  app       |  0x00001000  | 0x00000003 | 0x00000004 |
+|  norflash  |  abb       |  0x00001000  | 0x00000008 | 0x00000004 |
+=====================================================================
+```
+
+### LPM 命令行
+
+#### 1. 探测分区信息
+```lpmm probe norflash app ``` 
+
+探测 **norflash** block 设备上是否存在 **app** 这个分区
+
+```
+msh />lpmm probe norflash app
+find partition name is app
+Probed a block device | app | offset: 3 | size: 4 |
+```
+
+#### 2. 读取分区信息
+```lpmm read norflash app 0 1``` 
+
+读取 **norflash** 设备上,第 0 个 sector 开始,1 个 sector 长度的数据
+
+```
+Read data success. Start sector_no from 0x00000000, size is 4096. The data is:
+Offset (h) 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
+[00000000] 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F ................
+[00000010] 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F ................
+[00000020] 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F  !"#$%&'()*+,-./
+[00000030] 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F 0123456789:;<=>?
+```
+
+#### 3. 在分区上写数据
+
+```lpmm write norflash app 0 1``` 
+
+写 **norflash** 设备上,第 0 个 sector 开始,1 个 sector 长度的数据,block 设备每次读写都是一个 block , 目前不支持用户写自定义数据。
+
+```
+msh />lpmm write norflash app 0 1
+find partition name is app
+LPM Write Success at the Device name (norflash)  the partition name (app) .
+```
+
+#### 4. 创建一个新的分区
+
+```lpmm create norflash cpp 10``` 
+
+在**norflash** 设备上,创建一个分区**cpp**,大小为 **10** 个 block
+
+```
+msh />lpmm create norflash cpp 10
+Create block device | cpp | offset: 3 | size: 10 |.
+```
+
+#### 5. 删除一个分区
+
+```lpmm delete norflash app``` 
+
+删除 **norflash** 设备上的分区 **app**
+
+```
+msh />lpmm delete norflash app
+delete lpm_dev name is norflash  partition name is app
+Delete norflash Partition app Success.
+```
+
+#### 6. 删除所有分区
+
+```lpmm delete norflash all``` 
+
+删除 **norflash** 设备上的所有分区
+
+```
+msh />lpmm delete norflash all
+delete lpm_dev name is norflash  partition name is cpp
+delete lpm_dev name is norflash  partition name is abb
+delete lpm_dev name is norflash  partition name is app
+
+```
+
+#### 7. 显示分区信息
+
+```lpmm dump norflash part``` 
+
+打印 **norflash** 的分区信息
+
+```
+msh />lpmm dump norflash part
+==================== LPM partition table ============================
+|  dev_name  |  par_name  |  block_size  |   offset   |   length   |
+---------------------------------------------------------------------
+|  norflash  |  cpp       |  0x00001000  | 0x00000003 | 0x0000000a |
+|  norflash  |  abb       |  0x00001000  | 0x00000008 | 0x00000004 |
+|  norflash  |  app       |  0x00001000  | 0x00000003 | 0x0000000a |
+=====================================================================
+```
+
+#### 8. 显示 BLOCK 设备
+
+```lpmm dump norflash dev``` 
+
+打印被 **lpm** 管理的 block 设备
+
+```
+msh />lpmm dump norflash dev
+==================== LPM Device table =======================
+|  dev_name  | bytes_per_sector | sector_count | block_size |
+-------------------------------------------------------------
+|  norflash  |    0x00001000    |  0x00001000  | 0x00001000 |
+=============================================================
+```
+

+ 11 - 0
SConscript

@@ -0,0 +1,11 @@
+# RT-Thread building script for component
+
+from building import *
+
+cwd = GetCurrentDir()
+src = Glob('src/*.c')
+CPPPATH = [cwd + '/inc']
+
+group = DefineGroup('lpm', src, depend = ['PKG_USING_LPM'], CPPPATH = CPPPATH)
+
+Return('group')

+ 99 - 0
inc/lpm.h

@@ -0,0 +1,99 @@
+/*
+ * Copyright (c) 2006-2018, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ * 2020.12.11     wanghaijing  first version
+ */
+
+#include <rtthread.h>
+
+#define LPM_NAME_MAX 8
+
+#define LPM_VER "V1.1"
+
+struct lpm
+{
+    rt_slist_t device_list; /* 物理设备链表 */
+};
+
+/* 分区数据结构 */
+struct lpm_partition /* 分区结构 */
+{
+    char name[LPM_NAME_MAX];
+    uint32_t size;  //分配了多少个block
+    uint32_t offset;  //相对于存储设备是第几个block
+    rt_slist_t list;
+    struct lpm_dev *dev; /* 所属存储设备 */
+};
+
+/* 物理存储设备数据结构*/
+/* 支持三种底层存储设备,RTT Block 设备、MTD Nand 设备、通用存储设备:struct lpm_dev */
+struct lpm_dev /* 底层存储设备结构 */
+{
+    char name[LPM_NAME_MAX];
+    rt_uint32_t sector_count; /**< count of sectors */
+    rt_uint32_t bytes_per_sector; /**< number of bytes per sector */
+    rt_uint32_t block_size; /**< number of bytes to erase one block */
+    rt_slist_t dev_list;
+    rt_slist_t part_list;
+    void *mem_ptr;
+    struct lpm_dev_ops *ops;
+};
+struct lpm_dev_ops /* 操作接口,待定 */
+{
+    int (*init)(struct lpm_dev *dev);
+    int (*erase)(struct lpm_dev *dev, uint32_t block_no, size_t num);
+    int (*read)(struct lpm_dev *dev, uint32_t sector_no, uint8_t *buf, size_t size);
+    int (*write)(struct lpm_dev *dev, uint32_t sector_no, const uint8_t *buf, size_t size);
+};
+
+struct rt_lpm_device
+{
+    struct lpm_dev lpm_dev;
+    rt_device_t rt_device;
+};
+/* 初始化 */
+int lpm_init(void);
+
+/* 创建分区,最大创建 4G 的分区大小 */
+struct lpm_partition *lpm_partition_create(const char *dev_name, const char *name, uint32_t size);
+int lpm_partition_delete(const char *dev_name, const char *name);
+int lpm_partition_delete_all(const char *dev_name);
+
+/* >4G 寻址空间,blk 的概念更清晰 */
+struct lpm_partition * lpm_partition_find(const char *dev_name, const char *name);
+int lpm_partition_read(const struct lpm_partition *part, uint32_t sector_no, uint8_t *buf, size_t size);
+int lpm_partition_write(const struct lpm_partition *part, uint32_t sector_no, const uint8_t *buf, size_t size);
+int lpm_partition_erase(const struct lpm_partition *part, uint32_t block_no, size_t num);
+int lpm_partition_erase_all(const struct lpm_partition *part);
+int lpm_partition_delete_self(const struct lpm_partition *part);
+
+/* 将分区注册为块设备 */
+struct rt_device *lpm_blk_device_create(const char *dev_name, const char *parition_name);
+
+/* info */
+int lpm_dump_partition(void);
+int lpm_dump_dev(void);
+char* lpm_get_version(struct lpm_dev *dev);
+uint32_t lpm_partition_get_addr(const struct lpm_partition *part);
+uint32_t lpm_free(const char *dev_name);
+
+/* >4G 寻址空间,blk 的概念更清晰 */
+struct lpm_dev *lpm_dev_find(const char *dev_name);
+int lpm_dev_read(struct lpm_dev *dev, uint32_t sector_no, uint8_t *buf, size_t size);
+int lpm_dev_write(struct lpm_dev *dev, uint32_t sector_no, const uint8_t *buf, size_t size);
+int lpm_dev_erase(const struct lpm_dev *dev, uint32_t block_no, size_t num);
+int lpm_dev_erase_all(const struct lpm_dev *dev);
+
+/* 底层接口 */
+int lpm_dev_append(struct lpm_dev *dev);
+int lpm_dev_blk_append(struct rt_device *dev);
+int lpm_dev_nand_append(struct rt_device *dev);
+
+int lpm_part_info_load(struct lpm_dev *dev);
+
+uint32_t lpm_part_alloc(struct lpm_dev *dev, size_t size);
+int lpm_part_free(struct lpm_dev *dev, uint32_t addr);

+ 287 - 0
src/lpm.c

@@ -0,0 +1,287 @@
+/*
+ * Copyright (c) 2006-2018, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ * 2020.12.11     wanghaijing  first version
+ */
+
+#include <string.h>
+#include <stdlib.h>
+#include "lpm.h"
+
+struct lpm lpm;
+
+/* 初始化 */
+int lpm_init(void)
+{
+    rt_slist_init(&lpm.device_list);
+
+    /* init lpm */
+    return RT_EOK;
+}
+static void lpmm(uint8_t argc, char **argv)
+{
+//    struct lpm_dev *lpm_dev;
+    struct lpm_partition *part = NULL;
+    size_t i = 0, j = 0;
+
+#define CMD_PROBE_INDEX  0
+#define CMD_READ_INDEX   1
+#define CMD_WRITE_INDEX  2
+#define CMD_CREATE_INDEX 3
+#define CMD_DELETE_INDEX 4
+#define CMD_DUMP_INDEX   5
+#define HEXDUMP_WIDTH    16
+#define __is_print(ch) ((unsigned int)((ch) - ' ') < 127u - ' ')
+
+    const char* help_info[] = {
+            [CMD_PROBE_INDEX]  = "lpmm probe  dev_name part_name                 - e.g: lpmm probe norflash app",
+            [CMD_READ_INDEX]   = "lpmm read   dev_name part_name sector_no size  - e.g: lpmm read norflash app 0 1",
+            [CMD_WRITE_INDEX]  = "lpmm write  dev_name part_name sector_no size  - e.g: lpmm write norflash app 0 1",
+            [CMD_CREATE_INDEX] = "lpmm create dev_name part_name size            - e.g: lpmm create norflash app 10",
+            [CMD_DELETE_INDEX] = "lpmm delete dev_name part_name                 - e.g: lpmm delete norflash app",
+            [CMD_DUMP_INDEX]   = "lpmm dump   dev_name info or part_name info    - e.g: lpmm dump or lpm dump part", };
+
+    if (argc < 2)
+    {
+        rt_kprintf("Usage:\n");
+        for (i = 0; i < sizeof(help_info) / sizeof(char*); i++)
+        {
+            rt_kprintf("%s\n", help_info[i]);
+        }
+        rt_kprintf("\n");
+    }
+
+    else
+    {
+        const char *operator = argv[1];
+
+        if (!strcmp(operator, "probe"))
+        {
+            if (argc >= 4)
+            {
+                char* dev_name = argv[2];
+                char* part_name = argv[3];
+
+                if ((part = lpm_partition_find(dev_name, part_name)) == RT_NULL)
+                {
+                    rt_kprintf("Device %s Partition %s NOT found. Probe failed.\n", dev_name, part_name);
+                    part = RT_NULL;
+                }
+                else
+                {
+                    rt_kprintf("Probed a block device | %s | offset: %ld | size: %d |.\n", part->name, part->offset,
+                            part->size);
+                }
+            }
+        }
+        else if (!strcmp(operator, "create"))
+        {
+            if (argc >= 5)
+            {
+                char* dev_name = argv[2];
+                char* part_name = argv[3];
+                uint32_t part_size = atoi(argv[4]);
+
+                if ((part = lpm_partition_create(dev_name, part_name, part_size)) == RT_NULL)
+                {
+                    rt_kprintf("Create %s Partition %s failed.\n", dev_name, part_name);
+                    part = RT_NULL;
+                }
+                else
+                {
+                    rt_kprintf("Create block device | %s | offset: %ld | size: %d |.\n", part->name, part->offset,
+                            part->size);
+                }
+            }
+        }
+        else if (!strcmp(operator, "delete"))
+        {
+            if (argc >= 4)
+            {
+                if(!strcmp(argv[3], "all"))
+                {
+                    lpm_partition_delete_all(argv[2]);
+                }
+                else
+                {
+                    char* dev_name = argv[2];
+                    char* part_name = argv[3];
+
+                    if (lpm_partition_delete(dev_name, part_name) != RT_EOK)
+                    {
+                        rt_kprintf("Delete %s Partition %s failed.\n", dev_name, part_name);
+                    }
+                    else
+                    {
+                        rt_kprintf("Delete %s Partition %s Success.\n", dev_name, part_name);
+                    }
+                }
+            }
+        }
+        else if (!strcmp(operator, "read"))
+        {
+            if (argc >= 6)
+            {
+                struct lpm_partition *lpm_par;
+
+                char* dev_name = argv[2];
+                char* part_name = argv[3];
+                uint32_t sector_no = atoi(argv[4]);
+                uint32_t size = atoi(argv[5]);
+                uint8_t *read_buf = RT_NULL;
+                int result;
+
+                lpm_par = lpm_partition_find(dev_name, part_name);
+                if (lpm_par == RT_NULL)
+                {
+                    rt_kprintf("Error: the Device name (%s) or the partition name (%s) is not found.", dev_name,
+                            part_name);
+                    return;
+                }
+                else
+                {
+                    read_buf = rt_malloc(lpm_par->dev->block_size);
+                    if (read_buf == RT_NULL)
+                    {
+                        rt_kprintf("Low memory!\n");
+                    }
+
+                    result = lpm_partition_read(lpm_par, sector_no, read_buf, size);
+                    if (result >= 0)
+                    {
+                        size = size * (lpm_par->dev->block_size);
+
+                        rt_kprintf("Read data success. Start sector_no from 0x%08X, size is %ld. The data is:\n",
+                                sector_no, size);
+                        rt_kprintf("Offset (h) 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F\n");
+                        for (i = 0; i < size; i += HEXDUMP_WIDTH)
+                        {
+                            rt_kprintf("[%08X] ", sector_no + i);
+                            /* dump hex */
+                            for (j = 0; j < HEXDUMP_WIDTH; j++)
+                            {
+                                if (i + j < size)
+                                {
+                                    rt_kprintf("%02X ", read_buf[i + j]);
+                                }
+                                else
+                                {
+                                    rt_kprintf("   ");
+                                }
+                            }
+                            /* dump char for hex */
+                            for (j = 0; j < HEXDUMP_WIDTH; j++)
+                            {
+                                if (i + j < size)
+                                {
+                                    rt_kprintf("%c", __is_print(read_buf[i + j]) ? read_buf[i + j] : '.');
+                                }
+                            }
+                            rt_kprintf("\n");
+                        }
+                        rt_kprintf("\n");
+                        rt_free(read_buf);
+                    }
+                    else
+                    {
+                        rt_free(read_buf);
+                    }
+                }
+            }
+            else
+            {
+                rt_kprintf("Please enter the correct parameters!\r\n ");
+            }
+        }
+        else if (!strcmp(operator, "write"))
+        {
+            if (argc >= 6)
+            {
+                struct lpm_partition *lpm_par;
+
+                char* dev_name = argv[2];
+                char* part_name = argv[3];
+                uint32_t sector_no = atoi(argv[4]);
+                uint32_t size = atoi(argv[5]); //要写的 block 数量
+                uint8_t *write_buf = RT_NULL;
+                int result;
+                uint32_t num;
+
+                if(!size)
+                {
+                    rt_kprintf("Please set 'size' greater than 0!\n");
+                    return;
+                }
+
+                lpm_par = lpm_partition_find(dev_name, part_name);
+                if (lpm_par == RT_NULL)
+                {
+                    rt_kprintf("Error: the Device name (%s) or the partition name (%s) is not found.", dev_name,
+                            part_name);
+                    return;
+                }
+                else
+                {
+                    if(lpm_par->size < size )
+                    {
+                        rt_kprintf("The 'size' of the input is larger than the 'size of the partition'!\n");
+                        return;
+                    }
+
+                    write_buf = rt_calloc(1, size*(lpm_par->dev->block_size));
+                    if (write_buf == RT_NULL)
+                    {
+                        rt_kprintf("Low memory!\n");
+                    }
+
+                    num = size * (lpm_par->dev->block_size);
+
+                    for (i = 0; i < num; i++)
+                    {
+                        write_buf[i] = i & 0xFF;
+                    }
+
+                    result = lpm_partition_write(lpm_par, sector_no, write_buf, size);
+                    if (result >= 0)
+                    {
+                        rt_kprintf("LPM Write Success at the Device name (%s)  the partition name (%s) .\r\n", dev_name,
+                                part_name);
+                    }
+                    else
+                    {
+                        rt_kprintf("LPM Write Failed at the Device name (%s)  the partition name (%s) .\r\n", dev_name,
+                                part_name);
+                    }
+                    rt_free(write_buf);
+                }
+            }
+        }
+        else if (!strcmp(operator, "dump"))
+        {
+            if (argc >= 2)
+            {
+                if (!strcmp(argv[2], "part"))
+                {
+                    lpm_dump_partition();
+                }
+                else
+                {
+                    lpm_dump_dev();
+                }
+            }
+        }
+        else if (!strcmp(operator, "free"))
+        {
+            rt_kprintf("LPM device: %08s , residue 0x%08x.\r\n", argv[2], lpm_free(argv[2]));
+        }
+        else
+        {
+            rt_kprintf("Please enter the correct parameters!\r\n ");
+        }
+    }
+}
+MSH_CMD_EXPORT(lpmm, LPM (Logical partition management) operate.);

+ 110 - 0
src/lpm_dev.c

@@ -0,0 +1,110 @@
+/*
+ * Copyright (c) 2006-2018, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ * 2020.12.11     wanghaijing  first version
+ */
+
+#include "lpm.h"
+
+extern struct lpm lpm;
+
+#include "x_mem.h"
+
+struct lpm_dev *lpm_dev_find(const char *dev_name)
+{
+    rt_slist_t *node = RT_NULL;
+    struct lpm_dev *lpm_dev;
+
+    rt_slist_for_each(node, &(lpm.device_list))
+    {
+        lpm_dev = rt_slist_entry(node, struct lpm_dev, dev_list);
+        if (rt_strncmp(lpm_dev->name, dev_name, RT_NAME_MAX) == 0)
+        {
+            return lpm_dev;
+        }
+    }
+    return RT_NULL;
+}
+
+/* 底层接口 */
+int lpm_dev_append(struct lpm_dev *dev)
+{
+    x_mem_t lpm_mem;
+
+    RT_ASSERT(dev);
+
+    lpm_mem = x_create((void *) 0, (void *) dev->sector_count, 1); //todo 这里是因为 block 的大小与 sector 一致
+    if (lpm_mem == RT_NULL)
+    {
+        return -RT_ERROR;
+    }
+
+    dev->mem_ptr = lpm_mem;
+
+    lpm_part_alloc(dev, 2);
+
+    lpm_part_info_load(dev);
+
+    rt_slist_insert(&(lpm.device_list), &(dev->dev_list));
+
+    return RT_EOK;
+}
+
+/* dump all device */
+int lpm_dump_dev(void)
+{
+    rt_slist_t *node = RT_NULL;
+    struct lpm_dev *lpm_dev = RT_NULL;
+
+    rt_kprintf("==================== LPM Device table =======================\r\n");
+    rt_kprintf("|  dev_name  | bytes_per_sector | sector_count | block_size |\r\n");
+    rt_kprintf("-------------------------------------------------------------\r\n");
+
+    rt_slist_for_each(node, &(lpm.device_list))
+    {
+        lpm_dev = rt_slist_entry(node, struct lpm_dev, dev_list);
+
+        rt_kprintf("|  %-*.*s  |    0x%08lx    |  0x%08lx  | 0x%08lx |\r\n", RT_NAME_MAX, RT_NAME_MAX, lpm_dev->name, \
+                lpm_dev->bytes_per_sector, lpm_dev->sector_count, lpm_dev->block_size);
+    }
+
+    rt_kprintf("=============================================================\r\n");
+
+    if (lpm_dev != RT_NULL)
+    {
+        return RT_EOK;
+    }
+    return -RT_ERROR;
+}
+
+int lpm_dev_read(struct lpm_dev *dev, uint32_t sector_no, uint8_t *buf, size_t size)
+{
+    RT_ASSERT(dev);
+    RT_ASSERT(dev->ops);
+    RT_ASSERT(dev->ops->read);
+
+    return dev->ops->read(dev, sector_no, buf, size);
+}
+
+int lpm_dev_write(struct lpm_dev *dev, uint32_t sector_no, const uint8_t *buf, size_t size)
+{
+    RT_ASSERT(dev);
+    RT_ASSERT(dev->ops);
+    RT_ASSERT(dev->ops->write);
+
+    return dev->ops->write(dev, sector_no, buf, size);
+}
+
+int lpm_dev_erase(const struct lpm_dev *dev, uint32_t block_no, size_t num)
+{
+    return RT_EOK;
+}
+
+int lpm_dev_erase_all(const struct lpm_dev *dev)
+{
+    return RT_EOK;
+}

+ 204 - 0
src/lpm_dev_blk.c

@@ -0,0 +1,204 @@
+/*
+ * Copyright (c) 2006-2018, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ * 2020.12.11     wanghaijing  first version
+ */
+
+#include <rtdevice.h>
+#include <string.h>
+#include "lpm.h"
+
+int lpm_blk_dev_init(struct lpm_dev *dev)
+{
+    RT_ASSERT(dev);
+
+    return RT_EOK;
+}
+
+int lpm_blk_dev_read(struct lpm_dev *dev, uint32_t sector_no, uint8_t *buf, size_t size)
+{
+    rt_device_t device;
+
+    RT_ASSERT(dev);
+
+    device = ((struct rt_lpm_device*) dev)->rt_device;
+
+    return rt_device_read(device, sector_no, buf, size);
+}
+
+int lpm_blk_dev_write(struct lpm_dev *dev, uint32_t sector_no, const uint8_t *buf, size_t size)
+{
+    rt_device_t device;
+
+    RT_ASSERT(dev);
+
+    device = ((struct rt_lpm_device*) dev)->rt_device;
+
+    return rt_device_write(device, sector_no, buf, size);
+}
+
+int lpm_blk_dev_erase(struct lpm_dev *dev, uint32_t block_no, size_t num)
+{
+    RT_ASSERT(dev);
+
+    return RT_EOK;
+}
+
+extern struct lpm lpm;
+
+static struct lpm_dev_ops lpm_dev_ops = {
+        .init  = lpm_blk_dev_init,
+        .erase = lpm_blk_dev_erase,
+        .read  = lpm_blk_dev_read,
+        .write = lpm_blk_dev_write,
+};
+
+int lpm_dev_blk_append(struct rt_device *dev)
+{
+    rt_err_t result;
+    struct rt_device_blk_geometry geometry;
+    struct lpm_dev *lpm_blk_dev;
+
+    lpm_blk_dev = rt_malloc(sizeof(struct rt_lpm_device));
+    if (lpm_blk_dev == RT_NULL)
+    {
+        return -RT_ERROR;
+    }
+
+    if ((dev->flag & RT_DEVICE_FLAG_RDWR) == RT_DEVICE_FLAG_RDWR)
+    {
+        result = rt_device_open(dev, RT_DEVICE_FLAG_RDWR);
+        if (result != RT_EOK && result != -RT_EBUSY)
+        {
+            return result;
+        }
+        rt_memset(&geometry, 0, sizeof(geometry));
+        result = rt_device_control(dev, RT_DEVICE_CTRL_BLK_GETGEOME, &geometry);
+        if (result != RT_EOK)
+        {
+            rt_kprintf("device : %s cmd RT_DEVICE_CTRL_BLK_GETGEOME failed.\r\n");
+            return result;
+        }
+        rt_kprintf("device info:\r\n");
+        rt_kprintf("sector  size : %d byte\r\n", geometry.bytes_per_sector);
+        rt_kprintf("sector count : %d \r\n",     geometry.sector_count);
+        rt_kprintf("block   size : %d byte\r\n", geometry.block_size);
+    }
+
+    rt_memset(lpm_blk_dev->name, 0, LPM_NAME_MAX);
+    rt_strncpy(lpm_blk_dev->name, dev->parent.name, RT_NAME_MAX);
+
+    lpm_blk_dev->sector_count = geometry.sector_count;
+    lpm_blk_dev->bytes_per_sector = geometry.bytes_per_sector;
+    lpm_blk_dev->block_size = geometry.block_size;
+    lpm_blk_dev->dev_list.next = RT_NULL;
+    lpm_blk_dev->part_list.next = RT_NULL;
+    lpm_blk_dev->ops = &lpm_dev_ops;
+
+    ((struct rt_lpm_device*) lpm_blk_dev)->rt_device = dev;
+
+    lpm_dev_append(lpm_blk_dev);
+
+    return RT_EOK;
+}
+
+static rt_size_t lpm_blk_read(rt_device_t dev, rt_off_t pos, void* buffer, rt_size_t size)
+{
+    int ret = 0;
+
+    ret = lpm_partition_read(dev->user_data, pos , buffer, size);
+
+    if (ret != size)
+    {
+        ret = 0;
+    }
+    else
+    {
+        ret = size;
+    }
+
+    return ret;
+}
+
+static rt_size_t lpm_blk_write(rt_device_t dev, rt_off_t pos, const void* buffer, rt_size_t size)
+{
+    int ret = 0;
+
+    ret = lpm_partition_write(dev->user_data, pos , buffer, size);
+
+    if (ret != size)
+    {
+        ret = 0;
+    }
+    else
+    {
+        ret = size;
+    }
+
+    return ret;
+}
+
+static rt_err_t lpm_blk_control(rt_device_t dev, int cmd, void *args)
+{
+    if (cmd == RT_DEVICE_CTRL_BLK_GETGEOME)
+    {
+        struct rt_device_blk_geometry *geometry;
+
+        geometry = (struct rt_device_blk_geometry *) args;
+        if (geometry == RT_NULL)
+        {
+            return -RT_ERROR;
+        }
+
+        geometry->block_size =       ((struct lpm_partition*)(dev->user_data))->dev->block_size;
+        geometry->bytes_per_sector = ((struct lpm_partition*)(dev->user_data))->dev->bytes_per_sector;
+        geometry->sector_count =     ((struct lpm_partition*)(dev->user_data))->size *              \
+                                     ((((struct lpm_partition*)(dev->user_data))->dev->block_size) / \
+                                     ((struct lpm_partition*)(dev->user_data))->dev->bytes_per_sector);
+    }
+    else if (cmd == RT_DEVICE_CTRL_BLK_ERASE)
+    {
+        //todo
+    }
+
+    return RT_EOK;
+}
+
+struct rt_device *lpm_blk_device_create(const char *dev_name, const char *parition_name)
+{
+    struct lpm_partition *lpm_par;
+    struct rt_device *rt_dev;
+
+    /*find lpm partition*/
+    lpm_par = lpm_partition_find(dev_name, parition_name);
+    if (lpm_par == RT_NULL)
+    {
+        rt_kprintf("Error: the partition name (%s) is not found.", parition_name);
+        return RT_NULL;
+    }
+
+    rt_dev = (struct rt_device*) rt_malloc(sizeof(struct rt_device));
+
+    rt_memset(rt_dev->parent.name, 0, RT_NAME_MAX);
+    rt_strncpy(rt_dev->parent.name, parition_name, RT_NAME_MAX);
+
+    rt_dev->type = RT_Device_Class_Block;
+
+    rt_dev->init    = RT_NULL;
+    rt_dev->open    = RT_NULL;
+    rt_dev->close   = RT_NULL;
+    rt_dev->read    = lpm_blk_read;
+    rt_dev->write   = lpm_blk_write;
+    rt_dev->control = lpm_blk_control;
+
+    rt_dev->user_data = lpm_par;
+
+    rt_kprintf("The LPM block device (%s) created successfully \r\n", parition_name);
+    rt_device_register(rt_dev, parition_name, RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_STANDALONE);
+
+    return rt_dev;
+}

+ 15 - 0
src/lpm_dev_nand.c

@@ -0,0 +1,15 @@
+/*
+ * Copyright (c) 2006-2018, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ */
+
+#include "lpm.h"
+
+int lpm_dev_nand_append(struct rt_device *dev)
+{
+    return -1;
+}

+ 830 - 0
src/lpm_partition.c

@@ -0,0 +1,830 @@
+/*
+ * Copyright (c) 2006-2018, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ * 2020.12.11     wanghaijing  first version
+ */
+
+#include "lpm.h"
+
+extern struct lpm lpm;
+
+#include "x_mem.h"
+
+const rt_uint8_t auchCRCHi[] = { 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1,
+        0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
+        0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1,
+        0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
+        0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0,
+        0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
+        0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1,
+        0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40,
+        0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1,
+        0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
+        0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1,
+        0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
+        0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1,
+        0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
+        0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40 };
+
+const rt_uint8_t auchCRCLo[] = { 0x00, 0xC0, 0xC1, 0x01, 0xC3, 0x03, 0x02, 0xC2, 0xC6, 0x06, 0x07, 0xC7, 0x05, 0xC5,
+        0xC4, 0x04, 0xCC, 0x0C, 0x0D, 0xCD, 0x0F, 0xCF, 0xCE, 0x0E, 0x0A, 0xCA, 0xCB, 0x0B, 0xC9, 0x09, 0x08, 0xC8,
+        0xD8, 0x18, 0x19, 0xD9, 0x1B, 0xDB, 0xDA, 0x1A, 0x1E, 0xDE, 0xDF, 0x1F, 0xDD, 0x1D, 0x1C, 0xDC, 0x14, 0xD4,
+        0xD5, 0x15, 0xD7, 0x17, 0x16, 0xD6, 0xD2, 0x12, 0x13, 0xD3, 0x11, 0xD1, 0xD0, 0x10, 0xF0, 0x30, 0x31, 0xF1,
+        0x33, 0xF3, 0xF2, 0x32, 0x36, 0xF6, 0xF7, 0x37, 0xF5, 0x35, 0x34, 0xF4, 0x3C, 0xFC, 0xFD, 0x3D, 0xFF, 0x3F,
+        0x3E, 0xFE, 0xFA, 0x3A, 0x3B, 0xFB, 0x39, 0xF9, 0xF8, 0x38, 0x28, 0xE8, 0xE9, 0x29, 0xEB, 0x2B, 0x2A, 0xEA,
+        0xEE, 0x2E, 0x2F, 0xEF, 0x2D, 0xED, 0xEC, 0x2C, 0xE4, 0x24, 0x25, 0xE5, 0x27, 0xE7, 0xE6, 0x26, 0x22, 0xE2,
+        0xE3, 0x23, 0xE1, 0x21, 0x20, 0xE0, 0xA0, 0x60, 0x61, 0xA1, 0x63, 0xA3, 0xA2, 0x62, 0x66, 0xA6, 0xA7, 0x67,
+        0xA5, 0x65, 0x64, 0xA4, 0x6C, 0xAC, 0xAD, 0x6D, 0xAF, 0x6F, 0x6E, 0xAE, 0xAA, 0x6A, 0x6B, 0xAB, 0x69, 0xA9,
+        0xA8, 0x68, 0x78, 0xB8, 0xB9, 0x79, 0xBB, 0x7B, 0x7A, 0xBA, 0xBE, 0x7E, 0x7F, 0xBF, 0x7D, 0xBD, 0xBC, 0x7C,
+        0xB4, 0x74, 0x75, 0xB5, 0x77, 0xB7, 0xB6, 0x76, 0x72, 0xB2, 0xB3, 0x73, 0xB1, 0x71, 0x70, 0xB0, 0x50, 0x90,
+        0x91, 0x51, 0x93, 0x53, 0x52, 0x92, 0x96, 0x56, 0x57, 0x97, 0x55, 0x95, 0x94, 0x54, 0x9C, 0x5C, 0x5D, 0x9D,
+        0x5F, 0x9F, 0x9E, 0x5E, 0x5A, 0x9A, 0x9B, 0x5B, 0x99, 0x59, 0x58, 0x98, 0x88, 0x48, 0x49, 0x89, 0x4B, 0x8B,
+        0x8A, 0x4A, 0x4E, 0x8E, 0x8F, 0x4F, 0x8D, 0x4D, 0x4C, 0x8C, 0x44, 0x84, 0x85, 0x45, 0x87, 0x47, 0x46, 0x86,
+        0x82, 0x42, 0x43, 0x83, 0x41, 0x81, 0x80, 0x40 };
+
+/* partition magic word */
+static uint32_t magic_word1 = 0x45503130;
+static uint32_t magic_word2 = 0x45503130;
+static uint16_t lpmstatus = 0;
+static uint8_t  infopart = 0;
+
+struct lpm_part_info
+{
+    char name[LPM_NAME_MAX];
+    uint32_t size;
+    uint32_t block_no;
+};
+
+struct lpm_super_block
+{
+    uint32_t magic_word1;
+    uint32_t magic_word2;
+    char lpm_ver[LPM_NAME_MAX];
+    uint32_t part_num;
+    uint16_t status;
+    struct lpm_part_info part_info[];
+};
+
+uint32_t lpm_part_alloc(struct lpm_dev *dev, size_t size)
+{
+    RT_ASSERT(dev);
+
+    return (uint32_t) x_malloc(dev->mem_ptr, size);
+}
+
+int lpm_part_free(struct lpm_dev *dev, uint32_t addr)
+{
+    RT_ASSERT(dev);
+
+    return (uint32_t) x_free(dev->mem_ptr, (void*) addr);
+}
+
+uint32_t lpm_free(const char *dev_name)
+{
+    struct lpm_dev *dev;
+    unsigned int total, used;
+
+    dev = lpm_dev_find(dev_name);
+
+    if(dev == RT_NULL)
+        return -RT_ERROR;
+
+    x_info(dev->mem_ptr, &total, &used, RT_NULL);
+
+    return total - used;
+}
+
+void lpm_part_dump(struct lpm_dev *dev)
+{
+    RT_ASSERT(dev);
+
+    x_dump(dev->mem_ptr);
+}
+
+static struct lpm_super_block* lpm_create_crc(struct lpm_super_block *lpm_sup, uint32_t len)
+{
+    uint16_t length;
+
+    rt_uint8_t CRCHi = 0xFF;
+    rt_uint8_t CRCLo = 0xFF;
+    rt_uint32_t Index;
+
+    length = len;
+
+    while (len--)
+    {
+        Index = CRCHi ^ *((uint8_t*) lpm_sup++);
+        CRCHi = CRCLo ^ auchCRCHi[Index];
+        CRCLo = auchCRCLo[Index];
+    }
+
+    *((uint8_t*) lpm_sup++) = CRCHi;
+    *((uint8_t*) lpm_sup++) = CRCLo;
+
+    lpm_sup -= (length + 2);
+
+    return lpm_sup;
+}
+
+static int lpm_check_crc(const struct lpm_super_block *lpm_sup, uint32_t block_size)
+{
+    int len;
+    struct lpm_super_block *lpm_sup_check;
+
+    lpm_sup_check = rt_malloc(block_size);
+    if(lpm_sup_check == RT_NULL)
+    {
+        rt_kprintf("Low memory!\n");
+    }
+    rt_memcpy(lpm_sup_check, lpm_sup, block_size);//把数据拷贝到 lpm_sup_check 中
+
+    len = sizeof(struct lpm_part_info); //计算单个结构体的长度
+
+    len = len * lpm_sup->part_num;  //计算出 num 个分区结构体的长度
+
+    //计算出 lpm_sup 的实际长度
+    len += sizeof(struct lpm_super_block); // magic_word1 + magic_word2 + lpm_ver + part_num + status
+
+    lpm_sup_check = lpm_create_crc(lpm_sup_check, len); //重新求出 CRC
+
+    if((rt_memcmp(lpm_sup, lpm_sup_check, len + 2)) != 0) //对比 CRC
+    {
+        rt_kprintf("crc check failed! \r\n");
+        rt_free(lpm_sup_check);
+        return -RT_ERROR;
+    }
+
+    rt_free(lpm_sup_check);
+
+    return RT_EOK;
+}
+
+/* 从存储设备上加载分区信息 */
+int lpm_part_info_load(struct lpm_dev *dev)
+{
+    struct lpm_super_block *lpm_sup, *lpm_sup1, *lpm_sup2;
+    struct lpm_partition *lpm_par;
+    uint8_t res = 0;
+
+    RT_ASSERT(dev);
+
+    //读取校验 第一个超级块
+    lpm_sup1 = rt_malloc(dev->block_size);
+    if (lpm_sup1 == RT_NULL)
+    {
+        return -RT_ERROR;
+    }
+
+    //todo read 和 write 的时候最后一个 size  是 sector 的大小,而不是一个block 大小,这里特殊在于block 和 sector 一样大
+    dev->ops->read(dev, 0, (uint8_t*)lpm_sup1, 1);
+
+    if ((lpm_sup1->magic_word1 == magic_word1) && (lpm_sup1->magic_word2 == magic_word2))
+    {
+        if(lpm_check_crc(lpm_sup1, dev->block_size) != RT_EOK)
+        {
+            rt_kprintf("lpm_sup1 crc check failed! \r\n");
+            rt_free(lpm_sup1);
+
+            res |= 1 << 0; //bit0 置1 给一个 sup1 错误标志位
+        }
+    }
+    else
+    {
+        rt_free(lpm_sup1);
+
+        res |= 1 << 0; //bit0 置1 给一个 sup1 错误标志位
+    }
+
+    //读取校验 第二个超级块
+    lpm_sup2 = rt_malloc(dev->block_size);
+    if (lpm_sup2 == RT_NULL)
+    {
+        //申请不到内存
+        res |= 1 << 1; //bit1 置1 给一个 sup2 错误标志位
+    }
+    else
+    {
+        //todo read 和 write 的时候最后一个 size  是 sector 的大小,而不是一个block 大小,这里特殊在于block 和 sector 一样大
+        dev->ops->read(dev, 1, (uint8_t*)lpm_sup2, 1);
+
+        if ((lpm_sup2->magic_word1 == magic_word1) && (lpm_sup2->magic_word2 == magic_word2))
+        {
+            if(lpm_check_crc(lpm_sup2, dev->block_size) != RT_EOK)
+            {
+                rt_kprintf("lpm_sup2 crc check failed! \r\n");
+                rt_free(lpm_sup2);
+
+                res |= 1 << 1; //bit1 置1 给一个 sup2 错误标志位
+            }
+        }
+        else
+        {
+            rt_free(lpm_sup2);
+
+            res |= 1 << 1; //bit1 置1 给一个 sup2 错误标志位
+        }
+    }
+
+    if(res == 3)//bit0:1 都为1 就说明,超级块1和2 都没有记录分区信息
+    {
+        return -RT_ERROR;
+    }
+    else if(res == 0x01 ){ // 超级块1 出现错误
+        lpm_sup = lpm_sup2;
+
+        infopart = 1; //当前信息储存在 超级块1,下一次就要写在 超级块0
+    }
+    else if(res == 0x02){ // 超级块2 出现错误
+        lpm_sup = lpm_sup1;
+
+        infopart = 0; //当前信息储存在 超级块0,下一次就要写在 超级块1
+    }
+    else {  // 两个超级块都没有错误
+       if(lpm_sup2->status >= lpm_sup1->status)  //status 是 uint16,目前每次保存加 1,溢出情况的处理还未实现
+       {
+           lpm_sup = lpm_sup2;
+
+           rt_free(lpm_sup1);
+
+           infopart = 1; //当前信息储存在 超级块1,下一次就要写在 超级块0
+       }
+       else {
+           lpm_sup = lpm_sup1;
+
+           rt_free(lpm_sup2);
+
+           infopart = 0; //当前信息储存在 超级块0,下一次就要写在 超级块1
+       }
+    }
+
+    if (lpm_sup->part_num == 0)
+    {
+        rt_kprintf("Not found LPM partition, Please create first LPM partition\r\n");
+    }
+    else
+    {
+        int pos = 2;
+
+        for (int i = 0; i < lpm_sup->part_num; i++)
+        {
+            lpm_par = rt_malloc(sizeof(struct lpm_partition));
+            if (lpm_par == RT_NULL)
+            {
+                rt_free(lpm_sup);
+
+                return -RT_ERROR;
+            }
+
+            rt_strncpy(lpm_par->name, lpm_sup->part_info[i].name, RT_NAME_MAX);
+            lpm_par->offset = lpm_sup->part_info[i].block_no;
+            lpm_par->size = lpm_sup->part_info[i].size;
+            lpm_par->dev = dev;
+
+            if(pos != lpm_par->offset)
+            {
+                lpm_part_alloc(dev,lpm_par->offset - pos);
+                pos = lpm_par->offset;
+            }
+            lpm_part_alloc(dev,lpm_par->size);
+            pos += lpm_par->size;
+
+            rt_slist_append(&(dev->part_list), &(lpm_par->list));
+        }
+
+        pos = 2;
+
+        for (int i = 0; i < lpm_sup->part_num; i++)
+        {
+            if(pos != lpm_sup->part_info[i].block_no)
+            {
+                lpm_part_free(dev,pos);
+                pos = lpm_sup->part_info[i].block_no;
+            }
+            pos += lpm_sup->part_info[i].size;
+        }
+//        rt_kprintf("load part: \r\n");
+//        lpm_part_dump(dev);
+    }
+
+    lpmstatus = lpm_sup->status;
+
+    rt_free(lpm_sup);
+
+    return RT_EOK;
+}
+
+/* 保存分区信息到存储设备上 */
+int lpm_part_info_save(struct lpm_dev *dev)
+{
+    rt_slist_t *node = RT_NULL;
+    struct lpm_partition *lpm_par;
+    struct lpm_super_block *lpm_sup;
+    uint32_t i = 0, len;
+
+    RT_ASSERT(dev);
+
+    lpm_sup = rt_malloc(dev->block_size);//todo 如果一个block 无法存储更多的分区信息
+    if (lpm_sup == RT_NULL)
+    {
+        return -RT_ERROR;
+    }
+
+    //读取当前分区的信息
+    if(dev->ops->read(dev, infopart, (uint8_t*) lpm_sup, 1) < 0)
+    {
+        return -RT_ERROR;
+    }
+
+    lpm_sup->magic_word1 = magic_word1;
+    lpm_sup->magic_word2 = magic_word2;
+    rt_memcpy(lpm_sup->lpm_ver,LPM_VER,LPM_NAME_MAX);
+
+    rt_slist_for_each(node, &(dev->part_list))
+    {
+        lpm_par = rt_slist_entry(node, struct lpm_partition, list);
+        if (lpm_par != RT_NULL)
+        {
+            rt_strncpy(lpm_sup->part_info[i].name, lpm_par->name, RT_NAME_MAX);
+            lpm_sup->part_info[i].block_no = lpm_par->offset;
+            lpm_sup->part_info[i].size = lpm_par->size;
+
+            i++;
+        }
+    }
+
+    lpm_sup->part_num = i;
+
+    len = sizeof(struct lpm_part_info); //计算单个结构体的长度
+
+    len = len * lpm_sup->part_num;  //计算出 num 个分区结构体的长度
+
+    //计算出 lpm_sup 的实际长度
+    len += sizeof(struct lpm_super_block); // magic_word1 + magic_word2 + lpm_ver + part_num + status
+
+    lpm_sup->status += 1;
+
+    lpm_sup = lpm_create_crc(lpm_sup, len);
+
+    //写入下一个超级块
+    if(dev->ops->write(dev, (infopart ^= 1), (uint8_t*) lpm_sup, 1) > 0)
+    {
+        rt_free(lpm_sup);
+
+        return RT_EOK;
+    }
+    else {
+        rt_free(lpm_sup);
+
+        return -RT_ERROR;
+    }
+}
+
+struct lpm_partition *lpm_partition_create(const char *dev_name, const char *name, uint32_t size)
+{
+    struct lpm_dev *lpm_p;
+    struct lpm_partition *lpm_par;
+    struct lpm_partition *lpm_par_temp;
+    uint32_t offset;
+
+    if(name[0] != 0 && lpm_partition_find(dev_name, name) != RT_NULL)
+    {
+        rt_kprintf("The partition cannot be created,because the %s already exists.\n",name);
+        return RT_NULL;
+    }
+
+    /*find lpm device*/
+    lpm_p = lpm_dev_find(dev_name);
+    if (lpm_p == RT_NULL)
+    {
+        rt_kprintf("not find dev_name \n", dev_name);
+        return RT_NULL;
+    }
+
+    lpm_par = rt_malloc(sizeof(struct lpm_partition));
+    if (lpm_par == RT_NULL)
+    {
+        return RT_NULL;
+    }
+
+    rt_strncpy(lpm_par->name, name, RT_NAME_MAX);
+
+    offset = lpm_part_alloc(lpm_p, size);
+
+//    lpm_part_dump(lpm_p);//打印 LPM 内存分配情况
+
+    if( offset == RT_NULL)
+    {
+        rt_free(lpm_par);
+        return RT_NULL;
+    }
+
+    lpm_par->offset = offset; //block 的偏移量
+    lpm_par->size = size;  //offset 是偏移量  size 申请的 block 的数量
+    lpm_par->dev = lpm_p;
+
+    rt_slist_init(&(lpm_par->list));
+
+    rt_slist_t *dev_node = RT_NULL;
+    rt_slist_t *last_node = &(lpm_par->list);
+
+    if(rt_slist_isempty(&(lpm_p->part_list)))
+    {
+        rt_slist_insert(&(lpm_p->part_list), &(lpm_par->list));
+    }
+    else
+    {
+        rt_slist_for_each(dev_node, &(lpm_p->part_list))
+        {
+            lpm_par_temp = rt_slist_entry(dev_node, struct lpm_partition, list);
+
+            if(lpm_par->offset > lpm_par_temp->offset)
+            {
+                last_node = dev_node;
+                if(last_node->next == RT_NULL)
+                {
+                    rt_slist_insert(last_node, &(lpm_par->list));
+                    break;
+                }
+                continue;
+            }
+            else
+            {
+                rt_slist_insert(last_node, &(lpm_par->list));
+                break;
+            }
+        }
+    }
+
+    lpm_part_info_save(lpm_p);
+
+    return lpm_par;
+}
+
+int lpm_partition_delete(const char *dev_name, const char *name)
+{
+    struct lpm_dev *lpm_p;
+    struct lpm_partition *lpm_par;
+    rt_slist_t *par_node = RT_NULL;
+
+    /*find lpm device*/
+    lpm_p = lpm_dev_find(dev_name);
+    if (lpm_p == RT_NULL)
+    {
+        rt_kprintf("not find dev_name \n", dev_name);
+        return -RT_ERROR;
+    }
+
+    rt_slist_for_each(par_node, &(lpm_p->part_list))
+    {
+        lpm_par = rt_slist_entry(par_node, struct lpm_partition, list);
+
+        if (lpm_par != RT_NULL)
+        {
+            if (rt_strncmp(lpm_par->name, name, LPM_NAME_MAX) == 0)
+            {
+                rt_kprintf("delete lpm_dev name is %s  partition name is %s\r\n", lpm_p->name, lpm_par->name);
+                lpm_part_free(lpm_p, lpm_par->offset);
+                rt_slist_remove(&(lpm_p->part_list), &(lpm_par->list));
+
+                lpm_part_info_save(lpm_p);
+                rt_free(lpm_par);
+
+                return RT_EOK;
+            }
+        }
+        else
+        {
+            return -RT_ERROR;
+        }
+
+    }
+
+    return RT_EOK;
+}
+
+int lpm_partition_delete_self(const struct lpm_partition *part)
+{
+    struct lpm_dev *lpm_p = part->dev;
+    struct lpm_partition *lpm_par;
+    rt_slist_t *par_node = RT_NULL;
+
+    rt_slist_for_each(par_node, &(lpm_p->part_list))
+    {
+        lpm_par = rt_slist_entry(par_node, struct lpm_partition, list);
+
+        if (lpm_par != RT_NULL)
+        {
+            if (lpm_par->offset == part->offset)
+            {
+                rt_kprintf("delete lpm_dev name is %s  partition offset is %d\r\n", lpm_p->name, lpm_par->offset);
+                lpm_part_free(lpm_p, lpm_par->offset);
+                rt_slist_remove(&(lpm_p->part_list), &(lpm_par->list));
+
+                lpm_part_info_save(lpm_p);
+                rt_free(lpm_par);
+
+                return RT_EOK;
+            }
+        }
+        else
+        {
+            return -RT_ERROR;
+        }
+    }
+
+    return RT_EOK;
+}
+
+/*删除 dev 上的所有分区*/
+int lpm_partition_delete_all(const char *dev_name)
+{
+    struct lpm_dev *lpm_p;
+    struct lpm_partition *lpm_par;
+    rt_slist_t *dev_node = RT_NULL;
+    rt_slist_t *par_node = RT_NULL;
+
+    /*find lpm device*/
+    lpm_p = lpm_dev_find(dev_name);
+    if (lpm_p == RT_NULL)
+    {
+        rt_kprintf("not find dev_name \n", dev_name);
+        return -RT_ERROR;
+    }
+
+    rt_slist_for_each(dev_node, &(lpm.device_list))
+    {
+        lpm_p = rt_slist_entry(dev_node, struct lpm_dev, dev_list);
+
+        if (lpm_p != RT_NULL)
+        {
+            rt_slist_for_each(par_node, &(lpm_p->part_list))
+            {
+                lpm_par = rt_slist_entry(par_node, struct lpm_partition, list);
+
+                if (lpm_par != RT_NULL)
+                {
+                    rt_kprintf("delete lpm_dev name is %s  partition name is %s\r\n", lpm_p->name, lpm_par->name);
+
+                    lpm_part_free(lpm_p, lpm_par->offset);
+                    rt_slist_remove(&(lpm_p->part_list), &(lpm_par->list));
+
+                    rt_free(lpm_par);
+                }
+                else
+                {
+                    return -RT_ERROR;
+                }
+            }
+        }
+        else
+        {
+            return -RT_ERROR;
+        }
+        lpm_part_info_save(lpm_p);
+    }
+
+    return RT_EOK;
+}
+
+/* >4G 寻址空间,blk 的概念更清晰 */
+struct lpm_partition *lpm_partition_find(const char *dev_name, const char *name)
+{
+    struct lpm_dev *lpm_p;
+    struct lpm_partition *lpm_par;
+    rt_slist_t *node = RT_NULL;
+
+    /*find lpm device*/
+    lpm_p = lpm_dev_find(dev_name);
+    if (lpm_p == RT_NULL)
+    {
+        rt_kprintf("not find dev_name %s\n", dev_name);
+        return RT_NULL;
+    }
+
+    rt_slist_for_each(node, &(lpm_p->part_list))
+    {
+        lpm_par = rt_slist_entry(node, struct lpm_partition, list);
+        if (lpm_par != RT_NULL)
+        {
+            if (rt_strncmp(lpm_par->name, name, LPM_NAME_MAX) == 0)
+            {
+                return lpm_par;
+            }
+        }
+    }
+
+    return RT_NULL;
+}
+
+int lpm_partition_read(const struct lpm_partition *part, uint32_t sector_no, uint8_t *buf, size_t size)
+{
+    //用户传递进来的是 sector_num ,但是 part->offset 的偏移量是 block,需要计算  block 与 sector 的比例关系
+    uint32_t cur_offset;
+    uint32_t i;
+
+    RT_ASSERT(part);
+    RT_ASSERT(part->dev);
+    RT_ASSERT(part->dev->ops);
+    RT_ASSERT(part->dev->ops->read);
+
+    //计算当前 block 设备 block 与 sector 的关系
+    i = ((part->dev->block_size) / (part->dev->sector_count));
+
+    cur_offset = (part->offset) * i + sector_no;
+
+    return part->dev->ops->read(part->dev, cur_offset, buf, size); //传递进去单位也是 sector
+}
+
+int lpm_partition_write(const struct lpm_partition *part, uint32_t sector_no, const uint8_t *buf, size_t size)
+{
+    uint32_t cur_offset;
+    uint32_t i;
+
+    RT_ASSERT(part);
+    RT_ASSERT(part->dev);
+    RT_ASSERT(part->dev->ops);
+    RT_ASSERT(part->dev->ops->write);
+
+    i = (part->dev->block_size) / (part->dev->sector_count);
+
+    cur_offset = (part->offset) * i + sector_no;
+
+    return part->dev->ops->write(part->dev, cur_offset, buf, size);
+}
+
+int lpm_partition_erase(const struct lpm_partition *part, uint32_t block_no, size_t num)
+{
+    uint32_t cur_offset;
+    uint32_t i;
+
+    RT_ASSERT(part);
+    RT_ASSERT(part->dev);
+    RT_ASSERT(part->dev->ops);
+    RT_ASSERT(part->dev->ops->erase);
+
+    i = (part->dev->block_size) / (part->dev->sector_count);
+
+    cur_offset = (part->offset + block_no) * i;
+
+    return part->dev->ops->erase(part->dev, cur_offset, num * i);
+}
+
+int lpm_partition_erase_all(const struct lpm_partition *part)
+{
+    uint32_t cur_offset;
+    uint32_t i;
+
+    i = (part->dev->block_size) / (part->dev->sector_count);
+
+    cur_offset = (part->offset) * i;
+
+    return part->dev->ops->erase(part->dev, cur_offset, (part->size) * i);
+}
+
+int lpm_dump_partition(void)
+{
+    struct lpm_dev *lpm_p;
+    struct lpm_partition *lpm_par;
+    rt_slist_t *dev_node = RT_NULL;
+    rt_slist_t *par_node = RT_NULL;
+
+    rt_kprintf("==================== LPM partition table ============================\r\n");
+    rt_kprintf("|  dev_name  |  par_name  |  block_size  |   offset   |   length   |\r\n");
+    rt_kprintf("---------------------------------------------------------------------\r\n");
+
+    rt_slist_for_each(dev_node, &(lpm.device_list))
+    {
+        lpm_p = rt_slist_entry(dev_node, struct lpm_dev, dev_list);
+
+        if (lpm_p != RT_NULL)
+        {
+            rt_slist_for_each(par_node, &(lpm_p->part_list))
+            {
+                lpm_par = rt_slist_entry(par_node, struct lpm_partition, list);
+                if (lpm_par != RT_NULL)
+                {
+                    rt_kprintf("|  %-*.*s  |  %-*.*s  |  0x%08lx  | 0x%08lx | 0x%08lx |\r\n", RT_NAME_MAX, RT_NAME_MAX, lpm_p->name, \
+                            LPM_NAME_MAX, LPM_NAME_MAX, lpm_par->name, lpm_p->block_size, lpm_par->offset, lpm_par->size);
+                }
+                else
+                {
+                    return -RT_ERROR;
+                }
+            }
+        }
+        else
+        {
+            return -RT_ERROR;
+        }
+    }
+    rt_kprintf("=====================================================================\r\n");
+    return RT_EOK;
+}
+
+char* lpm_get_version(struct lpm_dev *dev)
+{
+    struct lpm_super_block *lpm_sup, *lpm_sup1, *lpm_sup2;
+    static char version[LPM_NAME_MAX];
+    uint8_t res = 0;
+
+    RT_ASSERT(dev);
+
+    lpm_sup1 = rt_malloc(dev->block_size);
+    if (lpm_sup1 == RT_NULL)
+    {
+        return RT_NULL;
+    }
+
+    dev->ops->read(dev, 0, (uint8_t*)lpm_sup1, 1);
+
+    if ((lpm_sup1->magic_word1 == magic_word1) && (lpm_sup1->magic_word2 == magic_word2))
+    {
+        if(lpm_check_crc(lpm_sup1, dev->block_size) != RT_EOK)
+        {
+            rt_kprintf("lpm_sup1 crc check failed! \r\n");
+            rt_free(lpm_sup1);
+
+            res |= 1 << 0;
+        }
+    }
+    else
+    {
+        rt_free(lpm_sup1);
+
+        res |= 1 << 0;
+    }
+
+    lpm_sup2 = rt_malloc(dev->block_size);
+    if (lpm_sup2 == RT_NULL)
+    {
+        res |= 1 << 1;
+    }
+    else
+    {
+        dev->ops->read(dev, 1, (uint8_t*)lpm_sup2, 1);
+
+        if ((lpm_sup2->magic_word1 == magic_word1) && (lpm_sup2->magic_word2 == magic_word2))
+        {
+            if(lpm_check_crc(lpm_sup2, dev->block_size) != RT_EOK)
+            {
+                rt_kprintf("lpm_sup2 crc check failed! \r\n");
+                rt_free(lpm_sup2);
+
+                res |= 1 << 1;
+            }
+        }
+        else
+        {
+            rt_free(lpm_sup2);
+
+            res |= 1 << 1;
+        }
+    }
+
+    if(res == 3)
+    {
+        return RT_NULL;
+    }
+    else if(res == 0x01 ){
+        lpm_sup = lpm_sup2;
+    }
+    else if(res == 0x02){
+        lpm_sup = lpm_sup1;
+    }
+    else {
+       if(lpm_sup2->status >= lpm_sup1->status)
+       {
+           lpm_sup = lpm_sup2;
+
+           rt_free(lpm_sup1);
+       }
+       else {
+           lpm_sup = lpm_sup1;
+
+           rt_free(lpm_sup2);
+       }
+    }
+
+    rt_memcpy(version, lpm_sup->lpm_ver, LPM_NAME_MAX);
+
+    rt_free(lpm_sup);
+
+    return version;
+}
+
+uint32_t lpm_partition_get_addr(const struct lpm_partition *part)
+{
+    uint32_t offset, addr;
+
+    RT_ASSERT(part);
+
+    offset = part->offset;
+
+    addr = part->dev->bytes_per_sector;
+
+    return offset * addr;
+}

+ 496 - 0
src/x_mem.c

@@ -0,0 +1,496 @@
+/*
+ * File      : x_mem.c
+ * COPYRIGHT (C) 2012-2020, Shanghai Real-Thread Electronic Technology Co.,Ltd.
+ * All Rights Reserved.
+ *
+ * This file is part of the RT-Thread MoM Electric Meter system.
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ * 2019-09-12      xxx          the first version
+ */
+
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <rtthread.h>
+
+#include "x_mem.h"
+
+struct heap_mem
+{
+    list_t list;
+    size_t len;
+    uint16_t used;
+    uint16_t reserved;
+};
+
+struct x_mem_tab
+{
+    struct list_node node;
+    int32_t used;
+    struct heap_mem tab[];
+};
+
+#define X_ALIGN(size, align)           (((size) + (align) - 1) & ~((align) - 1))
+#define X_ALIGN_DOWN(size, align)      ((size) & ~((align) - 1))
+
+#define HEAP_MAGIC 0x1ea0
+#define ASSERT(EX)
+
+#define X_MEM_TAB_CNT   (8)
+#define X_MEM_TAB_MAX   (8)
+
+#define MEM_USED_FLAG   (0x1 << 0)
+#define OBJ_USED_FLAG   (0x1 << 4)
+
+#define container_of(ptr, type, member) \
+    ((type *)((char *)(ptr) - (unsigned long)(&((type *)0)->member)))
+
+#define list_entry(node, type, member) \
+    container_of(node, type, member)
+
+#define list_for_each_entry(pos, head, member) \
+    for (pos = list_entry((head)->next, typeof(*pos), member); \
+         &pos->member != (head); \
+         pos = list_entry(pos->member.next, typeof(*pos), member))
+
+#define list_for_each_entry_safe(pos, n, head, member) \
+    for (pos = list_entry((head)->next, typeof(*pos), member), \
+         n = list_entry(pos->member.next, typeof(*pos), member); \
+         &pos->member != (head); \
+         pos = n, n = list_entry(n->member.next, typeof(*n), member))
+
+static void list_init(list_t *l)
+{
+    l->next = l->prev = l;
+}
+
+static void list_insert_before(list_t *l, list_t *n)
+{
+    l->prev->next = n;
+    n->prev = l->prev;
+
+    l->prev = n;
+    n->next = l;
+}
+
+static void list_insert_after(list_t *l, list_t *n)
+{
+    l->next->prev = n;
+    n->next = l->next;
+
+    l->next = n;
+    n->prev = l;
+}
+
+static void list_remove(list_t *n)
+{
+    n->next->prev = n->prev;
+    n->prev->next = n->next;
+
+    n->next = n->prev = n;
+}
+
+static struct x_mem_tab *get_mem_tab(x_mem_t x_mem, struct heap_mem *mem)
+{
+    struct x_mem_tab *tab;
+    uint32_t begin, end;
+
+    list_for_each_entry(tab, &x_mem->tab_head, node)
+    {
+        begin = (uint32_t)tab + sizeof(struct x_mem_tab);
+        end = begin + sizeof(struct heap_mem) * X_MEM_TAB_CNT;
+        if ((uint32_t)mem >= begin &&
+            (uint32_t)mem <= end &&
+            ((uint32_t)mem - begin) % sizeof(struct heap_mem) == 0)
+        {
+            return tab;
+        }
+    }
+    return NULL;
+}
+
+static struct heap_mem *get_mem_obj(x_mem_t x_mem)
+{
+    int i;
+    struct x_mem_tab *tab, *new_tab;
+
+    list_for_each_entry(tab, &x_mem->tab_head, node)
+    {
+        if (X_MEM_TAB_CNT - tab->used > 0)
+        {
+            for (i = 0; i < X_MEM_TAB_CNT; i++)
+            {
+                if (!(tab->tab[i].used & OBJ_USED_FLAG))
+                {
+                    tab->tab[i].used = OBJ_USED_FLAG;
+                    list_init(&tab->tab[i].list);
+                    tab->tab[i].len = 0;
+                    tab->used ++;
+                    return &tab->tab[i];
+                }
+            }
+        }
+    }
+    new_tab = calloc(1, sizeof(struct x_mem_tab) + sizeof(struct heap_mem) * X_MEM_TAB_CNT);
+    if (new_tab == NULL)
+    {
+        return NULL;
+    }
+    new_tab->used = 0;
+    list_init(&new_tab->node);
+    list_insert_after(&x_mem->tab_head, &new_tab->node);
+    return get_mem_obj(x_mem);
+}
+
+static void put_mem_obj(x_mem_t x_mem, struct heap_mem *mem)
+{
+    struct x_mem_tab *tab, *tmp;
+    int f_cnt;
+
+    tab = get_mem_tab(x_mem, mem);
+    if (tab == NULL)
+    {
+        return;
+    }
+    memset(mem, 0, sizeof(struct heap_mem));
+    tab->used --;
+
+    f_cnt = 0;
+    list_for_each_entry_safe(tab, tmp, &x_mem->tab_head, node)
+    {
+        if (f_cnt >= X_MEM_TAB_MAX && tab->used == 0)
+        {
+            list_remove(&tab->node);
+            free(tab);
+        }
+        else
+        {
+            f_cnt += X_MEM_TAB_CNT - tab->used;
+        }
+    }
+}
+
+x_mem_t x_create(void *begin_addr, void *end_addr, size_t align_size)
+{
+    uint32_t begin_align = X_ALIGN((uint32_t)begin_addr, align_size);
+    uint32_t end_align   = X_ALIGN_DOWN((uint32_t)end_addr, align_size);
+    x_mem_t x_mem;
+    struct heap_mem *mem;
+
+    x_mem = calloc(1, sizeof(struct x_mem));
+    if (x_mem == NULL)
+    {
+        return NULL;
+    }
+
+    /* calculate the aligned memory size */
+    x_mem->align_size = align_size;
+    x_mem->mem_size_aligned = end_align - begin_align;
+    x_mem->heap_ptr = (uint8_t *)begin_align;
+    list_init(&x_mem->head);
+    list_init(&x_mem->tab_head);
+
+    mem = get_mem_obj(x_mem);
+    if (mem == NULL)
+    {
+        free(x_mem);
+        return NULL;
+    }
+
+    mem->len = x_mem->mem_size_aligned;
+    list_init(&mem->list);
+    list_insert_after(&x_mem->head, &mem->list);
+
+    return x_mem;
+}
+
+void x_destroy(x_mem_t x_mem)
+{
+    struct x_mem_tab *mem_tab, *tmp;
+
+    if (x_mem ==  NULL)
+    {
+        return;
+    }
+
+    list_for_each_entry_safe(mem_tab, tmp, &x_mem->tab_head, node)
+    {
+        list_remove(&mem_tab->node);
+        free(mem_tab);
+    }
+
+    free(x_mem);
+}
+
+void *x_malloc(x_mem_t x_mem, unsigned int size)
+{
+    struct heap_mem *mem_obj, *mem_new;
+    size_t ptr = 0;
+
+    if (size == 0)
+    {
+        size = x_mem->align_size;
+    }
+
+    /* to determine whether the written data is out of bounds */
+    /* alignment size */
+    size = X_ALIGN(size, x_mem->align_size);
+
+    if (size > x_mem->mem_size_aligned)
+    {
+        return NULL;
+    }
+
+    list_for_each_entry(mem_obj, &x_mem->head, list)
+    {
+        if (!(mem_obj->used & MEM_USED_FLAG))
+        {
+            if (mem_obj->len > size)
+            {
+                mem_new = get_mem_obj(x_mem);
+                if (mem_new == NULL)
+                {
+                    return NULL;
+                }
+                mem_new->len = size;
+                mem_new->used |= MEM_USED_FLAG;
+                list_init(&mem_new->list);
+
+                mem_obj->len = mem_obj->len - size;
+                list_insert_before(&mem_obj->list, &mem_new->list);
+
+                x_mem->used_mem += size;
+                if (x_mem->used_mem > x_mem->max_mem)
+                {
+                    x_mem->max_mem = x_mem->used_mem;
+                }
+
+                return (void *)(ptr + x_mem->heap_ptr);
+            }
+            else if (mem_obj->len == size)
+            {
+                mem_obj->used |= MEM_USED_FLAG;
+
+                x_mem->used_mem += size;
+                if (x_mem->used_mem > x_mem->max_mem)
+                {
+                    x_mem->max_mem = x_mem->used_mem;
+                }
+
+                return (void *)(ptr + x_mem->heap_ptr);
+            }
+        }
+        ptr += mem_obj->len;
+    }
+
+    return NULL;
+}
+
+void *x_realloc(x_mem_t x_mem, void *mem, unsigned int newsize)
+{
+    size_t len, ptr;
+    struct heap_mem *mem_obj, *tmp;
+    void *nmem;
+
+    ptr = (uint8_t *)mem - x_mem->heap_ptr;
+    if (ptr > x_mem->mem_size_aligned)
+    {
+        return NULL;
+    }
+
+    /* alignment size */
+    newsize = X_ALIGN(newsize, x_mem->align_size);
+    if (newsize > x_mem->mem_size_aligned)
+    {
+        return NULL;
+    }
+    else if (newsize == 0)
+    {
+        x_free(x_mem, mem);
+        return NULL;
+    }
+
+    /* allocate a new memory block */
+    if (mem == NULL)
+        return x_malloc(x_mem, newsize);
+
+    len = 0;
+    list_for_each_entry_safe(mem_obj, tmp, &x_mem->head, list)
+    {
+        if (ptr == len)
+        {
+            if (mem_obj->used & MEM_USED_FLAG)
+            {
+                if (&tmp->list != &x_mem->head && (!(tmp->used & MEM_USED_FLAG)))
+                {
+                    if (tmp->len + mem_obj->len > newsize)
+                    {
+                        tmp->len = newsize - mem_obj->len;
+                        mem_obj->len = newsize;
+                        return mem;
+                    }
+                    else if (tmp->len + mem_obj->len == newsize)
+                    {
+                        mem_obj->len = newsize;
+                        list_remove(&tmp->list);
+                        put_mem_obj(x_mem, tmp);
+                        return mem;
+                    }
+                    else
+                    {
+                        /* expand memory */
+                        nmem = x_malloc(x_mem, newsize);
+                        if (nmem != NULL) /* check memory */
+                        {
+                            memcpy(nmem, mem, mem_obj->len);
+                            x_free(x_mem, mem);
+                        }
+                        return mem;
+                    }
+                }
+            }
+            else
+            {
+                return NULL;
+            }
+        }
+        else if (ptr < len)
+        {
+            return NULL;
+        }
+        len += mem_obj->len;
+    }
+    return NULL;
+}
+
+void *x_calloc(x_mem_t x_mem, unsigned int count, unsigned int size)
+{
+    void *p;
+
+    /* allocate 'count' objects of size 'size' */
+    p = x_malloc(x_mem, count * size);
+
+    /* zero the memory */
+    if (p)
+        memset(p, 0, count * size);
+
+    return p;
+}
+
+/**
+ * This function will release the previously allocated memory block by
+ * x_malloc. The released memory block is taken back to system heap.
+ *
+ * @param rmem the address of memory which will be released
+ */
+void *x_free(x_mem_t x_mem, void *mem)
+{
+    struct heap_mem *mem_obj, *mem_last, *tmp;
+    size_t ptr, len;
+
+    if (mem == NULL)
+        return NULL;
+
+    ptr = (uint8_t *)mem - x_mem->heap_ptr;
+    if (ptr > x_mem->mem_size_aligned)
+    {
+        //failed. return mem
+        return mem;
+    }
+
+    len = 0;
+    mem_last = NULL;
+    list_for_each_entry_safe(mem_obj, tmp, &x_mem->head, list)
+    {
+        if (ptr == len)
+        {
+            if (mem_obj->used & MEM_USED_FLAG)
+            {
+                
+                mem_obj->used &= ~MEM_USED_FLAG;
+                x_mem->used_mem -= mem_obj->len;
+
+                if (mem_last && (!(mem_last->used & MEM_USED_FLAG)))
+                {
+                    mem_last->len += mem_obj->len;
+                    list_remove(&mem_obj->list);
+                    put_mem_obj(x_mem, mem_obj);
+                    mem_obj = mem_last;
+                }
+
+                if (&tmp->list != &x_mem->head && (!(tmp->used & MEM_USED_FLAG)))
+                {
+                    mem_obj->len += tmp->len;
+                    list_remove(&tmp->list);
+                    put_mem_obj(x_mem, tmp);
+                }
+                return NULL;
+            }
+            else
+            {
+                //failed. return mem
+                return mem;
+            }
+        }
+        else if (ptr < len)
+        {
+            //failed. return mem
+            return mem;
+        }
+        len += mem_obj->len;
+        mem_last = mem_obj;
+    }
+    //failed. return mem
+    return mem;
+}
+
+void x_info(x_mem_t x_mem, unsigned int *total, unsigned int *used, unsigned int *max_used)
+{
+    if (total != NULL)
+        *total = x_mem->mem_size_aligned;
+    if (used  != NULL)
+        *used = x_mem->used_mem;
+    if (max_used != NULL)
+        *max_used = x_mem->max_mem;
+}
+
+void x_dump(x_mem_t x_mem)
+{
+    struct heap_mem *mem_obj;
+    uint8_t *p = x_mem->heap_ptr;
+    struct x_mem_tab *tab;
+
+    printf("\ntotal memory: %d\n", x_mem->mem_size_aligned);
+    printf("used memory : %d\n", x_mem->used_mem);
+    printf("maximum allocated memory: %d\n", x_mem->max_mem);
+
+    printf("\n--memory item information --\n");
+    list_for_each_entry(mem_obj, &x_mem->head, list)
+    {
+        printf("[%04p - ", p);
+        if (mem_obj->len < 1024)
+            printf("%05d", mem_obj->len);
+        else if (mem_obj->len < 1024 * 1024)
+            printf("%04dK", mem_obj->len / 1024);
+        else
+            printf("%04dM", mem_obj->len / (1024 * 1024));
+
+        if (mem_obj->used & MEM_USED_FLAG)
+        {
+            printf("] X\n");
+        }
+        else
+        {
+            printf("]\n");
+        }
+        p += mem_obj->len;
+    }
+
+    list_for_each_entry(tab, &x_mem->tab_head, node)
+    {
+        printf("tab[%p] used:%d\n", tab, tab->used);
+    }
+}

+ 48 - 0
src/x_mem.h

@@ -0,0 +1,48 @@
+/*
+ * File      : x_mem.h
+ * COPYRIGHT (C) 2012-2020, Shanghai Real-Thread Electronic Technology Co.,Ltd.
+ * All Rights Reserved.
+ *
+ * This file is part of the RT-Thread MoM Electric Meter system.
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ * 2019-09-12      xxx          the first version
+ */
+
+#ifndef __X_MEM_H__
+#define __X_MEM_H__
+
+#include <stdint.h>
+
+#define ALIGN_SIZE      4
+#define X_MEM_BOUNDARY  0xbd
+
+struct list_node
+{
+    struct list_node *next;                          /**< point to next node. */
+    struct list_node *prev;                          /**< point to prev node. */
+};
+typedef struct list_node list_t;                     /**< Type for lists. */
+
+struct x_mem
+{
+    uint8_t *heap_ptr;
+    size_t align_size;
+    size_t mem_size_aligned;
+    size_t used_mem, max_mem;
+    struct list_node tab_head;
+    list_t head;
+};
+typedef struct x_mem * x_mem_t;
+
+x_mem_t x_create(void *begin_addr, void *end_addr, size_t align_size);
+void x_destroy(x_mem_t x_mem);
+void *x_malloc(x_mem_t x_mem, unsigned int size);
+void *x_calloc(x_mem_t x_mem, unsigned int count, unsigned int size);
+void *x_realloc(x_mem_t x_mem, void *rmem, unsigned int newsize);
+void *x_free(x_mem_t x_mem, void *mem);
+void x_info(x_mem_t x_mem, unsigned int *total, unsigned int *used, unsigned int *max_used);
+void x_dump(x_mem_t x_mem);
+
+#endif