319 lines
12 KiB
C
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 */
|