Files
MSE-SoftwEng/pico-sensor/McuLib/minIni/minGlue-Flash.c
2025-05-06 13:07:01 +00:00

319 lines
12 KiB
C

/* Glue functions for a flash (page) based storage system, without a file system.
*
* By CompuPhase, 2008-2012
* This "glue file" is in the public domain. It is distributed without
* warranties or conditions of any kind, either express or implied.
*
*/
#include "McuMinINIconfig.h" /* MinIni config file */
#if McuMinINI_CONFIG_FS==McuMinINI_CONFIG_FS_TYPE_FLASH_FS
#include "minGlue-Flash.h"
#include <stddef.h>
#include <string.h>
#include "McuLib.h"
#include "McuLog.h"
#include "McuUtility.h"
#include "McuFlash.h"
/* NOTE: we only support one 'file' in FLASH, and only one 'file' in RAM. The one in RAM is for the read-write and temporary one */
/* read-only FLASH 'file' is at McuMinINI_CONFIG_FLASH_NVM_ADDR_START */
#if !McuMinINI_CONFIG_READ_ONLY
static unsigned char dataBuf[McuMinINI_CONFIG_FLASH_NVM_MAX_DATA_SIZE]; /* ini file for read/write */
#endif
int ini_openread(const TCHAR *filename, INI_FILETYPE *file) {
/* open file in read-only mode. This will use directly the data in FLASH */
memset(file, 0, sizeof(INI_FILETYPE));
file->header = (MinIniFlashFileHeader*)(McuMinINI_CONFIG_FLASH_NVM_ADDR_START);
file->data = (unsigned char*)file->header + sizeof(MinIniFlashFileHeader);
if (file->header->magicNumber != MININI_FLASH_MAGIC_DATA_NUMBER_ID) {
return 0; /* failed, magic number does not match */
}
if (McuUtility_strcmp((char*)file->header->dataName, (char*)filename)!=0) {
return 0; /* failed, not the file name of the storage */
}
file->curr = file->data;
file->isOpen = true;
file->isReadOnly = true;
return 1; /* ok */
}
static bool isTempFile(const TCHAR *filename) {
size_t len;
len = McuUtility_strlen(filename);
if (len==0) {
return false; /* illegal file name */
}
if (filename[len-1]=='~') { /* temporary file name */
return true;
}
return false;
}
#if !McuMinINI_CONFIG_READ_ONLY
int ini_openwrite(const TCHAR *filename, INI_FILETYPE *file) {
/* create always a new file */
memset(file, 0, sizeof(INI_FILETYPE)); /* initialize all fields in header */
memset(dataBuf, 0, sizeof(dataBuf)); /* initialize all data */
file->header = (MinIniFlashFileHeader*)dataBuf;
file->data = (unsigned char*)file->header + sizeof(MinIniFlashFileHeader);
file->header->magicNumber = MININI_FLASH_MAGIC_DATA_NUMBER_ID;
McuUtility_strcpy(file->header->dataName, sizeof(file->header->dataName), (unsigned char*)filename);
file->header->dataSize = 0;
file->curr = file->data;
file->isOpen = true;
file->isReadOnly = false;
return 1; /* ok */
}
#endif
int ini_close(INI_FILETYPE *file) {
file->isOpen = false;
if (!file->isReadOnly && !isTempFile((const char*)file->header->dataName)) { /* RAM data, and not temp file? */
/* store data in FLASH */
if (McuFlash_Program((void*)McuMinINI_CONFIG_FLASH_NVM_ADDR_START, file->header, McuMinINI_CONFIG_FLASH_NVM_MAX_DATA_SIZE)!=ERR_OK) {
return 0; /* failed */
}
}
return 1; /* ok */
}
int ini_read(TCHAR *buffer, size_t size, INI_FILETYPE *file) {
/* read a string until EOF or '\n' */
unsigned char ch;
buffer[0] = '\0'; /* zero terminate */
for(;;) {
if (file->curr >= file->data+file->header->dataSize) { /* beyond boundaries? */
file->curr = file->data+file->header->dataSize; /* point to max position possible, one byte beyond */
return 0; /* EOF */
}
ch = *file->curr; /* read character */
file->curr++; /* move pointer */
McuUtility_chcat((unsigned char*)buffer, size, ch); /* add character to buffer */
if (ch=='\n') { /* reached end of line */
return 1; /* ok */
}
}
return 1; /* ok */
}
#if !McuMinINI_CONFIG_READ_ONLY
int ini_write(TCHAR *buffer, INI_FILETYPE *file) {
size_t len, remaining;
/* write zero terminated string to file */
if (file->isReadOnly) {
return 1; /* error, file is read-only */
}
/* data is in RAM buffer */
len = McuUtility_strlen(buffer);
remaining = dataBuf+sizeof(dataBuf)-file->curr;
McuUtility_strcpy(file->curr, remaining, (const unsigned char*)buffer);
file->curr += len;
if (file->curr >= (unsigned char*)file->header+McuMinINI_CONFIG_FLASH_NVM_MAX_DATA_SIZE) { /* outside valid memory? */
file->curr = (unsigned char*)file->header+McuMinINI_CONFIG_FLASH_NVM_MAX_DATA_SIZE; /* set to highest possible location */
return 0; /* error */
}
if (file->curr >= file->data+file->header->dataSize) { /* moved beyond current size? file is growing */
file->header->dataSize = file->curr - file->data; /* update size */
return 1; /* ok */
}
return 1; /* ok */
}
#endif
#if !McuMinINI_CONFIG_READ_ONLY
int ini_remove(const TCHAR *filename) {
MinIniFlashFileHeader *hp;
/* check first if we are removing the data in FLASH */
hp = (MinIniFlashFileHeader*)McuMinINI_CONFIG_FLASH_NVM_ADDR_START;
if ( hp->magicNumber==MININI_FLASH_MAGIC_DATA_NUMBER_ID /* valid file */
&& McuUtility_strcmp((char*)hp->dataName, filename)==0 /* file name matches */
)
{
/* flash data file */
if (McuFlash_Erase((void*)McuMinINI_CONFIG_FLASH_NVM_ADDR_START, McuMinINI_CONFIG_FLASH_NVM_NOF_BLOCKS*McuMinINI_CONFIG_FLASH_NVM_BLOCK_SIZE)==ERR_OK) {
return 1; /* ok */
} else {
return 0; /* error */
}
}
/* check if we are removing the temp file */
hp = (MinIniFlashFileHeader*)dataBuf;
if ( hp->magicNumber==MININI_FLASH_MAGIC_DATA_NUMBER_ID /* valid file */
&& McuUtility_strcmp((char*)hp->dataName, filename)==0 /* it the data in RAM */
)
{
/* RAM data file */
memset(dataBuf, 0, sizeof(dataBuf));
return 1; /* ok */
}
return 0; /* error */
}
#endif
int ini_tell(INI_FILETYPE *file, INI_FILEPOS *pos) {
/* return the current file pointer (offset into file) */
*pos = file->curr - file->data;
return 1; /* ok */
}
int ini_seek(INI_FILETYPE *file, INI_FILEPOS *pos) {
/* move the file pointer to the given position */
file->curr = file->data + *pos; /* move current data pointer */
if (file->curr >= (unsigned char*)file->header+McuMinINI_CONFIG_FLASH_NVM_MAX_DATA_SIZE) { /* outside limits? */
file->curr = (unsigned char*)file->header + McuMinINI_CONFIG_FLASH_NVM_MAX_DATA_SIZE; /* back to valid range, which can be one byte beyond buffer */
return 0; /* error, EOF */
}
return 1; /* ok */
}
#if !McuMinINI_CONFIG_READ_ONLY
int ini_rename(const TCHAR *source, const TCHAR *dest) {
/* e.g. test.in~ -> test.ini: this always will do a store from RAM to FLASH! */
MinIniFlashFileHeader *hp;
if (isTempFile(source)) { /* store temporary file into flash */
hp = (MinIniFlashFileHeader*)dataBuf;
if (McuUtility_strcmp((char*)hp->dataName, source)!=0) { /* file name in RAM does not match? */
return 0; /* error */
}
McuUtility_strcpy(hp->dataName, sizeof(hp->dataName), (unsigned char*)dest); /* rename file */
/* store in flash */
if (McuFlash_Program((void*)McuMinINI_CONFIG_FLASH_NVM_ADDR_START, (unsigned char*)dataBuf, sizeof(dataBuf))!=ERR_OK) {
return 0; /* failed */
}
memset(dataBuf, 0, sizeof(dataBuf)); /* erase RAM file content */
}
return 1; /* ok */
}
#endif
int ini_deinit(void) {
/* nothing needed */
return 0; /* ok */
}
int ini_init(void) {
#if McuLib_CONFIG_CPU_IS_LPC55xx
if((McuMinINI_CONFIG_FLASH_NVM_MAX_DATA_SIZE%McuFlash_CONFIG_FLASH_BLOCK_SIZE)!=0) {
#elif McuLib_CONFIG_CPU_VARIANT==McuLib_CONFIG_CPU_VARIANT_RP2040
if((McuMinINI_CONFIG_FLASH_NVM_MAX_DATA_SIZE%McuFlash_CONFIG_FLASH_BLOCK_SIZE)!=0) {
#else
if( ! (McuMinINI_CONFIG_FLASH_NVM_MAX_DATA_SIZE==64
|| McuMinINI_CONFIG_FLASH_NVM_MAX_DATA_SIZE==128
|| McuMinINI_CONFIG_FLASH_NVM_MAX_DATA_SIZE==256
|| McuMinINI_CONFIG_FLASH_NVM_MAX_DATA_SIZE==512
|| McuMinINI_CONFIG_FLASH_NVM_MAX_DATA_SIZE==1024
|| McuMinINI_CONFIG_FLASH_NVM_MAX_DATA_SIZE==2048
|| McuMinINI_CONFIG_FLASH_NVM_MAX_DATA_SIZE==4096
|| McuMinINI_CONFIG_FLASH_NVM_MAX_DATA_SIZE==8192)
)
{
#endif
/* data size (number of bytes) needs to be 64, 128, 256, 512, 1024 bytes for the flash programming! */
McuLog_fatal("wrong size of data!");
for(;;) {}
}
return 0; /* ok */
}
static void PrintDataStatus(const McuShell_StdIOType *io, MinIniFlashFileHeader *hp, const unsigned char *dataName) {
uint8_t buf[48];
if (!McuFlash_IsAccessible(hp, sizeof(MinIniFlashFileHeader))) { /* accessing erased FLASH on LPC55Sxx will cause hard fault! */
McuUtility_strcpy(buf, sizeof(buf), (unsigned char*)"ERASED, not accessible\r\n");
McuShell_SendStatusStr(dataName, buf, io->stdOut);
return;
}
McuUtility_strcpy(buf, sizeof(buf), (unsigned char*)"magic 0x");
McuUtility_strcatNum32Hex(buf, sizeof(buf), hp->magicNumber);
McuUtility_strcat(buf, sizeof(buf), (unsigned char*)", ");
if (hp->magicNumber==MININI_FLASH_MAGIC_DATA_NUMBER_ID) {
McuUtility_strcat(buf, sizeof(buf), hp->dataName);
McuUtility_strcat(buf, sizeof(buf), (unsigned char*)", size ");
McuUtility_strcatNum32u(buf, sizeof(buf), hp->dataSize);
} else {
McuUtility_strcat(buf, sizeof(buf), (unsigned char*)"<not valid>");
}
McuUtility_strcat(buf, sizeof(buf), (unsigned char*)"\r\n");
McuShell_SendStatusStr(dataName, buf, io->stdOut);
}
static uint8_t PrintStatus(const McuShell_StdIOType *io) {
uint8_t buf[48];
McuShell_SendStatusStr((unsigned char*)"ini", (unsigned char*)"ini flash status\r\n", io->stdOut);
McuUtility_strcpy(buf, sizeof(buf), (unsigned char*)"start 0x");
McuUtility_strcatNum32Hex(buf, sizeof(buf), McuMinINI_CONFIG_FLASH_NVM_ADDR_START);
McuUtility_strcat(buf, sizeof(buf), (unsigned char*)", block 0x");
McuUtility_strcatNum16Hex(buf, sizeof(buf), McuMinINI_CONFIG_FLASH_NVM_BLOCK_SIZE);
McuUtility_strcat(buf, sizeof(buf), (unsigned char*)", nof ");
McuUtility_strcatNum16u(buf, sizeof(buf), McuMinINI_CONFIG_FLASH_NVM_NOF_BLOCKS);
McuUtility_strcat(buf, sizeof(buf), (unsigned char*)"\r\n");
McuShell_SendStatusStr((unsigned char*)" flash", buf, io->stdOut);
McuUtility_Num32uToStr(buf, sizeof(buf), McuMinINI_CONFIG_FLASH_NVM_MAX_DATA_SIZE);
McuUtility_strcat(buf, sizeof(buf), (unsigned char*)" bytes\r\n");
McuShell_SendStatusStr((unsigned char*)" max data", buf, io->stdOut);
PrintDataStatus(io, (MinIniFlashFileHeader*)McuMinINI_CONFIG_FLASH_NVM_ADDR_START, (const unsigned char*)" data");
#if !McuMinINI_CONFIG_READ_ONLY
PrintDataStatus(io, (MinIniFlashFileHeader*)dataBuf, (const unsigned char*)" ram");
#endif
return ERR_OK;
}
static uint8_t DumpData(const McuShell_StdIOType *io) {
MinIniFlashFileHeader *hp;
const unsigned char *p;
hp = (MinIniFlashFileHeader*)McuMinINI_CONFIG_FLASH_NVM_ADDR_START;
PrintDataStatus(io, hp, (const unsigned char*)"data");
if (hp->magicNumber==MININI_FLASH_MAGIC_DATA_NUMBER_ID) {
p = (const unsigned char*)hp + sizeof(MinIniFlashFileHeader);
for(unsigned int i=0; i<hp->dataSize; i++) {
io->stdOut(*p);
p++;
}
}
hp = (MinIniFlashFileHeader*)dataBuf;
PrintDataStatus(io, hp, (const unsigned char*)"ram");
if (hp->magicNumber==MININI_FLASH_MAGIC_DATA_NUMBER_ID) {
p = (const unsigned char*)hp + sizeof(MinIniFlashFileHeader);
for(unsigned int i=0; i<hp->dataSize; i++) {
io->stdOut(*p);
p++;
}
}
return ERR_OK;
}
uint8_t ini_ParseCommand(const unsigned char *cmd, bool *handled, const McuShell_StdIOType *io) {
if (McuUtility_strcmp((char*)cmd, McuShell_CMD_HELP)==0 || McuUtility_strcmp((char*)cmd, "ini help")==0) {
McuShell_SendHelpStr((unsigned char*)"ini", (const unsigned char*)"Group of flash ini commands\r\n", io->stdOut);
McuShell_SendHelpStr((unsigned char*)" help|status", (unsigned char*)"Print help or status information\r\n", io->stdOut);
McuShell_SendHelpStr((unsigned char*)" dump", (unsigned char*)"Dump data information\r\n", io->stdOut);
McuShell_SendHelpStr((unsigned char*)" erase", (unsigned char*)"Erase data information\r\n", io->stdOut);
*handled = TRUE;
return ERR_OK;
} else if ((McuUtility_strcmp((char*)cmd, McuShell_CMD_STATUS)==0) || (McuUtility_strcmp((char*)cmd, "ini status")==0)) {
*handled = TRUE;
return PrintStatus(io);
} else if (McuUtility_strcmp((char*)cmd, "ini dump")==0) {
*handled = TRUE;
return DumpData(io);
} else if (McuUtility_strcmp((char*)cmd, "ini erase")==0) {
*handled = TRUE;
return McuFlash_Erase((void*)McuMinINI_CONFIG_FLASH_NVM_ADDR_START, McuMinINI_CONFIG_FLASH_NVM_NOF_BLOCKS*McuMinINI_CONFIG_FLASH_NVM_BLOCK_SIZE);
}
return ERR_OK;
}
#endif /* McuMinINI_CONFIG_FS==McuMinINI_CONFIG_FS_TYPE_KINETIS_FLASH_FS */