#include "sdcard.h" void writeFile(FILE *f, const void *data, size_t size) { if (f != NULL) { fwrite(data, size, 1, f); fflush(f); fsync(fileno(f)); // Critical: this ensures actual write to disk } } FILE *csvFile = NULL; FILE *sensFile = NULL; void initSD(void) { esp_err_t ret; // Options for mounting the filesystem. // If format_if_mount_failed is set to true, SD card will be partitioned and // formatted in case when mounting fails. esp_vfs_fat_sdmmc_mount_config_t mount_config = { .format_if_mount_failed = true, .max_files = 100, .allocation_unit_size = 16 * 1024}; sdmmc_card_t *card; const char mount_point[] = MOUNT_POINT; ESP_LOGI(TAGSD, "Initializing SD card"); // Use settings defined above to initialize SD card and mount FAT filesystem. // Note: esp_vfs_fat_sdmmc/sdspi_mount is all-in-one convenience functions. // Please check its source code and implement error recovery when developing // production applications. ESP_LOGI(TAGSD, "Using SPI peripheral"); // By default, SD card frequency is initialized to SDMMC_FREQ_DEFAULT (20MHz) // For setting a specific frequency, use host.max_freq_khz (range 400kHz - 20MHz for SDSPI) // Example: for fixed frequency of 10MHz, use host.max_freq_khz = 10000; sdmmc_host_t host = SDSPI_HOST_DEFAULT(); host.slot = SPI3_HOST; // This initializes the slot without card detect (CD) and write protect (WP) signals. // Modify slot_config.gpio_cd and slot_config.gpio_wp if your board has these signals. sdspi_device_config_t slot_config = SDSPI_DEVICE_CONFIG_DEFAULT(); slot_config.gpio_cs = HSPI_SD_CS; slot_config.host_id = host.slot; ESP_LOGI(TAGSD, "Mounting filesystem"); ret = esp_vfs_fat_sdspi_mount(mount_point, &host, &slot_config, &mount_config, &card); if (ret != ESP_OK) { if (ret == ESP_FAIL) { ESP_LOGE(TAGSD, "Failed to mount filesystem. " "If you want the card to be formatted, set the CONFIG_EXAMPLE_FORMAT_IF_MOUNT_FAILED menuconfig option."); } else { ESP_LOGE(TAGSD, "Failed to initialize the card (%s). " "Make sure SD card lines have pull-up resistors in place.", esp_err_to_name(ret)); } return; } ESP_LOGI(TAGSD, "Filesystem mounted"); // Card has been initialized, print its properties sdmmc_card_print_info(stdout, card); int index = 0; FILE *f = fopen(COUNTER_FILE, "r"); if (f) { fscanf(f, "%d", &index); fclose(f); } // === 2. Increment and write back === f = fopen(COUNTER_FILE, "w"); if (!f) { ESP_LOGE(TAGSD, "Failed to open counter file"); return; } index++; if (f != NULL) { fprintf(f, "%d", index); fflush(f); fsync(fileno(f)); // Critical: this ensures actual write to disk fclose(f); ESP_LOGI(TAGSD, "Index is now %d", index); } // === 3. Make folder === char folder_path[MAX_PATH - 20]; snprintf(folder_path, MAX_PATH, MOUNT_POINT "/%d", index); mkdir(folder_path, 0777); // safe if exists already // === 4. Create CSV and BIN === char csv_path[MAX_PATH], bin_path[MAX_PATH]; snprintf(csv_path, MAX_PATH, "%s/data.csv", folder_path); snprintf(bin_path, MAX_PATH, "%s/data.bin", folder_path); csvFile = fopen(csv_path, "w"); sensFile = fopen(bin_path, "wb"); if (csvFile != NULL) { fprintf(csvFile, "missionTimer,packetIndex,telemetryIndex,packetType," "accX,accY,accZ,gyroX,gyroY,gyroZ,magX,magY,magZ,accTemp," "eCO2,tVOC,currentCCS,rawCCS," "volts,current,power,rawtemperature,rawhumidity,rawpressure,rawgas," "gasValid,heaterStable,gasRange,gasIndex," "airTemp,relHumidity,baroPressure,gasResistance," "iaqScore,tempScore,humidityScore,gasScore," "gpsTime,latitude,longitude,altitude,fixQuality,numSatellites,date,speed," "predLatitude,predLongitude,predAltitude," "NH3,CO,NO2,UVC," "currentServoA,targetServoA,currentServoB,targetServoB," "presentDevices\n"); fflush(csvFile); fsync(fileno(csvFile)); // Critical: this ensures actual write to disk } }