2766 lines
92 KiB
C
2766 lines
92 KiB
C
/****************************************************************************
|
|
|
|
Copyright(c) 2019 by Aerospace C.Power (Chongqing) Microelectronics. ALL RIGHTS RESERVED.
|
|
|
|
This Information is proprietary to Aerospace C.Power (Chongqing) Microelectronics and MAY NOT
|
|
be copied by any method or incorporated into another program without
|
|
the express written consent of Aerospace C.Power. This Information or any portion
|
|
thereof remains the property of Aerospace C.Power. The Information contained herein
|
|
is believed to be accurate and Aerospace C.Power assumes no responsibility or
|
|
liability for its use in any way and conveys no license or title under
|
|
any patent or copyright and makes no representation or warranty that this
|
|
Information is free from patent or copyright infringement.
|
|
|
|
****************************************************************************/
|
|
/* iot common header files */
|
|
#include "iot_config.h"
|
|
#include "iot_io_api.h"
|
|
#include "iot_errno_api.h"
|
|
#include "iot_utils_api.h"
|
|
|
|
#include "iot_dm_flash.h"
|
|
#include "iot_spi_api.h"
|
|
#include "iot_gpio_api.h"
|
|
#include "os_lock_api.h"
|
|
#include "os_mem_api.h"
|
|
|
|
#define DM_MODULE_ID 0
|
|
|
|
/* Manufacturer ID & name. Size of name will not over IOT_DM_MANUFACTURER_NAME_LEN. */
|
|
#define DM_FLASH_MFID_TB \
|
|
{\
|
|
{0x00, (uint8_t *)"Unknown"},\
|
|
{0xC2, (uint8_t *)"Macronix"},\
|
|
{0xEF, (uint8_t *)"Winbond"},\
|
|
}
|
|
|
|
/* Flash size config. */
|
|
#define DM_FLASH_CHIP_SIZE 0x00400000 /* 4MB */
|
|
#define DM_FLASH_SECTOR_SIZE 0x00001000 /* 4KB */
|
|
#define DM_FLASH_PAGE_SIZE 0x00000100 /* 256B */
|
|
|
|
/* Default information of blocks for 4MB flash. */
|
|
/*
|
|
#define DM_FLASH_4M_BLOCKS \
|
|
{\
|
|
{, 0x00001000},\ Header, 1 * sectors, 4K
|
|
{, 0x00008000},\ Variable, 8 * sectors, 32K
|
|
{, 0x00045000},\ Load control, one year. 69 * sectors, 276K
|
|
{, 0x00012000},\ Event control, 1/4 * Load. 18 * sectors, 72K
|
|
{, 0x00012000},\ Private event control, 1/4 * Load. 18 * sectors, 72K
|
|
{, 0x0008A000},\ Load record, one year. 138 * sectors, 552K
|
|
{, 0x0002D000},\ Event record, 1/4 * Load. 45 * sectors, 180K
|
|
{, 0x0002D000},\ Private event record, 1/4 * Load. 45 * sectors, 180K
|
|
{, 0x002AA000},\ Private data. 686 * sectors, 2728K
|
|
}
|
|
*/
|
|
#define DM_FLASH_4M_BLOCKS \
|
|
{\
|
|
{0x00000000, 0x00001000},\
|
|
{0x00001000, 0x00008000},\
|
|
{0x00009000, 0x00045000},\
|
|
{0x0004E000, 0x00012000},\
|
|
{0x00060000, 0x00012000},\
|
|
{0x00072000, 0x0008A000},\
|
|
{0x000FC000, 0x0002D000},\
|
|
{0x00129000, 0x0002D000},\
|
|
{0x00156000, 0x002AA000},\
|
|
}
|
|
|
|
typedef struct _iot_dm_flash_sector_buffer_t {
|
|
uint32_t len;
|
|
void *buf;
|
|
}iot_dm_flash_sec_buf_t;
|
|
|
|
typedef struct _iot_dm_flash_mfid_name_t {
|
|
uint32_t mfid;
|
|
uint8_t *name;
|
|
}iot_dm_flash_mfid_name_t;
|
|
|
|
typedef struct _iot_dm_flash_operation_code_t {
|
|
uint8_t wren; /* Write enable. */
|
|
uint8_t wrdi; /* Write disable. */
|
|
uint8_t rdid; /* Read Identifcation . */
|
|
uint8_t rdsr; /* Read Status Register. */
|
|
uint8_t wrsr; /* Write Status Register. */
|
|
uint8_t read; /* Read Data Bytes. */
|
|
uint8_t se; /* Sector erase. */
|
|
uint8_t pp; /* Page Program */
|
|
}iot_dm_flash_opcode_t;
|
|
|
|
iot_dm_flash_opcode_t common_op = {
|
|
.wren = 0x06,
|
|
.wrdi = 0x04,
|
|
.rdid = 0x9F,
|
|
.rdsr = 0x05,
|
|
.wrsr = 0x01,
|
|
.read = 0x03,
|
|
.se = 0x20,
|
|
.pp = 0x02,
|
|
};
|
|
|
|
typedef struct _iot_dm_flash_object_t {
|
|
/* flag to indicate if this module ready */
|
|
uint32_t init_done_flag;
|
|
/* spi device number for driver layer */
|
|
uint32_t spi_dev;
|
|
/* variable index. */
|
|
uint32_t var_idx;
|
|
/* variable value */
|
|
iot_dm_vari_t variable;
|
|
/* lock for flash operation */
|
|
os_mutex_h lock;
|
|
/* header of this flash, stored from offset 0x00 on flash chip. */
|
|
iot_dm_flash_t header;
|
|
/* Information about this flash chip */
|
|
iot_dm_flash_chip_t chip;
|
|
/* buffer for sector rude write */
|
|
iot_dm_flash_sec_buf_t sbuf;
|
|
/* opcode for this flash chip */
|
|
iot_dm_flash_opcode_t *op_code;
|
|
}iot_dm_flash_obj_t;
|
|
|
|
static iot_dm_flash_obj_t g_dm_flash_obj;
|
|
|
|
/* locks for operation on flash chip. */
|
|
#define dm_flash_lock() os_acquire_mutex(g_dm_flash_obj.lock)
|
|
#define dm_flash_unlock() os_release_mutex(g_dm_flash_obj.lock)
|
|
|
|
/* get address of first byte on flash sector from offset. */
|
|
#define dm_flash_get_sector(offset) ((offset) & (~(g_dm_flash_obj.chip.sec_size - 1)))
|
|
/* get address of first byte on flash page from offset. */
|
|
#define dm_flash_get_page(offset) ((offset) & (~(g_dm_flash_obj.chip.page_size - 1)))
|
|
|
|
/* get the day number from timestamp. */
|
|
#define dm_flash_get_day(timestamp) ((timestamp) / (24 * 60 * 60))
|
|
/* get the second number from timestamp. */
|
|
#define dm_flash_get_seconds(timestamp) ((timestamp) % (24 * 60 * 60))
|
|
/* constract timestamp from day & seconds */
|
|
#define dm_flash_get_timestamp(day, seconds) ((day) * (24 * 60 * 60) + seconds)
|
|
|
|
/* tool micro , min() & max() */
|
|
#define dm_flash_max(a, b) ((a) > (b) ? (a) : (b))
|
|
#define dm_flash_min(a, b) ((a) > (b) ? (b) : (a))
|
|
|
|
/* Flag to tell if flash ready to access. */
|
|
#define DM_FLASH_READY_FLAG 0xF628FD9E
|
|
#define dm_flash_set_ready() (g_dm_flash_obj.init_done_flag = DM_FLASH_READY_FLAG)
|
|
#define dm_flash_set_not_ready() (g_dm_flash_obj.init_done_flag = 0)
|
|
#define dm_flash_is_ready() (DM_FLASH_READY_FLAG == g_dm_flash_obj.init_done_flag)
|
|
|
|
/* SPI GPIO config: */
|
|
#define DM_FLASH_GPIO_CLK 22
|
|
#define DM_FLASH_GPIO_CS 31
|
|
#define DM_FLASH_GPIO_MOSI 28
|
|
#define DM_FLASH_GPIO_MISO 36
|
|
|
|
/* Flash status register bits */
|
|
#define DM_FLASH_WIP 0x01
|
|
#define DM_FLASH_WEL 0x02
|
|
|
|
/* wait cycles when set WEL or clear WIP */
|
|
#define DM_FLASH_WAIT_TIMES 1000000
|
|
|
|
/************************* DEBUG START ************************/
|
|
#define DM_FLASH_DEBUG_TEST 1
|
|
/************************* DEBUG END ************************/
|
|
static char flash_dmup_buf[1024 + 16];
|
|
static uint8_t test_buf[256];
|
|
void dm_flash_dump_bin(void * buf, uint32_t len)
|
|
{
|
|
char *p = buf, *q = flash_dmup_buf;
|
|
uint32_t i, buf_len;
|
|
|
|
buf_len = iot_sprintf(q, "DUMP(%03d):", len);
|
|
|
|
for(i = 0; (i < len) && (buf_len < 1024); i++, p++) {
|
|
buf_len += iot_sprintf(q + buf_len, " %02x", ((int)*p) & 0xFF);
|
|
}
|
|
|
|
iot_cus_printf("\n[DM_DRV@%04d]:%s", __LINE__, flash_dmup_buf);
|
|
|
|
return;
|
|
}
|
|
|
|
/**
|
|
* @brief dm_flash_raw_read_status() - Read status reg of flash chip.
|
|
* @return status -- status of flash chip.
|
|
*/
|
|
static uint32_t dm_flash_raw_read_status(void)
|
|
{
|
|
char cmd_buf[4];
|
|
xfer_buf x_buf[2];
|
|
|
|
os_mem_set(x_buf, 0x0, sizeof(x_buf));
|
|
|
|
x_buf[0].p_nt = &x_buf[1];
|
|
x_buf[0].size = 1;
|
|
x_buf[0].txbuf = cmd_buf;
|
|
|
|
x_buf[1].size = 1;
|
|
x_buf[1].rxbuf = cmd_buf;
|
|
|
|
cmd_buf[0] = g_dm_flash_obj.op_code->rdsr;
|
|
|
|
if(ERR_OK != iot_spi_poll_transfer(g_dm_flash_obj.spi_dev, x_buf)) {
|
|
iot_cus_printf("\n[DM_DRV@%04d]:read status failed!", __LINE__);
|
|
cmd_buf[0] = 0xFF;
|
|
}
|
|
|
|
return ((uint32_t)cmd_buf[0]) & 0xFF;
|
|
}
|
|
|
|
/**
|
|
* @brief dm_flash_raw_write_enable() - set write ability of flash.
|
|
* @param enable: true - enable, false - disable.
|
|
* @return ERR_FAIL -- Operation failed.
|
|
* @return ERR_OK -- Operation Successful.
|
|
*/
|
|
static uint32_t dm_flash_raw_write_enable(uint32_t enable)
|
|
{
|
|
char cmd_buf[4];
|
|
xfer_buf x_buf[1];
|
|
|
|
os_mem_set(x_buf, 0x0, sizeof(x_buf));
|
|
|
|
x_buf[0].size = 1;
|
|
x_buf[0].txbuf = cmd_buf;
|
|
|
|
cmd_buf[0] = enable ? g_dm_flash_obj.op_code->wren : g_dm_flash_obj.op_code->wrdi;
|
|
|
|
return iot_spi_poll_transfer(g_dm_flash_obj.spi_dev, x_buf);
|
|
}
|
|
|
|
/**
|
|
* @brief dm_flash_raw_write_start() - set command to flash to start writing / erase data array.
|
|
* @return ERR_FAIL -- Operation failed.
|
|
* @return ERR_OK -- Operation Successful.
|
|
*/
|
|
static uint32_t dm_flash_raw_write_start(void)
|
|
{
|
|
uint32_t try_cnt, status;
|
|
|
|
try_cnt = DM_FLASH_WAIT_TIMES;
|
|
|
|
/* 1ST : wait for WIP clear. */
|
|
do
|
|
{
|
|
status = dm_flash_raw_read_status();
|
|
|
|
if(!(DM_FLASH_WIP & status)) {
|
|
break;
|
|
}
|
|
}while(--try_cnt);
|
|
|
|
if(0 == try_cnt) {
|
|
iot_cus_printf("\n[DM_DRV@%04d]:wait WIP timeout!", __LINE__);
|
|
return ERR_FAIL;
|
|
}
|
|
|
|
try_cnt = DM_FLASH_WAIT_TIMES;
|
|
|
|
/* 2ND : set WEL and wait success. */
|
|
do
|
|
{
|
|
if(ERR_OK != dm_flash_raw_write_enable(true)) {
|
|
iot_cus_printf("\n[DM_DRV@%04d]:read status reg failed!", __LINE__);
|
|
return ERR_FAIL;
|
|
}
|
|
|
|
status = dm_flash_raw_read_status();
|
|
|
|
if(DM_FLASH_WEL & status) {
|
|
break;
|
|
}
|
|
}while(--try_cnt);
|
|
|
|
if(0 == try_cnt) {
|
|
iot_cus_printf("\n[DM_DRV@%04d]:wait WEL timeout!", __LINE__);
|
|
return ERR_FAIL;
|
|
}
|
|
|
|
return ERR_OK;
|
|
}
|
|
|
|
/**
|
|
* @brief dm_flash_raw_write_end() - set command to flash to stop writing / erase data array.
|
|
* @return ERR_FAIL -- Operation failed.
|
|
* @return ERR_OK -- Operation Successful.
|
|
*/
|
|
#define dm_flash_raw_write_end() dm_flash_raw_write_enable(false)
|
|
|
|
/**
|
|
* @brief dm_flash_raw_read() - random read from flash. Only X1 mode supported.
|
|
* @param offset: offset of flash chip where to read.
|
|
* @param p_buf: buffer to store data.
|
|
* @param size: size of data to read.
|
|
* @return ERR_FAIL -- Operation failed.
|
|
* @return ERR_OK -- Operation Successful.
|
|
*/
|
|
static uint32_t dm_flash_raw_read(uint32_t offset, uint8_t *p_buf, uint32_t size)
|
|
{
|
|
char cmd_buf[4];
|
|
xfer_buf x_buf[2];
|
|
uint32_t try_cnt = DM_FLASH_WAIT_TIMES;
|
|
|
|
os_mem_set(x_buf, 0x0, sizeof(x_buf));
|
|
|
|
x_buf[0].p_nt = &x_buf[1];
|
|
x_buf[0].size = 4;
|
|
x_buf[0].txbuf = cmd_buf;
|
|
|
|
x_buf[1].p_nt = NULL;
|
|
x_buf[1].size = size;
|
|
x_buf[1].rxbuf = (char *)p_buf;
|
|
|
|
cmd_buf[0] = g_dm_flash_obj.op_code->read;
|
|
cmd_buf[1] = (offset >> 16) & 0xFF;
|
|
cmd_buf[2] = (offset >> 8) & 0xFF;
|
|
cmd_buf[3] = (offset) & 0xFF;
|
|
|
|
/* wait for WIP clear. */
|
|
do
|
|
{
|
|
if(!(DM_FLASH_WIP & dm_flash_raw_read_status())) {
|
|
break;
|
|
}
|
|
}while(--try_cnt);
|
|
|
|
/* read the flash chip. */
|
|
if(0 == try_cnt
|
|
|| ERR_OK != iot_spi_poll_transfer(g_dm_flash_obj.spi_dev, x_buf)) {
|
|
iot_cus_printf("\n[DM_DRV@%04d]:read timeout!", __LINE__);
|
|
return ERR_FAIL;
|
|
}
|
|
|
|
return ERR_OK;
|
|
}
|
|
|
|
/**
|
|
* @brief dm_flash_raw_write_page() - random write data to any page, cannot cross page.
|
|
* @param offset: offset of flash chip where to write.
|
|
* @param p_buf: buffer to store data.
|
|
* @param size: size of data to write.
|
|
* @return ERR_FAIL -- Operation failed.
|
|
* @return ERR_OK -- Operation Successful.
|
|
*/
|
|
static uint32_t dm_flash_raw_write_page(uint32_t offset, uint8_t *p_buf, uint32_t size)
|
|
{
|
|
uint32_t page_addr;
|
|
char cmd_buf[4];
|
|
xfer_buf x_buf[2];
|
|
|
|
page_addr = offset;
|
|
|
|
os_mem_set(x_buf, 0x0, sizeof(x_buf));
|
|
|
|
x_buf[0].p_nt = &x_buf[1];
|
|
x_buf[0].size = 4;
|
|
x_buf[0].txbuf = cmd_buf;
|
|
|
|
x_buf[1].size = size;
|
|
x_buf[1].txbuf = (char *)p_buf;
|
|
|
|
cmd_buf[0] = g_dm_flash_obj.op_code->pp;
|
|
cmd_buf[1] = (page_addr >> 16) & 0xFF;
|
|
cmd_buf[2] = (page_addr >> 8) & 0xFF;
|
|
cmd_buf[3] = (page_addr) & 0xFF;
|
|
|
|
dm_flash_raw_write_start();
|
|
|
|
if(ERR_OK != iot_spi_poll_transfer(g_dm_flash_obj.spi_dev, x_buf)) {
|
|
iot_cus_printf("\n[DM_DRV@%04d]:send write failed!", __LINE__);
|
|
return ERR_FAIL;
|
|
}
|
|
|
|
return ERR_OK;
|
|
}
|
|
|
|
/**
|
|
* @brief dm_flash_raw_erase_sector() - erase one sector.
|
|
* @param offset: offset of flash chip where to erase.
|
|
* @return ERR_FAIL -- Operation failed.
|
|
* @return ERR_OK -- Operation Successful.
|
|
*/
|
|
static uint32_t dm_flash_raw_erase_sector(uint32_t offset)
|
|
{
|
|
uint32_t sec_addr;
|
|
char cmd_buf[4];
|
|
xfer_buf x_buf[1];
|
|
|
|
sec_addr = dm_flash_get_sector(offset);
|
|
|
|
os_mem_set(x_buf, 0x0, sizeof(x_buf));
|
|
|
|
x_buf[0].size = 4;
|
|
x_buf[0].txbuf = cmd_buf;
|
|
|
|
cmd_buf[0] = g_dm_flash_obj.op_code->se;
|
|
cmd_buf[1] = (sec_addr >> 16) & 0xFF;
|
|
cmd_buf[2] = (sec_addr >> 8) & 0xFF;
|
|
cmd_buf[3] = (sec_addr) & 0xFF;
|
|
|
|
dm_flash_raw_write_start();
|
|
|
|
if(ERR_OK != iot_spi_poll_transfer(g_dm_flash_obj.spi_dev, x_buf)) {
|
|
iot_cus_printf("\n[DM_DRV@%04d]:send erase failed!", __LINE__);
|
|
return ERR_FAIL;
|
|
}
|
|
|
|
iot_cus_printf("\n[DM_DRV@%04d]:erase sec#%p!", __LINE__, offset);
|
|
|
|
return ERR_OK;
|
|
}
|
|
|
|
/**
|
|
* @brief dm_flash_raw_write_sector() - write whole sector-size buffer to flash.
|
|
* @param offset: offset of flash chip where to write.
|
|
* @param p_buf: buffer to hold data.
|
|
* @param erase: if to erase this sectoer.
|
|
* @return ERR_FAIL -- Operation failed.
|
|
* @return ERR_OK -- Operation Successful.
|
|
*/
|
|
static uint32_t dm_flash_raw_write_sector(uint32_t offset, uint8_t *p_buf, uint32_t erase)
|
|
{
|
|
uint32_t page, sec_offset;
|
|
|
|
/* erase sector */
|
|
if(erase) {
|
|
if(ERR_OK != dm_flash_raw_erase_sector(offset)) {
|
|
iot_cus_printf("\n[DM_DRV@%04d]:sec#0x%x erase failed!", __LINE__, offset);
|
|
return ERR_FAIL;
|
|
}
|
|
}
|
|
|
|
sec_offset = dm_flash_get_sector(offset);
|
|
page = 0;
|
|
|
|
/* data write to sector */
|
|
for(; page < g_dm_flash_obj.chip.sec_size; page += g_dm_flash_obj.chip.page_size) {
|
|
if(ERR_OK != dm_flash_raw_write_page(sec_offset + page, p_buf + page, g_dm_flash_obj.chip.page_size)) {
|
|
iot_cus_printf("\n[DM_DRV@%04d]:sec#0x%x write failed!", __LINE__, offset + page);
|
|
return ERR_FAIL;
|
|
}
|
|
}
|
|
|
|
iot_cus_printf("\n[DM_DRV@%04d]:write sec#%p!", __LINE__, offset);
|
|
|
|
return ERR_OK;
|
|
}
|
|
|
|
/**
|
|
* @brief dm_flash_raw_read_mfid() - read manufacturer & device ID from chip.
|
|
* @param p_buf: buffer to hold data.
|
|
* @param size: size to read, in bytes.
|
|
* @return ERR_FAIL -- Operation failed.
|
|
* @return ERR_OK -- Operation Successful.
|
|
*/
|
|
static uint32_t dm_flash_raw_read_mfid(uint8_t *p_buf, uint32_t size)
|
|
{
|
|
char cmd_buf[4];
|
|
xfer_buf x_buf[2];
|
|
|
|
os_mem_set(x_buf, 0x0, sizeof(x_buf));
|
|
|
|
x_buf[0].p_nt = &x_buf[1];
|
|
x_buf[0].size = 1;
|
|
x_buf[0].txbuf = cmd_buf;
|
|
|
|
x_buf[1].size = size;
|
|
x_buf[1].rxbuf = (char *)p_buf;
|
|
|
|
cmd_buf[0] = g_dm_flash_obj.op_code->rdid;
|
|
|
|
return iot_spi_poll_transfer(g_dm_flash_obj.spi_dev, x_buf);
|
|
}
|
|
|
|
/**
|
|
* @brief dm_flash_raw_random_read() - random read from flash chip from any where, any size.
|
|
* @param offset: offset of flash chip where to read.
|
|
* @param p_buf: buffer to hold data.
|
|
* @param size: size to read, in bytes.
|
|
* @return ERR_FAIL -- Operation failed.
|
|
* @return ERR_OK -- Operation Successful.
|
|
*/
|
|
static uint32_t dm_flash_raw_random_read(uint32_t offset, uint8_t *p_buf, uint32_t size)
|
|
{
|
|
uint32_t ret;
|
|
|
|
ret = dm_flash_raw_read(offset, p_buf, size);
|
|
|
|
return ret;
|
|
}
|
|
|
|
/**
|
|
* @brief dm_flash_raw_random_write() - random write from flash chip from any where, any size.
|
|
* @param offset: offset of flash chip where to write.
|
|
* @param p_buf: buffer to hold data.
|
|
* @param size: size to write, in bytes.
|
|
* @return ERR_FAIL -- Operation failed.
|
|
* @return ERR_OK -- Operation Successful.
|
|
*/
|
|
static uint32_t dm_flash_raw_random_write(uint32_t offset, uint8_t *buf, uint32_t size)
|
|
{
|
|
uint32_t sec_pre_size, sec_end, sec_pst_size, sec_idx, sec_size;
|
|
uint8_t *buf_pos = buf;
|
|
iot_dm_flash_sec_buf_t *p_buf = &g_dm_flash_obj.sbuf;
|
|
|
|
sec_size = g_dm_flash_obj.chip.sec_size;
|
|
|
|
/* offset of the first sector will be written */
|
|
sec_idx = dm_flash_get_sector(offset);
|
|
/* offset of the last sector will be written */
|
|
sec_end = dm_flash_get_sector(offset + size - 1);
|
|
/*
|
|
sec_pre_size : size of data need be written on the first sector.
|
|
sec_pst_size : size of data need be written on the last sector.
|
|
|
|
both sec_pre_size & sec_pst_size, we need read all data from sector then write
|
|
changed data back onto it.
|
|
*/
|
|
if(sec_end == sec_idx) {
|
|
/* all data will be written on only one sector. we just process sec_pre_size. */
|
|
sec_pre_size = size;
|
|
sec_pst_size = 0;
|
|
} else {
|
|
/* all data cross over more than one sector. */
|
|
sec_pre_size = offset & (sec_size - 1);
|
|
if(sec_pre_size > 0) {
|
|
/* get the true pre_size. */
|
|
sec_pre_size = sec_size - sec_pre_size;
|
|
} else {
|
|
/*
|
|
all data of first sector will be written. no need to process sec_pre_size.
|
|
the first sector is in middle ones. do nothing here
|
|
*/
|
|
}
|
|
|
|
sec_pst_size = (offset + size) & (sec_size - 1);
|
|
if(sec_pst_size > 0) {
|
|
/* just process sec_pst_size. do nothing here. */
|
|
} else {
|
|
/*
|
|
all data of first sector will be written. no need to process sec_pst_size.
|
|
put last sector in middle ones.
|
|
*/
|
|
sec_end += sec_size;
|
|
}
|
|
}
|
|
|
|
iot_cus_printf("\n[DM_DRV@%04d]:random write start sec#%p, end sec#%p, pre size#%p, post size %p!",
|
|
__LINE__, sec_idx, sec_end, sec_pre_size, sec_pst_size);
|
|
|
|
/* process the first sector */
|
|
if(sec_pre_size > 0) {
|
|
/* backup data on first sector. */
|
|
if(ERR_OK != dm_flash_raw_random_read(sec_idx, p_buf->buf, sec_size)) {
|
|
iot_cus_printf("\n[DM_DRV@%04d]:sec#0x%x read failed!", __LINE__, sec_idx);
|
|
return ERR_FAIL;
|
|
}
|
|
|
|
/* cover old data. */
|
|
os_mem_cpy(p_buf->buf + sec_size - sec_pre_size, buf_pos, sec_pre_size);
|
|
|
|
if(ERR_OK != dm_flash_raw_write_sector(sec_idx, p_buf->buf, true)) {
|
|
iot_cus_printf("\n[DM_DRV@%04d]:sec#0x%x write failed!", __LINE__, sec_idx);
|
|
return ERR_FAIL;
|
|
}
|
|
|
|
/* offset to the next sector. */
|
|
sec_idx += sec_size;
|
|
buf_pos += sec_pre_size;
|
|
}
|
|
|
|
/* process the middle sectors */
|
|
for(;sec_idx < sec_end; sec_idx += sec_size) {
|
|
if(ERR_OK != dm_flash_raw_write_sector(sec_idx, buf_pos, true)) {
|
|
iot_cus_printf("\n[DM_DRV@%04d]:sec#0x%x write failed!", __LINE__, sec_idx);
|
|
return ERR_FAIL;
|
|
}
|
|
buf_pos += sec_size;
|
|
}
|
|
|
|
/* process the last sector */
|
|
if(sec_pst_size > 0) {
|
|
/* backup data on first sector. */
|
|
if(ERR_OK != dm_flash_raw_random_read(sec_idx, p_buf->buf, sec_size)) {
|
|
iot_cus_printf("\n[DM_DRV@%04d]:sec#0x%x read failed!", __LINE__, sec_idx);
|
|
return ERR_FAIL;
|
|
}
|
|
|
|
/* cover old data. */
|
|
os_mem_cpy(p_buf->buf, buf_pos, sec_pst_size);
|
|
|
|
if(ERR_OK != dm_flash_raw_write_sector(sec_idx, p_buf->buf, true)) {
|
|
iot_cus_printf("\n[DM_DRV@%04d]:sec#0x%x write failed!", __LINE__, sec_idx);
|
|
return ERR_FAIL;
|
|
}
|
|
}
|
|
|
|
return ERR_OK;
|
|
}
|
|
|
|
/**
|
|
* @brief dm_flash_raw_random_erase() - random erase from flash chip from any where, any size.
|
|
* @param offset: offset of flash chip where to erase.
|
|
* @param size: size to erase, in bytes.
|
|
* @return ERR_FAIL -- Operation failed.
|
|
* @return ERR_OK -- Operation Successful.
|
|
*/
|
|
static uint32_t dm_flash_raw_random_erase(uint32_t offset, uint32_t size)
|
|
{
|
|
uint32_t sec_pre_size, sec_end, sec_pst_size, sec_idx, sec_size;
|
|
iot_dm_flash_sec_buf_t *p_buf = &g_dm_flash_obj.sbuf;
|
|
|
|
sec_size = g_dm_flash_obj.chip.sec_size;
|
|
|
|
/* offset of the first sector will be erased */
|
|
sec_idx = dm_flash_get_sector(offset);
|
|
/* offset of the last sector will be erased */
|
|
sec_end = dm_flash_get_sector(offset + size - 1);
|
|
/*
|
|
sec_pre_size : size of data need be erased on the first sector.
|
|
sec_pst_size : size of data need be erased on the last sector.
|
|
|
|
both sec_pre_size & sec_pst_size, we need read all data from sector then write
|
|
changed data back onto it.
|
|
*/
|
|
if(sec_end == sec_idx) {
|
|
/* all data will be erased on only one sector. we just process sec_pre_size. */
|
|
sec_pre_size = size;
|
|
sec_pst_size = 0;
|
|
} else {
|
|
/* all data cross over more than one sector. */
|
|
sec_pre_size = offset & (sec_size - 1);
|
|
if(sec_pre_size > 0) {
|
|
/* get the true pre_size. */
|
|
sec_pre_size = sec_size - sec_pre_size;
|
|
} else {
|
|
/*
|
|
all data of first sector will be erased. no need to process sec_pre_size.
|
|
the first sector is in middle ones. do nothing here
|
|
*/
|
|
}
|
|
|
|
sec_pst_size = (offset + size) & (sec_size - 1);
|
|
if(sec_pst_size > 0) {
|
|
/* just process sec_pst_size. do nothing here. */
|
|
} else {
|
|
/*
|
|
all data of first sector will be erased. no need to process sec_pst_size.
|
|
put last sector in middle ones.
|
|
*/
|
|
sec_end += sec_size;
|
|
}
|
|
}
|
|
|
|
iot_cus_printf("\n[DM_DRV@%04d]:random erase start sec#%p, end sec#%p, pre size#%p, post size %p!",
|
|
__LINE__, sec_idx, sec_end, sec_pre_size, sec_pst_size);
|
|
|
|
/* process the first sector */
|
|
if(sec_pre_size > 0) {
|
|
/* backup data on first sector. */
|
|
if(ERR_OK != dm_flash_raw_random_read(sec_idx, p_buf->buf, sec_size)) {
|
|
iot_cus_printf("\n[DM_DRV@%04d]:sec#0x%x read failed!", __LINE__, sec_idx);
|
|
return ERR_FAIL;
|
|
}
|
|
/* cover old data. */
|
|
os_mem_set(p_buf->buf + sec_size - sec_pre_size, 0xFF, sec_pre_size);
|
|
|
|
if(ERR_OK != dm_flash_raw_write_sector(sec_idx, p_buf->buf, true)) {
|
|
iot_cus_printf("\n[DM_DRV@%04d]:sec#0x%x write failed!", __LINE__, sec_idx);
|
|
return ERR_FAIL;
|
|
}
|
|
|
|
/* offset to the next sector. */
|
|
sec_idx += sec_size;
|
|
}
|
|
|
|
/* process the middle sectors */
|
|
for(;sec_idx < sec_end; sec_idx += sec_size) {
|
|
if(ERR_OK != dm_flash_raw_erase_sector(sec_idx)) {
|
|
iot_cus_printf("\n[DM_DRV@%04d]:sec#0x%x erase failed!", __LINE__, offset);
|
|
return ERR_FAIL;
|
|
}
|
|
}
|
|
|
|
/* process the last sector */
|
|
if(sec_pst_size > 0) {
|
|
/* backup data on first sector. */
|
|
if(ERR_OK != dm_flash_raw_random_read(sec_idx, p_buf->buf, sec_size)) {
|
|
iot_cus_printf("\n[DM_DRV@%04d]:sec#0x%x read failed!", __LINE__, sec_idx);
|
|
return ERR_FAIL;
|
|
}
|
|
|
|
/* cover old data. */
|
|
os_mem_set(p_buf->buf, 0xFF, sec_pst_size);
|
|
|
|
if(ERR_OK != dm_flash_raw_write_sector(sec_idx, p_buf->buf, true)) {
|
|
iot_cus_printf("\n[DM_DRV@%04d]:sec#0x%x write failed!", __LINE__, sec_idx);
|
|
return ERR_FAIL;
|
|
}
|
|
}
|
|
|
|
return ERR_OK;
|
|
}
|
|
|
|
/**
|
|
* @brief dm_flash_block_is_empty_item() - Check if an item is empty, all 0xFF.
|
|
* @param item: buffer to hold data.
|
|
* @param item_size: size to exame, in bytes.
|
|
* @return true - empty, false - not empty.
|
|
*/
|
|
static inline uint32_t dm_flash_block_is_empty_item(void *item, uint32_t item_size)
|
|
{
|
|
uint8_t *c_byte = (uint8_t *)item, *e_byte = (uint8_t *)item + item_size;
|
|
while((c_byte < e_byte) && (0xFF == *(c_byte++)));
|
|
return ((c_byte == e_byte) ? true : false);
|
|
}
|
|
|
|
/**
|
|
* @brief dm_flash_block_get_item_size() - get size of item in each blocks.
|
|
* @param block: block index.
|
|
* @return size of item.
|
|
*/
|
|
static uint32_t dm_flash_block_get_item_size(uint32_t block)
|
|
{
|
|
switch(block)
|
|
{
|
|
case DM_FLASH_BLOCK_HEADER:
|
|
return sizeof(iot_dm_flash_t);
|
|
case DM_FLASH_BLOCK_VARIABLE:
|
|
return sizeof(iot_dm_vari_t);
|
|
case DM_FLASH_BLOCK_LOAD_CTRL:
|
|
return sizeof(iot_dm_load_day_t);
|
|
case DM_FLASH_BLOCK_LOAD_REC:
|
|
return sizeof(iot_dm_load_record_t);
|
|
case DM_FLASH_BLOCK_EVENT_CTRL:
|
|
return sizeof(iot_dm_event_day_t);
|
|
case DM_FLASH_BLOCK_EVENT_REC:
|
|
return sizeof(iot_dm_event_record_t);
|
|
case DM_FLASH_BLOCK_PRIV_EVENT_CTRL:
|
|
return sizeof(iot_dm_event_day_t);
|
|
case DM_FLASH_BLOCK_PRIV_EVENT_REC:
|
|
default:
|
|
return sizeof(iot_dm_event_record_t);
|
|
}
|
|
|
|
/* will not hit */
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* @brief dm_flash_block_get_index_max() - get max index of items in given block.
|
|
* @param block: block index.
|
|
* @return max index of this block, start from 0.
|
|
*/
|
|
static uint32_t dm_flash_block_get_index_max(uint32_t block)
|
|
{
|
|
iot_dm_flash_block_desc_t *blk = &g_dm_flash_obj.header.block[block];
|
|
uint32_t sec_size = g_dm_flash_obj.chip.sec_size, count;
|
|
|
|
switch(block)
|
|
{
|
|
case DM_FLASH_BLOCK_HEADER:
|
|
count = (blk->size / sec_size) * (sec_size / sizeof(iot_dm_flash_t));
|
|
break;
|
|
case DM_FLASH_BLOCK_VARIABLE:
|
|
count = (blk->size / sec_size) * (sec_size / sizeof(iot_dm_vari_t));
|
|
break;
|
|
case DM_FLASH_BLOCK_LOAD_CTRL:
|
|
count = (blk->size / sec_size) * (sec_size / sizeof(iot_dm_load_day_t));
|
|
break;
|
|
case DM_FLASH_BLOCK_LOAD_REC:
|
|
count = (blk->size / sec_size) * (sec_size / sizeof(iot_dm_load_record_t));
|
|
break;
|
|
case DM_FLASH_BLOCK_EVENT_CTRL:
|
|
count = (blk->size / sec_size) * (sec_size / sizeof(iot_dm_event_day_t));
|
|
break;
|
|
case DM_FLASH_BLOCK_EVENT_REC:
|
|
count = (blk->size / sec_size) * (sec_size / sizeof(iot_dm_event_record_t));
|
|
break;
|
|
case DM_FLASH_BLOCK_PRIV_EVENT_CTRL:
|
|
count = (blk->size / sec_size) * (sec_size / sizeof(iot_dm_event_day_t));
|
|
break;
|
|
case DM_FLASH_BLOCK_PRIV_EVENT_REC:
|
|
default:
|
|
count = (blk->size / sec_size) * (sec_size / sizeof(iot_dm_event_record_t));
|
|
break;
|
|
}
|
|
|
|
return count - 1;
|
|
}
|
|
|
|
/**
|
|
* @brief dm_flash_block_get_item_count_per_sector() - get count of items a sector holds.
|
|
* @param block: block index.
|
|
* @return count of items.
|
|
*/
|
|
static uint32_t dm_flash_block_get_item_count_per_sector(uint32_t block)
|
|
{
|
|
return g_dm_flash_obj.chip.sec_size / dm_flash_block_get_item_size(block);
|
|
}
|
|
|
|
/**
|
|
* @brief dm_flash_block_convert_index_to_offset() - convent index of an item
|
|
* on a block to the offset of this item on the flash chip.
|
|
* @param block: block index.
|
|
* @param index: index of item on this block.
|
|
* @return offset of this index of items.
|
|
*/
|
|
static uint32_t dm_flash_block_convert_index_to_offset(uint32_t block, uint32_t index)
|
|
{
|
|
uint32_t offset, tol_index, cnt_p_sec, item_size;
|
|
|
|
item_size = dm_flash_block_get_item_size(block);
|
|
|
|
cnt_p_sec = dm_flash_block_get_item_count_per_sector(block);
|
|
|
|
/* count of total items on this block. */
|
|
tol_index = (g_dm_flash_obj.header.block[block].size / g_dm_flash_obj.chip.sec_size)
|
|
* cnt_p_sec;
|
|
|
|
if(index > tol_index) {
|
|
/* this will not hit. roll back from index of 0. */
|
|
index %= tol_index;
|
|
}
|
|
|
|
/* calculate the offset on flash chip. */
|
|
offset = (index / cnt_p_sec) * g_dm_flash_obj.chip.sec_size
|
|
+ (index % cnt_p_sec) * item_size + g_dm_flash_obj.header.block[block].start;
|
|
|
|
return offset;
|
|
}
|
|
|
|
/**
|
|
* @brief dm_flash_block_get_index_with_delta() - to plus or minus a delta from given index.
|
|
* @param block: block index.
|
|
* @param index: index of item on this block.
|
|
* @param delta: delta value to plus from given index.
|
|
* @return the final index.
|
|
*/
|
|
static uint32_t dm_flash_block_get_index_with_delta(uint32_t block, uint32_t index, int32_t delta)
|
|
{
|
|
int32_t next_index, tol_index, item_size, cur_index;
|
|
|
|
item_size = dm_flash_block_get_item_size(block);
|
|
|
|
/* count of total items on this block. */
|
|
tol_index = (g_dm_flash_obj.header.block[block].size / g_dm_flash_obj.chip.sec_size)
|
|
* (g_dm_flash_obj.chip.sec_size / item_size);
|
|
|
|
cur_index = (int32_t)index; /* index always >= 0 */
|
|
|
|
/* calculate next index, will think about roll back when cur_index + delta over range. */
|
|
if(cur_index + delta >= tol_index) {
|
|
/* cur_index + delta over max index */
|
|
next_index = cur_index + delta - tol_index;
|
|
iot_cus_printf("\n[DM_DRV@%04d]:block=%d, index=%d, delta=%d, next=%d!",
|
|
__LINE__, block, cur_index, delta, next_index);
|
|
} else if(cur_index + delta < 0) {
|
|
/* cur_index + delta bellow min index */
|
|
next_index = cur_index + delta + tol_index;
|
|
iot_cus_printf("\n[DM_DRV@%04d]:block=%d, index=%d, delta=%d, next=%d!",
|
|
__LINE__, block, cur_index, delta, next_index);
|
|
} else {
|
|
/* cur_index + delta right in range */
|
|
next_index = cur_index + delta;
|
|
}
|
|
|
|
// iot_cus_printf("\n[DM_DRV@%04d]:index=%d, delta=%d, next=%d!", cur_index, delta, next_index, 4, 5, 6);
|
|
|
|
IOT_ASSERT((next_index >= 0) && (next_index < tol_index));
|
|
|
|
/* next_index always >= 0 */
|
|
return (uint32_t)next_index;
|
|
}
|
|
|
|
/**
|
|
* @brief dm_flash_block_get_next_index() - get index next behind given one.
|
|
* @param block: block index.
|
|
* @param index: index of item on this block.
|
|
* @return the next index.
|
|
*/
|
|
#define dm_flash_block_get_next_index(block, index) dm_flash_block_get_index_with_delta(block, index, 1)
|
|
|
|
/**
|
|
* @brief dm_flash_block_get_last_index() - get index next before given one.
|
|
* @param block: block index.
|
|
* @param index: index of item on this block.
|
|
* @return the last index.
|
|
*/
|
|
#define dm_flash_block_get_last_index(block, index) dm_flash_block_get_index_with_delta(block, index, -1)
|
|
|
|
/**
|
|
* @brief dm_flash_block_roll_write_item() - roll write an item into any block. This function
|
|
* will erase next sector if no more than 2 positions of item left on current sector.
|
|
* @param block: block index.
|
|
* @param index: index of item on this block to write this item.
|
|
* @param item: item to write.
|
|
* @return 0xffffffff - error, else - next write index.
|
|
*/
|
|
static uint32_t dm_flash_block_roll_write_item(uint32_t block, uint32_t index, void *item)
|
|
{
|
|
uint32_t offset, page_size, left_bytes, next_index, item_size, sec_size;
|
|
iot_dm_flash_block_desc_t *p_block;
|
|
|
|
page_size = g_dm_flash_obj.chip.page_size;
|
|
sec_size = g_dm_flash_obj.chip.sec_size;
|
|
item_size = dm_flash_block_get_item_size(block);
|
|
|
|
/* check valid of index */
|
|
next_index = dm_flash_block_get_index_max(block);
|
|
if(index > next_index) {
|
|
iot_cus_printf("\n[DM_DRV@%04d]:invalid index=%d, max=%d!",
|
|
__LINE__, index, next_index);
|
|
return (uint32_t)(-1);
|
|
}
|
|
|
|
/* block information about start & size */
|
|
p_block = &g_dm_flash_obj.header.block[block];
|
|
|
|
/* get offset of flash chip */
|
|
offset = dm_flash_block_convert_index_to_offset(block, index);
|
|
|
|
/* bytes left on this sector */
|
|
left_bytes = dm_flash_get_sector(offset) + sec_size - (offset + item_size);
|
|
|
|
/* erase next sector when there is only one empty item for writing. */
|
|
if((left_bytes / item_size) < 2) {
|
|
iot_cus_printf("\n[DM_DRV@%04d]:left size=%d @ offset%p on block#%d, erase next sector!",
|
|
__LINE__, left_bytes, offset, block);
|
|
/* offset on next sector. */
|
|
offset = dm_flash_get_sector(offset) + sec_size;
|
|
/* check if current sector is over range */
|
|
offset = (offset >= (p_block->start + p_block->size)) ? p_block->start : offset;
|
|
if(ERR_OK != dm_flash_raw_erase_sector(offset)) {
|
|
iot_cus_printf("\n[DM_DRV@%04d]:sec#0x%x erase failed!", __LINE__, offset);
|
|
return (uint32_t)(-1);
|
|
}
|
|
/* offset of flash chip */
|
|
offset = dm_flash_block_convert_index_to_offset(block, index);
|
|
}
|
|
|
|
/* write data after next sector erased if no empty item on current sector. */
|
|
|
|
/* bytes lest on this page */
|
|
left_bytes = dm_flash_get_page(offset) + page_size - offset;
|
|
|
|
if(left_bytes >= item_size) {
|
|
/* all data on the same page. */
|
|
if(ERR_OK != dm_flash_raw_write_page(offset, item, item_size)) {
|
|
iot_cus_printf("\n[DM_DRV@%04d]:roll write failed!", __LINE__);
|
|
return (uint32_t)(-1);
|
|
}
|
|
|
|
if(ERR_OK != dm_flash_raw_read(offset, test_buf, item_size)) {
|
|
iot_cus_printf("\n[DM_DRV@%04d]:dm_flash_raw_read failed!", __LINE__);
|
|
}
|
|
|
|
if(os_mem_cmp(test_buf, item, item_size)) {
|
|
iot_cus_printf("\n[DM_DRV@%04d]:roll write cmp failed!", __LINE__);
|
|
dm_flash_dump_bin(item, item_size);
|
|
dm_flash_dump_bin(test_buf, item_size);
|
|
}
|
|
|
|
} else {
|
|
/* all data cross 2 pages. */
|
|
if(ERR_OK != dm_flash_raw_write_page(offset, item, left_bytes)) {
|
|
iot_cus_printf("\n[DM_DRV@%04d]:roll write failed!", __LINE__);
|
|
return (uint32_t)(-1);
|
|
}
|
|
if(ERR_OK != dm_flash_raw_write_page(offset + left_bytes, item + left_bytes, item_size - left_bytes)) {
|
|
iot_cus_printf("\n[DM_DRV@%04d]:roll write failed!", __LINE__);
|
|
return (uint32_t)(-1);
|
|
}
|
|
}
|
|
|
|
/* get next index to write */
|
|
next_index = dm_flash_block_get_next_index(block, index);
|
|
|
|
return next_index;
|
|
}
|
|
|
|
/**
|
|
* @brief dm_flash_block_roll_write_variable() - roll write variable block.
|
|
* @param var: variable data to write.
|
|
* @return ERR_FAIL - Operation failed, ERR_OK - Operation Successful
|
|
*/
|
|
static uint32_t dm_flash_block_roll_write_variable(iot_dm_vari_t *var)
|
|
{
|
|
uint32_t ret;
|
|
|
|
ret = dm_flash_block_roll_write_item(DM_FLASH_BLOCK_VARIABLE, g_dm_flash_obj.var_idx, var);
|
|
|
|
if((uint32_t)(-1) == ret) {
|
|
iot_cus_printf("\n[DM_DRV@%04d]:write variable failed!", __LINE__);
|
|
return ERR_FAIL;
|
|
}
|
|
|
|
/* the return is the next index to be writtn. */
|
|
g_dm_flash_obj.var_idx = ret;
|
|
|
|
return ERR_OK;
|
|
}
|
|
|
|
/**
|
|
* @brief dm_flash_block_read_record_continuous() - read item value from index
|
|
* start_idx to end_idx(included) on block. start_idx <= end_idx.
|
|
* @param block: block index.
|
|
* @param start_idx: start index.
|
|
* @param end_idx: end index.
|
|
* @param item: buffer to hold item.
|
|
* @return ERR_FAIL - Operation failed, ERR_OK - Operation Successful
|
|
*/
|
|
static uint32_t dm_flash_block_read_record_continuous(uint32_t block,
|
|
uint32_t start_idx, uint32_t end_idx, void *item)
|
|
{
|
|
uint32_t offset, sec_pre_cnt, sec_end, sec_pst_cnt, sec_idx, cnt_per_sec;
|
|
uint32_t item_size, rd_bytes;
|
|
uint8_t *buf = item;
|
|
|
|
cnt_per_sec = dm_flash_block_get_item_count_per_sector(block);
|
|
|
|
sec_idx = start_idx / cnt_per_sec;
|
|
|
|
sec_end = end_idx / cnt_per_sec;
|
|
|
|
item_size = dm_flash_block_get_item_size( block);
|
|
|
|
/*
|
|
sec_pre_cnt : count of items to be read from the first sector.
|
|
sec_pst_cnt : count of items to be read from the last sector.
|
|
*/
|
|
|
|
if(sec_idx == sec_end) {
|
|
/* all items are on the first sector. */
|
|
sec_pre_cnt = end_idx - start_idx + 1;
|
|
sec_pst_cnt = 0;
|
|
} else {
|
|
/* get count of item on first sector */
|
|
sec_pre_cnt = start_idx % cnt_per_sec;
|
|
|
|
if(sec_pre_cnt > 0) {
|
|
/* not the first item on sector, we need sec_pre_cnt items from first sector*/
|
|
sec_pre_cnt = cnt_per_sec - sec_pre_cnt;
|
|
} else {
|
|
/* process as a whole sector. nothing to do */
|
|
// sec_pre_cnt = 0;
|
|
}
|
|
|
|
/* get count of item on last sector */
|
|
sec_pst_cnt = (end_idx % cnt_per_sec);
|
|
|
|
if(sec_pst_cnt == (cnt_per_sec - 1)) {
|
|
/* process as a whole sector */
|
|
sec_pst_cnt = 0;
|
|
/* extend to next sector, with sec_pst_cnt = 0. */
|
|
sec_end += 1;
|
|
} else {
|
|
/* not the last item on sector. get count from index (+1) */
|
|
sec_pst_cnt += 1;
|
|
}
|
|
}
|
|
|
|
iot_cus_printf("\n[DM_DRV@%04d]:record read block#%d, sec_start#%d, sec_end#%d, pre count#0x%x, post count#0x%x!",
|
|
__LINE__, block, sec_idx, sec_end, sec_pre_cnt, sec_pst_cnt);
|
|
|
|
/* process the first sector */
|
|
if(sec_pre_cnt > 0) {
|
|
rd_bytes = sec_pre_cnt * item_size;
|
|
offset = dm_flash_block_convert_index_to_offset(block, start_idx);
|
|
iot_cus_printf("\n[DM_DRV@%04d]:read offset=%p, bytes=%d!",
|
|
__LINE__, offset, rd_bytes);
|
|
if(ERR_OK != dm_flash_raw_read(offset, buf, rd_bytes)) {
|
|
iot_cus_printf("\n[DM_DRV@%04d]:read failed offset=%p, bytes=%d!",
|
|
__LINE__, offset, rd_bytes);
|
|
return ERR_FAIL;
|
|
}
|
|
|
|
/* offset to the next sector. */
|
|
sec_idx++;
|
|
buf += rd_bytes;
|
|
}
|
|
|
|
/* process the middle sector */
|
|
rd_bytes = cnt_per_sec * item_size;
|
|
for(;sec_idx < sec_end; sec_idx++) {
|
|
offset = dm_flash_block_convert_index_to_offset(block, sec_idx * cnt_per_sec);
|
|
iot_cus_printf("\n[DM_DRV@%04d]:read offset=%p, bytes=%d!",
|
|
__LINE__, offset, rd_bytes);
|
|
if(ERR_OK != dm_flash_raw_read(offset, buf, rd_bytes)) {
|
|
iot_cus_printf("\n[DM_DRV@%04d]:read failed offset=%p, bytes=%d!",
|
|
__LINE__, offset, rd_bytes);
|
|
return ERR_FAIL;
|
|
}
|
|
buf += rd_bytes;
|
|
}
|
|
|
|
/* process the last sector */
|
|
if(sec_pst_cnt > 0) {
|
|
offset = dm_flash_block_convert_index_to_offset(block, sec_idx * cnt_per_sec);
|
|
rd_bytes = sec_pst_cnt * item_size;
|
|
iot_cus_printf("\n[DM_DRV@%04d]:read offset=%p, bytes=%d!",
|
|
__LINE__, offset, rd_bytes);
|
|
if(ERR_OK != dm_flash_raw_read(offset, buf, rd_bytes)) {
|
|
iot_cus_printf("\n[DM_DRV@%04d]:read failed offset=%p, bytes=%d!",
|
|
__LINE__, offset, rd_bytes);
|
|
return ERR_FAIL;
|
|
}
|
|
}
|
|
|
|
return ERR_OK;
|
|
}
|
|
|
|
/**
|
|
* @brief dm_flash_block_read_record() - read item value from index
|
|
* start_idx, given number of items on block.
|
|
* @param block: block index.
|
|
* @param start_idx: start index.
|
|
* @param count: count of items.
|
|
* @param item: buffer to hold item.
|
|
* @return ERR_FAIL - Operation failed, ERR_OK - Operation Successful
|
|
*/
|
|
static uint32_t dm_flash_block_read_record(uint32_t block, uint32_t start_idx, uint32_t count, void *item)
|
|
{
|
|
uint32_t index;
|
|
uint8_t *buf = item;
|
|
|
|
/* Max index of this block. */
|
|
index = dm_flash_block_get_index_max(block);
|
|
|
|
iot_cus_printf("\n[DM_DRV@%04d]:record read block#%d, start#%d, count#%d, max#%d!",
|
|
__LINE__, block, start_idx, count, index);
|
|
|
|
if((start_idx > index) || (count > index - start_idx + 1)) {
|
|
iot_cus_printf("\n[DM_DRV@%04d]:index over range!", __LINE__);
|
|
return ERR_FAIL;
|
|
}
|
|
|
|
/* will think about start_idx + count over max index. */
|
|
if(start_idx + count > index + 1) {
|
|
/* start_idx + count over max index, read index from start_idx ~ max index first */
|
|
if(ERR_OK != dm_flash_block_read_record_continuous(block, start_idx, index, buf)) {
|
|
iot_cus_printf("\n[DM_DRV@%04d]:continuous read failed %d to %d!", __LINE__, start_idx, index);
|
|
return ERR_FAIL;
|
|
}
|
|
buf += (index - start_idx + 1) * dm_flash_block_get_item_size(block);
|
|
/* read index from 0 ~ (count - read_cnt) then. */
|
|
if(ERR_OK != dm_flash_block_read_record_continuous(block, 0, count - (index + 1 - start_idx) - 1, buf)) {
|
|
iot_cus_printf("\n[DM_DRV@%04d]:continuous read failed %d to %d!", __LINE__, 0, count - (index - start_idx));
|
|
return ERR_FAIL;
|
|
}
|
|
} else {
|
|
/* start_idx + count in range, read once. */
|
|
if(ERR_OK != dm_flash_block_read_record_continuous(block, start_idx, start_idx + count - 1, buf)) {
|
|
iot_cus_printf("\n[DM_DRV@%04d]:continuous read failed %d to %d!", __LINE__, start_idx, start_idx + count);
|
|
return ERR_FAIL;
|
|
}
|
|
}
|
|
|
|
return ERR_OK;
|
|
}
|
|
|
|
/**
|
|
* @brief dm_flash_block_read_variable() - read the last variable data from block.
|
|
* @param var: buffer to hold variable data.
|
|
* @param index: next index to write variable data.
|
|
* @return ERR_FAIL - Operation failed, ERR_OK - Operation Successful
|
|
*/
|
|
static uint32_t dm_flash_block_read_variable(iot_dm_vari_t *var, uint32_t *index)
|
|
{
|
|
uint32_t sec_s, sec_e, sec, sec_size, item_cnt_per_sec, item_size;
|
|
uint8_t *buf = g_dm_flash_obj.sbuf.buf, *item, *item_e;
|
|
uint16_t invalid_item = false, try_last_item = true;
|
|
iot_dm_vari_t rd_var;
|
|
|
|
item_size = dm_flash_block_get_item_size(DM_FLASH_BLOCK_VARIABLE);
|
|
|
|
sec_size = g_dm_flash_obj.chip.sec_size;
|
|
sec_s = g_dm_flash_obj.header.block[DM_FLASH_BLOCK_VARIABLE].start;
|
|
sec_e = sec_s + g_dm_flash_obj.header.block[DM_FLASH_BLOCK_VARIABLE].size;
|
|
item_cnt_per_sec = sec_size / item_size;
|
|
item_e = buf + item_cnt_per_sec * item_size;
|
|
|
|
item = buf; /* -Werror=maybe-uninitialized */
|
|
|
|
iot_cus_printf("\n[DM_DRV@%04d]:search var from %p to %p, item size=%d.",
|
|
__LINE__, sec_s, sec_e, item_size);
|
|
|
|
/* search on whold block */
|
|
for(sec = sec_s; sec < sec_e; sec += sec_size) {
|
|
if(ERR_OK != dm_flash_raw_random_read(sec, buf, sec_size)) {
|
|
iot_cus_printf("\n[DM_DRV@%04d]:sec#0x%x read failed!", __LINE__, sec);
|
|
return ERR_FAIL;
|
|
}
|
|
|
|
for(item = buf; item < item_e; item += item_size) {
|
|
if(dm_flash_block_is_empty_item(item, item_size)) {
|
|
/* we find an empty item, this means the pre-item is the item we find. */
|
|
if(item != buf) {
|
|
/* get the item we found. */
|
|
os_mem_cpy(&rd_var, item - item_size, item_size);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
if(item < item_e) {
|
|
/* we found empty item, break. */
|
|
break;
|
|
}
|
|
/* store the last item on this sector, maybe the first item on next sector is empty. */
|
|
os_mem_cpy(&rd_var, item - item_size, item_size);
|
|
}
|
|
|
|
iot_cus_printf("\n[DM_DRV@%04d]:search done on sec@%p, item@idx_%d. ",
|
|
__LINE__, sec, (item - buf - item_size) / item_size);
|
|
|
|
/* will not hit, all sectors are full. */
|
|
if((sec == sec_e) && ((item == item_e))) {
|
|
iot_cus_printf("\n[DM_DRV@%04d]:no empty item found, set default!", __LINE__);
|
|
os_mem_set(&rd_var, 0xFF, item_size);
|
|
}
|
|
|
|
/* first item on first sector is empty, check last 2 item on last sector. */
|
|
if((item == buf) && (sec == sec_s)) {
|
|
sec = sec_e - sec_size;
|
|
item = buf + (item_cnt_per_sec - 2) * item_size;
|
|
if(ERR_OK != dm_flash_raw_random_read(sec + item_size * (item_cnt_per_sec - 2),
|
|
item, 2 * item_size)) {
|
|
iot_cus_printf("\n[DM_DRV@%04d]:sec#0x%x read failed!", __LINE__, sec);
|
|
return ERR_FAIL;
|
|
}
|
|
item += item_size;
|
|
if(!dm_flash_block_is_empty_item(item, item_size)) {
|
|
os_mem_cpy(&rd_var, item, item_size);
|
|
} else {
|
|
/*
|
|
the last one is empty, means there was power off between
|
|
the time erase first sector to write last item.
|
|
*/
|
|
item -= item_size;
|
|
os_mem_cpy(&rd_var, item, item_size);
|
|
}
|
|
}
|
|
|
|
if(dm_flash_block_is_empty_item(&rd_var, item_size)) {
|
|
/* maybe a new flash chip. */
|
|
*index = 0;
|
|
os_mem_set(&rd_var, 0x0, item_size);
|
|
iot_cus_printf("\n[DM_DRV@%04d]:no valid variable item found!", __LINE__);
|
|
/* erase first sector to use it. */
|
|
if(ERR_OK != dm_flash_raw_erase_sector
|
|
(dm_flash_block_convert_index_to_offset(DM_FLASH_BLOCK_VARIABLE, *index))) {
|
|
iot_cus_printf("\n[DM_DRV@%04d]:erase failed!", __LINE__);
|
|
return ERR_FAIL;
|
|
}
|
|
} else {
|
|
*index = ((sec - sec_s) / sec_size) * item_cnt_per_sec
|
|
+ (item - buf) / item_size;
|
|
|
|
check_the_valid_of_item:
|
|
|
|
iot_cus_printf("\n[DM_DRV@%04d]:var-item:index=%d,meter_base=%d!",
|
|
__LINE__, *index , rd_var.meter_base);
|
|
iot_cus_printf("\n[DM_DRV@%04d]:var-item-load:ctrl_idx=%d,rec_idx=%d,timestamp=%d!",
|
|
__LINE__,
|
|
rd_var.load.item_ctrl_idx ,
|
|
rd_var.load.item_rec_idx,
|
|
rd_var.load.item_timestamp);
|
|
iot_cus_printf("\n[DM_DRV@%04d]:var-item-event:ctrl_idx=%d,rec_idx=%d,timestamp=%d!",
|
|
__LINE__,
|
|
rd_var.event.item_ctrl_idx ,
|
|
rd_var.event.item_rec_idx,
|
|
rd_var.event.item_timestamp);
|
|
iot_cus_printf("\n[DM_DRV@%04d]:var-item-priv_event:ctrl_idx=%d,rec_idx=%d,timestamp=%d!",
|
|
__LINE__,
|
|
rd_var.priv_event.item_ctrl_idx ,
|
|
rd_var.priv_event.item_rec_idx,
|
|
rd_var.priv_event.item_timestamp);
|
|
|
|
/* check the valid of indexes on each block. */
|
|
if((dm_flash_block_get_index_max(DM_FLASH_BLOCK_LOAD_CTRL) < rd_var.load.item_ctrl_idx)
|
|
|| (dm_flash_block_get_index_max(DM_FLASH_BLOCK_LOAD_REC) < rd_var.load.item_rec_idx)
|
|
|| (dm_flash_block_get_index_max(DM_FLASH_BLOCK_EVENT_CTRL) < rd_var.event.item_rec_idx)
|
|
|| (dm_flash_block_get_index_max(DM_FLASH_BLOCK_EVENT_REC) < rd_var.event.item_rec_idx)
|
|
|| (dm_flash_block_get_index_max(DM_FLASH_BLOCK_PRIV_EVENT_CTRL) < rd_var.priv_event.item_rec_idx)
|
|
|| (dm_flash_block_get_index_max(DM_FLASH_BLOCK_PRIV_EVENT_REC) < rd_var.priv_event.item_rec_idx)) {
|
|
iot_cus_printf("\n[DM_DRV@%04d]:invalid item found!", __LINE__);
|
|
invalid_item = true;
|
|
}
|
|
|
|
if(invalid_item && try_last_item) {
|
|
/* item invalid, but we just try one item before this one.*/
|
|
try_last_item = false;
|
|
invalid_item = false;
|
|
*index = dm_flash_block_get_last_index(DM_FLASH_BLOCK_VARIABLE, *index);
|
|
if(ERR_OK != dm_flash_block_read_record_continuous
|
|
(DM_FLASH_BLOCK_VARIABLE, *index, *index, &rd_var)) {
|
|
iot_cus_printf("\n[DM_DRV@%04d]:read variable index=%x failed!", __LINE__, *index);
|
|
return ERR_FAIL;
|
|
}
|
|
/* check again. */
|
|
goto check_the_valid_of_item;
|
|
|
|
} else if(invalid_item) {
|
|
/* no valid item, set as default. */
|
|
*index = 0;
|
|
os_mem_set(&rd_var, 0x0, item_size);
|
|
}
|
|
}
|
|
|
|
os_mem_cpy(var, &rd_var, item_size);
|
|
|
|
return ERR_OK;
|
|
}
|
|
|
|
/**
|
|
* @brief dm_flash_block_roll_write_record() - roll write record into block.
|
|
* @param rec_block: record block index.
|
|
* @param item: buffer to hold item.
|
|
* @param timestamp: timestamp of this item.
|
|
* @return ERR_FAIL - Operation failed, ERR_OK - Operation Successful
|
|
*/
|
|
static uint32_t dm_flash_block_roll_write_record(uint32_t rec_block, uint8_t *item,
|
|
uint32_t timestamp)
|
|
{
|
|
uint32_t ret, rec_cur_index, ctrl_block;
|
|
uint8_t day_buf[dm_flash_max(sizeof(iot_dm_load_day_t), sizeof(iot_dm_event_day_t))];
|
|
iot_dm_block_info_t *p_block;
|
|
iot_dm_event_day_t *evt_day = (iot_dm_event_day_t *)day_buf;
|
|
iot_dm_load_day_t *ld_day = (iot_dm_load_day_t *)day_buf;
|
|
|
|
if(DM_FLASH_BLOCK_LOAD_REC == rec_block) {
|
|
p_block = &g_dm_flash_obj.variable.load;
|
|
ctrl_block = DM_FLASH_BLOCK_LOAD_CTRL;
|
|
} else if(DM_FLASH_BLOCK_EVENT_REC == rec_block) {
|
|
p_block = &g_dm_flash_obj.variable.event;
|
|
ctrl_block = DM_FLASH_BLOCK_EVENT_CTRL;
|
|
} else {
|
|
p_block = &g_dm_flash_obj.variable.priv_event;
|
|
rec_block = DM_FLASH_BLOCK_PRIV_EVENT_REC;
|
|
ctrl_block = DM_FLASH_BLOCK_PRIV_EVENT_CTRL;
|
|
}
|
|
|
|
/* write record first, write control later. */
|
|
ret = dm_flash_block_roll_write_item(rec_block, p_block->item_rec_idx, item);
|
|
|
|
if((uint32_t)(-1) == ret) {
|
|
dm_flash_unlock();
|
|
iot_cus_printf("\n[DM_DRV@%04d]:write record failed, index=%d!", __LINE__, p_block->item_rec_idx);
|
|
return ERR_FAIL;
|
|
}
|
|
|
|
rec_cur_index = p_block->item_rec_idx;
|
|
p_block->item_rec_idx = ret;
|
|
|
|
/* check to write control. we do not care about history or future. */
|
|
if(dm_flash_get_day(timestamp) != dm_flash_get_day(p_block->item_timestamp)) {
|
|
if(DM_FLASH_BLOCK_LOAD_REC == rec_block) {
|
|
ld_day->index = rec_cur_index;
|
|
ld_day->timestamp = timestamp;
|
|
} else {
|
|
evt_day->index = rec_cur_index;
|
|
evt_day->timestamp = timestamp;
|
|
}
|
|
|
|
/* write day information after record data written. */
|
|
ret = dm_flash_block_roll_write_item(ctrl_block, p_block->item_ctrl_idx, day_buf);
|
|
|
|
iot_cus_printf("\n[DM_DRV@%04d]:write new day(idx=%d, timestamp=%d), index %d to %d, timestamp %d to %d!",
|
|
__LINE__, rec_cur_index, timestamp, p_block->item_ctrl_idx, ret, p_block->item_timestamp, timestamp);
|
|
|
|
if((uint32_t)(-1) == ret) {
|
|
iot_cus_printf("\n[DM_DRV@%04d]:write contrl failed, index=%d!", __LINE__, p_block->item_ctrl_idx);
|
|
return ERR_FAIL;
|
|
}
|
|
|
|
p_block->item_ctrl_idx = ret;
|
|
}
|
|
|
|
p_block->item_timestamp = timestamp;
|
|
|
|
/* update variable block at last. */
|
|
if(ERR_OK != dm_flash_block_roll_write_variable(&g_dm_flash_obj.variable)) {
|
|
iot_cus_printf("\n[DM_DRV@%04d]:write variable failed!", __LINE__);
|
|
return ERR_FAIL;
|
|
}
|
|
|
|
return ERR_OK;
|
|
}
|
|
|
|
/**
|
|
* @brief dm_flash_block_read_record_count_of_day() - get count of record on given day.
|
|
*
|
|
* a. if the day is history, *num = next_day->index - day->index. we will search whole
|
|
* control block to find day & next_day out.
|
|
* The items index aws bellow:
|
|
* |0.1.2.3.4.5.6...cur_index.......1st_index_on_next_sec....max-2.max-1.max|
|
|
* | <- pre_count -> | (EMPTY) | <- pst_count -> |
|
|
*
|
|
* our search items include the items have index from cur_index to 0 first, and max to 1st_index_on_next_sec.
|
|
* 1. At only position of index we meet an empty item, we regard this as no item matchable.
|
|
* 2. At only position of index we meet an item has timestamp same as argument, we mask this
|
|
* item as day, and the item next to it(index of next_day = (index of day) + 1) as next_day.
|
|
* Then we got the number.
|
|
* 3. if no item has timestamp the same as argument,we regard this as no item matchable.
|
|
* there is a area masked as (EMPTY), they are those items that on the same sector
|
|
* as item of cur_index. They MUST be empty, so we ignore them.
|
|
*
|
|
* b. if the day is current day(on recording), *num = cur_rec_index - last_day->index.
|
|
*
|
|
* @param rec_block: record block index.
|
|
* @param timestamp: timestamp of this item.
|
|
* @param num: buffer to hold count.
|
|
* @param rec_start_index: buffer to index of record start from.
|
|
* @return ERR_FAIL - Operation failed, ERR_OK - Operation Successful
|
|
*/
|
|
static uint32_t dm_flash_block_read_record_count_of_day(uint32_t rec_block, uint32_t timestamp,
|
|
uint32_t *num, uint32_t *rec_start_index)
|
|
{
|
|
iot_dm_block_info_t *blk_info;
|
|
uint8_t *buf, *item;
|
|
uint32_t cur_index, index, front_count, rear_count, ctrl_block;
|
|
uint32_t step, item_day_size, rd_count, rec_start_index_of_last_day, rd_ts, search_end_index;
|
|
|
|
step = 100; /* 100 items every reading from flash chip */
|
|
|
|
if(DM_FLASH_BLOCK_LOAD_REC == rec_block) {
|
|
blk_info = &g_dm_flash_obj.variable.load;
|
|
ctrl_block = DM_FLASH_BLOCK_LOAD_CTRL;
|
|
item_day_size = sizeof(iot_dm_load_day_t);
|
|
} else if(DM_FLASH_BLOCK_EVENT_REC == rec_block) {
|
|
blk_info = &g_dm_flash_obj.variable.event;
|
|
ctrl_block = DM_FLASH_BLOCK_EVENT_CTRL;
|
|
item_day_size = sizeof(iot_dm_event_day_t);
|
|
} else {
|
|
blk_info = &g_dm_flash_obj.variable.priv_event;
|
|
ctrl_block = DM_FLASH_BLOCK_PRIV_EVENT_CTRL;
|
|
rec_block = DM_FLASH_BLOCK_PRIV_EVENT_REC;
|
|
item_day_size = sizeof(iot_dm_event_day_t);
|
|
}
|
|
|
|
if(NULL == (buf = os_mem_malloc(DM_MODULE_ID, item_day_size * step))) {
|
|
iot_cus_printf("\n[DM_DRV@%04d]:os_mem_malloc faild, size#%d!",
|
|
__LINE__, item_day_size * step);
|
|
return ERR_FAIL;
|
|
}
|
|
/* get the last item because it may be the last item we just write. */
|
|
cur_index = dm_flash_block_get_last_index(ctrl_block, blk_info->item_ctrl_idx);
|
|
if(ERR_OK != dm_flash_block_read_record(ctrl_block, cur_index, 1, buf)) {
|
|
iot_cus_printf("\n[DM_DRV@%04d]:record read faild, blk#%d, idx#%d, cnt#%d!",
|
|
__LINE__, ctrl_block, cur_index, 1);
|
|
os_mem_free(buf);
|
|
return ERR_FAIL;
|
|
}
|
|
|
|
iot_cus_printf("\n[DM_DRV@%04d]:last ctrl first index=%d, timestamp=%d!",
|
|
__LINE__,
|
|
((iot_dm_load_day_t *)buf)->index,
|
|
((iot_dm_load_day_t *)buf)->timestamp);
|
|
|
|
index = (DM_FLASH_BLOCK_LOAD_REC == rec_block) ?
|
|
((iot_dm_load_day_t *)buf)->index : ((iot_dm_event_day_t *)buf)->index;
|
|
|
|
if(index > dm_flash_block_get_index_max(rec_block)) {
|
|
/* this will not hit, index is invalid. TODO: handle error. */
|
|
*num = 0;
|
|
iot_cus_printf("\n[DM_DRV@%04d]:invalid item on last position!", __LINE__);
|
|
os_mem_free(buf);
|
|
return ERR_OK;
|
|
}
|
|
|
|
if(dm_flash_get_day(timestamp) == dm_flash_get_day(blk_info->item_timestamp)) {
|
|
/*
|
|
day of timestamp is just the day we are processing,
|
|
so num = next_index_of_records - first_index_of_records
|
|
*/
|
|
iot_cus_printf("\n[DM_DRV@%04d]:timestamp %d is today for me!", __LINE__, timestamp);
|
|
index = dm_flash_block_get_index_max(rec_block);
|
|
cur_index = (DM_FLASH_BLOCK_LOAD_REC == rec_block) ?
|
|
((iot_dm_load_day_t *)buf)->index : ((iot_dm_event_day_t *)buf)->index;
|
|
*num = (cur_index <= blk_info->item_rec_idx) ?
|
|
(blk_info->item_rec_idx - cur_index) : (index - cur_index + 1 + blk_info->item_rec_idx);
|
|
|
|
*rec_start_index = cur_index;
|
|
|
|
iot_cus_printf("\n[DM_DRV@%04d]:record num#%d, start_block_idx#%d, blk#%d, timestamp#%d!",
|
|
__LINE__, *num, *rec_start_index, rec_block, timestamp);
|
|
os_mem_free(buf);
|
|
return ERR_OK;
|
|
}
|
|
|
|
/* history and future are regarded as history. */
|
|
iot_cus_printf("\n[DM_DRV@%04d]:timestamp %d is histry for me!", __LINE__, timestamp);
|
|
|
|
/* Not today, get index of the day before current day as starting index for searching. */
|
|
cur_index = dm_flash_block_get_last_index(ctrl_block, cur_index);
|
|
|
|
/* Get the first index on the next sector as ending index for searching. */
|
|
index = dm_flash_block_get_item_count_per_sector(ctrl_block);
|
|
search_end_index = ((cur_index + index) / index) * index;
|
|
|
|
/* Get max index of this block. */
|
|
index = dm_flash_block_get_index_max(ctrl_block);
|
|
/* rear_count: count of items for searching from search_end_index to index_max */
|
|
if(search_end_index > index) {
|
|
rear_count = 0;
|
|
} else {
|
|
rear_count = index - search_end_index + 1;
|
|
}
|
|
/* front_count: count of items for searching from 0 to cur_index */
|
|
front_count = cur_index + 1;
|
|
|
|
/* store record index of today for calculating count of items. */
|
|
rec_start_index_of_last_day = (DM_FLASH_BLOCK_LOAD_REC == rec_block) ?
|
|
((iot_dm_load_day_t *)buf)->index : ((iot_dm_event_day_t *)buf)->index;
|
|
|
|
do {
|
|
if(front_count > 0) {
|
|
/* search index of item from cur_index to 0 firstly. */
|
|
rd_count = dm_flash_min(front_count, step);
|
|
cur_index = front_count - rd_count;
|
|
front_count -= rd_count;
|
|
} else if(rear_count > 0){
|
|
/* search index of item from index_max to search_end_index then. */
|
|
rd_count = dm_flash_min(rear_count, step);
|
|
cur_index -= (rd_count - 1);
|
|
rear_count -= rd_count;
|
|
} else {
|
|
/* all items searched but no matchable found */
|
|
iot_cus_printf("\n[DM_DRV@%04d]:no matchable timestamp$%d found!",
|
|
__LINE__, timestamp);
|
|
*num = 0;
|
|
break;
|
|
}
|
|
|
|
/* read items from flash chip */
|
|
if(ERR_OK != dm_flash_block_read_record(ctrl_block, cur_index, rd_count, buf)) {
|
|
iot_cus_printf("\n[DM_DRV@%04d]:record read faild, blk#%d, idx#%d, cnt#%d!",
|
|
__LINE__, ctrl_block, cur_index, rd_count);
|
|
os_mem_free(buf);
|
|
return ERR_FAIL;
|
|
}
|
|
|
|
/* point to the last one iterm. */
|
|
item = (buf + (rd_count - 1) * item_day_size);
|
|
|
|
/* search items in the buffer read from flash chip. */
|
|
for(index = 0; index < rd_count; index++ ) {
|
|
if(dm_flash_block_is_empty_item(item, item_day_size)) {
|
|
/* empty item means search finish && no matchable item */
|
|
iot_cus_printf("\n[DM_DRV@%04d]:no matchable timestamp$%d found!",
|
|
__LINE__, timestamp);
|
|
*num = 0;
|
|
break;
|
|
}
|
|
|
|
rd_ts = (DM_FLASH_BLOCK_LOAD_REC == rec_block) ?
|
|
((iot_dm_load_day_t *)item)->timestamp : ((iot_dm_event_day_t *)item)->timestamp;
|
|
|
|
if(dm_flash_get_day(timestamp) == dm_flash_get_day(rd_ts)) {
|
|
/* we found the item on the day of timestamp */
|
|
iot_cus_printf("\n[DM_DRV@%04d]:matchable iterm found timestamp#%d, index#%d. next day index#%d!",
|
|
__LINE__, ((iot_dm_load_day_t *)item)->timestamp,
|
|
((iot_dm_load_day_t *)item)->index, rec_start_index_of_last_day);
|
|
|
|
rd_ts = (DM_FLASH_BLOCK_LOAD_REC == rec_block) ?
|
|
((iot_dm_load_day_t *)item)->index : ((iot_dm_event_day_t *)item)->index;
|
|
/* calculate count of records on this day */
|
|
if(rd_ts > rec_start_index_of_last_day) {
|
|
*num = dm_flash_block_get_index_max(rec_block) - rd_ts + 1
|
|
+ rec_start_index_of_last_day;
|
|
} else {
|
|
*num = rec_start_index_of_last_day - rd_ts;
|
|
}
|
|
/* get the start index of records on record_block on this day. */
|
|
*rec_start_index = rd_ts;
|
|
break;
|
|
}
|
|
|
|
/* store record index of this day for calculating count of items. */
|
|
rec_start_index_of_last_day = (DM_FLASH_BLOCK_LOAD_REC == rec_block) ?
|
|
((iot_dm_load_day_t *)item)->index : ((iot_dm_event_day_t *)item)->index;
|
|
|
|
item -= item_day_size;
|
|
}
|
|
|
|
if(index < rd_count) {
|
|
/* stop searching. we meet empty item(NOT found) or matchable item(Found) */
|
|
break;
|
|
}
|
|
|
|
cur_index = dm_flash_block_get_last_index(ctrl_block, cur_index);
|
|
}while(1);
|
|
|
|
os_mem_free(buf);
|
|
|
|
iot_cus_printf("\n[DM_DRV@%04d]:record num#%d, start_block_idx#%d, blk#%d, timestamp#%d!",
|
|
__LINE__, *num, *rec_start_index, rec_block, timestamp);
|
|
|
|
return ERR_OK;
|
|
}
|
|
|
|
/**
|
|
* @brief dm_flash_block_set_header_as_default() - to set flash layout to default.
|
|
* @param phr: buffer to hold header structure.
|
|
* @return ERR_FAIL - Operation failed, ERR_OK - Operation Successful
|
|
*/
|
|
static uint32_t dm_flash_block_set_header_as_default(iot_dm_flash_t *phr)
|
|
{
|
|
os_mem_set(phr, 0x0, sizeof(*phr));
|
|
|
|
phr->magic = IOT_DM_FLASH_HEADER_MAGIC;
|
|
|
|
/* Init the blocks information. */
|
|
if(IOT_DM_SIZE_nMB(4) == g_dm_flash_obj.chip.chip_size) {
|
|
iot_dm_flash_block_desc_t block[] = DM_FLASH_4M_BLOCKS;
|
|
/* Set default block information */
|
|
os_mem_cpy(phr->block, block, sizeof(phr->block));
|
|
} else {
|
|
iot_cus_printf("\n[DM_DRV@%04d]:unkown chip size#0x%x!",
|
|
__LINE__, g_dm_flash_obj.chip.chip_size);
|
|
return ERR_FAIL;
|
|
}
|
|
|
|
/* write back into flash */
|
|
if(ERR_OK != dm_flash_raw_random_write(phr->block[DM_FLASH_BLOCK_HEADER].start,
|
|
(uint8_t *)phr, sizeof(*phr))) {
|
|
iot_cus_printf("\n[DM_DRV@%04d]:write header failed!", __LINE__);
|
|
return ERR_FAIL;
|
|
}
|
|
|
|
return ERR_OK;
|
|
}
|
|
|
|
/**
|
|
* @brief dm_flash_block_read_header() - read header infor from chip,
|
|
* header will be set default if infor is invalid.
|
|
* @return ERR_FAIL - Operation failed, ERR_OK - Operation Successful
|
|
*/
|
|
static uint32_t dm_flash_block_read_header(void)
|
|
{
|
|
iot_dm_flash_t *phr = &g_dm_flash_obj.header;
|
|
|
|
/* read info from flash */
|
|
if(ERR_OK != dm_flash_raw_random_read(phr->block[DM_FLASH_BLOCK_HEADER].start,
|
|
(uint8_t *)phr, sizeof(*phr))) {
|
|
iot_cus_printf("\n[DM_DRV@%04d]:read header failed!", __LINE__);
|
|
return ERR_FAIL;
|
|
}
|
|
|
|
if(IOT_DM_FLASH_HEADER_MAGIC != phr->magic) {
|
|
iot_cus_printf("\n[DM_DRV@%04d]:invalid flash header!", __LINE__);
|
|
if(ERR_OK != dm_flash_block_set_header_as_default(phr)) {
|
|
iot_cus_printf("\n[DM_DRV@%04d]:header set default failed!", __LINE__);
|
|
return ERR_FAIL;
|
|
}
|
|
}
|
|
|
|
return ERR_OK;
|
|
}
|
|
|
|
/**
|
|
* @brief dm_flash_block_erase_block() - erase given block.
|
|
* @return ERR_FAIL - Operation failed, ERR_OK - Operation Successful
|
|
*/
|
|
uint32_t dm_flash_block_erase_block(uint32_t block)
|
|
{
|
|
uint32_t erase_block, last_block, ret;
|
|
iot_dm_flash_block_desc_t *p_block = g_dm_flash_obj.header.block;
|
|
|
|
if(!dm_flash_is_ready()) {
|
|
iot_cus_printf("\n[DM_DRV@%04d]:driver not ready!", __LINE__);
|
|
return ERR_FAIL;
|
|
}
|
|
|
|
switch(block)
|
|
{
|
|
case DM_FLASH_BLOCK_HEADER:
|
|
case DM_FLASH_BLOCK_VARIABLE:
|
|
case DM_FLASH_BLOCK_LOAD_CTRL:
|
|
case DM_FLASH_BLOCK_LOAD_REC:
|
|
case DM_FLASH_BLOCK_EVENT_CTRL:
|
|
case DM_FLASH_BLOCK_EVENT_REC:
|
|
case DM_FLASH_BLOCK_PRIV_EVENT_CTRL:
|
|
case DM_FLASH_BLOCK_PRIV_EVENT_REC:
|
|
{
|
|
erase_block = block;
|
|
last_block = block + 1;
|
|
break;
|
|
}
|
|
case DM_FLASH_BLOCK_MAX:
|
|
{
|
|
erase_block = DM_FLASH_BLOCK_HEADER;
|
|
last_block = DM_FLASH_BLOCK_MAX;
|
|
break;
|
|
}
|
|
default:
|
|
{
|
|
iot_cus_printf("\n[DM_DRV@%04d]:invalid block#%d!", __LINE__, block);
|
|
return ERR_FAIL;
|
|
}
|
|
}
|
|
|
|
iot_cus_printf("\n[DM_DRV@%04d]:erase block#%d to %d!", __LINE__, block, last_block - 1);
|
|
|
|
ret = ERR_OK;
|
|
|
|
for(; erase_block < last_block; erase_block++) {
|
|
if(ERR_OK != dm_flash_raw_random_erase(p_block[erase_block].start, p_block[erase_block].size)) {
|
|
iot_cus_printf("\n[DM_DRV@%04d]:erase block#%d failed!", __LINE__, erase_block);
|
|
ret = ERR_FAIL;
|
|
break;
|
|
}
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
/**
|
|
* @brief dm_flash_init_hardware() - initialize spi device.
|
|
* @return ERR_FAIL - Operation failed, ERR_OK - Operation Successful
|
|
*/
|
|
static uint32_t dm_flash_init_hardware(void)
|
|
{
|
|
iot_spi_cfg_t gpio_cfg;
|
|
|
|
/* GPIO config. */
|
|
gpio_cfg.gpio.clk = DM_FLASH_GPIO_CLK;
|
|
gpio_cfg.gpio.cs = DM_FLASH_GPIO_CS;
|
|
gpio_cfg.gpio.miso = DM_FLASH_GPIO_MISO;
|
|
gpio_cfg.gpio.mosi = DM_FLASH_GPIO_MOSI;
|
|
|
|
/* Init SPI module & config GPIOs. */
|
|
if(ERR_OK != iot_spi_module_init(&gpio_cfg)) {
|
|
iot_cus_printf("\n[DM_DRV@%04d]:spi module init failed!", __LINE__);
|
|
return ERR_FAIL;
|
|
}
|
|
|
|
g_dm_flash_obj.spi_dev = DEVICE_SPI0_MASTER;
|
|
|
|
/* Open SPI device for operation. */
|
|
if(ERR_OK != iot_spi_dev_register(g_dm_flash_obj.spi_dev, true, false, NULL, 0, false)) {
|
|
iot_cus_printf("\n[DM_DRV@%04d]:spi register failed!", __LINE__);
|
|
return ERR_FAIL;
|
|
}
|
|
|
|
return ERR_OK;
|
|
}
|
|
|
|
/**
|
|
* @brief dm_flash_init_chip() - initialize flash chip.
|
|
* @return ERR_FAIL - Operation failed, ERR_OK - Operation Successful
|
|
*/
|
|
static uint32_t dm_flash_init_chip(void)
|
|
{
|
|
uint8_t cha_buf[4];
|
|
uint32_t arr_idx;
|
|
iot_dm_flash_chip_t *p_chip = &g_dm_flash_obj.chip;
|
|
iot_dm_flash_mfid_name_t id_arr[] = DM_FLASH_MFID_TB;
|
|
|
|
g_dm_flash_obj.op_code = &common_op;
|
|
|
|
if(ERR_OK != dm_flash_raw_read_mfid(cha_buf, 3)) {
|
|
iot_cus_printf("\n[DM_DRV@%04d]:mfid read failed!", __LINE__);
|
|
return ERR_FAIL;
|
|
}
|
|
|
|
/* To match the mfid. */
|
|
for(arr_idx = 0; arr_idx < (sizeof(id_arr) / sizeof(id_arr[0])); arr_idx ++) {
|
|
if((((uint32_t)cha_buf[0]) & 0xFF) == id_arr[arr_idx].mfid) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
/* Not match , Set unknown */
|
|
if(arr_idx >= (sizeof(id_arr) / sizeof(id_arr[0]))) {
|
|
arr_idx = 0;
|
|
}
|
|
|
|
p_chip->m_id = id_arr[arr_idx].mfid;
|
|
os_mem_cpy(p_chip->manufacturer, id_arr[arr_idx].name,
|
|
IOT_DM_MANUFACTURER_NAME_LEN);
|
|
p_chip->d_id = (cha_buf[1] << 8) | cha_buf[2];
|
|
|
|
iot_cus_printf("\n[DM_DRV@%04d]:Manufacturer: %s, mfid#0x%x, did#0x%x!",
|
|
__LINE__, p_chip->manufacturer, p_chip->m_id, p_chip->d_id);
|
|
|
|
/* TODO : read from sfdp. */
|
|
p_chip->chip_size = DM_FLASH_CHIP_SIZE;
|
|
p_chip->sec_size = DM_FLASH_SECTOR_SIZE;
|
|
p_chip->page_size = DM_FLASH_PAGE_SIZE;
|
|
|
|
iot_cus_printf("\n[DM_DRV@%04d]:size : chip#0x%x, sector#0x%x, page#0x%x!",
|
|
__LINE__, p_chip->chip_size, p_chip->sec_size, p_chip->page_size);
|
|
|
|
g_dm_flash_obj.sbuf.buf = os_mem_malloc(DM_MODULE_ID, p_chip->sec_size);
|
|
|
|
if(NULL == g_dm_flash_obj.sbuf.buf) {
|
|
iot_cus_printf("\n[DM_DRV@%04d]:malloc size#%d failed!", __LINE__, p_chip->sec_size);
|
|
return ERR_FAIL;
|
|
}
|
|
|
|
g_dm_flash_obj.sbuf.len = p_chip->sec_size;
|
|
|
|
g_dm_flash_obj.lock = os_create_mutex(DM_MODULE_ID);
|
|
|
|
if(NULL == g_dm_flash_obj.lock) {
|
|
iot_cus_printf("\n[DM_DRV@%04d]:creat lock failed!", __LINE__);
|
|
os_mem_free(g_dm_flash_obj.sbuf.buf);
|
|
return ERR_FAIL;
|
|
}
|
|
|
|
return ERR_OK;
|
|
}
|
|
|
|
/**
|
|
* @brief dm_flash_init_layout() - initialize layout of flash.
|
|
* @return ERR_FAIL - Operation failed, ERR_OK - Operation Successful
|
|
*/
|
|
static uint32_t dm_flash_init_layout(void)
|
|
{
|
|
if(ERR_OK != dm_flash_block_read_header()) {
|
|
iot_cus_printf("\n[DM_DRV@%04d]:read header infor failed!", __LINE__);
|
|
return ERR_FAIL;
|
|
}
|
|
|
|
if(ERR_OK != dm_flash_block_read_variable(&g_dm_flash_obj.variable, &g_dm_flash_obj.var_idx)) {
|
|
iot_cus_printf("\n[DM_DRV@%04d]:read variable infor failed!", __LINE__);
|
|
return ERR_FAIL;
|
|
}
|
|
|
|
return ERR_OK;
|
|
}
|
|
|
|
uint32_t iot_dm_flash_init_module(void)
|
|
{
|
|
if(dm_flash_is_ready()) {
|
|
iot_cus_printf("\n[DM_DRV@%04d]:driver re-init!", __LINE__);
|
|
return ERR_OK;
|
|
}
|
|
|
|
if(ERR_OK != dm_flash_init_hardware()) {
|
|
iot_cus_printf("\n[DM_DRV@%04d]:hardware init failed!", __LINE__);
|
|
goto flash_init_failed;
|
|
}
|
|
|
|
if(ERR_OK != dm_flash_init_chip()) {
|
|
iot_cus_printf("\n[DM_DRV@%04d]:flash infor init failed!", __LINE__);
|
|
goto flash_init_failed;
|
|
}
|
|
|
|
if(ERR_OK != dm_flash_init_layout()) {
|
|
iot_cus_printf("\n[DM_DRV@%04d]:flash layout init failed!", __LINE__);
|
|
goto flash_init_failed;
|
|
}
|
|
|
|
iot_cus_printf("\n[DM_DRV@%04d]:flash init done!", __LINE__);
|
|
|
|
dm_flash_set_ready();
|
|
|
|
return ERR_OK;
|
|
|
|
flash_init_failed:
|
|
|
|
dm_flash_set_not_ready();
|
|
|
|
return ERR_FAIL;
|
|
}
|
|
|
|
uint32_t iot_dm_flash_read(uint32_t offset, uint8_t *buf, uint32_t size)
|
|
{
|
|
uint32_t ret;
|
|
|
|
if(!dm_flash_is_ready()) {
|
|
iot_cus_printf("\n[DM_DRV@%04d]:driver not ready!", __LINE__);
|
|
return ERR_FAIL;
|
|
}
|
|
|
|
if(NULL == buf || (offset + size) > g_dm_flash_obj.chip.chip_size) {
|
|
iot_cus_printf("\n[DM_DRV@%04d]:invalid param!", __LINE__);
|
|
return ERR_FAIL;
|
|
}
|
|
|
|
dm_flash_lock();
|
|
ret = dm_flash_raw_random_read(offset, buf, size);
|
|
dm_flash_unlock();
|
|
|
|
return ret;
|
|
}
|
|
|
|
uint32_t iot_dm_flash_write(uint32_t offset, uint8_t *buf, uint32_t size)
|
|
{
|
|
uint32_t ret;
|
|
|
|
if(!dm_flash_is_ready()) {
|
|
iot_cus_printf("\n[DM_DRV@%04d]:driver not ready!", __LINE__);
|
|
return ERR_FAIL;
|
|
}
|
|
|
|
if(NULL == buf || (offset + size) > g_dm_flash_obj.chip.chip_size) {
|
|
iot_cus_printf("\n[DM_DRV@%04d]:invalid param!", __LINE__);
|
|
return ERR_FAIL;
|
|
}
|
|
|
|
dm_flash_lock();
|
|
ret = dm_flash_raw_random_write(offset, buf, size);
|
|
dm_flash_unlock();
|
|
|
|
return ret;
|
|
}
|
|
|
|
uint32_t iot_dm_flash_get_chipinfo(iot_dm_flash_chip_t *info)
|
|
{
|
|
if(!dm_flash_is_ready()) {
|
|
iot_cus_printf("\n[DM_DRV@%04d]:driver not ready!", __LINE__);
|
|
return ERR_FAIL;
|
|
}
|
|
|
|
dm_flash_lock();
|
|
os_mem_cpy(info, &g_dm_flash_obj.chip, sizeof(g_dm_flash_obj.chip));
|
|
dm_flash_unlock();
|
|
|
|
return ERR_OK;
|
|
}
|
|
|
|
uint32_t iot_dm_flash_get_blockinfo(uint32_t block, iot_dm_flash_block_usage_desc_t block_info[])
|
|
{
|
|
if(!dm_flash_is_ready()) {
|
|
iot_cus_printf("\n[DM_DRV@%04d]:driver not ready!", __LINE__);
|
|
return ERR_FAIL;
|
|
}
|
|
|
|
if(block > DM_FLASH_BLOCK_MAX || NULL == block_info) {
|
|
iot_cus_printf("\n[DM_DRV@%04d]:invalid param!", __LINE__);
|
|
return ERR_FAIL;
|
|
}
|
|
|
|
dm_flash_lock();
|
|
|
|
if(block < DM_FLASH_BLOCK_MAX) {
|
|
os_mem_cpy(block_info, &g_dm_flash_obj.header.block[block], sizeof(g_dm_flash_obj.header.block[block]));
|
|
} else if(block == DM_FLASH_BLOCK_MAX) {
|
|
os_mem_cpy(block_info, g_dm_flash_obj.header.block, sizeof(g_dm_flash_obj.header.block));
|
|
}
|
|
|
|
dm_flash_unlock();
|
|
|
|
return ERR_OK;
|
|
}
|
|
|
|
uint32_t iot_dm_flash_write_event(uint32_t timestamp, iot_dm_event_record_t *record)
|
|
{
|
|
uint32_t ret;
|
|
|
|
if(!dm_flash_is_ready()) {
|
|
iot_cus_printf("\n[DM_DRV@%04d]:driver not ready!", __LINE__);
|
|
return ERR_FAIL;
|
|
}
|
|
|
|
dm_flash_lock();
|
|
|
|
ret = dm_flash_block_roll_write_record(DM_FLASH_BLOCK_EVENT_REC, (uint8_t*)record, timestamp);
|
|
|
|
dm_flash_unlock();
|
|
|
|
return ret;
|
|
}
|
|
|
|
uint32_t iot_dm_flash_write_private_event(uint32_t timestamp, iot_dm_event_record_t *record)
|
|
{
|
|
uint32_t ret;
|
|
|
|
if(!dm_flash_is_ready()) {
|
|
iot_cus_printf("\n[DM_DRV@%04d]:driver not ready!", __LINE__);
|
|
return ERR_FAIL;
|
|
}
|
|
|
|
dm_flash_lock();
|
|
|
|
ret = dm_flash_block_roll_write_record(DM_FLASH_BLOCK_PRIV_EVENT_REC, (uint8_t*)record, timestamp);
|
|
|
|
dm_flash_unlock();
|
|
|
|
return ret;
|
|
}
|
|
|
|
uint32_t iot_dm_flash_write_load(uint32_t timestamp, iot_dm_load_record_t *record)
|
|
{
|
|
uint32_t ret;
|
|
|
|
if(!dm_flash_is_ready()) {
|
|
iot_cus_printf("\n[DM_DRV@%04d]:driver not ready!", __LINE__);
|
|
return ERR_FAIL;
|
|
}
|
|
|
|
dm_flash_lock();
|
|
|
|
ret = dm_flash_block_roll_write_record(DM_FLASH_BLOCK_LOAD_REC, (uint8_t*)record, timestamp);
|
|
|
|
dm_flash_unlock();
|
|
|
|
return ret;
|
|
}
|
|
|
|
uint32_t iot_dm_flash_write_threshold(iot_dm_threshold_t *threshold)
|
|
{
|
|
uint32_t ret;
|
|
|
|
if(!dm_flash_is_ready()) {
|
|
iot_cus_printf("\n[DM_DRV@%04d]:driver not ready!", __LINE__);
|
|
return ERR_FAIL;
|
|
}
|
|
|
|
if(NULL == threshold) {
|
|
iot_cus_printf("\n[DM_DRV@%04d]:invalid param!", __LINE__);
|
|
return ERR_FAIL;
|
|
}
|
|
|
|
iot_cus_printf("\n[DM_DRV@%04d]:write threshold i_standby#%dmA, i_work#%dmA, p_trap#%dW!",
|
|
__LINE__, threshold->i_standby, threshold->i_work, threshold->p_trap);
|
|
|
|
g_dm_flash_obj.header.meter.threshold.i_standby = threshold->i_standby;
|
|
g_dm_flash_obj.header.meter.threshold.i_work = threshold->i_work;
|
|
g_dm_flash_obj.header.meter.threshold.p_trap = threshold->p_trap;
|
|
|
|
dm_flash_lock();
|
|
/* write back into flash */
|
|
ret = dm_flash_raw_random_write(0x0, (uint8_t *)&g_dm_flash_obj.header, sizeof(g_dm_flash_obj.header));
|
|
dm_flash_unlock();
|
|
|
|
if(ERR_OK != ret) {
|
|
iot_cus_printf("\n[DM_DRV@%04d]:write header failed!", __LINE__);
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
uint32_t iot_dm_flash_write_meter_base(uint32_t base_value)
|
|
{
|
|
uint32_t ret;
|
|
|
|
if(!dm_flash_is_ready()) {
|
|
iot_cus_printf("\n[DM_DRV@%04d]:driver not ready!", __LINE__);
|
|
return ERR_FAIL;
|
|
}
|
|
|
|
dm_flash_lock();
|
|
g_dm_flash_obj.variable.meter_base = base_value;
|
|
ret = dm_flash_block_roll_write_variable(&g_dm_flash_obj.variable);
|
|
dm_flash_unlock();
|
|
|
|
return ret;
|
|
}
|
|
|
|
uint32_t iot_dm_flash_read_event_num_of_day(uint32_t timestamp, uint32_t *num)
|
|
{
|
|
uint32_t ret, next_start;
|
|
|
|
if(!dm_flash_is_ready()) {
|
|
iot_cus_printf("\n[DM_DRV@%04d]:driver not ready!", __LINE__);
|
|
return ERR_FAIL;
|
|
}
|
|
|
|
dm_flash_lock();
|
|
|
|
ret = dm_flash_block_read_record_count_of_day(DM_FLASH_BLOCK_EVENT_REC, timestamp, num, &next_start);
|
|
|
|
/* we do not need this. */
|
|
(void)next_start;
|
|
|
|
dm_flash_unlock();
|
|
|
|
return ret;
|
|
}
|
|
|
|
uint32_t iot_dm_flash_read_private_event_num_of_day(uint32_t timestamp, uint32_t *num)
|
|
{
|
|
uint32_t ret, next_start;
|
|
|
|
if(!dm_flash_is_ready()) {
|
|
iot_cus_printf("\n[DM_DRV@%04d]:driver not ready!", __LINE__);
|
|
return ERR_FAIL;
|
|
}
|
|
|
|
dm_flash_lock();
|
|
|
|
ret = dm_flash_block_read_record_count_of_day(DM_FLASH_BLOCK_PRIV_EVENT_REC, timestamp, num, &next_start);
|
|
|
|
/* we do not need this. */
|
|
(void)next_start;
|
|
|
|
dm_flash_unlock();
|
|
|
|
return ret;
|
|
}
|
|
|
|
|
|
uint32_t iot_dm_flash_read_load_num_of_day(uint32_t timestamp, uint32_t *num)
|
|
{
|
|
uint32_t ret, next_start;
|
|
|
|
if(!dm_flash_is_ready()) {
|
|
iot_cus_printf("\n[DM_DRV@%04d]:driver not ready!", __LINE__);
|
|
return ERR_FAIL;
|
|
}
|
|
|
|
dm_flash_lock();
|
|
|
|
ret = dm_flash_block_read_record_count_of_day(DM_FLASH_BLOCK_LOAD_REC, timestamp, num, &next_start);
|
|
|
|
/* we do not need this. */
|
|
(void)next_start;
|
|
|
|
dm_flash_unlock();
|
|
|
|
return ret;
|
|
}
|
|
|
|
uint32_t iot_dm_flash_read_load(uint32_t timestamp, uint32_t count,
|
|
iot_dm_load_record_t *record, uint32_t *valid_count)
|
|
{
|
|
uint32_t totall_count, left_count, read_count, start_block_idx, ret, i, seconds;
|
|
iot_dm_load_record_t *p_rec, *p_buf = record;
|
|
|
|
if(!dm_flash_is_ready()) {
|
|
iot_cus_printf("\n[DM_DRV@%04d]:driver not ready!", __LINE__);
|
|
return ERR_FAIL;
|
|
}
|
|
|
|
iot_cus_printf("\n[DM_DRV@%04d]:read load, timestamp#%d, count#%d!",
|
|
__LINE__, timestamp, count);
|
|
|
|
left_count = count;
|
|
|
|
/* seconds on timestamp, to compare with all records */
|
|
seconds = dm_flash_get_seconds(timestamp);
|
|
|
|
dm_flash_lock();
|
|
|
|
/* get toltal count of records on given day. */
|
|
ret = dm_flash_block_read_record_count_of_day(DM_FLASH_BLOCK_LOAD_REC,
|
|
timestamp, &totall_count, &start_block_idx);
|
|
|
|
if(ERR_OK != ret) {
|
|
iot_cus_printf("\n[DM_DRV@%04d]:read num of day failed!", __LINE__);
|
|
dm_flash_unlock();
|
|
return ERR_FAIL;
|
|
}
|
|
|
|
/* search all records on the day to get the ones who matchs seconds in timestamp. */
|
|
while((left_count > 0) && (totall_count > 0)) {
|
|
|
|
read_count = dm_flash_min(left_count, totall_count);
|
|
/* read records on the day in parts */
|
|
ret = dm_flash_block_read_record(DM_FLASH_BLOCK_LOAD_REC, start_block_idx,
|
|
read_count, p_buf);
|
|
|
|
if(ERR_OK != ret) {
|
|
iot_cus_printf("\n[DM_DRV@%04d]:read event of day failed!", __LINE__);
|
|
dm_flash_unlock();
|
|
return ERR_FAIL;
|
|
}
|
|
|
|
start_block_idx = dm_flash_block_get_next_index(DM_FLASH_BLOCK_LOAD_REC,
|
|
start_block_idx + read_count - 1);
|
|
|
|
totall_count -= read_count;
|
|
|
|
p_rec = p_buf;
|
|
|
|
/* search the records match the seconds. */
|
|
for(i = 0; i < read_count; i++) {
|
|
if(p_rec->seconds >= seconds) {
|
|
os_mem_cpy(p_buf, p_rec, sizeof(*p_rec));
|
|
p_buf++;
|
|
left_count--;
|
|
}
|
|
p_rec++;
|
|
}
|
|
|
|
}
|
|
|
|
*valid_count = count - left_count;
|
|
|
|
dm_flash_unlock();
|
|
|
|
return ret;
|
|
}
|
|
|
|
uint32_t iot_dm_flash_read_private_event(uint32_t timestamp, uint32_t start_idx,
|
|
uint32_t end_idx, iot_dm_event_record_t *record, uint32_t *valid_count)
|
|
{
|
|
uint32_t count, start_block_idx, ret;
|
|
|
|
if(!dm_flash_is_ready()) {
|
|
iot_cus_printf("\n[DM_DRV@%04d]:driver not ready!", __LINE__);
|
|
return ERR_FAIL;
|
|
}
|
|
|
|
if((end_idx < start_idx) || NULL == valid_count) {
|
|
iot_cus_printf("\n[DM_DRV@%04d]:invalid param!", __LINE__);
|
|
return ERR_FAIL;
|
|
}
|
|
|
|
dm_flash_lock();
|
|
|
|
ret = dm_flash_block_read_record_count_of_day(DM_FLASH_BLOCK_PRIV_EVENT_REC,
|
|
timestamp, &count, &start_block_idx);
|
|
|
|
if(ERR_OK != ret) {
|
|
iot_cus_printf("\n[DM_DRV@%04d]:read num of day failed!", __LINE__);
|
|
dm_flash_unlock();
|
|
return ERR_FAIL;
|
|
}
|
|
|
|
iot_cus_printf("\n[DM_DRV@%04d]:read event timestamp#%d, start_idx#%d, " \
|
|
"end_idx#%d, valid count#%d, start_block_idx#%d!",
|
|
__LINE__, timestamp, start_idx, end_idx, count, start_block_idx);
|
|
|
|
end_idx = (end_idx + 1) > count ? (count - 1): end_idx;
|
|
|
|
if (end_idx < start_idx) {
|
|
iot_cus_printf("\n[DM_DRV@%04d]:No such index to read!", __LINE__);
|
|
*valid_count = 0;
|
|
dm_flash_unlock();
|
|
return ERR_OK;
|
|
}
|
|
|
|
*valid_count = end_idx - start_idx + 1;
|
|
|
|
start_block_idx += start_idx;
|
|
|
|
ret = dm_flash_block_read_record(DM_FLASH_BLOCK_PRIV_EVENT_REC, start_block_idx,
|
|
end_idx - start_idx + 1, record);
|
|
|
|
if(ERR_OK != ret) {
|
|
iot_cus_printf("\n[DM_DRV@%04d]:read event of day failed!", __LINE__);
|
|
dm_flash_unlock();
|
|
return ERR_FAIL;
|
|
}
|
|
|
|
dm_flash_unlock();
|
|
|
|
return ret;
|
|
}
|
|
|
|
uint32_t iot_dm_flash_read_event(uint32_t timestamp, uint32_t start_idx,
|
|
uint32_t end_idx, iot_dm_event_record_t *record, uint32_t *valid_count)
|
|
{
|
|
uint32_t count, start_block_idx, ret;
|
|
|
|
if(!dm_flash_is_ready()) {
|
|
iot_cus_printf("\n[DM_DRV@%04d]:driver not ready!", __LINE__);
|
|
return ERR_FAIL;
|
|
}
|
|
|
|
if((end_idx < start_idx) || NULL == valid_count) {
|
|
iot_cus_printf("\n[DM_DRV@%04d]:invalid param!", __LINE__);
|
|
return ERR_FAIL;
|
|
}
|
|
|
|
dm_flash_lock();
|
|
|
|
ret = dm_flash_block_read_record_count_of_day(DM_FLASH_BLOCK_EVENT_REC,
|
|
timestamp, &count, &start_block_idx);
|
|
|
|
if(ERR_OK != ret) {
|
|
iot_cus_printf("\n[DM_DRV@%04d]:read num of day failed!", __LINE__);
|
|
dm_flash_unlock();
|
|
return ERR_FAIL;
|
|
}
|
|
|
|
iot_cus_printf("\n[DM_DRV@%04d]:read event timestamp#%d, start_idx#%d, " \
|
|
"end_idx#%d, valid count#%d, start_block_idx#%d!",
|
|
__LINE__, timestamp, start_idx, end_idx, count, start_block_idx);
|
|
|
|
end_idx = (end_idx + 1) > count ? (count - 1): end_idx;
|
|
|
|
if (end_idx < start_idx) {
|
|
iot_cus_printf("\n[DM_DRV@%04d]:No such index to read!", __LINE__);
|
|
*valid_count = 0;
|
|
dm_flash_unlock();
|
|
return ERR_OK;
|
|
}
|
|
|
|
*valid_count = end_idx - start_idx + 1;
|
|
|
|
start_block_idx += start_idx;
|
|
|
|
ret = dm_flash_block_read_record(DM_FLASH_BLOCK_EVENT_REC, start_block_idx,
|
|
end_idx - start_idx + 1, record);
|
|
|
|
if(ERR_OK != ret) {
|
|
iot_cus_printf("\n[DM_DRV@%04d]:read event of day failed!", __LINE__);
|
|
dm_flash_unlock();
|
|
return ERR_FAIL;
|
|
}
|
|
|
|
dm_flash_unlock();
|
|
|
|
return ret;
|
|
}
|
|
|
|
uint32_t iot_dm_flash_read_threshold(iot_dm_threshold_t *threshold)
|
|
{
|
|
if(!dm_flash_is_ready()) {
|
|
iot_cus_printf("\n[DM_DRV@%04d]:driver not ready!", __LINE__);
|
|
return ERR_FAIL;
|
|
}
|
|
|
|
if(NULL == threshold) {
|
|
iot_cus_printf("\n[DM_DRV@%04d]:invalid param!", __LINE__);
|
|
return ERR_FAIL;
|
|
}
|
|
|
|
dm_flash_lock();
|
|
threshold->i_standby = g_dm_flash_obj.header.meter.threshold.i_standby;
|
|
threshold->i_work = g_dm_flash_obj.header.meter.threshold.i_work;
|
|
threshold->p_trap = g_dm_flash_obj.header.meter.threshold.p_trap;
|
|
dm_flash_unlock();
|
|
|
|
iot_cus_printf("\n[DM_DRV@%04d]:read threshold i_standby#%dmA, i_work#%dmA, p_trap#%dW!",
|
|
__LINE__, threshold->i_standby, threshold->i_work, threshold->p_trap);
|
|
|
|
return ERR_OK;
|
|
}
|
|
|
|
uint32_t iot_dm_flash_read_meter_base(uint32_t *base_value)
|
|
{
|
|
if(!dm_flash_is_ready()) {
|
|
iot_cus_printf("\n[DM_DRV@%04d]:driver not ready!", __LINE__);
|
|
return ERR_FAIL;
|
|
}
|
|
|
|
if(NULL == base_value) {
|
|
iot_cus_printf("\n[DM_DRV@%04d]:param error!", __LINE__);
|
|
return ERR_FAIL;
|
|
}
|
|
|
|
dm_flash_lock();
|
|
*base_value = g_dm_flash_obj.variable.meter_base;
|
|
dm_flash_unlock();
|
|
|
|
return ERR_OK;
|
|
}
|
|
|
|
uint32_t iot_dm_flash_read_last_record_timestamp(uint32_t *timestamp)
|
|
{
|
|
uint32_t stamp;
|
|
|
|
if(!dm_flash_is_ready()) {
|
|
iot_cus_printf("\n[DM_DRV@%04d]:driver not ready!", __LINE__);
|
|
return ERR_FAIL;
|
|
}
|
|
|
|
if(NULL == timestamp) {
|
|
iot_cus_printf("\n[DM_DRV@%04d]:param error!", __LINE__);
|
|
return ERR_FAIL;
|
|
}
|
|
|
|
dm_flash_lock();
|
|
|
|
stamp = dm_flash_max(g_dm_flash_obj.variable.priv_event.item_timestamp,
|
|
g_dm_flash_obj.variable.event.item_timestamp);
|
|
|
|
stamp = dm_flash_max(stamp, g_dm_flash_obj.variable.load.item_timestamp);
|
|
|
|
dm_flash_unlock();
|
|
|
|
*timestamp = stamp;
|
|
|
|
return ERR_OK;
|
|
}
|
|
|
|
#if DM_FLASH_DEBUG_TEST
|
|
#include "os_task_api.h"
|
|
#include "iot_dm_event.h"
|
|
os_task_h test_dm_flash_task_h;
|
|
uint32_t os_delay(uint32_t millisec);
|
|
|
|
void iot_cus_print_config(bool_t enable);
|
|
void iot_print_config(bool_t enable);
|
|
|
|
static void test_dm_flash_infor(void)
|
|
{
|
|
uint32_t i;
|
|
iot_dm_flash_opcode_t *pcd;
|
|
iot_dm_flash_chip_t *chip;
|
|
iot_dm_vari_t *var;
|
|
iot_dm_flash_t *hd;
|
|
|
|
chip = &g_dm_flash_obj.chip;
|
|
iot_cus_printf("\n Manufacturer:%s.", chip->manufacturer);
|
|
iot_cus_printf("\n ID:mid#0x%x,did#0x%x.", chip->m_id, chip->d_id);
|
|
iot_cus_printf("\n Size:chip#0x%x,sector#0x%x,page#0x%x.", chip->chip_size,
|
|
chip->sec_size, chip->page_size);
|
|
|
|
pcd = g_dm_flash_obj.op_code;
|
|
iot_cus_printf("\n Opcode:WREN#0x%x,WRDI#0x%x,RDID#0x%x,RDSR#0x%x,WRSR#0x%x,READ#0x%x,SE#0x%x,PP#0x%x.",
|
|
pcd->wren, pcd->wrdi, pcd->rdid, pcd->rdsr, pcd->wrsr, pcd->read, pcd->se, pcd->pp);
|
|
|
|
var = &g_dm_flash_obj.variable;
|
|
hd = &g_dm_flash_obj.header;
|
|
for(i = 0; i < DM_FLASH_BLOCK_MAX; i++) {
|
|
iot_cus_printf("\n Block#%d:start#0x%x,size#0x%x.",
|
|
i, hd->block[i].start, hd->block[i].size);
|
|
}
|
|
iot_cus_printf("\n Variable index#%d, meter base#%d.", g_dm_flash_obj.var_idx,
|
|
var->meter_base);
|
|
iot_cus_printf("\n Variable load:rec_idx#%d,ctrl_idx#%d,timestamp#%d.",
|
|
var->load.item_rec_idx, var->load.item_ctrl_idx, var->load.item_timestamp);
|
|
iot_cus_printf("\n Variable event:rec_idx#%d,ctrl_idx#%d,timestamp#%d.",
|
|
var->event.item_rec_idx, var->event.item_ctrl_idx, var->event.item_timestamp);
|
|
iot_cus_printf("\n Variable priv_event:rec_idx#%d,ctrl_idx#%d,timestamp#%d.",
|
|
var->priv_event.item_rec_idx, var->priv_event.item_ctrl_idx, var->priv_event.item_timestamp);
|
|
|
|
iot_cus_printf("\n Threshold:I_standby#%d,I_work#%d,P_trap#%d.",
|
|
hd->meter.threshold.i_standby, hd->meter.threshold.i_work, hd->meter.threshold.p_trap);
|
|
|
|
return;
|
|
}
|
|
|
|
static uint32_t test_dm_write_record(uint32_t block, uint32_t item_cnt)
|
|
{
|
|
uint32_t item, ret, timestamp;
|
|
iot_dm_event_record_t rec_data, *evt_rec;
|
|
iot_dm_load_record_t *load_rec;
|
|
|
|
iot_cus_printf("\n[DM_DRV@%04d]:start write records, block#%d count#%d!", __LINE__, block, item_cnt);
|
|
|
|
evt_rec = &rec_data;
|
|
load_rec = (iot_dm_load_record_t *)evt_rec;
|
|
|
|
if(DM_FLASH_BLOCK_LOAD_REC == block) {
|
|
timestamp = g_dm_flash_obj.variable.load.item_timestamp;
|
|
iot_cus_printf("\n[DM_DRV@%04d]:test write load record count %d!", __LINE__, item_cnt);
|
|
} else if(DM_FLASH_BLOCK_EVENT_REC == block) {
|
|
timestamp = g_dm_flash_obj.variable.event.item_timestamp;
|
|
iot_cus_printf("\n[DM_DRV@%04d]:test write event record count %d!", __LINE__, item_cnt);
|
|
} else {
|
|
timestamp = g_dm_flash_obj.variable.priv_event.item_timestamp;
|
|
block = DM_FLASH_BLOCK_PRIV_EVENT_CTRL;
|
|
iot_cus_printf("\n[DM_DRV@%04d]:test write private event record count %d!", __LINE__, item_cnt);
|
|
}
|
|
|
|
timestamp += 60 * 60 * 24 + 100;
|
|
|
|
for(item = 0; item < item_cnt; item++) {
|
|
evt_rec->etype = DM_EVENT_DEV_TRAP_START;
|
|
evt_rec->state = DM_STATE_DEV_TRAPING;
|
|
evt_rec->seconds = item * 5;
|
|
evt_rec->w = item * 10;
|
|
evt_rec->p = item * 8;
|
|
evt_rec->i = item * 6;
|
|
evt_rec->v = item * 4;
|
|
evt_rec->f = item * 2;
|
|
|
|
if(DM_FLASH_BLOCK_LOAD_REC == block) {
|
|
ret = iot_dm_flash_write_load(timestamp, load_rec);
|
|
} else if(DM_FLASH_BLOCK_EVENT_REC == block) {
|
|
ret = iot_dm_flash_write_event(timestamp, evt_rec);
|
|
} else {
|
|
ret = iot_dm_flash_write_private_event(timestamp, evt_rec);
|
|
}
|
|
|
|
if(ERR_OK != ret) {
|
|
iot_cus_printf("\n[DM_DRV@%04d]:write record index#%d failed!", __LINE__, item);
|
|
return ERR_FAIL;
|
|
}
|
|
os_delay(100);
|
|
}
|
|
|
|
iot_cus_printf("\n[DM_DRV@%04d]:record write successfully, block#%d count#%d!", __LINE__, block, item_cnt);
|
|
|
|
return ERR_OK;
|
|
}
|
|
|
|
static uint32_t test_dm_read_record(uint32_t block)
|
|
{
|
|
uint32_t timestamp, ret, item_cnt, item;
|
|
void *buf = NULL;
|
|
iot_dm_event_record_t *evt_rec;
|
|
iot_dm_load_record_t *ld_rec;
|
|
|
|
iot_cus_printf("\n[DM_DRV@%04d]:start read records, block#%d!", __LINE__, block);
|
|
|
|
if(DM_FLASH_BLOCK_LOAD_REC == block) {
|
|
timestamp = g_dm_flash_obj.variable.load.item_timestamp;
|
|
ret = iot_dm_flash_read_load_num_of_day(timestamp, &item_cnt);
|
|
if(ERR_OK != ret) {
|
|
iot_cus_printf("\n[DM_DRV@%04d]:test read load record failed!", __LINE__);
|
|
goto err_out;
|
|
}
|
|
iot_cus_printf("\n[DM_DRV@%04d]:test read load record count %d!", __LINE__, item_cnt);
|
|
if(0 == item_cnt) {
|
|
iot_cus_printf("\n[DM_DRV@%04d]:no record found!", __LINE__);
|
|
goto err_out;
|
|
}
|
|
if(NULL == (buf = os_mem_malloc(0, sizeof(*ld_rec) * item_cnt))) {
|
|
iot_cus_printf("\n[DM_DRV@%04d]:malloc failed!", __LINE__);
|
|
goto err_out;
|
|
}
|
|
|
|
if(ERR_OK != iot_dm_flash_read_load(timestamp, item_cnt, buf, &item)) {
|
|
iot_cus_printf("\n[DM_DRV@%04d]:read record failed!", __LINE__);
|
|
goto err_out;
|
|
}
|
|
|
|
} else if(DM_FLASH_BLOCK_EVENT_REC == block) {
|
|
timestamp = g_dm_flash_obj.variable.event.item_timestamp;
|
|
ret = iot_dm_flash_read_event_num_of_day(timestamp, &item_cnt);
|
|
if(ERR_OK != ret) {
|
|
iot_cus_printf("\n[DM_DRV@%04d]:test read load record failed!", __LINE__);
|
|
goto err_out;
|
|
}
|
|
iot_cus_printf("\n[DM_DRV@%04d]:test read event record count %d!", __LINE__, item_cnt);
|
|
if(0 == item_cnt) {
|
|
iot_cus_printf("\n[DM_DRV@%04d]:no record found!", __LINE__);
|
|
goto err_out;
|
|
}
|
|
if(NULL == (buf = (uint8_t *)os_mem_malloc(0, sizeof(*evt_rec) * item_cnt))) {
|
|
iot_cus_printf("\n[DM_DRV@%04d]:malloc failed!", __LINE__);
|
|
goto err_out;
|
|
}
|
|
if(ERR_OK != iot_dm_flash_read_event(timestamp, 0, item_cnt - 1, buf, &item)) {
|
|
iot_cus_printf("\n[DM_DRV@%04d]:read record failed!", __LINE__);
|
|
goto err_out;
|
|
}
|
|
} else {
|
|
block = DM_FLASH_BLOCK_PRIV_EVENT_REC;
|
|
timestamp = g_dm_flash_obj.variable.priv_event.item_timestamp;
|
|
ret = iot_dm_flash_read_private_event_num_of_day(timestamp, &item_cnt);
|
|
if(ERR_OK != ret) {
|
|
iot_cus_printf("\n[DM_DRV@%04d]:test read load record failed!", __LINE__);
|
|
goto err_out;
|
|
}
|
|
iot_cus_printf("\n[DM_DRV@%04d]:test read private event record count %d!", __LINE__, item_cnt);
|
|
if(0 == item_cnt) {
|
|
iot_cus_printf("\n[DM_DRV@%04d]:no record found!", __LINE__);
|
|
goto err_out;
|
|
}
|
|
if(NULL == (buf = (uint8_t *)os_mem_malloc(0, sizeof(*evt_rec) * item_cnt))) {
|
|
iot_cus_printf("\n[DM_DRV@%04d]:malloc failed!", __LINE__);
|
|
goto err_out;
|
|
}
|
|
if(ERR_OK != iot_dm_flash_read_private_event(timestamp, 0, item_cnt - 1, buf, &item)) {
|
|
iot_cus_printf("\n[DM_DRV@%04d]:read record failed!", __LINE__);
|
|
goto err_out;
|
|
}
|
|
}
|
|
|
|
evt_rec = (iot_dm_event_record_t *)buf;
|
|
ld_rec = (iot_dm_load_record_t *)buf;
|
|
|
|
iot_cus_printf("\n[DM_DRV@%04d]:compare record %d / %d!", __LINE__, item, item_cnt);
|
|
|
|
item_cnt = item;
|
|
|
|
for(item = 0; item < item_cnt; item++) {
|
|
if(DM_FLASH_BLOCK_LOAD_CTRL == block) {
|
|
if((ld_rec->f != item * 2)
|
|
|| (ld_rec->i != item * 6)
|
|
|| (ld_rec->p != item * 8)
|
|
|| (ld_rec->v != item * 4)
|
|
|| (ld_rec->seconds != item * 5)
|
|
|| (ld_rec->w != item * 10)) {
|
|
iot_cus_printf("\n[DM_DRV@%04d]:invalid item#%d,i#%d,p#%d,v#%d,w#%d!",
|
|
__LINE__, item, ld_rec->i, ld_rec->p, ld_rec->v, ld_rec->w);
|
|
goto err_out;
|
|
}
|
|
ld_rec++;
|
|
} else {
|
|
if((evt_rec->f != item * 2)
|
|
|| (evt_rec->i != item * 6)
|
|
|| (evt_rec->p != item * 8)
|
|
|| (evt_rec->v != item * 4)
|
|
|| (evt_rec->w != item * 10)
|
|
|| (evt_rec->seconds != item * 5)
|
|
|| (evt_rec->state != DM_STATE_DEV_TRAPING)
|
|
|| (evt_rec->etype != DM_EVENT_DEV_TRAP_START)) {
|
|
iot_cus_printf("\n[DM_DRV@%04d]:invalid item#%d,i#%d,p#%d,v#%d,w#%d!",
|
|
__LINE__, item, evt_rec->i, evt_rec->p, evt_rec->v, evt_rec->w);
|
|
iot_cus_printf("\n[DM_DRV@%04d]:invalid item#%d,seconds#%d,state#%d,etype#%d!",
|
|
__LINE__, item, evt_rec->seconds, evt_rec->state, evt_rec->etype);
|
|
goto err_out;
|
|
}
|
|
evt_rec++;
|
|
}
|
|
}
|
|
if(NULL != buf) {
|
|
os_mem_free(buf);
|
|
}
|
|
iot_cus_printf("\n[DM_DRV@%04d]:record read check successfully!", __LINE__);
|
|
|
|
return ERR_OK;
|
|
|
|
err_out:
|
|
|
|
if(NULL != buf) {
|
|
os_mem_free(buf);
|
|
}
|
|
|
|
iot_cus_printf("\n[DM_DRV@%04d]:record read check failed!", __LINE__);
|
|
|
|
return ERR_FAIL;
|
|
}
|
|
|
|
|
|
static uint32_t test_dm_rew(uint32_t block, uint32_t pattern)
|
|
{
|
|
uint32_t sec_s, sec_e, sec_c, sec_i, *int_s, *int_e, sec_size;
|
|
uint8_t *sec_buf = g_dm_flash_obj.sbuf.buf;
|
|
|
|
sec_size = g_dm_flash_obj.chip.sec_size;
|
|
sec_s = g_dm_flash_obj.header.block[block].start;
|
|
sec_e = sec_s + g_dm_flash_obj.header.block[block].size;
|
|
sec_c = g_dm_flash_obj.header.block[block].size / sec_size;
|
|
int_e = (uint32_t *)(sec_buf + sec_size);
|
|
|
|
iot_cus_printf("\n[DM_DRV@%04d]:block#%d test sector %p -> %p, count %d!",
|
|
__LINE__, block, sec_s, sec_e, sec_c);
|
|
|
|
iot_cus_printf("\n[DM_DRV@%04d]:test erase!", __LINE__);
|
|
/* erase */
|
|
if(ERR_OK != dm_flash_block_erase_block(block)) {
|
|
iot_cus_printf("\n[DM_DRV@%04d]:erase return failed!", __LINE__);
|
|
return ERR_FAIL;
|
|
}
|
|
|
|
iot_cus_printf("\n[DM_DRV@%04d]:blank check!", __LINE__);
|
|
/* blank check. */
|
|
for(sec_i = sec_s; sec_i < sec_e; sec_i += sec_size) {
|
|
os_delay(100);
|
|
if(ERR_OK != iot_dm_flash_read(sec_i, sec_buf, sec_size)) {
|
|
iot_cus_printf("\n[DM_DRV@%04d]:read sectoer %p failed!", __LINE__, sec_i);
|
|
return ERR_FAIL;
|
|
}
|
|
int_s = (uint32_t *)sec_buf;
|
|
for(; int_s < int_e; int_s++) {
|
|
if(0xFFFFFFFF != *int_s) {
|
|
iot_cus_printf("\n[DM_DRV@%04d]:erase sector %p blank check failed @%p, val=%p !",
|
|
__LINE__, sec_i, int_s - (uint32_t *)sec_buf, *int_s);
|
|
return ERR_FAIL;
|
|
}
|
|
}
|
|
iot_cus_printf(".");
|
|
}
|
|
|
|
iot_cus_printf("\n[DM_DRV@%04d]:test write!", __LINE__);
|
|
/* write */
|
|
int_s = (uint32_t *)sec_buf;
|
|
for(; int_s < int_e; int_s++) {
|
|
*int_s = pattern;
|
|
}
|
|
for(sec_i = sec_s; sec_i < sec_e; sec_i += sec_size) {
|
|
os_delay(100);
|
|
if(ERR_OK != iot_dm_flash_write(sec_i, sec_buf, sec_size)) {
|
|
iot_cus_printf("\n[DM_DRV@%04d]:write sectoer %p failed!", __LINE__, sec_i);
|
|
return ERR_FAIL;
|
|
}
|
|
iot_cus_printf(".");
|
|
}
|
|
|
|
iot_cus_printf("\n[DM_DRV@%04d]:pattern=%p check!", __LINE__, pattern);
|
|
/* pattern check. */
|
|
for(sec_i = sec_s; sec_i < sec_e; sec_i += sec_size) {
|
|
os_delay(100);
|
|
if(ERR_OK != iot_dm_flash_read(sec_i, sec_buf, sec_size)) {
|
|
iot_cus_printf("\n[DM_DRV@%04d]:read sectoer %p failed!", __LINE__, sec_i);
|
|
return ERR_FAIL;
|
|
}
|
|
int_s = (uint32_t *)sec_buf;
|
|
for(; int_s < int_e; int_s++) {
|
|
if(pattern != *int_s) {
|
|
iot_cus_printf("\n[DM_DRV@%04d]:write sector %p pattern check failed @%p, val=%p !",
|
|
__LINE__, sec_i, int_s - (uint32_t *)sec_buf, *int_s);
|
|
return ERR_FAIL;
|
|
}
|
|
}
|
|
iot_cus_printf(".");
|
|
}
|
|
|
|
iot_cus_printf("\n[DM_DRV@%04d]:erase read & write check passed!", __LINE__);
|
|
|
|
dm_flash_block_erase_block(block);
|
|
|
|
return ERR_OK;
|
|
}
|
|
|
|
static void test_dm_task(void *arg)
|
|
{
|
|
uint32_t ret = ERR_FAIL, stage, rec_rw_block = DM_FLASH_BLOCK_PRIV_EVENT_REC,
|
|
raw_rw_block = DM_FLASH_BLOCK_EVENT_CTRL;
|
|
|
|
(void)arg;
|
|
|
|
stage = 0;
|
|
iot_cus_printf("\n[DM_DRV@%04d]:start init flash!", __LINE__);
|
|
ret = iot_dm_flash_init_module();
|
|
if(ERR_OK != ret) goto err_out;
|
|
iot_cus_printf("\n[DM_DRV@%04d]:start dump flash infor!", __LINE__);
|
|
test_dm_flash_infor();
|
|
|
|
os_delay(500);
|
|
|
|
stage = 1;
|
|
iot_cus_printf("\n[DM_DRV@%04d]:start test raw read/erase/write!", __LINE__);
|
|
ret = test_dm_rew(raw_rw_block, 0xFEEDBEEF);
|
|
if(ERR_OK != ret) goto err_out;
|
|
|
|
os_delay(500);
|
|
|
|
stage = 2;
|
|
iot_cus_printf("\n[DM_DRV@%04d]:start test record write / read!", __LINE__);
|
|
ret = test_dm_write_record(rec_rw_block,
|
|
dm_flash_block_get_item_count_per_sector(rec_rw_block) + 1);
|
|
if(ERR_OK != ret) goto err_out;
|
|
|
|
test_dm_flash_infor();
|
|
|
|
os_delay(500);
|
|
|
|
ret = test_dm_read_record(rec_rw_block);
|
|
if(ERR_OK != ret) goto err_out;
|
|
|
|
os_delay(500);
|
|
|
|
ret = ERR_OK;
|
|
|
|
err_out:
|
|
|
|
if(ERR_OK == ret) {
|
|
iot_cus_printf("\n[DM_DRV@%04d]:flash test passed @%d!", __LINE__, stage);
|
|
} else {
|
|
iot_cus_printf("\n[DM_DRV@%04d]:flash test failed @%d!", __LINE__, stage);
|
|
}
|
|
|
|
iot_cus_printf("\n[DM_DRV@%04d]:start clear test data!", __LINE__);
|
|
//dm_flash_block_erase_block(DM_FLASH_BLOCK_HEADER);
|
|
//dm_flash_block_erase_block(DM_FLASH_BLOCK_VARIABLE);
|
|
//dm_flash_block_erase_block(rec_rw_block);
|
|
|
|
os_delete_task(test_dm_flash_task_h);
|
|
|
|
return;
|
|
}
|
|
|
|
void test_dm_flash_go(void)
|
|
{
|
|
test_dm_flash_task_h = os_create_task(test_dm_task, 0, 7);
|
|
|
|
iot_cus_print_config(true);
|
|
iot_print_config(true);
|
|
|
|
if(NULL == test_dm_flash_task_h) {
|
|
iot_cus_printf("\n[DM_DRV@%04d]:create test task failed!", __LINE__);
|
|
} else {
|
|
iot_cus_printf("\n[DM_DRV@%04d]:create test task successfully!", __LINE__);
|
|
}
|
|
|
|
return;
|
|
}
|
|
#endif
|