#include #include #include #include #include #include #include "sd/sd.h" #include "esp_err.h" #include "esp_log.h" #include "esp_vfs_fat.h" #include "sdmmc_cmd.h" #include "driver/gpio.h" #include "driver/sdspi_host.h" #include "driver/spi_common.h" #define MAX_CHAR_SIZE 64 #define MOUNT_POINT "/sdcard" #define SD_PIN_MOSI (GPIO_NUM_11) #define SD_PIN_MISO (GPIO_NUM_13) #define SD_PIN_CLK (GPIO_NUM_12) #define SD_PIN_CS (GPIO_NUM_10) static sdmmc_card_t* card = NULL; static const char *TAG = "sd"; static char** _file_list = NULL; static size_t _current_file = 0; static size_t _file_count = 0; static esp_err_t get_top_level_files(void); void sd_init(void){ if(card != NULL){ ESP_LOGW(TAG, "SD card already initialized"); return; } sdmmc_host_t host = SDSPI_HOST_DEFAULT(); host.unaligned_multi_block_rw_max_chunk_size = 8; spi_bus_config_t bus_config = { .mosi_io_num = SD_PIN_MOSI, .miso_io_num = SD_PIN_MISO, .sclk_io_num = SD_PIN_CLK, .quadwp_io_num = GPIO_NUM_NC, .quadhd_io_num = GPIO_NUM_NC, .max_transfer_sz = 4000, }; esp_err_t ret = spi_bus_initialize(host.slot, &bus_config, SDSPI_DEFAULT_DMA); if(ret != ESP_OK){ ESP_LOGE(TAG, "Failed to initialize SD SPI bus (%s)", esp_err_to_name(ret)); return; } sdspi_device_config_t slot_config = SDSPI_DEVICE_CONFIG_DEFAULT(); slot_config.gpio_cs = SD_PIN_CS; slot_config.host_id = host.slot; esp_vfs_fat_sdmmc_mount_config_t mount_config = { .format_if_mount_failed = false, .max_files = MAX_SIMULTANEOUS_OPEN_FILES, .allocation_unit_size = 16 * 1024 }; const char mount_point[] = MOUNT_POINT; ret = esp_vfs_fat_sdspi_mount(mount_point, &host, &slot_config, &mount_config, &card); if(ret != ESP_OK){ if(ret == ESP_FAIL) ESP_LOGE(TAG, "Failed to mount filesystem."); else ESP_LOGE(TAG, "Failed to initialize the card (%s). ", esp_err_to_name(ret)); spi_bus_free(host.slot); return; } ESP_LOGI(TAG, "SD card initialized"); if(get_top_level_files() == ESP_OK) ESP_LOGI(TAG, "Found %d files in root directory", _file_count); else ESP_LOGW(TAG, "No files found in root directory"); } void print_sd_card_info(void){ if(card == NULL) return; sdmmc_card_print_info(stdout, card); } static inline void make_file_path(char* buffer, size_t buffer_size, const char* filename){ snprintf(buffer, buffer_size, "%s/%s", MOUNT_POINT, filename); } FILE* sd_open_read(const char* filename){ if(filename == NULL) return NULL; char full_path[strlen(MOUNT_POINT) + strlen(filename) + 2]; make_file_path(full_path, sizeof(full_path), filename); return fopen(full_path, "r"); } FILE* sd_open_write(const char* filename){ if(filename == NULL) return NULL; char full_path[strlen(MOUNT_POINT) + strlen(filename) + 2]; make_file_path(full_path, sizeof(full_path), filename); return fopen(full_path, "w"); } void sd_close_file(FILE* file){ if(file != NULL) fclose(file); } static esp_err_t get_top_level_files(void){ char** file_list = NULL; size_t count = 0; size_t capacity = 0; DIR* dir = opendir(MOUNT_POINT); if(dir == NULL){ ESP_LOGE(TAG, "Failed to open directory: %s", MOUNT_POINT); return ESP_FAIL; } struct dirent* entry; while((entry = readdir(dir)) != NULL){ if(entry->d_type == DT_REG){ ESP_LOGI(TAG, "Found file: %s", entry->d_name); size_t name_length = strlen(entry->d_name); if(name_length >= MAX_CHAR_SIZE){ ESP_LOGW(TAG, "File name too long: %s", entry->d_name); continue; } if(count == capacity){ size_t new_capacity = capacity == 0 ? 8 : capacity * 2; char** new_file_list = (char**)realloc(file_list, sizeof(char*) * new_capacity); if(new_file_list == NULL){ ESP_LOGE(TAG, "Failed to allocate memory for file list"); for(size_t j = 0; j < count; j++) free(file_list[j]); free(file_list); closedir(dir); return ESP_FAIL; } file_list = new_file_list; capacity = new_capacity; } file_list[count] = (char*)malloc(sizeof(char) * (name_length + 1)); if(file_list[count] == NULL){ ESP_LOGE(TAG, "Failed to allocate memory for file name"); for(size_t j = 0; j < count; j++) free(file_list[j]); free(file_list); closedir(dir); return ESP_FAIL; } memcpy(file_list[count], entry->d_name, name_length + 1); count++; } } closedir(dir); if(count == 0){ ESP_LOGW(TAG, "No files found in directory: %s", MOUNT_POINT); free(file_list); _file_list = NULL; _current_file = 0; return ESP_FAIL; } _file_list = file_list; _file_count = count; return ESP_OK; } size_t sd_get_file_count(void){ return _file_count; } const char* sd_get_next_file(void){ if(_current_file >= _file_count) _current_file = 0; return _file_list[_current_file++]; } const char* sd_get_previous_file(void){ if(_current_file == 0) _current_file = _file_count; return _file_list[--_current_file]; } void sd_destroy(void){ if(card != NULL){ esp_vfs_fat_sdcard_unmount(MOUNT_POINT, card); card = NULL; ESP_LOGI(TAG, "SD card unmounted"); } if(_file_list != NULL){ for(int i = 0; i < _file_count; i++) free((void*)_file_list[i]); free((void*)_file_list); _file_list = NULL; } _file_count = 0; _current_file = 0; }