/* 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 #include #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*)""); } 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; idataSize; 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; idataSize; 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 */