Files
kunlun/app/smart_meter/src/iot_dm_flash.c
2024-09-28 14:24:04 +08:00

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