test_spiffs.cpp 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248
  1. #include <stdio.h>
  2. #include <string.h>
  3. #include <stdint.h>
  4. #include <sys/mman.h>
  5. #include <dirent.h>
  6. #include <limits.h>
  7. #include "esp_partition.h"
  8. #include "spiffs.h"
  9. #include "spiffs_nucleus.h"
  10. #include "spiffs_api.h"
  11. #include "catch.hpp"
  12. extern "C" void init_spi_flash(const char* chip_size, size_t block_size, size_t sector_size, size_t page_size, const char* partition_bin);
  13. static void init_spiffs(spiffs *fs, uint32_t max_files)
  14. {
  15. spiffs_config cfg;
  16. s32_t spiffs_res;
  17. const esp_partition_t *partition = esp_partition_find_first(ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_DATA_SPIFFS, "storage");
  18. REQUIRE(partition);
  19. // Configure objects needed by SPIFFS
  20. esp_spiffs_t *user_data = (esp_spiffs_t*) calloc(1, sizeof(*user_data));
  21. user_data->partition = partition;
  22. fs->user_data = (void*)user_data;
  23. cfg.hal_erase_f = spiffs_api_erase;
  24. cfg.hal_read_f = spiffs_api_read;
  25. cfg.hal_write_f = spiffs_api_write;
  26. cfg.log_block_size = CONFIG_WL_SECTOR_SIZE;
  27. cfg.log_page_size = CONFIG_SPIFFS_PAGE_SIZE;
  28. cfg.phys_addr = 0;
  29. cfg.phys_erase_block = CONFIG_WL_SECTOR_SIZE;
  30. cfg.phys_size = partition->size;
  31. uint32_t work_sz = cfg.log_page_size * 2;
  32. uint8_t *work = (uint8_t*) malloc(work_sz);
  33. uint32_t fds_sz = max_files * sizeof(spiffs_fd);
  34. uint8_t *fds = (uint8_t*) malloc(fds_sz);
  35. #if CONFIG_SPIFFS_CACHE
  36. uint32_t cache_sz = sizeof(spiffs_cache) + max_files * (sizeof(spiffs_cache_page)
  37. + cfg.log_page_size);
  38. uint8_t *cache = (uint8_t*) malloc(cache_sz);
  39. #else
  40. uint32_t cache_sz = 0;
  41. uint8_t cache = NULL;
  42. #endif
  43. // Special mounting procedure: mount, format, mount as per
  44. // https://github.com/pellepl/spiffs/wiki/Using-spiffs
  45. spiffs_res = SPIFFS_mount(fs, &cfg, work, fds, fds_sz,
  46. cache, cache_sz, spiffs_api_check);
  47. if (spiffs_res == SPIFFS_ERR_NOT_A_FS) {
  48. spiffs_res = SPIFFS_format(fs);
  49. REQUIRE(spiffs_res >= SPIFFS_OK);
  50. spiffs_res = SPIFFS_mount(fs, &cfg, work, fds, fds_sz,
  51. cache, cache_sz, spiffs_api_check);
  52. }
  53. REQUIRE(spiffs_res >= SPIFFS_OK);
  54. }
  55. static void deinit_spiffs(spiffs *fs)
  56. {
  57. SPIFFS_unmount(fs);
  58. free(fs->work);
  59. free(fs->user_data);
  60. free(fs->fd_space);
  61. #if CONFIG_SPIFFS_CACHE
  62. free(fs->cache);
  63. #endif
  64. }
  65. static void check_spiffs_files(spiffs *fs, const char *base_path, char* cur_path)
  66. {
  67. DIR *dir;
  68. struct dirent *entry;
  69. size_t len = strlen(cur_path);
  70. if (len == 0) {
  71. strcpy(cur_path, base_path);
  72. len = strlen(base_path);
  73. }
  74. dir = opendir(cur_path);
  75. REQUIRE(dir != 0);
  76. while ((entry = readdir(dir)) != NULL) {
  77. char *name = entry->d_name;
  78. if (entry->d_type == DT_DIR) {
  79. if (!strcmp(name, ".") || !strcmp(name, ".."))
  80. continue;
  81. cur_path[len] = '/';
  82. strcpy(cur_path + len + 1, name);
  83. check_spiffs_files(fs, base_path, cur_path);
  84. cur_path[len] = '\0';
  85. } else {
  86. char path[PATH_MAX];
  87. // Read the file from host FS
  88. strcpy(path, cur_path);
  89. strcat(path, "/");
  90. strcat(path, name);
  91. FILE* f = fopen(path , "r");
  92. REQUIRE(f);
  93. fseek(f, 0, SEEK_END);
  94. long sz = ftell(f);
  95. fseek(f, 0, SEEK_SET);
  96. char *f_contents = (char*) malloc(sz);
  97. fread(f_contents, 1, sz, f);
  98. fclose(f);
  99. s32_t spiffs_res;
  100. // Read the file from SPIFFS
  101. char *spiffs_path = path + strlen(base_path);
  102. spiffs_res = SPIFFS_open(fs, spiffs_path, SPIFFS_RDONLY, 0);
  103. REQUIRE(spiffs_res > SPIFFS_OK);
  104. spiffs_file fd = spiffs_res;
  105. spiffs_stat stat;
  106. spiffs_res = SPIFFS_stat(fs, spiffs_path, &stat);
  107. char *spiffs_f_contents = (char*) malloc(stat.size);
  108. spiffs_res = SPIFFS_read(fs, fd, spiffs_f_contents, stat.size);
  109. REQUIRE(spiffs_res == stat.size);
  110. // Compare the contents
  111. REQUIRE(sz == stat.size);
  112. bool same = memcmp(f_contents, spiffs_f_contents, sz) == 0;
  113. REQUIRE(same);
  114. free(f_contents);
  115. free(spiffs_f_contents);
  116. }
  117. }
  118. closedir(dir);
  119. }
  120. TEST_CASE("format disk, open file, write and read file", "[spiffs]")
  121. {
  122. init_spi_flash(CONFIG_ESPTOOLPY_FLASHSIZE, CONFIG_WL_SECTOR_SIZE * 16, CONFIG_WL_SECTOR_SIZE, CONFIG_WL_SECTOR_SIZE, "partition_table.bin");
  123. spiffs fs;
  124. s32_t spiffs_res;
  125. init_spiffs(&fs, 5);
  126. // Open test file
  127. spiffs_res = SPIFFS_open(&fs, "test.txt", SPIFFS_O_CREAT | SPIFFS_O_RDWR, 0);
  128. REQUIRE(spiffs_res >= SPIFFS_OK);
  129. // Generate data
  130. spiffs_file file = spiffs_res;
  131. uint32_t data_size = 100000;
  132. char *data = (char*) malloc(data_size);
  133. char *read = (char*) malloc(data_size);
  134. for(uint32_t i = 0; i < data_size; i += sizeof(i))
  135. {
  136. *((uint32_t*)(data + i)) = i;
  137. }
  138. // Write data to file
  139. spiffs_res = SPIFFS_write(&fs, file, (void*)data, data_size);
  140. REQUIRE(spiffs_res >= SPIFFS_OK);
  141. REQUIRE(spiffs_res == data_size);
  142. // Set the file object pointer to the beginning
  143. spiffs_res = SPIFFS_lseek(&fs, file, 0, SPIFFS_SEEK_SET);
  144. REQUIRE(spiffs_res >= SPIFFS_OK);
  145. // Read the file
  146. spiffs_res = SPIFFS_read(&fs, file, (void*)read, data_size);
  147. REQUIRE(spiffs_res >= SPIFFS_OK);
  148. REQUIRE(spiffs_res == data_size);
  149. // Close the test file
  150. spiffs_res = SPIFFS_close(&fs, file);
  151. REQUIRE(spiffs_res >= SPIFFS_OK);
  152. REQUIRE(memcmp(data, read, data_size) == 0);
  153. deinit_spiffs(&fs);
  154. free(read);
  155. free(data);
  156. }
  157. TEST_CASE("can read spiffs image", "[spiffs]")
  158. {
  159. init_spi_flash(CONFIG_ESPTOOLPY_FLASHSIZE, CONFIG_WL_SECTOR_SIZE * 16, CONFIG_WL_SECTOR_SIZE, CONFIG_WL_SECTOR_SIZE, "partition_table.bin");
  160. spiffs fs;
  161. s32_t spiffs_res;
  162. const esp_partition_t *partition = esp_partition_find_first(ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_DATA_SPIFFS, "storage");
  163. // Write the contents of the image file to partition
  164. FILE* img_file = fopen("image.bin", "r");
  165. REQUIRE(img_file);
  166. fseek(img_file, 0, SEEK_END);
  167. long img_size = ftell(img_file);
  168. fseek(img_file, 0, SEEK_SET);
  169. char *img = (char*) malloc(img_size);
  170. fread(img, 1, img_size, img_file);
  171. fclose(img_file);
  172. REQUIRE(partition->size == img_size);
  173. esp_partition_erase_range(partition, 0, partition->size);
  174. esp_partition_write(partition, 0, img, img_size);
  175. free(img);
  176. // Mount the spiffs partition and init filesystem, using the contents of
  177. // the image file
  178. init_spiffs(&fs, 1024);
  179. // Check spiffs consistency
  180. spiffs_res = SPIFFS_check(&fs);
  181. REQUIRE(spiffs_res == SPIFFS_OK);
  182. char path_buf[PATH_MAX];
  183. // The image is created from the spiffs source directory. Compare the files in that
  184. // directory to the files read from the SPIFFS image.
  185. check_spiffs_files(&fs, "../spiffs", path_buf);
  186. deinit_spiffs(&fs);
  187. }