minIni_cache.cpp 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197
  1. // Custom .ini file access caching layer for minIni.
  2. // This reduces boot delay by only reading the ini file once
  3. // after boot or SD-card removal.
  4. #include <minGlue.h>
  5. #include <SdFat.h>
  6. // This can be overridden in platformio.ini
  7. // Set to 0 to disable the cache.
  8. #ifndef INI_CACHE_SIZE
  9. #define INI_CACHE_SIZE 4096
  10. #endif
  11. // Use the SdFs instance from main program
  12. extern SdFs SD;
  13. static struct {
  14. bool valid;
  15. INI_FILETYPE *fp;
  16. #if INI_CACHE_SIZE > 0
  17. const char *filename;
  18. uint32_t filelen;
  19. INI_FILEPOS current_pos;
  20. char cachedata[INI_CACHE_SIZE];
  21. #endif
  22. } g_ini_cache;
  23. // Invalidate any cached file contents
  24. void invalidate_ini_cache()
  25. {
  26. g_ini_cache.valid = false;
  27. g_ini_cache.fp = NULL;
  28. }
  29. // Read the config file into RAM
  30. void reload_ini_cache(const char *filename)
  31. {
  32. g_ini_cache.valid = false;
  33. g_ini_cache.fp = NULL;
  34. #if INI_CACHE_SIZE > 0
  35. g_ini_cache.filename = filename;
  36. FsFile config = SD.open(filename, O_RDONLY);
  37. g_ini_cache.filelen = config.fileSize();
  38. if (config.isOpen() && g_ini_cache.filelen <= INI_CACHE_SIZE)
  39. {
  40. if (config.read(g_ini_cache.cachedata, g_ini_cache.filelen) == g_ini_cache.filelen)
  41. {
  42. g_ini_cache.valid = true;
  43. }
  44. }
  45. config.close();
  46. #endif
  47. }
  48. // Open .ini file either from cache or from SD card
  49. bool ini_openread(const char *filename, INI_FILETYPE *fp)
  50. {
  51. #if INI_CACHE_SIZE > 0
  52. if (SD.exists(filename) &&
  53. g_ini_cache.valid &&
  54. (filename == g_ini_cache.filename || strcmp(filename, g_ini_cache.filename) == 0))
  55. {
  56. fp->close();
  57. g_ini_cache.fp = fp;
  58. g_ini_cache.current_pos.position = 0;
  59. return true;
  60. }
  61. invalidate_ini_cache(); // new file?
  62. #endif
  63. return fp->open(SD.vol(), filename, O_RDONLY);
  64. }
  65. bool ini_openwrite(const char *filename, INI_FILETYPE *fp) {
  66. #if INI_CACHE_SIZE > 0
  67. invalidate_ini_cache(); // We'll be writing so just use the actual fp.
  68. #endif
  69. return fp->open(SD.vol(), filename, O_WRITE | O_CREAT);
  70. }
  71. bool ini_openrewrite(const char *filename, INI_FILETYPE *fp) {
  72. #if INI_CACHE_SIZE > 0
  73. invalidate_ini_cache(); // We'll be writing so just use the actual fp.
  74. #endif
  75. return fp->open(SD.vol(), filename, O_RDWR | O_CREAT);
  76. }
  77. // Close previously opened file
  78. bool ini_close(INI_FILETYPE *fp)
  79. {
  80. #if INI_CACHE_SIZE > 0
  81. if (g_ini_cache.valid && g_ini_cache.fp == fp)
  82. {
  83. g_ini_cache.fp = NULL;
  84. return true;
  85. }
  86. #endif
  87. {
  88. return fp->close();
  89. }
  90. }
  91. // Read a single line from cache or from SD card
  92. bool ini_read(char *buffer, int size, INI_FILETYPE *fp)
  93. {
  94. #if INI_CACHE_SIZE > 0
  95. if (g_ini_cache.fp == fp)
  96. {
  97. if (!g_ini_cache.valid)
  98. {
  99. reload_ini_cache(g_ini_cache.filename);
  100. }
  101. if (g_ini_cache.valid)
  102. {
  103. // Read one line from cache
  104. uint32_t srcpos = g_ini_cache.current_pos.position;
  105. int dstpos = 0;
  106. while (srcpos < g_ini_cache.filelen &&
  107. dstpos < size - 1)
  108. {
  109. char b = g_ini_cache.cachedata[srcpos++];
  110. buffer[dstpos++] = b;
  111. if (b == '\n') break;
  112. }
  113. buffer[dstpos] = 0;
  114. g_ini_cache.current_pos.position = srcpos;
  115. return dstpos > 0;
  116. }
  117. }
  118. #endif
  119. {
  120. // Read from SD card
  121. return fp->fgets(buffer, size) > 0;
  122. }
  123. }
  124. // Get the position inside the file
  125. void ini_tell(INI_FILETYPE *fp, INI_FILEPOS *pos)
  126. {
  127. #if INI_CACHE_SIZE > 0
  128. if (g_ini_cache.fp == fp)
  129. {
  130. *pos = g_ini_cache.current_pos;
  131. }
  132. else
  133. #endif
  134. {
  135. fp->fgetpos(pos);
  136. }
  137. }
  138. // Go back to previously saved position
  139. void ini_seek(INI_FILETYPE *fp, INI_FILEPOS *pos)
  140. {
  141. #if INI_CACHE_SIZE > 0
  142. if (g_ini_cache.fp == fp)
  143. {
  144. g_ini_cache.current_pos = *pos;
  145. }
  146. else
  147. #endif
  148. {
  149. fp->fsetpos(pos);
  150. }
  151. }
  152. void ini_rename(const char *source, const char *destination) {
  153. if (SD.exists(destination)) {
  154. SD.remove(destination);
  155. }
  156. SD.rename(source, destination);
  157. #if INI_CACHE_SIZE > 0
  158. invalidate_ini_cache();
  159. #endif
  160. }
  161. void ini_write(char *buffer, INI_FILETYPE *fp) {
  162. fp->write(buffer);
  163. invalidate_ini_cache(); // for next open
  164. }
  165. const char* ini_get_cache_ptr(uint32_t* out_len) {
  166. if (g_ini_cache.valid) {
  167. if (out_len) *out_len = g_ini_cache.filelen;
  168. return g_ini_cache.cachedata;
  169. }
  170. if (out_len) *out_len = 0;
  171. return nullptr;
  172. }