import RT-Thread@9217865c without bsp, libcpu and components/net
This commit is contained in:
commit
e2376a3709
1414 changed files with 390370 additions and 0 deletions
62
components/fal/src/fal.c
Normal file
62
components/fal/src/fal.c
Normal file
|
@ -0,0 +1,62 @@
|
|||
/*
|
||||
* Copyright (c) 2006-2018, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2018-05-17 armink the first version
|
||||
*/
|
||||
|
||||
#include <fal.h>
|
||||
|
||||
static uint8_t init_ok = 0;
|
||||
|
||||
/**
|
||||
* FAL (Flash Abstraction Layer) initialization.
|
||||
* It will initialize all flash device and all flash partition.
|
||||
*
|
||||
* @return >= 0: partitions total number
|
||||
*/
|
||||
int fal_init(void)
|
||||
{
|
||||
extern int fal_flash_init(void);
|
||||
extern int fal_partition_init(void);
|
||||
|
||||
int result;
|
||||
|
||||
/* initialize all flash device on FAL flash table */
|
||||
result = fal_flash_init();
|
||||
|
||||
if (result < 0) {
|
||||
goto __exit;
|
||||
}
|
||||
|
||||
/* initialize all flash partition on FAL partition table */
|
||||
result = fal_partition_init();
|
||||
|
||||
__exit:
|
||||
|
||||
if ((result > 0) && (!init_ok))
|
||||
{
|
||||
init_ok = 1;
|
||||
log_i("RT-Thread Flash Abstraction Layer initialize success.");
|
||||
}
|
||||
else if(result <= 0)
|
||||
{
|
||||
init_ok = 0;
|
||||
log_e("RT-Thread Flash Abstraction Layer initialize failed.");
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the FAL is initialized successfully
|
||||
*
|
||||
* @return 0: not init or init failed; 1: init success
|
||||
*/
|
||||
int fal_init_check(void)
|
||||
{
|
||||
return init_ok;
|
||||
}
|
79
components/fal/src/fal_flash.c
Normal file
79
components/fal/src/fal_flash.c
Normal file
|
@ -0,0 +1,79 @@
|
|||
/*
|
||||
* Copyright (c) 2006-2018, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2018-05-17 armink the first version
|
||||
*/
|
||||
|
||||
#include <fal.h>
|
||||
#include <string.h>
|
||||
|
||||
/* flash device table, must defined by user */
|
||||
#if !defined(FAL_FLASH_DEV_TABLE)
|
||||
#error "You must defined flash device table (FAL_FLASH_DEV_TABLE) on 'fal_cfg.h'"
|
||||
#endif
|
||||
|
||||
static const struct fal_flash_dev * const device_table[] = FAL_FLASH_DEV_TABLE;
|
||||
static const size_t device_table_len = sizeof(device_table) / sizeof(device_table[0]);
|
||||
static uint8_t init_ok = 0;
|
||||
|
||||
/**
|
||||
* Initialize all flash device on FAL flash table
|
||||
*
|
||||
* @return result
|
||||
*/
|
||||
int fal_flash_init(void)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
if (init_ok)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (i = 0; i < device_table_len; i++)
|
||||
{
|
||||
assert(device_table[i]->ops.read);
|
||||
assert(device_table[i]->ops.write);
|
||||
assert(device_table[i]->ops.erase);
|
||||
/* init flash device on flash table */
|
||||
if (device_table[i]->ops.init)
|
||||
{
|
||||
device_table[i]->ops.init();
|
||||
}
|
||||
log_d("Flash device | %*.*s | addr: 0x%08lx | len: 0x%08x | blk_size: 0x%08x |initialized finish.",
|
||||
FAL_DEV_NAME_MAX, FAL_DEV_NAME_MAX, device_table[i]->name, device_table[i]->addr, device_table[i]->len,
|
||||
device_table[i]->blk_size);
|
||||
}
|
||||
|
||||
init_ok = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* find flash device by name
|
||||
*
|
||||
* @param name flash device name
|
||||
*
|
||||
* @return != NULL: flash device
|
||||
* NULL: not found
|
||||
*/
|
||||
const struct fal_flash_dev *fal_flash_device_find(const char *name)
|
||||
{
|
||||
assert(init_ok);
|
||||
assert(name);
|
||||
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < device_table_len; i++)
|
||||
{
|
||||
if (!strncmp(name, device_table[i]->name, FAL_DEV_NAME_MAX)) {
|
||||
return device_table[i];
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
514
components/fal/src/fal_partition.c
Normal file
514
components/fal/src/fal_partition.c
Normal file
|
@ -0,0 +1,514 @@
|
|||
/*
|
||||
* Copyright (c) 2006-2018, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2018-05-17 armink the first version
|
||||
*/
|
||||
|
||||
#include <fal.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
/* partition magic word */
|
||||
#define FAL_PART_MAGIC_WORD 0x45503130
|
||||
#define FAL_PART_MAGIC_WORD_H 0x4550L
|
||||
#define FAL_PART_MAGIC_WORD_L 0x3130L
|
||||
#define FAL_PART_MAGIC_WROD 0x45503130
|
||||
|
||||
struct part_flash_info
|
||||
{
|
||||
const struct fal_flash_dev *flash_dev;
|
||||
};
|
||||
|
||||
/**
|
||||
* FAL partition table config has defined on 'fal_cfg.h'.
|
||||
* When this option is disable, it will auto find the partition table on a specified location in flash partition.
|
||||
*/
|
||||
#ifdef FAL_PART_HAS_TABLE_CFG
|
||||
|
||||
/* check partition table definition */
|
||||
#if !defined(FAL_PART_TABLE)
|
||||
#error "You must defined FAL_PART_TABLE on 'fal_cfg.h'"
|
||||
#endif
|
||||
|
||||
/* partition table definition */
|
||||
static const struct fal_partition partition_table_def[] = FAL_PART_TABLE;
|
||||
static const struct fal_partition *partition_table = NULL;
|
||||
/* partition and flash object information cache table */
|
||||
static struct part_flash_info part_flash_cache[sizeof(partition_table_def) / sizeof(partition_table_def[0])] = { 0 };
|
||||
|
||||
#else /* FAL_PART_HAS_TABLE_CFG */
|
||||
|
||||
#if !defined(FAL_PART_TABLE_FLASH_DEV_NAME)
|
||||
#error "You must defined FAL_PART_TABLE_FLASH_DEV_NAME on 'fal_cfg.h'"
|
||||
#endif
|
||||
|
||||
/* check partition table end offset address definition */
|
||||
#if !defined(FAL_PART_TABLE_END_OFFSET)
|
||||
#error "You must defined FAL_PART_TABLE_END_OFFSET on 'fal_cfg.h'"
|
||||
#endif
|
||||
|
||||
static struct fal_partition *partition_table = NULL;
|
||||
static struct part_flash_info *part_flash_cache = NULL;
|
||||
#endif /* FAL_PART_HAS_TABLE_CFG */
|
||||
|
||||
static uint8_t init_ok = 0;
|
||||
static size_t partition_table_len = 0;
|
||||
|
||||
/**
|
||||
* print the partition table
|
||||
*/
|
||||
void fal_show_part_table(void)
|
||||
{
|
||||
char *item1 = "name", *item2 = "flash_dev";
|
||||
size_t i, part_name_max = strlen(item1), flash_dev_name_max = strlen(item2);
|
||||
const struct fal_partition *part;
|
||||
|
||||
if (partition_table_len)
|
||||
{
|
||||
for (i = 0; i < partition_table_len; i++)
|
||||
{
|
||||
part = &partition_table[i];
|
||||
if (strlen(part->name) > part_name_max)
|
||||
{
|
||||
part_name_max = strlen(part->name);
|
||||
}
|
||||
if (strlen(part->flash_name) > flash_dev_name_max)
|
||||
{
|
||||
flash_dev_name_max = strlen(part->flash_name);
|
||||
}
|
||||
}
|
||||
}
|
||||
log_i("==================== FAL partition table ====================");
|
||||
log_i("| %-*.*s | %-*.*s | offset | length |", part_name_max, FAL_DEV_NAME_MAX, item1, flash_dev_name_max,
|
||||
FAL_DEV_NAME_MAX, item2);
|
||||
log_i("-------------------------------------------------------------");
|
||||
for (i = 0; i < partition_table_len; i++)
|
||||
{
|
||||
|
||||
#ifdef FAL_PART_HAS_TABLE_CFG
|
||||
part = &partition_table[i];
|
||||
#else
|
||||
part = &partition_table[partition_table_len - i - 1];
|
||||
#endif
|
||||
|
||||
log_i("| %-*.*s | %-*.*s | 0x%08lx | 0x%08x |", part_name_max, FAL_DEV_NAME_MAX, part->name, flash_dev_name_max,
|
||||
FAL_DEV_NAME_MAX, part->flash_name, part->offset, part->len);
|
||||
}
|
||||
log_i("=============================================================");
|
||||
}
|
||||
|
||||
static int check_and_update_part_cache(const struct fal_partition *table, size_t len)
|
||||
{
|
||||
const struct fal_flash_dev *flash_dev = NULL;
|
||||
size_t i;
|
||||
|
||||
#ifndef FAL_PART_HAS_TABLE_CFG
|
||||
if (part_flash_cache)
|
||||
{
|
||||
FAL_FREE(part_flash_cache);
|
||||
}
|
||||
part_flash_cache = FAL_MALLOC(len * sizeof(struct part_flash_info));
|
||||
if (part_flash_cache == NULL)
|
||||
{
|
||||
log_e("Initialize failed! No memory for partition table cache");
|
||||
return -2;
|
||||
}
|
||||
#endif
|
||||
|
||||
for (i = 0; i < len; i++)
|
||||
{
|
||||
flash_dev = fal_flash_device_find(table[i].flash_name);
|
||||
if (flash_dev == NULL)
|
||||
{
|
||||
log_d("Warning: Do NOT found the flash device(%s).", table[i].flash_name);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (table[i].offset >= (long)flash_dev->len)
|
||||
{
|
||||
log_e("Initialize failed! Partition(%s) offset address(%ld) out of flash bound(<%d).",
|
||||
table[i].name, table[i].offset, flash_dev->len);
|
||||
partition_table_len = 0;
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
part_flash_cache[i].flash_dev = flash_dev;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize all flash partition on FAL partition table
|
||||
*
|
||||
* @return partitions total number
|
||||
*/
|
||||
int fal_partition_init(void)
|
||||
{
|
||||
|
||||
if (init_ok)
|
||||
{
|
||||
return partition_table_len;
|
||||
}
|
||||
|
||||
#ifdef FAL_PART_HAS_TABLE_CFG
|
||||
partition_table = &partition_table_def[0];
|
||||
partition_table_len = sizeof(partition_table_def) / sizeof(partition_table_def[0]);
|
||||
#else
|
||||
/* load partition table from the end address FAL_PART_TABLE_END_OFFSET, error return 0 */
|
||||
long part_table_offset = FAL_PART_TABLE_END_OFFSET;
|
||||
size_t table_num = 0, table_item_size = 0;
|
||||
uint8_t part_table_find_ok = 0;
|
||||
uint32_t read_magic_word;
|
||||
fal_partition_t new_part = NULL;
|
||||
size_t i;
|
||||
const struct fal_flash_dev *flash_dev = NULL;
|
||||
|
||||
flash_dev = fal_flash_device_find(FAL_PART_TABLE_FLASH_DEV_NAME);
|
||||
if (flash_dev == NULL)
|
||||
{
|
||||
log_e("Initialize failed! Flash device (%s) NOT found.", FAL_PART_TABLE_FLASH_DEV_NAME);
|
||||
goto _exit;
|
||||
}
|
||||
|
||||
/* check partition table offset address */
|
||||
if (part_table_offset < 0 || part_table_offset >= (long) flash_dev->len)
|
||||
{
|
||||
log_e("Setting partition table end offset address(%ld) out of flash bound(<%d).", part_table_offset, flash_dev->len);
|
||||
goto _exit;
|
||||
}
|
||||
|
||||
table_item_size = sizeof(struct fal_partition);
|
||||
new_part = (fal_partition_t)FAL_MALLOC(table_item_size);
|
||||
if (new_part == NULL)
|
||||
{
|
||||
log_e("Initialize failed! No memory for table buffer.");
|
||||
goto _exit;
|
||||
}
|
||||
|
||||
/* find partition table location */
|
||||
{
|
||||
uint8_t read_buf[64];
|
||||
|
||||
part_table_offset -= sizeof(read_buf);
|
||||
while (part_table_offset >= 0)
|
||||
{
|
||||
if (flash_dev->ops.read(part_table_offset, read_buf, sizeof(read_buf)) > 0)
|
||||
{
|
||||
/* find magic word in read buf */
|
||||
for (i = 0; i < sizeof(read_buf) - sizeof(read_magic_word) + 1; i++)
|
||||
{
|
||||
read_magic_word = read_buf[0 + i] + (read_buf[1 + i] << 8) + (read_buf[2 + i] << 16) + (read_buf[3 + i] << 24);
|
||||
if (read_magic_word == ((FAL_PART_MAGIC_WORD_H << 16) + FAL_PART_MAGIC_WORD_L))
|
||||
{
|
||||
part_table_find_ok = 1;
|
||||
part_table_offset += i;
|
||||
log_d("Find the partition table on '%s' offset @0x%08lx.", FAL_PART_TABLE_FLASH_DEV_NAME,
|
||||
part_table_offset);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* read failed */
|
||||
break;
|
||||
}
|
||||
|
||||
if (part_table_find_ok)
|
||||
{
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* calculate next read buf position */
|
||||
if (part_table_offset >= (long)sizeof(read_buf))
|
||||
{
|
||||
part_table_offset -= sizeof(read_buf);
|
||||
part_table_offset += (sizeof(read_magic_word) - 1);
|
||||
}
|
||||
else if (part_table_offset != 0)
|
||||
{
|
||||
part_table_offset = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* find failed */
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* load partition table */
|
||||
while (part_table_find_ok)
|
||||
{
|
||||
memset(new_part, 0x00, table_num);
|
||||
if (flash_dev->ops.read(part_table_offset - table_item_size * (table_num), (uint8_t *) new_part,
|
||||
table_item_size) < 0)
|
||||
{
|
||||
log_e("Initialize failed! Flash device (%s) read error!", flash_dev->name);
|
||||
table_num = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
if (new_part->magic_word != ((FAL_PART_MAGIC_WORD_H << 16) + FAL_PART_MAGIC_WORD_L))
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
partition_table = (fal_partition_t) FAL_REALLOC(partition_table, table_item_size * (table_num + 1));
|
||||
if (partition_table == NULL)
|
||||
{
|
||||
log_e("Initialize failed! No memory for partition table");
|
||||
table_num = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
memcpy(partition_table + table_num, new_part, table_item_size);
|
||||
|
||||
table_num++;
|
||||
};
|
||||
|
||||
if (table_num == 0)
|
||||
{
|
||||
log_e("Partition table NOT found on flash: %s (len: %d) from offset: 0x%08x.", FAL_PART_TABLE_FLASH_DEV_NAME,
|
||||
FAL_DEV_NAME_MAX, FAL_PART_TABLE_END_OFFSET);
|
||||
goto _exit;
|
||||
}
|
||||
else
|
||||
{
|
||||
partition_table_len = table_num;
|
||||
}
|
||||
#endif /* FAL_PART_HAS_TABLE_CFG */
|
||||
|
||||
/* check the partition table device exists */
|
||||
if (check_and_update_part_cache(partition_table, partition_table_len) != 0)
|
||||
{
|
||||
goto _exit;
|
||||
}
|
||||
|
||||
init_ok = 1;
|
||||
|
||||
_exit:
|
||||
|
||||
#if FAL_DEBUG
|
||||
fal_show_part_table();
|
||||
#endif
|
||||
|
||||
#ifndef FAL_PART_HAS_TABLE_CFG
|
||||
if (new_part)
|
||||
{
|
||||
FAL_FREE(new_part);
|
||||
}
|
||||
#endif /* !FAL_PART_HAS_TABLE_CFG */
|
||||
|
||||
return partition_table_len;
|
||||
}
|
||||
|
||||
/**
|
||||
* find the partition by name
|
||||
*
|
||||
* @param name partition name
|
||||
*
|
||||
* @return != NULL: partition
|
||||
* NULL: not found
|
||||
*/
|
||||
const struct fal_partition *fal_partition_find(const char *name)
|
||||
{
|
||||
assert(init_ok);
|
||||
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < partition_table_len; i++)
|
||||
{
|
||||
if (!strcmp(name, partition_table[i].name))
|
||||
{
|
||||
return &partition_table[i];
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static const struct fal_flash_dev *flash_device_find_by_part(const struct fal_partition *part)
|
||||
{
|
||||
assert(part >= partition_table);
|
||||
assert(part <= &partition_table[partition_table_len - 1]);
|
||||
|
||||
return part_flash_cache[part - partition_table].flash_dev;
|
||||
}
|
||||
|
||||
/**
|
||||
* get the partition table
|
||||
*
|
||||
* @param len return the partition table length
|
||||
*
|
||||
* @return partition table
|
||||
*/
|
||||
const struct fal_partition *fal_get_partition_table(size_t *len)
|
||||
{
|
||||
assert(init_ok);
|
||||
assert(len);
|
||||
|
||||
*len = partition_table_len;
|
||||
|
||||
return partition_table;
|
||||
}
|
||||
|
||||
/**
|
||||
* set partition table temporarily
|
||||
* This setting will modify the partition table temporarily, the setting will be lost after restart.
|
||||
*
|
||||
* @param table partition table
|
||||
* @param len partition table length
|
||||
*/
|
||||
void fal_set_partition_table_temp(struct fal_partition *table, size_t len)
|
||||
{
|
||||
assert(init_ok);
|
||||
assert(table);
|
||||
|
||||
check_and_update_part_cache(table, len);
|
||||
|
||||
partition_table_len = len;
|
||||
partition_table = table;
|
||||
}
|
||||
|
||||
/**
|
||||
* read data from partition
|
||||
*
|
||||
* @param part partition
|
||||
* @param addr relative address for partition
|
||||
* @param buf read buffer
|
||||
* @param size read size
|
||||
*
|
||||
* @return >= 0: successful read data size
|
||||
* -1: error
|
||||
*/
|
||||
int fal_partition_read(const struct fal_partition *part, uint32_t addr, uint8_t *buf, size_t size)
|
||||
{
|
||||
int ret = 0;
|
||||
const struct fal_flash_dev *flash_dev = NULL;
|
||||
|
||||
assert(part);
|
||||
assert(buf);
|
||||
|
||||
if (addr + size > part->len)
|
||||
{
|
||||
log_e("Partition read error! Partition address out of bound.");
|
||||
return -1;
|
||||
}
|
||||
|
||||
flash_dev = flash_device_find_by_part(part);
|
||||
if (flash_dev == NULL)
|
||||
{
|
||||
log_e("Partition read error! Don't found flash device(%s) of the partition(%s).", part->flash_name, part->name);
|
||||
return -1;
|
||||
}
|
||||
|
||||
ret = flash_dev->ops.read(part->offset + addr, buf, size);
|
||||
if (ret < 0)
|
||||
{
|
||||
log_e("Partition read error! Flash device(%s) read error!", part->flash_name);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* write data to partition
|
||||
*
|
||||
* @param part partition
|
||||
* @param addr relative address for partition
|
||||
* @param buf write buffer
|
||||
* @param size write size
|
||||
*
|
||||
* @return >= 0: successful write data size
|
||||
* -1: error
|
||||
*/
|
||||
int fal_partition_write(const struct fal_partition *part, uint32_t addr, const uint8_t *buf, size_t size)
|
||||
{
|
||||
int ret = 0;
|
||||
const struct fal_flash_dev *flash_dev = NULL;
|
||||
|
||||
assert(part);
|
||||
assert(buf);
|
||||
|
||||
if (addr + size > part->len)
|
||||
{
|
||||
log_e("Partition write error! Partition address out of bound.");
|
||||
return -1;
|
||||
}
|
||||
|
||||
flash_dev = flash_device_find_by_part(part);
|
||||
if (flash_dev == NULL)
|
||||
{
|
||||
log_e("Partition write error! Don't found flash device(%s) of the partition(%s).", part->flash_name, part->name);
|
||||
return -1;
|
||||
}
|
||||
|
||||
ret = flash_dev->ops.write(part->offset + addr, buf, size);
|
||||
if (ret < 0)
|
||||
{
|
||||
log_e("Partition write error! Flash device(%s) write error!", part->flash_name);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* erase partition data
|
||||
*
|
||||
* @param part partition
|
||||
* @param addr relative address for partition
|
||||
* @param size erase size
|
||||
*
|
||||
* @return >= 0: successful erased data size
|
||||
* -1: error
|
||||
*/
|
||||
int fal_partition_erase(const struct fal_partition *part, uint32_t addr, size_t size)
|
||||
{
|
||||
int ret = 0;
|
||||
const struct fal_flash_dev *flash_dev = NULL;
|
||||
|
||||
assert(part);
|
||||
|
||||
if (addr + size > part->len)
|
||||
{
|
||||
log_e("Partition erase error! Partition address out of bound.");
|
||||
return -1;
|
||||
}
|
||||
|
||||
flash_dev = flash_device_find_by_part(part);
|
||||
if (flash_dev == NULL)
|
||||
{
|
||||
log_e("Partition erase error! Don't found flash device(%s) of the partition(%s).", part->flash_name, part->name);
|
||||
return -1;
|
||||
}
|
||||
|
||||
ret = flash_dev->ops.erase(part->offset + addr, size);
|
||||
if (ret < 0)
|
||||
{
|
||||
log_e("Partition erase error! Flash device(%s) erase error!", part->flash_name);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* erase partition all data
|
||||
*
|
||||
* @param part partition
|
||||
*
|
||||
* @return >= 0: successful erased data size
|
||||
* -1: error
|
||||
*/
|
||||
int fal_partition_erase_all(const struct fal_partition *part)
|
||||
{
|
||||
return fal_partition_erase(part, 0, part->len);
|
||||
}
|
939
components/fal/src/fal_rtt.c
Normal file
939
components/fal/src/fal_rtt.c
Normal file
|
@ -0,0 +1,939 @@
|
|||
/*
|
||||
* Copyright (c) 2006-2022, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2018-06-23 armink the first version
|
||||
* 2019-08-22 MurphyZhao adapt to none rt-thread case
|
||||
*/
|
||||
|
||||
#include <fal.h>
|
||||
|
||||
#ifdef RT_VER_NUM
|
||||
#include <rtthread.h>
|
||||
#include <rtdevice.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
/* ========================== block device ======================== */
|
||||
struct fal_blk_device
|
||||
{
|
||||
struct rt_device parent;
|
||||
struct rt_device_blk_geometry geometry;
|
||||
const struct fal_partition *fal_part;
|
||||
};
|
||||
|
||||
/* RT-Thread device interface */
|
||||
#if RTTHREAD_VERSION >= 30000
|
||||
static rt_err_t blk_dev_control(rt_device_t dev, int cmd, void *args)
|
||||
#else
|
||||
static rt_err_t blk_dev_control(rt_device_t dev, rt_uint8_t cmd, void *args)
|
||||
#endif
|
||||
{
|
||||
struct fal_blk_device *part = (struct fal_blk_device*) dev;
|
||||
|
||||
assert(part != RT_NULL);
|
||||
|
||||
if (cmd == RT_DEVICE_CTRL_BLK_GETGEOME)
|
||||
{
|
||||
struct rt_device_blk_geometry *geometry;
|
||||
|
||||
geometry = (struct rt_device_blk_geometry *) args;
|
||||
if (geometry == RT_NULL)
|
||||
{
|
||||
return -RT_ERROR;
|
||||
}
|
||||
|
||||
memcpy(geometry, &part->geometry, sizeof(struct rt_device_blk_geometry));
|
||||
}
|
||||
else if (cmd == RT_DEVICE_CTRL_BLK_ERASE)
|
||||
{
|
||||
rt_uint32_t *addrs = (rt_uint32_t *) args, start_addr = addrs[0], end_addr = addrs[1], phy_start_addr;
|
||||
rt_size_t phy_size;
|
||||
|
||||
if (addrs == RT_NULL || start_addr > end_addr)
|
||||
{
|
||||
return -RT_ERROR;
|
||||
}
|
||||
|
||||
if (end_addr == start_addr)
|
||||
{
|
||||
end_addr++;
|
||||
}
|
||||
|
||||
phy_start_addr = start_addr * part->geometry.bytes_per_sector;
|
||||
phy_size = (end_addr - start_addr) * part->geometry.bytes_per_sector;
|
||||
|
||||
if (fal_partition_erase(part->fal_part, phy_start_addr, phy_size) < 0)
|
||||
{
|
||||
return -RT_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static rt_ssize_t blk_dev_read(rt_device_t dev, rt_off_t pos, void* buffer, rt_size_t size)
|
||||
{
|
||||
int ret = 0;
|
||||
struct fal_blk_device *part = (struct fal_blk_device*) dev;
|
||||
|
||||
assert(part != RT_NULL);
|
||||
|
||||
ret = fal_partition_read(part->fal_part, pos * part->geometry.block_size, buffer, size * part->geometry.block_size);
|
||||
|
||||
if (ret != (int)(size * part->geometry.block_size))
|
||||
{
|
||||
ret = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
ret = size;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static rt_ssize_t blk_dev_write(rt_device_t dev, rt_off_t pos, const void* buffer, rt_size_t size)
|
||||
{
|
||||
int ret = 0;
|
||||
struct fal_blk_device *part;
|
||||
rt_off_t phy_pos;
|
||||
rt_size_t phy_size;
|
||||
|
||||
part = (struct fal_blk_device*) dev;
|
||||
assert(part != RT_NULL);
|
||||
|
||||
/* change the block device's logic address to physical address */
|
||||
phy_pos = pos * part->geometry.bytes_per_sector;
|
||||
phy_size = size * part->geometry.bytes_per_sector;
|
||||
|
||||
ret = fal_partition_erase(part->fal_part, phy_pos, phy_size);
|
||||
|
||||
if (ret == (int) phy_size)
|
||||
{
|
||||
ret = fal_partition_write(part->fal_part, phy_pos, buffer, phy_size);
|
||||
}
|
||||
|
||||
if (ret != (int) phy_size)
|
||||
{
|
||||
ret = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
ret = size;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
#ifdef RT_USING_DEVICE_OPS
|
||||
const static struct rt_device_ops blk_dev_ops =
|
||||
{
|
||||
RT_NULL,
|
||||
RT_NULL,
|
||||
RT_NULL,
|
||||
blk_dev_read,
|
||||
blk_dev_write,
|
||||
blk_dev_control
|
||||
};
|
||||
#endif
|
||||
|
||||
/**
|
||||
* create RT-Thread block device by specified partition
|
||||
*
|
||||
* @param parition_name partition name
|
||||
*
|
||||
* @return != NULL: created block device
|
||||
* NULL: created failed
|
||||
*/
|
||||
struct rt_device *fal_blk_device_create(const char *parition_name)
|
||||
{
|
||||
struct fal_blk_device *blk_dev;
|
||||
const struct fal_partition *fal_part = fal_partition_find(parition_name);
|
||||
const struct fal_flash_dev *fal_flash = NULL;
|
||||
|
||||
if (!fal_part)
|
||||
{
|
||||
log_e("Error: the partition name (%s) is not found.", parition_name);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if ((fal_flash = fal_flash_device_find(fal_part->flash_name)) == NULL)
|
||||
{
|
||||
log_e("Error: the flash device name (%s) is not found.", fal_part->flash_name);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
blk_dev = (struct fal_blk_device*) rt_malloc(sizeof(struct fal_blk_device));
|
||||
if (blk_dev)
|
||||
{
|
||||
blk_dev->fal_part = fal_part;
|
||||
blk_dev->geometry.bytes_per_sector = fal_flash->blk_size;
|
||||
blk_dev->geometry.block_size = fal_flash->blk_size;
|
||||
blk_dev->geometry.sector_count = fal_part->len / fal_flash->blk_size;
|
||||
|
||||
/* register device */
|
||||
blk_dev->parent.type = RT_Device_Class_Block;
|
||||
|
||||
#ifdef RT_USING_DEVICE_OPS
|
||||
blk_dev->parent.ops = &blk_dev_ops;
|
||||
#else
|
||||
blk_dev->parent.init = NULL;
|
||||
blk_dev->parent.open = NULL;
|
||||
blk_dev->parent.close = NULL;
|
||||
blk_dev->parent.read = blk_dev_read;
|
||||
blk_dev->parent.write = blk_dev_write;
|
||||
blk_dev->parent.control = blk_dev_control;
|
||||
#endif
|
||||
|
||||
/* no private */
|
||||
blk_dev->parent.user_data = RT_NULL;
|
||||
|
||||
log_i("The FAL block device (%s) created successfully", fal_part->name);
|
||||
rt_device_register(RT_DEVICE(blk_dev), fal_part->name, RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_STANDALONE);
|
||||
}
|
||||
else
|
||||
{
|
||||
log_e("Error: no memory for create FAL block device");
|
||||
}
|
||||
|
||||
return RT_DEVICE(blk_dev);
|
||||
}
|
||||
|
||||
/* ========================== MTD nor device ======================== */
|
||||
#if defined(RT_USING_MTD_NOR)
|
||||
|
||||
struct fal_mtd_nor_device
|
||||
{
|
||||
struct rt_mtd_nor_device parent;
|
||||
const struct fal_partition *fal_part;
|
||||
};
|
||||
|
||||
static rt_ssize_t mtd_nor_dev_read(struct rt_mtd_nor_device* device, rt_off_t offset, rt_uint8_t* data, rt_uint32_t length)
|
||||
{
|
||||
int ret = 0;
|
||||
struct fal_mtd_nor_device *part = (struct fal_mtd_nor_device*) device;
|
||||
|
||||
assert(part != RT_NULL);
|
||||
|
||||
ret = fal_partition_read(part->fal_part, offset, data, length);
|
||||
|
||||
if (ret != (int)length)
|
||||
{
|
||||
ret = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
ret = length;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static rt_ssize_t mtd_nor_dev_write(struct rt_mtd_nor_device* device, rt_off_t offset, const rt_uint8_t* data, rt_uint32_t length)
|
||||
{
|
||||
int ret = 0;
|
||||
struct fal_mtd_nor_device *part;
|
||||
|
||||
part = (struct fal_mtd_nor_device*) device;
|
||||
assert(part != RT_NULL);
|
||||
|
||||
ret = fal_partition_write(part->fal_part, offset, data, length);
|
||||
|
||||
if (ret != (int) length)
|
||||
{
|
||||
ret = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
ret = length;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static rt_err_t mtd_nor_dev_erase(struct rt_mtd_nor_device* device, rt_off_t offset, rt_uint32_t length)
|
||||
{
|
||||
int ret = 0;
|
||||
struct fal_mtd_nor_device *part;
|
||||
|
||||
part = (struct fal_mtd_nor_device*) device;
|
||||
assert(part != RT_NULL);
|
||||
|
||||
ret = fal_partition_erase(part->fal_part, offset, length);
|
||||
|
||||
if ((rt_uint32_t)ret != length || ret < 0)
|
||||
{
|
||||
return -RT_ERROR;
|
||||
}
|
||||
else
|
||||
{
|
||||
return RT_EOK;
|
||||
}
|
||||
}
|
||||
|
||||
static const struct rt_mtd_nor_driver_ops _ops =
|
||||
{
|
||||
RT_NULL,
|
||||
mtd_nor_dev_read,
|
||||
mtd_nor_dev_write,
|
||||
mtd_nor_dev_erase,
|
||||
};
|
||||
|
||||
/**
|
||||
* create RT-Thread MTD NOR device by specified partition
|
||||
*
|
||||
* @param parition_name partition name
|
||||
*
|
||||
* @return != NULL: created MTD NOR device
|
||||
* NULL: created failed
|
||||
*/
|
||||
struct rt_device *fal_mtd_nor_device_create(const char *parition_name)
|
||||
{
|
||||
struct fal_mtd_nor_device *mtd_nor_dev;
|
||||
const struct fal_partition *fal_part = fal_partition_find(parition_name);
|
||||
const struct fal_flash_dev *fal_flash = NULL;
|
||||
|
||||
if (!fal_part)
|
||||
{
|
||||
log_e("Error: the partition name (%s) is not found.", parition_name);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if ((fal_flash = fal_flash_device_find(fal_part->flash_name)) == NULL)
|
||||
{
|
||||
log_e("Error: the flash device name (%s) is not found.", fal_part->flash_name);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
mtd_nor_dev = (struct fal_mtd_nor_device*) rt_malloc(sizeof(struct fal_mtd_nor_device));
|
||||
if (mtd_nor_dev)
|
||||
{
|
||||
mtd_nor_dev->fal_part = fal_part;
|
||||
|
||||
mtd_nor_dev->parent.block_start = 0;
|
||||
mtd_nor_dev->parent.block_end = fal_part->len / fal_flash->blk_size;
|
||||
mtd_nor_dev->parent.block_size = fal_flash->blk_size;
|
||||
|
||||
/* set ops */
|
||||
mtd_nor_dev->parent.ops = &_ops;
|
||||
|
||||
log_i("The FAL MTD NOR device (%s) created successfully", fal_part->name);
|
||||
rt_mtd_nor_register_device(fal_part->name, &mtd_nor_dev->parent);
|
||||
}
|
||||
else
|
||||
{
|
||||
log_e("Error: no memory for create FAL MTD NOR device");
|
||||
}
|
||||
|
||||
return RT_DEVICE(&mtd_nor_dev->parent);
|
||||
}
|
||||
|
||||
#endif /* defined(RT_USING_MTD_NOR) */
|
||||
|
||||
|
||||
/* ========================== char device ======================== */
|
||||
struct fal_char_device
|
||||
{
|
||||
struct rt_device parent;
|
||||
const struct fal_partition *fal_part;
|
||||
};
|
||||
|
||||
/* RT-Thread device interface */
|
||||
static rt_ssize_t char_dev_read(rt_device_t dev, rt_off_t pos, void *buffer, rt_size_t size)
|
||||
{
|
||||
int ret = 0;
|
||||
struct fal_char_device *part = (struct fal_char_device *) dev;
|
||||
|
||||
assert(part != RT_NULL);
|
||||
|
||||
if (pos + size > part->fal_part->len)
|
||||
size = part->fal_part->len - pos;
|
||||
|
||||
ret = fal_partition_read(part->fal_part, pos, buffer, size);
|
||||
|
||||
if (ret != (int)(size))
|
||||
ret = 0;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static rt_ssize_t char_dev_write(rt_device_t dev, rt_off_t pos, const void *buffer, rt_size_t size)
|
||||
{
|
||||
int ret = 0;
|
||||
struct fal_char_device *part;
|
||||
|
||||
part = (struct fal_char_device *) dev;
|
||||
assert(part != RT_NULL);
|
||||
|
||||
if (pos == 0)
|
||||
{
|
||||
fal_partition_erase_all(part->fal_part);
|
||||
}
|
||||
else if (pos + size > part->fal_part->len)
|
||||
{
|
||||
size = part->fal_part->len - pos;
|
||||
}
|
||||
|
||||
ret = fal_partition_write(part->fal_part, pos, buffer, size);
|
||||
|
||||
if (ret != (int) size)
|
||||
ret = 0;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
#ifdef RT_USING_DEVICE_OPS
|
||||
const static struct rt_device_ops char_dev_ops =
|
||||
{
|
||||
RT_NULL,
|
||||
RT_NULL,
|
||||
RT_NULL,
|
||||
char_dev_read,
|
||||
char_dev_write,
|
||||
RT_NULL
|
||||
};
|
||||
#endif
|
||||
|
||||
#ifdef RT_USING_POSIX_DEVIO
|
||||
#include <dfs_file.h>
|
||||
#include <unistd.h>
|
||||
#include <stdio.h> /* rename() */
|
||||
#include <sys/stat.h>
|
||||
#include <sys/statfs.h> /* statfs() */
|
||||
|
||||
/* RT-Thread device filesystem interface */
|
||||
static int char_dev_fopen(struct dfs_file *fd)
|
||||
{
|
||||
struct fal_char_device *part = (struct fal_char_device *) fd->vnode->data;
|
||||
|
||||
assert(part != RT_NULL);
|
||||
|
||||
switch (fd->flags & O_ACCMODE)
|
||||
{
|
||||
case O_RDONLY:
|
||||
break;
|
||||
case O_WRONLY:
|
||||
case O_RDWR:
|
||||
/* erase partition when device file open */
|
||||
fal_partition_erase_all(part->fal_part);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
fd->pos = 0;
|
||||
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static int char_dev_fread(struct dfs_file *fd, void *buf, size_t count)
|
||||
{
|
||||
int ret = 0;
|
||||
struct fal_char_device *part = (struct fal_char_device *) fd->vnode->data;
|
||||
|
||||
assert(part != RT_NULL);
|
||||
|
||||
if (fd->pos + count > part->fal_part->len)
|
||||
count = part->fal_part->len - fd->pos;
|
||||
|
||||
ret = fal_partition_read(part->fal_part, fd->pos, buf, count);
|
||||
|
||||
if (ret != (int)(count))
|
||||
return 0;
|
||||
|
||||
fd->pos += ret;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int char_dev_fwrite(struct dfs_file *fd, const void *buf, size_t count)
|
||||
{
|
||||
int ret = 0;
|
||||
struct fal_char_device *part = (struct fal_char_device *) fd->vnode->data;
|
||||
|
||||
assert(part != RT_NULL);
|
||||
|
||||
if (fd->pos + count > part->fal_part->len)
|
||||
count = part->fal_part->len - fd->pos;
|
||||
|
||||
ret = fal_partition_write(part->fal_part, fd->pos, buf, count);
|
||||
|
||||
if (ret != (int) count)
|
||||
return 0;
|
||||
|
||||
fd->pos += ret;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const struct dfs_file_ops char_dev_fops =
|
||||
{
|
||||
char_dev_fopen,
|
||||
RT_NULL,
|
||||
RT_NULL,
|
||||
char_dev_fread,
|
||||
char_dev_fwrite,
|
||||
RT_NULL, /* flush */
|
||||
RT_NULL, /* lseek */
|
||||
RT_NULL, /* getdents */
|
||||
RT_NULL,
|
||||
};
|
||||
#endif /* defined(RT_USING_POSIX_DEVIO) */
|
||||
|
||||
/**
|
||||
* create RT-Thread char device by specified partition
|
||||
*
|
||||
* @param parition_name partition name
|
||||
*
|
||||
* @return != NULL: created char device
|
||||
* NULL: created failed
|
||||
*/
|
||||
struct rt_device *fal_char_device_create(const char *parition_name)
|
||||
{
|
||||
struct fal_char_device *char_dev;
|
||||
const struct fal_partition *fal_part = fal_partition_find(parition_name);
|
||||
|
||||
if (!fal_part)
|
||||
{
|
||||
log_e("Error: the partition name (%s) is not found.", parition_name);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if ((fal_flash_device_find(fal_part->flash_name)) == NULL)
|
||||
{
|
||||
log_e("Error: the flash device name (%s) is not found.", fal_part->flash_name);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
char_dev = (struct fal_char_device *) rt_malloc(sizeof(struct fal_char_device));
|
||||
if (char_dev)
|
||||
{
|
||||
char_dev->fal_part = fal_part;
|
||||
|
||||
/* register device */
|
||||
char_dev->parent.type = RT_Device_Class_Char;
|
||||
|
||||
#ifdef RT_USING_DEVICE_OPS
|
||||
char_dev->parent.ops = &char_dev_ops;
|
||||
#else
|
||||
char_dev->parent.init = NULL;
|
||||
char_dev->parent.open = NULL;
|
||||
char_dev->parent.close = NULL;
|
||||
char_dev->parent.read = char_dev_read;
|
||||
char_dev->parent.write = char_dev_write;
|
||||
char_dev->parent.control = NULL;
|
||||
/* no private */
|
||||
char_dev->parent.user_data = NULL;
|
||||
#endif
|
||||
|
||||
rt_device_register(RT_DEVICE(char_dev), fal_part->name, RT_DEVICE_FLAG_RDWR);
|
||||
log_i("The FAL char device (%s) created successfully", fal_part->name);
|
||||
|
||||
#ifdef RT_USING_POSIX_DEVIO
|
||||
/* set fops */
|
||||
char_dev->parent.fops = &char_dev_fops;
|
||||
#endif
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
log_e("Error: no memory for create FAL char device");
|
||||
}
|
||||
|
||||
return RT_DEVICE(char_dev);
|
||||
}
|
||||
|
||||
#if defined(RT_USING_FINSH) && defined(FINSH_USING_MSH)
|
||||
|
||||
#include <finsh.h>
|
||||
extern int fal_init_check(void);
|
||||
|
||||
static void fal(uint8_t argc, char **argv) {
|
||||
|
||||
#define __is_print(ch) ((unsigned int)((ch) - ' ') < 127u - ' ')
|
||||
#define HEXDUMP_WIDTH 16
|
||||
#define CMD_PROBE_INDEX 0
|
||||
#define CMD_READ_INDEX 1
|
||||
#define CMD_WRITE_INDEX 2
|
||||
#define CMD_ERASE_INDEX 3
|
||||
#define CMD_BENCH_INDEX 4
|
||||
|
||||
int result = 0;
|
||||
static const struct fal_flash_dev *flash_dev = NULL;
|
||||
static const struct fal_partition *part_dev = NULL;
|
||||
size_t i = 0, j = 0;
|
||||
|
||||
const char* help_info[] =
|
||||
{
|
||||
[CMD_PROBE_INDEX] = "fal probe [dev_name|part_name] - probe flash device or partition by given name",
|
||||
[CMD_READ_INDEX] = "fal read addr size - read 'size' bytes starting at 'addr'",
|
||||
[CMD_WRITE_INDEX] = "fal write addr data1 ... dataN - write some bytes 'data' starting at 'addr'",
|
||||
[CMD_ERASE_INDEX] = "fal erase addr size - erase 'size' bytes starting at 'addr'",
|
||||
[CMD_BENCH_INDEX] = "fal bench <blk_size> - benchmark test with per block size",
|
||||
};
|
||||
|
||||
if (fal_init_check() != 1)
|
||||
{
|
||||
rt_kprintf("\n[Warning] FAL is not initialized or failed to initialize!\n\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (argc < 2)
|
||||
{
|
||||
rt_kprintf("Usage:\n");
|
||||
for (i = 0; i < sizeof(help_info) / sizeof(char*); i++)
|
||||
{
|
||||
rt_kprintf("%s\n", help_info[i]);
|
||||
}
|
||||
rt_kprintf("\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
const char *operator = argv[1];
|
||||
uint32_t addr, size;
|
||||
|
||||
if (!strcmp(operator, "probe"))
|
||||
{
|
||||
if (argc >= 3)
|
||||
{
|
||||
char *dev_name = argv[2];
|
||||
if ((flash_dev = fal_flash_device_find(dev_name)) != NULL)
|
||||
{
|
||||
part_dev = NULL;
|
||||
}
|
||||
else if ((part_dev = fal_partition_find(dev_name)) != NULL)
|
||||
{
|
||||
flash_dev = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
rt_kprintf("Device %s NOT found. Probe failed.\n", dev_name);
|
||||
flash_dev = NULL;
|
||||
part_dev = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if (flash_dev)
|
||||
{
|
||||
rt_kprintf("Probed a flash device | %s | addr: %ld | len: %d |.\n", flash_dev->name,
|
||||
flash_dev->addr, flash_dev->len);
|
||||
}
|
||||
else if (part_dev)
|
||||
{
|
||||
rt_kprintf("Probed a flash partition | %s | flash_dev: %s | offset: %ld | len: %d |.\n",
|
||||
part_dev->name, part_dev->flash_name, part_dev->offset, part_dev->len);
|
||||
}
|
||||
else
|
||||
{
|
||||
rt_kprintf("No flash device or partition was probed.\n");
|
||||
rt_kprintf("Usage: %s.\n", help_info[CMD_PROBE_INDEX]);
|
||||
fal_show_part_table();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!flash_dev && !part_dev)
|
||||
{
|
||||
rt_kprintf("No flash device or partition was probed. Please run 'fal probe'.\n");
|
||||
return;
|
||||
}
|
||||
if (!rt_strcmp(operator, "read"))
|
||||
{
|
||||
if (argc < 4)
|
||||
{
|
||||
rt_kprintf("Usage: %s.\n", help_info[CMD_READ_INDEX]);
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
addr = strtol(argv[2], NULL, 0);
|
||||
size = strtol(argv[3], NULL, 0);
|
||||
uint8_t *data = rt_malloc(size);
|
||||
if (data)
|
||||
{
|
||||
if (flash_dev)
|
||||
{
|
||||
result = flash_dev->ops.read(addr, data, size);
|
||||
}
|
||||
else if (part_dev)
|
||||
{
|
||||
result = fal_partition_read(part_dev, addr, data, size);
|
||||
}
|
||||
if (result >= 0)
|
||||
{
|
||||
rt_kprintf("Read data success. Start from 0x%08X, size is %ld. The data is:\n", addr,
|
||||
size);
|
||||
rt_kprintf("Offset (h) 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F\n");
|
||||
for (i = 0; i < size; i += HEXDUMP_WIDTH)
|
||||
{
|
||||
rt_kprintf("[%08X] ", addr + i);
|
||||
/* dump hex */
|
||||
for (j = 0; j < HEXDUMP_WIDTH; j++)
|
||||
{
|
||||
if (i + j < size)
|
||||
{
|
||||
rt_kprintf("%02X ", data[i + j]);
|
||||
}
|
||||
else
|
||||
{
|
||||
rt_kprintf(" ");
|
||||
}
|
||||
}
|
||||
/* dump char for hex */
|
||||
for (j = 0; j < HEXDUMP_WIDTH; j++)
|
||||
{
|
||||
if (i + j < size)
|
||||
{
|
||||
rt_kprintf("%c", __is_print(data[i + j]) ? data[i + j] : '.');
|
||||
}
|
||||
}
|
||||
rt_kprintf("\n");
|
||||
}
|
||||
rt_kprintf("\n");
|
||||
}
|
||||
rt_free(data);
|
||||
}
|
||||
else
|
||||
{
|
||||
rt_kprintf("Low memory!\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (!strcmp(operator, "write"))
|
||||
{
|
||||
if (argc < 4)
|
||||
{
|
||||
rt_kprintf("Usage: %s.\n", help_info[CMD_WRITE_INDEX]);
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
addr = strtol(argv[2], NULL, 0);
|
||||
size = argc - 3;
|
||||
uint8_t *data = rt_malloc(size);
|
||||
if (data)
|
||||
{
|
||||
for (i = 0; i < size; i++)
|
||||
{
|
||||
data[i] = strtol(argv[3 + i], NULL, 0);
|
||||
}
|
||||
if (flash_dev)
|
||||
{
|
||||
result = flash_dev->ops.write(addr, data, size);
|
||||
}
|
||||
else if (part_dev)
|
||||
{
|
||||
result = fal_partition_write(part_dev, addr, data, size);
|
||||
}
|
||||
if (result >= 0)
|
||||
{
|
||||
rt_kprintf("Write data success. Start from 0x%08X, size is %ld.\n", addr, size);
|
||||
rt_kprintf("Write data: ");
|
||||
for (i = 0; i < size; i++)
|
||||
{
|
||||
rt_kprintf("%d ", data[i]);
|
||||
}
|
||||
rt_kprintf(".\n");
|
||||
}
|
||||
rt_free(data);
|
||||
}
|
||||
else
|
||||
{
|
||||
rt_kprintf("Low memory!\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (!rt_strcmp(operator, "erase"))
|
||||
{
|
||||
if (argc < 4)
|
||||
{
|
||||
rt_kprintf("Usage: %s.\n", help_info[CMD_ERASE_INDEX]);
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
addr = strtol(argv[2], NULL, 0);
|
||||
size = strtol(argv[3], NULL, 0);
|
||||
if (flash_dev)
|
||||
{
|
||||
result = flash_dev->ops.erase(addr, size);
|
||||
}
|
||||
else if (part_dev)
|
||||
{
|
||||
result = fal_partition_erase(part_dev, addr, size);
|
||||
}
|
||||
if (result >= 0)
|
||||
{
|
||||
rt_kprintf("Erase data success. Start from 0x%08X, size is %ld.\n", addr, size);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (!strcmp(operator, "bench"))
|
||||
{
|
||||
if (argc < 3)
|
||||
{
|
||||
rt_kprintf("Usage: %s.\n", help_info[CMD_BENCH_INDEX]);
|
||||
return;
|
||||
}
|
||||
else if ((argc > 3 && strcmp(argv[3], "yes")) || argc < 4)
|
||||
{
|
||||
rt_kprintf("DANGER: It will erase full chip or partition! Please run 'fal bench %d yes'.\n", strtol(argv[2], NULL, 0));
|
||||
return;
|
||||
}
|
||||
/* full chip benchmark test */
|
||||
uint32_t start_time, time_cast;
|
||||
size_t write_size = strtol(argv[2], NULL, 0), read_size = strtol(argv[2], NULL, 0), cur_op_size;
|
||||
uint8_t *write_data = (uint8_t *)rt_malloc(write_size), *read_data = (uint8_t *)rt_malloc(read_size);
|
||||
|
||||
if (write_data && read_data)
|
||||
{
|
||||
for (i = 0; i < write_size; i ++) {
|
||||
write_data[i] = i & 0xFF;
|
||||
}
|
||||
if (flash_dev)
|
||||
{
|
||||
size = flash_dev->len;
|
||||
}
|
||||
else if (part_dev)
|
||||
{
|
||||
size = part_dev->len;
|
||||
}
|
||||
/* benchmark testing */
|
||||
rt_kprintf("Erasing %ld bytes data, waiting...\n", size);
|
||||
start_time = rt_tick_get();
|
||||
if (flash_dev)
|
||||
{
|
||||
result = flash_dev->ops.erase(0, size);
|
||||
}
|
||||
else if (part_dev)
|
||||
{
|
||||
result = fal_partition_erase(part_dev, 0, size);
|
||||
}
|
||||
if (result >= 0)
|
||||
{
|
||||
time_cast = rt_tick_get() - start_time;
|
||||
rt_kprintf("Erase benchmark success, total time: %d.%03dS.\n", time_cast / RT_TICK_PER_SECOND,
|
||||
time_cast % RT_TICK_PER_SECOND / ((RT_TICK_PER_SECOND * 1 + 999) / 1000));
|
||||
}
|
||||
else
|
||||
{
|
||||
rt_kprintf("Erase benchmark has an error. Error code: %d.\n", result);
|
||||
}
|
||||
/* write test */
|
||||
rt_kprintf("Writing %ld bytes data, waiting...\n", size);
|
||||
start_time = rt_tick_get();
|
||||
for (i = 0; i < size; i += write_size)
|
||||
{
|
||||
if (i + write_size <= size)
|
||||
{
|
||||
cur_op_size = write_size;
|
||||
}
|
||||
else
|
||||
{
|
||||
cur_op_size = size - i;
|
||||
}
|
||||
if (flash_dev)
|
||||
{
|
||||
result = flash_dev->ops.write(i, write_data, cur_op_size);
|
||||
}
|
||||
else if (part_dev)
|
||||
{
|
||||
result = fal_partition_write(part_dev, i, write_data, cur_op_size);
|
||||
}
|
||||
if (result < 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (result >= 0)
|
||||
{
|
||||
time_cast = rt_tick_get() - start_time;
|
||||
rt_kprintf("Write benchmark success, total time: %d.%03dS.\n", time_cast / RT_TICK_PER_SECOND,
|
||||
time_cast % RT_TICK_PER_SECOND / ((RT_TICK_PER_SECOND * 1 + 999) / 1000));
|
||||
}
|
||||
else
|
||||
{
|
||||
rt_kprintf("Write benchmark has an error. Error code: %d.\n", result);
|
||||
}
|
||||
/* read test */
|
||||
rt_kprintf("Reading %ld bytes data, waiting...\n", size);
|
||||
start_time = rt_tick_get();
|
||||
for (i = 0; i < size; i += read_size)
|
||||
{
|
||||
if (i + read_size <= size)
|
||||
{
|
||||
cur_op_size = read_size;
|
||||
}
|
||||
else
|
||||
{
|
||||
cur_op_size = size - i;
|
||||
}
|
||||
if (flash_dev)
|
||||
{
|
||||
result = flash_dev->ops.read(i, read_data, cur_op_size);
|
||||
}
|
||||
else if (part_dev)
|
||||
{
|
||||
result = fal_partition_read(part_dev, i, read_data, cur_op_size);
|
||||
}
|
||||
/* data check */
|
||||
for (size_t index = 0; index < cur_op_size; index ++)
|
||||
{
|
||||
if (write_data[index] != read_data[index])
|
||||
{
|
||||
rt_kprintf("%d %d %02x %02x.\n", i, index, write_data[index], read_data[index]);
|
||||
}
|
||||
}
|
||||
|
||||
if (memcmp(write_data, read_data, cur_op_size))
|
||||
{
|
||||
result = -RT_ERROR;
|
||||
rt_kprintf("Data check ERROR! Please check you flash by other command.\n");
|
||||
}
|
||||
/* has an error */
|
||||
if (result < 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (result >= 0)
|
||||
{
|
||||
time_cast = rt_tick_get() - start_time;
|
||||
rt_kprintf("Read benchmark success, total time: %d.%03dS.\n", time_cast / RT_TICK_PER_SECOND,
|
||||
time_cast % RT_TICK_PER_SECOND / ((RT_TICK_PER_SECOND * 1 + 999) / 1000));
|
||||
}
|
||||
else
|
||||
{
|
||||
rt_kprintf("Read benchmark has an error. Error code: %d.\n", result);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
rt_kprintf("Low memory!\n");
|
||||
}
|
||||
rt_free(write_data);
|
||||
rt_free(read_data);
|
||||
}
|
||||
else
|
||||
{
|
||||
rt_kprintf("Usage:\n");
|
||||
for (i = 0; i < sizeof(help_info) / sizeof(char*); i++)
|
||||
{
|
||||
rt_kprintf("%s\n", help_info[i]);
|
||||
}
|
||||
rt_kprintf("\n");
|
||||
return;
|
||||
}
|
||||
if (result < 0) {
|
||||
rt_kprintf("This operate has an error. Error code: %d.\n", result);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
MSH_CMD_EXPORT(fal, FAL (Flash Abstraction Layer) operate.);
|
||||
|
||||
#endif /* defined(RT_USING_FINSH) && defined(FINSH_USING_MSH) */
|
||||
#endif /* RT_VER_NUM */
|
Loading…
Add table
Add a link
Reference in a new issue