start sd implementation

This commit is contained in:
2025-05-03 23:09:11 +02:00
parent 76eb216716
commit ee54abb663
7 changed files with 187 additions and 218 deletions

View File

@@ -25,6 +25,8 @@ idf_component_register(SRCS
"components/servocontroller.h"
"components/radio.c"
"components/radio.h"
"components/sdcard.c"
"components/sdcard.h"
"main.c"
INCLUDE_DIRS ".")

View File

@@ -18,7 +18,7 @@ typedef struct __attribute__((packed))
char syncPhrase[10]; //10
uint32_t packetIndex; //14
uint8_t packetType; //15
uint32_t missionTimer; //19
uint64_t missionTimer; //19
uint32_t CRCCheck;
} DownBoundPacket;

View File

@@ -8,6 +8,7 @@
#include "esp_rom_crc.h"
#include <hw/buscfg.h>
#include "sensors.h"
#include "sdcard.h"
#define TAG "LoRa"
@@ -71,6 +72,8 @@ static void send_packet_without_retries(uint8_t *data, uint16_t size)
{
if (xSemaphoreTake(loraRadioMutex, portMAX_DELAY) == pdTRUE)
{
writeFile(sensFile, data, size);
if (!LoRaSend(data, size, SX126x_TXMODE_SYNC))
{
ESP_LOGW(TAG, "LoRaSend failed");
@@ -86,9 +89,10 @@ static void send_packet_without_retries(uint8_t *data, uint16_t size)
static void send_packet_with_retries(uint8_t *data, uint16_t size)
{
for (int retry = 0; retry <= MAX_RETRIES; retry++)
if (xSemaphoreTake(loraRadioMutex, portMAX_DELAY) == pdTRUE)
{
if (xSemaphoreTake(loraRadioMutex, portMAX_DELAY) == pdTRUE)
writeFile(sensFile, data, size);
for (int retry = 0; retry <= MAX_RETRIES; retry++)
{
if (!LoRaSend(data, size, SX126x_TXMODE_SYNC))
{
@@ -135,6 +139,69 @@ void prepare_and_send_telemetry(uint64_t missionTimer)
memcpy(bufOut + offset, &telemetryPacket, sizeof(telemetryPacket));
offset += sizeof(telemetryPacket);
if (csvFile != NULL) {
fprintf(csvFile,
"%llu,%lu,%u,%u," // missionTimer, packetIndex, telemetryIndex, packetType
"%d,%d,%d,%d,%d,%d,%d,%d,%d,%d," // MPU
"%u,%u,%d,%u," // CCS
"%u,%u,%u,%lu,%u,%lu,%u," // INA, BME basic
"%s,%s,%u,%u," // bools and gas index/range
"%.2f,%.2f,%.2f,%.2f," // Bosch env data
"%u,%.2f,%.2f,%.2f," // IAQ + scores
"%lu,%ld,%ld,%d,%u,%u,%u,%u," // GPS data
"%ld,%ld,%d," // Predicted GPS
"%ld,%ld,%ld,%ld," // ADC
"%d,%d,%d,%d," // Servo
"%u\n", // presentDevices
missionTimer,
downboundPacket.packetIndex,
telemetryPacket.telemetryIndex,
downboundPacket.packetType,
telemetryPacket.accelerationX, telemetryPacket.accelerationY, telemetryPacket.accelerationZ,
telemetryPacket.gyroX, telemetryPacket.gyroY, telemetryPacket.gyroZ,
telemetryPacket.magnetX, telemetryPacket.magnetY, telemetryPacket.magnetZ,
telemetryPacket.accelerometer_temperature,
telemetryPacket.eCO2, telemetryPacket.tvoc, telemetryPacket.currentCCS, telemetryPacket.rawCCSData,
telemetryPacket.volts, telemetryPacket.current, telemetryPacket.power,
telemetryPacket.temperature, telemetryPacket.humidity, telemetryPacket.pressure, telemetryPacket.gas,
telemetryPacket.gas_valid ? "Yes" : "No",
telemetryPacket.heater_stable ? "Yes" : "No",
telemetryPacket.gas_range, telemetryPacket.gas_index,
telemetryPacket.air_temperature, telemetryPacket.relative_humidity,
telemetryPacket.barometric_pressure, telemetryPacket.gas_resistance,
telemetryPacket.iaq_score,
telemetryPacket.temperature_score, telemetryPacket.humidity_score, telemetryPacket.gas_score,
telemetryPacket.time_seconds,
telemetryPacket.latitude_centi_degrees,
telemetryPacket.longitude_centi_degrees,
telemetryPacket.altitude_centi_meters,
telemetryPacket.fix_quality,
telemetryPacket.num_satellites,
telemetryPacket.date_yyddmm,
telemetryPacket.speed_centi_knots,
telemetryPacket.predicted_latitude_centi_degrees,
telemetryPacket.predicted_longitude_centi_degrees,
telemetryPacket.predicted_altitude_centi_meters,
telemetryPacket.NH3, telemetryPacket.CO, telemetryPacket.NO2, telemetryPacket.UVC,
telemetryPacket.currentServoA, telemetryPacket.targetServoA,
telemetryPacket.currentServoB, telemetryPacket.targetServoB,
telemetryPacket.presentDevices);
fflush(csvFile);
fsync(fileno(csvFile)); // Critical: this ensures actual write to disk
}
send_packet_without_retries(bufOut, offset);
packetReadiness = 0;
}
@@ -308,7 +375,6 @@ void lora_comms_task(void *pvParameters)
{
int64_t start_time = esp_timer_get_time();
ESP_LOGI(TAG, "fdfgtfet");
if (packetReadiness)
{
ESP_LOGI(TAG, "Preparing telemetry");

View File

@@ -1,124 +1,19 @@
#include "sdcard.h"
static void s_generate_numbered_filename(char *out_path, size_t max_len) {
DIR *dir = opendir(MOUNT_POINT);
if (!dir) {
ESP_LOGE(TAG, "Failed to open directory");
snprintf(out_path, max_len, MOUNT_POINT"/data1.txt"); // fallback
return;
}
int max_num = 0;
struct dirent *entry;
while ((entry = readdir(dir)) != NULL) {
if (strncmp(entry->d_name, "data", 4) == 0 && strstr(entry->d_name, ".txt")) {
int num = 0;
if (sscanf(entry->d_name, "data%d.txt", &num) == 1) {
if (num > max_num) {
max_num = num;
}
}
}
}
closedir(dir);
snprintf(out_path, max_len, MOUNT_POINT"/data%d.txt", max_num + 1);
}
/* SD card and FAT filesystem example.
This example uses SPI peripheral to communicate with SD card.
This example code is in the Public Domain (or CC0 licensed, at your option.)
Unless required by applicable law or agreed to in writing, this
software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
CONDITIONS OF ANY KIND, either express or implied.
*/
#include <string.h>
#include <sys/unistd.h>
#include <sys/stat.h>
#include "esp_vfs_fat.h"
#include "sdmmc_cmd.h"
#include "sd_test_io.h"
#if SOC_SDMMC_IO_POWER_EXTERNAL
#include "sd_pwr_ctrl_by_on_chip_ldo.h"
#endif
#define EXAMPLE_MAX_CHAR_SIZE 64
static const char *TAG = "example";
#define MOUNT_POINT "/sdcard"
#ifdef CONFIG_EXAMPLE_DEBUG_PIN_CONNECTIONS
const char* names[] = {"CLK ", "MOSI", "MISO", "CS "};
const int pins[] = {CONFIG_EXAMPLE_PIN_CLK,
CONFIG_EXAMPLE_PIN_MOSI,
CONFIG_EXAMPLE_PIN_MISO,
CONFIG_EXAMPLE_PIN_CS};
const int pin_count = sizeof(pins)/sizeof(pins[0]);
#if CONFIG_EXAMPLE_ENABLE_ADC_FEATURE
const int adc_channels[] = {CONFIG_EXAMPLE_ADC_PIN_CLK,
CONFIG_EXAMPLE_ADC_PIN_MOSI,
CONFIG_EXAMPLE_ADC_PIN_MISO,
CONFIG_EXAMPLE_ADC_PIN_CS};
#endif //CONFIG_EXAMPLE_ENABLE_ADC_FEATURE
pin_configuration_t config = {
.names = names,
.pins = pins,
#if CONFIG_EXAMPLE_ENABLE_ADC_FEATURE
.adc_channels = adc_channels,
#endif
};
#endif //CONFIG_EXAMPLE_DEBUG_PIN_CONNECTIONS
// Pin assignments can be set in menuconfig, see "SD SPI Example Configuration" menu.
// You can also change the pin assignments here by changing the following 4 lines.
#define PIN_NUM_MISO CONFIG_EXAMPLE_PIN_MISO
#define PIN_NUM_MOSI CONFIG_EXAMPLE_PIN_MOSI
#define PIN_NUM_CLK CONFIG_EXAMPLE_PIN_CLK
#define PIN_NUM_CS CONFIG_EXAMPLE_PIN_CS
static esp_err_t s_example_write_file(const char *path, char *data)
void writeFile(FILE *f, const void *data, size_t size)
{
ESP_LOGI(TAG, "Opening file %s", path);
FILE *f = fopen(path, "w");
if (f == NULL) {
ESP_LOGE(TAG, "Failed to open file for writing");
return ESP_FAIL;
if (f != NULL)
{
fwrite(data, size, 1, f);
fflush(f);
fsync(fileno(f)); // Critical: this ensures actual write to disk
}
fprintf(f, data);
fclose(f);
ESP_LOGI(TAG, "File written");
return ESP_OK;
}
static esp_err_t s_example_read_file(const char *path)
{
ESP_LOGI(TAG, "Reading file %s", path);
FILE *f = fopen(path, "r");
if (f == NULL) {
ESP_LOGE(TAG, "Failed to open file for reading");
return ESP_FAIL;
}
char line[EXAMPLE_MAX_CHAR_SIZE];
fgets(line, sizeof(line), f);
fclose(f);
FILE *csvFile = NULL;
FILE *sensFile = NULL;
// strip newline
char *pos = strchr(line, '\n');
if (pos) {
*pos = '\0';
}
ESP_LOGI(TAG, "Read from file: '%s'", line);
return ESP_OK;
}
void app_main(void)
void initSD(void)
{
esp_err_t ret;
@@ -126,137 +21,108 @@ void app_main(void)
// 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 = {
#ifdef CONFIG_EXAMPLE_FORMAT_IF_MOUNT_FAILED
.format_if_mount_failed = true,
#else
.format_if_mount_failed = false,
#endif // EXAMPLE_FORMAT_IF_MOUNT_FAILED
.max_files = 5,
.allocation_unit_size = 16 * 1024
};
.max_files = 100,
.allocation_unit_size = 16 * 1024};
sdmmc_card_t *card;
const char mount_point[] = MOUNT_POINT;
ESP_LOGI(TAG, "Initializing SD card");
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(TAG, "Using SPI peripheral");
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();
spi_bus_config_t bus_cfg = {
.mosi_io_num = PIN_NUM_MOSI,
.miso_io_num = PIN_NUM_MISO,
.sclk_io_num = PIN_NUM_CLK,
.quadwp_io_num = -1,
.quadhd_io_num = -1,
.max_transfer_sz = 4000,
};
ret = spi_bus_initialize(host.slot, &bus_cfg, SDSPI_DEFAULT_DMA);
if (ret != ESP_OK) {
ESP_LOGE(TAG, "Failed to initialize bus.");
return;
}
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 = PIN_NUM_CS;
slot_config.gpio_cs = HSPI_SD_CS;
slot_config.host_id = host.slot;
ESP_LOGI(TAG, "Mounting filesystem");
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(TAG, "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(TAG, "Failed to initialize the card (%s). "
"Make sure SD card lines have pull-up resistors in place.", esp_err_to_name(ret));
#ifdef CONFIG_EXAMPLE_DEBUG_PIN_CONNECTIONS
check_sd_card_pins(&config, pin_count);
#endif
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(TAG, "Filesystem mounted");
ESP_LOGI(TAGSD, "Filesystem mounted");
// Card has been initialized, print its properties
sdmmc_card_print_info(stdout, card);
// Use POSIX and C standard library functions to work with files.
int index = 0;
FILE *f = fopen(COUNTER_FILE, "r");
if (f)
{
fscanf(f, "%d", &index);
fclose(f);
}
// First create a file.
const char *file_hello = MOUNT_POINT"/hello.txt";
char data[EXAMPLE_MAX_CHAR_SIZE];
snprintf(data, EXAMPLE_MAX_CHAR_SIZE, "%s %s!\n", "Hello", card->cid.name);
ret = s_example_write_file(file_hello, data);
if (ret != ESP_OK) {
// === 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)
{
const char *file_foo = MOUNT_POINT"/foo.txt";
// Check if destination file exists before renaming
struct stat st;
if (stat(file_foo, &st) == 0) {
// Delete it if it exists
unlink(file_foo);
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);
}
// Rename original file
ESP_LOGI(TAG, "Renaming file %s to %s", file_hello, file_foo);
if (rename(file_hello, file_foo) != 0) {
ESP_LOGE(TAG, "Rename failed");
return;
// === 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
}
ret = s_example_read_file(file_foo);
if (ret != ESP_OK) {
return;
}
// Format FATFS
#ifdef CONFIG_EXAMPLE_FORMAT_SD_CARD
ret = esp_vfs_fat_sdcard_format(mount_point, card);
if (ret != ESP_OK) {
ESP_LOGE(TAG, "Failed to format FATFS (%s)", esp_err_to_name(ret));
return;
}
if (stat(file_foo, &st) == 0) {
ESP_LOGI(TAG, "file still exists");
return;
} else {
ESP_LOGI(TAG, "file doesn't exist, formatting done");
}
#endif // CONFIG_EXAMPLE_FORMAT_SD_CARD
const char *file_nihao = MOUNT_POINT"/nihao.txt";
memset(data, 0, EXAMPLE_MAX_CHAR_SIZE);
snprintf(data, EXAMPLE_MAX_CHAR_SIZE, "%s %s!\n", "Nihao", card->cid.name);
ret = s_example_write_file(file_nihao, data);
if (ret != ESP_OK) {
return;
}
//Open file for reading
ret = s_example_read_file(file_nihao);
if (ret != ESP_OK) {
return;
}
// All done, unmount partition and disable SPI peripheral
esp_vfs_fat_sdcard_unmount(mount_point, card);
ESP_LOGI(TAG, "Card unmounted");
//deinitialize the bus after all devices are removed
spi_bus_free(host.slot);
}

26
main/components/sdcard.h Normal file
View File

@@ -0,0 +1,26 @@
#ifndef SDCARD_COMPONENT
#define SDCARD_COMPONENT
#include <string.h>
#include <sys/unistd.h>
#include <sys/stat.h>
#include "esp_vfs_fat.h"
#include "sdmmc_cmd.h"
#include "../hw/buscfg.h"
#define TAGSD "SDSubsys"
#define COUNTER_FILE "cnt.txt"
#define MOUNT_POINT "/sdcard"
void writeFile(FILE *f, const void *data, size_t size);
extern FILE *csvFile;
extern FILE *sensFile;
#define MAX_PATH 80
void initSD(void);
#endif

View File

@@ -9,7 +9,8 @@
#include "esp_vfs_fat.h"
#include "sdmmc_cmd.h"
#define MOUNT_POINT "/canSensors"
#define MOUNT_POINT "/sdcard"
#define MAX_LINE_LENGTH 64
#define BLINK_GPIO 2
@@ -143,6 +144,9 @@ void init_connected()
void i2c_sensors_task(void *pvParameters)
{
memset(foundDevices, 0, sizeof(foundDevices));
memset(prevDevices, 0, sizeof(prevDevices));

View File

@@ -25,6 +25,7 @@
#include "hw/mcp23018.h"
#include "hw/mpu9250.h"
#include "hw/buscfg.h"
#include "components/sdcard.h"
#include "hw/gps.h"
@@ -48,6 +49,8 @@ void app_main(void)
// };
// ESP_ERROR_CHECK(spi_bus_initialize(SPI2_HOST, &MCPBusCfg, SPI_DMA_DISABLED));
gpio_pullup_en(HSPI_MISO_GPIO);
gpio_pullup_en(HSPI_SD_CS);
spi_bus_config_t HighSpeedBusCfg = {
// CONNECTED to LoRa and SD card
.mosi_io_num = HSPI_MOSI_GPIO,
@@ -64,6 +67,8 @@ void app_main(void)
mcp23018_init();
initSD();
void servoControllerInit();
ESP_LOGI(TAG, "BEGIN ESP TASKS");