Files

733 lines
16 KiB
C

/**
* @file card_flash_impl.c
* @brief 卡号白名单:EEPROM `S_CARD_MNG` + SPI Flash 定长槽(48B/槽,与 fault 相同的帧头+CRC 低字节)
*
* 单槽布局:RECORD_HEADER + CARD_FLASH_BODY_T(46) + crc8
* 写任意槽需对该槽所在扇区做读-合并-擦除-整扇区写回(NOR Flash 不可原地改已写位)。
*/
#include "publicdata/public_define.h"
#include "publicdata/publicdata.h"
#include "app_fatfs/fatfs_card.h"
#include "app_fatfs/fatfs_init.h"
#include "card_flash_impl.h"
#include "eeprom/fm24cl16.h"
#include "externalflash/flash_external_data.h"
#include <string.h>
/* 动态内存抽象:默认使用 FreeRTOS 堆接口,可按需覆盖 */
#ifndef FLASH_MGR_MALLOC
#define FLASH_MGR_MALLOC(sz) pvPortMalloc((sz))
#endif
#ifndef FLASH_MGR_FREE
#define FLASH_MGR_FREE(ptr) vPortFree((ptr))
#endif
#if FATFS_EN
#if 1
#define CARD_FLASH_MAX_CNT CARD_MAX_COUNT
#define CARD_BODY_SIZE 46u
#define CARD_SLOT_SIZE 48u
#define CARD_SLOTS_PER_SECTOR ((U32_T)SPI_SECTOR_SIZE / (U32_T)CARD_SLOT_SIZE)
#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L
_Static_assert(sizeof(CARD_FLASH_BODY_T) == 46u, "CARD_FLASH_BODY_T must be 46 bytes");
#endif
static bool g_card_init;
static S_CARD_MNG s_cardMng;
/**
* @brief z_strnlen。
*/
static size_t z_strnlen(const char *s, size_t max)
{
size_t i;
for (i = 0; i < max && s[i] != '\0'; i++) {
}
return i;
}
/**
* @brief v_pack_card_num。
*/
static void v_pack_card_num(const char *src, U8_T dst[32])
{
memset(dst, 0, 32u);
if (src == NULL) {
return;
}
size_t n = z_strnlen(src, (size_t)CARD_NUM_MAX_LEN);
memcpy(dst, src, n);
}
/**
* @brief b_card_num_eq。
*/
static bool b_card_num_eq(const char *src, const U8_T dst[32])
{
U8_T a[32];
v_pack_card_num(src, a);
return memcmp(a, dst, 32u) == 0;
}
/**
* @brief v_read_eeprom_card_mng。
*/
static void v_read_eeprom_card_mng(S_CARD_MNG *m)
{
int i;
S_CARD_MNG tmp;
for (i = 0; i < 3; i++) {
if (eeprom_read(EEPROM_ADDR_CARD_MNG, (U8_T *)&tmp, (S32_T)sizeof(S_CARD_MNG)) == HAL_OK) {
m->u16_head = tmp.u16_head;
m->u16_cardCnt = tmp.u16_cardCnt;
m->u16_reserved = tmp.u16_reserved;
return;
}
}
m->u16_head = 0;
m->u16_cardCnt = 0;
m->u16_reserved = 0;
}
/**
* @brief v_write_eeprom_card_mng。
*/
static void v_write_eeprom_card_mng(const S_CARD_MNG *m)
{
S_CARD_MNG out;
out.u16_head = CARD_MNG_HEAD;
out.u16_cardCnt = m->u16_cardCnt;
out.u16_reserved = m->u16_reserved;
eeprom_write(EEPROM_ADDR_CARD_MNG, (U8_T *)&out, (S32_T)sizeof(S_CARD_MNG));
}
/**
* @brief u32_slot_addr。
*/
static U32_T u32_slot_addr(U16_T slot)
{
U32_T sec = (U32_T)slot / CARD_SLOTS_PER_SECTOR;
U32_T j = (U32_T)slot % CARD_SLOTS_PER_SECTOR;
return (U32_T)DATAFLASH_CARD_ADDR + sec * (U32_T)SPI_SECTOR_SIZE + j * (U32_T)CARD_SLOT_SIZE;
}
/**
* @brief v_read_slot_raw。
*/
static void v_read_slot_raw(U16_T slot, U8_T *out)
{
(void)s32_flash_dataflash_read(u32_slot_addr(slot), out, CARD_SLOT_SIZE);
}
/**
* @brief b_slot_buf_valid。
*/
static bool b_slot_buf_valid(const U8_T *buf)
{
U8_T crc;
if (buf[0] != RECORD_HEADER) {
return false;
}
crc = (U8_T)u16_crc_checksum((U8_T *)(buf + 1), (U16_T)CARD_BODY_SIZE);
return buf[CARD_SLOT_SIZE - 1u] == crc;
}
/**
* @brief v_body_to_card_info。
*/
static void v_body_to_card_info(const CARD_FLASH_BODY_T *b, CardInfo *ci)
{
uint32_t ct;
uint32_t lt;
memset(ci, 0, sizeof(*ci));
memcpy(ci->card_num, b->card_num, sizeof(b->card_num));
ci->card_num[CARD_NUM_MAX_LEN - 1u] = '\0';
ci->balance = b->amount_milli / 10u;
memcpy(&ct, &b->rsv[0], 4u);
memcpy(&lt, &b->rsv[4], 4u);
ci->create_time = ct;
ci->last_use_time = lt;
ci->status = b->status;
memcpy(ci->reserved, b->rsv, sizeof(b->rsv));
}
/**
* @brief v_card_info_to_body。
*/
static void v_card_info_to_body(const CardInfo *ci, CARD_FLASH_BODY_T *b)
{
memset(b, 0, sizeof(*b));
v_pack_card_num(ci->card_num, b->card_num);
b->amount_milli = ci->balance * 10u;
b->status = ci->status;
memcpy(&b->rsv[0], &ci->create_time, 4u);
memcpy(&b->rsv[4], &ci->last_use_time, 4u);
}
/**
* @brief u16_count_valid_slots。
*/
static U16_T u16_count_valid_slots(void)
{
U16_T n = 0;
U16_T i;
U8_T buf[CARD_SLOT_SIZE];
for (i = 0; i < CARD_FLASH_MAX_CNT; i++) {
v_read_slot_raw(i, buf);
if (b_slot_buf_valid(buf)) {
n++;
}
}
return n;
}
/**
* @brief s_find_slot_by_num。
*/
static S16_T s_find_slot_by_num(const char *num)
{
U16_T i;
U8_T buf[CARD_SLOT_SIZE];
if (num == NULL) {
return -1;
}
for (i = 0; i < CARD_FLASH_MAX_CNT; i++) {
v_read_slot_raw(i, buf);
if (!b_slot_buf_valid(buf)) {
continue;
}
if (b_card_num_eq(num, buf + 1)) {
return (S16_T)i;
}
}
return -1;
}
/**
* @brief s_find_free_slot。
*/
static S16_T s_find_free_slot(void)
{
U16_T i;
U8_T buf[CARD_SLOT_SIZE];
for (i = 0; i < CARD_FLASH_MAX_CNT; i++) {
v_read_slot_raw(i, buf);
if (!b_slot_buf_valid(buf)) {
return (S16_T)i;
}
}
return -1;
}
/**
* @brief v_erase_all_card_sectors。
*/
static void v_erase_all_card_sectors(void)
{
U8_T s;
for (s = 0; s < (U8_T)DATAFLASH_CARD_SECTOR_CNT; s++) {
(void)s32_flash_dataflash_erase_sector((U32_T)DATAFLASH_CARD_ADDR + (U32_T)s * (U32_T)SPI_SECTOR_SIZE);
}
}
/**
* @brief 写单槽:读扇区内其它有效槽,合并后擦除扇区再写回整扇区
* @param body_or_null 非 NULL 写入/更新;NULL 表示删除该槽(置为擦除态)
*/
static CardStatus e_flush_slot(U16_T slot, const CARD_FLASH_BODY_T *body_or_null)
{
U32_T sec = (U32_T)slot / CARD_SLOTS_PER_SECTOR;
U32_T j = (U32_T)slot % CARD_SLOTS_PER_SECTOR;
U32_T sector_base = (U32_T)DATAFLASH_CARD_ADDR + sec * (U32_T)SPI_SECTOR_SIZE;
U32_T k;
U8_T tmp[CARD_SLOT_SIZE];
U8_T *sector_rw = (U8_T *)FLASH_MGR_MALLOC((size_t)SPI_SECTOR_SIZE);
if (sector_rw == NULL) {
return CARD_STATUS_WRITE_FAILED;
}
memset(sector_rw, 0xFF, SPI_SECTOR_SIZE);
for (k = 0; k < CARD_SLOTS_PER_SECTOR; k++) {
U16_T g = (U16_T)(sec * CARD_SLOTS_PER_SECTOR + k);
if (g >= CARD_FLASH_MAX_CNT) {
break;
}
if (g == slot) {
continue;
}
v_read_slot_raw(g, tmp);
if (b_slot_buf_valid(tmp)) {
memcpy(&sector_rw[k * CARD_SLOT_SIZE], tmp, CARD_SLOT_SIZE);
}
}
if (body_or_null != NULL) {
U8_T *dst = &sector_rw[j * CARD_SLOT_SIZE];
dst[0] = RECORD_HEADER;
memcpy(dst + 1, body_or_null, sizeof(CARD_FLASH_BODY_T));
dst[CARD_SLOT_SIZE - 1u] =
(U8_T)u16_crc_checksum(dst + 1, (U16_T)CARD_BODY_SIZE);
}
(void)s32_flash_dataflash_erase_sector(sector_base);
if (s32_flash_dataflash_write(sector_base, sector_rw, (U32_T)SPI_SECTOR_SIZE) != 0u) {
FLASH_MGR_FREE(sector_rw);
return CARD_STATUS_WRITE_FAILED;
}
FLASH_MGR_FREE(sector_rw);
return CARD_STATUS_OK;
}
/**
* @brief card_init。
*/
CardStatus card_init(void)
{
U16_T actual;
if (g_card_init) {
return CARD_STATUS_ALREADY_INIT;
}
v_read_eeprom_card_mng(&s_cardMng);
actual = u16_count_valid_slots();
if (s_cardMng.u16_head != CARD_MNG_HEAD) {
s_cardMng.u16_head = CARD_MNG_HEAD;
s_cardMng.u16_cardCnt = actual;
s_cardMng.u16_reserved = 0;
v_write_eeprom_card_mng(&s_cardMng);
} else if (s_cardMng.u16_cardCnt != actual) {
s_cardMng.u16_cardCnt = actual;
v_write_eeprom_card_mng(&s_cardMng);
}
g_card_init = true;
FATFS_PRINT("card flash: init ok, cnt=%u\r\n", (unsigned)s_cardMng.u16_cardCnt);
return CARD_STATUS_OK;
}
/**
* @brief card_deinit。
*/
void card_deinit(void)
{
g_card_init = false;
}
/**
* @brief card_add。
*/
CardStatus card_add(const CardInfo *card_info)
{
CARD_FLASH_BODY_T body;
S16_T free_slot;
if (!g_card_init) {
return CARD_STATUS_INIT_FAILED;
}
if (card_info == NULL) {
return CARD_STATUS_PARAM_ERROR;
}
if (s_find_slot_by_num(card_info->card_num) >= 0) {
return CARD_STATUS_CARD_EXIST;
}
free_slot = s_find_free_slot();
if (free_slot < 0) {
return CARD_STATUS_NO_SPACE;
}
v_card_info_to_body(card_info, &body);
if (e_flush_slot((U16_T)free_slot, &body) != CARD_STATUS_OK) {
return CARD_STATUS_WRITE_FAILED;
}
s_cardMng.u16_cardCnt++;
v_write_eeprom_card_mng(&s_cardMng);
return CARD_STATUS_OK;
}
/**
* @brief card_update。
*/
CardStatus card_update(const CardInfo *card_info)
{
CARD_FLASH_BODY_T body;
S16_T idx;
if (!g_card_init) {
return CARD_STATUS_INIT_FAILED;
}
if (card_info == NULL) {
return CARD_STATUS_PARAM_ERROR;
}
idx = s_find_slot_by_num(card_info->card_num);
if (idx < 0) {
return CARD_STATUS_CARD_NOT_FOUND;
}
v_card_info_to_body(card_info, &body);
if (e_flush_slot((U16_T)idx, &body) != CARD_STATUS_OK) {
return CARD_STATUS_WRITE_FAILED;
}
return CARD_STATUS_OK;
}
/**
* @brief card_delete。
*/
CardStatus card_delete(const char *card_num)
{
S16_T idx;
if (!g_card_init) {
return CARD_STATUS_INIT_FAILED;
}
if (card_num == NULL) {
return CARD_STATUS_PARAM_ERROR;
}
idx = s_find_slot_by_num(card_num);
if (idx < 0) {
return CARD_STATUS_CARD_NOT_FOUND;
}
if (e_flush_slot((U16_T)idx, NULL) != CARD_STATUS_OK) {
return CARD_STATUS_WRITE_FAILED;
}
if (s_cardMng.u16_cardCnt > 0) {
s_cardMng.u16_cardCnt--;
}
v_write_eeprom_card_mng(&s_cardMng);
return CARD_STATUS_OK;
}
/**
* @brief card_find。
*/
CardStatus card_find(const char *card_num, CardInfo *card_info)
{
S16_T idx;
U8_T buf[CARD_SLOT_SIZE];
CARD_FLASH_BODY_T body;
if (!g_card_init) {
return CARD_STATUS_INIT_FAILED;
}
if (card_num == NULL || card_info == NULL) {
return CARD_STATUS_PARAM_ERROR;
}
idx = s_find_slot_by_num(card_num);
if (idx < 0) {
return CARD_STATUS_CARD_NOT_FOUND;
}
v_read_slot_raw((U16_T)idx, buf);
if (!b_slot_buf_valid(buf)) {
return CARD_STATUS_READ_FAILED;
}
memcpy(&body, buf + 1, sizeof(CARD_FLASH_BODY_T));
v_body_to_card_info(&body, card_info);
return CARD_STATUS_OK;
}
/**
* @brief card_get_count。
*/
CardStatus card_get_count(uint32_t *count)
{
if (!g_card_init) {
return CARD_STATUS_INIT_FAILED;
}
if (count == NULL) {
return CARD_STATUS_PARAM_ERROR;
}
*count = (uint32_t)s_cardMng.u16_cardCnt;
return CARD_STATUS_OK;
}
/**
* @brief card_get_all。
*/
CardStatus card_get_all(CardInfo *card_list, uint32_t *count, uint32_t max_count)
{
U16_T i;
U32_T n;
U8_T buf[CARD_SLOT_SIZE];
CARD_FLASH_BODY_T body;
if (!g_card_init) {
return CARD_STATUS_INIT_FAILED;
}
if (count == NULL) {
return CARD_STATUS_PARAM_ERROR;
}
n = 0;
for (i = 0; i < CARD_FLASH_MAX_CNT && n < max_count; i++) {
v_read_slot_raw(i, buf);
if (!b_slot_buf_valid(buf)) {
continue;
}
if (card_list != NULL) {
memcpy(&body, buf + 1, sizeof(CARD_FLASH_BODY_T));
v_body_to_card_info(&body, &card_list[n]);
}
n++;
}
*count = n;
return CARD_STATUS_OK;
}
/**
* @brief card_check_exist。
*/
CardStatus card_check_exist(const char *card_num, bool *exist)
{
if (card_num == NULL || exist == NULL) {
return CARD_STATUS_PARAM_ERROR;
}
if (!g_card_init) {
return CARD_STATUS_INIT_FAILED;
}
*exist = (s_find_slot_by_num(card_num) >= 0);
return CARD_STATUS_OK;
}
/**
* @brief card_backup。
*/
CardStatus card_backup(void)
{
/* 无独立备份区;保留接口兼容旧 CSV 备份语义 */
return CARD_STATUS_OK;
}
/**
* @brief card_restore。
*/
CardStatus card_restore(void)
{
return CARD_STATUS_OK;
}
/**
* @brief card_clear_all。
*/
CardStatus card_clear_all(void)
{
if (!g_card_init) {
return CARD_STATUS_INIT_FAILED;
}
v_erase_all_card_sectors();
s_cardMng.u16_head = CARD_MNG_HEAD;
s_cardMng.u16_cardCnt = 0;
s_cardMng.u16_reserved = 0;
v_write_eeprom_card_mng(&s_cardMng);
FATFS_PRINT("card flash: cleared\r\n");
return CARD_STATUS_OK;
}
#else /* !FATFS_ENABLE_CARD */
CardStatus card_init(void)
{
return CARD_STATUS_INIT_FAILED;
}
void card_deinit(void) {}
/**
* @brief card_add。
*/
CardStatus card_add(const CardInfo *card_info)
{
(void)card_info;
return CARD_STATUS_INIT_FAILED;
}
/**
* @brief card_update。
*/
CardStatus card_update(const CardInfo *card_info)
{
(void)card_info;
return CARD_STATUS_INIT_FAILED;
}
/**
* @brief card_delete。
*/
CardStatus card_delete(const char *card_num)
{
(void)card_num;
return CARD_STATUS_INIT_FAILED;
}
/**
* @brief card_find。
*/
CardStatus card_find(const char *card_num, CardInfo *card_info)
{
(void)card_num;
(void)card_info;
return CARD_STATUS_INIT_FAILED;
}
/**
* @brief card_get_count。
*/
CardStatus card_get_count(uint32_t *count)
{
if (count) {
*count = 0;
}
return CARD_STATUS_INIT_FAILED;
}
/**
* @brief card_get_all。
*/
CardStatus card_get_all(CardInfo *card_list, uint32_t *count, uint32_t max_count)
{
(void)card_list;
(void)max_count;
if (count) {
*count = 0;
}
return CARD_STATUS_INIT_FAILED;
}
/**
* @brief card_check_exist。
*/
CardStatus card_check_exist(const char *card_num, bool *exist)
{
(void)card_num;
if (exist) {
*exist = false;
}
return CARD_STATUS_INIT_FAILED;
}
/**
* @brief card_backup。
*/
CardStatus card_backup(void)
{
return CARD_STATUS_INIT_FAILED;
}
/**
* @brief card_restore。
*/
CardStatus card_restore(void)
{
return CARD_STATUS_INIT_FAILED;
}
/**
* @brief card_clear_all。
*/
CardStatus card_clear_all(void)
{
return CARD_STATUS_INIT_FAILED;
}
#endif /* FATFS_ENABLE_CARD */
#else /* !FATFS_EN */
CardStatus card_init(void)
{
return CARD_STATUS_INIT_FAILED;
}
void card_deinit(void) {}
/**
* @brief card_add。
*/
CardStatus card_add(const CardInfo *card_info)
{
(void)card_info;
return CARD_STATUS_INIT_FAILED;
}
/**
* @brief card_update。
*/
CardStatus card_update(const CardInfo *card_info)
{
(void)card_info;
return CARD_STATUS_INIT_FAILED;
}
/**
* @brief card_delete。
*/
CardStatus card_delete(const char *card_num)
{
(void)card_num;
return CARD_STATUS_INIT_FAILED;
}
/**
* @brief card_find。
*/
CardStatus card_find(const char *card_num, CardInfo *card_info)
{
(void)card_num;
(void)card_info;
return CARD_STATUS_INIT_FAILED;
}
/**
* @brief card_get_count。
*/
CardStatus card_get_count(uint32_t *count)
{
if (count) {
*count = 0;
}
return CARD_STATUS_INIT_FAILED;
}
/**
* @brief card_get_all。
*/
CardStatus card_get_all(CardInfo *card_list, uint32_t *count, uint32_t max_count)
{
(void)card_list;
(void)max_count;
if (count) {
*count = 0;
}
return CARD_STATUS_INIT_FAILED;
}
/**
* @brief card_check_exist。
*/
CardStatus card_check_exist(const char *card_num, bool *exist)
{
(void)card_num;
if (exist) {
*exist = false;
}
return CARD_STATUS_INIT_FAILED;
}
/**
* @brief card_backup。
*/
CardStatus card_backup(void)
{
return CARD_STATUS_INIT_FAILED;
}
/**
* @brief card_restore。
*/
CardStatus card_restore(void)
{
return CARD_STATUS_INIT_FAILED;
}
/**
* @brief card_clear_all。
*/
CardStatus card_clear_all(void)
{
return CARD_STATUS_INIT_FAILED;
}
#endif /* FATFS_EN */