/** * Block 3: CSV Writer für C-ITS Sniffer * * Erstellt CSV-Dateien mit empfangenen C-ITS Nachrichten * Neue Datei alle 10 Minuten */ #include #include #include #include #include #include "sdkconfig.h" #include "esp_err.h" #include "esp_log.h" #include "esp_vfs_fat.h" #include "freertos/FreeRTOS.h" #include "freertos/task.h" static const char *TAG = "CSV_WRITER"; // CSV Datei Handle static FILE *csv_file = NULL; static char current_filename[64]; static time_t last_write_time = 0; #define CSV_WRITE_INTERVAL_SEC (600) // 10 Minuten /** * C-ITS Message Header (BSI Format) */ typedef struct { uint32_t timestamp_sec; uint32_t timestamp_usec; uint16_t length; uint8_t sender_id[6]; // MAC Address uint8_t message_type; // BSI Message Type uint8_t channel; // Kanal int16_t rssi; // Signal Stärke } cits_message_t; /** * CSV Header schreiben */ static void write_csv_header(FILE *fp) { fprintf(fp, "timestamp_sec,timestamp_usec,length,sender_mac,message_type,channel,rssi\n"); } /** * CSV Zeile schreiben */ static void write_csv_row(FILE *fp, cits_message_t *msg) { char mac_str[18]; snprintf(mac_str, sizeof(mac_str), "%02x:%02x:%02x:%02x:%02x:%02x", msg->sender_id[0], msg->sender_id[1], msg->sender_id[2], msg->sender_id[3], msg->sender_id[4], msg->sender_id[5]); fprintf(fp, "%u,%u,%u,%s,%u,%u,%d\n", msg->timestamp_sec, msg->timestamp_usec, msg->length, mac_str, msg->message_type, msg->channel, msg->rssi); } /** * Neue CSV-Datei erstellen */ static esp_err_t create_new_csv_file(void) { time_t now; struct tm *tm_info; time(&now); tm_info = localtime(&now); // Dateinamen mit Zeitstempel snprintf(current_filename, sizeof(current_filename), "/data/cits_%04d%02d%02d_%02d%02d%02d.csv", tm_info->tm_year + 1900, tm_info->tm_mon + 1, tm_info->tm_mday, tm_info->tm_hour, tm_info->tm_min, tm_info->tm_sec); if (csv_file != NULL) { fclose(csv_file); } csv_file = fopen(current_filename, "w"); if (csv_file == NULL) { ESP_LOGE(TAG, "Failed to create CSV file: %s", current_filename); return ESP_FAIL; } write_csv_header(csv_file); fflush(csv_file); ESP_LOGI(TAG, "Created new CSV file: %s", current_filename); return ESP_OK; } /** * Prüfen ob neue Datei nötig (10 Minuten Intervall) */ static void check_new_csv_file(void) { time_t now; time(&now); if (difftime(now, last_write_time) >= CSV_WRITE_INTERVAL_SEC) { create_new_csv_file(); last_write_time = now; } } /** * C-ITS Nachricht speichern * * @param msg Nachricht Daten */ void csv_store_cits_message(cits_message_t *msg) { if (csv_file == NULL) { create_new_csv_file(); if (csv_file == NULL) { return; } } check_new_csv_file(); write_csv_row(csv_file, msg); fflush(csv_file); } /** * CSV System initialisieren */ esp_err_t csv_writer_init(void) { // SPI Flash Filesystem mounten static wl_handle_t wl_handle; const esp_vfs_fat_mount_config_t mount_config = { .max_files = 4, .format_if_mount_failed = true }; esp_err_t ret = esp_vfs_fat_spiflash_mount_rw_wl("/data", "storage", &mount_config, &wl_handle); if (ret != ESP_OK) { ESP_LOGE(TAG, "Failed to mount FATFS (%s)", esp_err_to_name(ret)); return ret; } // Erste CSV Datei erstellen return create_new_csv_file(); } /** * CSV System beenden */ void csv_writer_deinit(void) { if (csv_file != NULL) { fclose(csv_file); csv_file = NULL; } }