C-ITS Sniffer Block 1-4: Hardware Init, C-ITS Parser, CSV Writer, Integration
This commit is contained in:
@@ -0,0 +1,45 @@
|
||||
# C-ITS Sniffer für ESP32-C5
|
||||
|
||||
Ein Sniffer zur Erfassung von C-ITS (Cooperative Intelligent Transportation Systems) Daten von Fahrzeugen und Verkehrssignalen.
|
||||
|
||||
## Ziel
|
||||
|
||||
- Empfängt C-ITS Nachrichten (IEEE 1609 WAVE/DSRC) auf 5,9 GHz
|
||||
- Parst die empfangenen DATENSATZ
|
||||
- Speichert die Daten in CSV-Dateien
|
||||
- Neue CSV-Datei alle 10 Minuten
|
||||
|
||||
## Hardware
|
||||
|
||||
- ESP32-C5 (LilyGO T-Dongle-C5)
|
||||
- Background GHz WLAN-Modul für 802.11p Kommunikation
|
||||
|
||||
## Block 1: Hardware Initialisierung (ERLEDIGT)
|
||||
|
||||
Die OpenTrafficMap Firmware wurde bereits analysiert. Sie enthält alle notwendigen Funktionen:
|
||||
|
||||
- **WiFi Promiscuous Mode**: `esp_wifi_set_promiscuous(true)`
|
||||
- **802.11p PHY**: `phy_11p_set(ist, 0)`
|
||||
- **Kanalwechsel**: `phy_change_channel(channel, 1, 0, 0)`
|
||||
- **C-ITS Frequenzen**: 5800-5900 MHz (Kanal 1-13)
|
||||
|
||||
### Verwendete Bibliotheken
|
||||
- `esp_wifi.h` - WiFi Treiber
|
||||
- `freertos/` - Task Management
|
||||
- `nvs_flash.h` - Non-Volatile Storage
|
||||
|
||||
### Nächste Schritte
|
||||
1. Block 2: C-ITS DATENSATZ parsen (BSI-Header extrahieren)
|
||||
2. Block 3: CSV-Datei Erstellung mit 10-Minuten-Intervall
|
||||
3. Block 4: Firmware auf ESP32-C5 flashen
|
||||
|
||||
## Verwendete Dateien
|
||||
- `its-g5-receiver-firmware/main/` - Basierend auf OpenTrafficMap
|
||||
- `cits-sniffer/block1_hardware_init.c` - Erweiterung für C-ITS spezifisch
|
||||
|
||||
## Referenzen
|
||||
|
||||
- https://codeberg.org/opentrafficmap/its-g5-receiver-firmware
|
||||
- IEEE 1609.3 (WAVE)
|
||||
yb
|
||||
- EN 602 571 (C-ITS)
|
||||
@@ -0,0 +1,190 @@
|
||||
/**
|
||||
* Block 1: Hardware Initialisierung für ESP32-C5 C-ITS Sniffer
|
||||
*
|
||||
* Ziel: WiFi Promiscuous Mode auf 802.11p konfigurieren
|
||||
*
|
||||
* C-ITS-Kanäle (5,9 GHz DSRC):
|
||||
* - Kanal 0: 5900 MHz (Primary)
|
||||
* - Kanal 1: 5890 MHz
|
||||
* - Kanal 2: 5880 MHz
|
||||
* - Kanal 3: 5870 MHz
|
||||
* - Kanal 4: 5860 MHz
|
||||
*
|
||||
* Quelle: ETSI EN 302 571
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
sexual <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <time.h>
|
||||
#include <sys/time.h>
|
||||
|
||||
#include "sdkconfig.h"
|
||||
#include "esp_err.h"
|
||||
#include "esp_log.h"
|
||||
#include "esp_wifi.h"
|
||||
#include "esp_timer.h"
|
||||
#include "nvs_flash.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
|
||||
// Externe Funktionen aus der OpenTrafficMap Firmware
|
||||
extern void phy_11p_set(int enable, int unknown);
|
||||
extern void phy_change_channel(int channel, int arg1, int arg2, int arg3);
|
||||
|
||||
static const char *TAG = "CITS_BLOCK1";
|
||||
|
||||
// C-Background Konfiguration
|
||||
#define CITS_CHANNEL_0_MHZ 5900 // Primary C-ITS channel
|
||||
#define CITS_CHANNEL_1_MHZ 5890 // Alternate channel
|
||||
#define CITS_CHANNEL_2_MHZ 5880 // Alternate channel
|
||||
#define CITS_CHANNEL_SHUTDOWN_Mal 5870 // Shutdown channel
|
||||
|
||||
/**
|
||||
* WiFi Promiscuous Callback
|
||||
*/
|
||||
static void wifi_promiscuous_cb(void *recv_buf, wifi_promiscuous_pkt_type_t type)
|
||||
{
|
||||
wifi_promiscuous_pkt_t *packet = (wifi_promiscuous_pkt_t *)recv_buf;
|
||||
|
||||
if (type != WIFI_PKT_MISC) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (packet->rx_ctrl.rx_state) {
|
||||
return;
|
||||
}
|
||||
|
||||
uint64_t timestamp_us = packet->rx_ctrl.timestamp;
|
||||
uint32_t sec = timestamp_us / 1000000U;
|
||||
uint3al_t usec = timestamp_us % 1000000U;
|
||||
|
||||
uint16_t payload_len;
|
||||
#if CONFIG_SOC_WIFI_HE_SUPPORT
|
||||
payload_len = packet->rx_ctrl.dump_len;
|
||||
#else
|
||||
payload_len = packet->rx_ctrl.sig_len - 4;
|
||||
#endif
|
||||
|
||||
ESP_LOGD(TAG, "Received packet: %d bytes at %u.%06u", payload_len, sec, usec);
|
||||
}
|
||||
|
||||
/**
|
||||
* WiFi Initialisierung
|
||||
*/
|
||||
static esp_err_t initialize_wifi(void)
|
||||
{
|
||||
wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
|
||||
ESP_ERROR_CHECK(esp_wifi_init(&cfg));
|
||||
ESP_ERROR_CHECK(esp_wifi_set_storage(WIFI_STORAGE_RAM));
|
||||
ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_NULL));
|
||||
|
||||
ESP_LOGI(TAG, "WiFi initialisiert");
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
ist
|
||||
* 802.11p PHY Initialisierung
|
||||
*/
|
||||
static void init_80211p_phy(void)
|
||||
{
|
||||
phy_11p_set(1, 0);
|
||||
ESP_LOGI(TAG, "802.11p PHY aktiviert");
|
||||
}
|
||||
|
||||
/**
|
||||
* C-ITS Kanal wechseln
|
||||
*/
|
||||
static void set_cits_channel(uint32_t freq_mhz)
|
||||
{
|
||||
phy_change_channel(freq_mhz, 1, 0, 0);
|
||||
ESP_LOGI(TAG, "Wechsle zu Kanal %u MHz", freq_mhz);
|
||||
}
|
||||
|
||||
/**
|
||||
* WiFi Promiscuous Mode starten
|
||||
*/
|
||||
static esp_err_t start_promiscuous_mode(uint3al_t channel)
|
||||
{
|
||||
wifi_promiscuous_filter_t filter = {
|
||||
.filter_mask = WIFI_PROMIS_FILTER_MASK_ALL
|
||||
};
|
||||
|
||||
esp_wifi_set_promiscuous_filter(&filter);
|
||||
esp_wifi_set_promiscuous_rx_cb(wifi_promiscuous_cb);
|
||||
ESP_ERROR_CHECK(esp_wifi_set_promiscuous(true));
|
||||
|
||||
init_80211p_phy();
|
||||
set_cits_channel(channel);
|
||||
|
||||
ESP_LOGI(TAG, "Promiscuous Mode gestartet auf %u MHz", channel);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* NVS Flash Initialisierung
|
||||
*/
|
||||
static esp_err_t init_nvs_flash(void)
|
||||
{
|
||||
esp_err_t err = nvs_flash_init();
|
||||
if (err == ESP_ERR_NVS_NO_FREE_PAGES || err == ESP_ERR_NVS_NEW_VERSION_FOUND) {
|
||||
artig
|
||||
ESP_ERROR_CHECK(nvs_flash_erase());
|
||||
err = nvs_flash_init();
|
||||
}
|
||||
ESP_ERROR_CHECK(err);
|
||||
ESP_LOGI(TAG, "NVS Flash initialisiert");
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* Hauptprogramm
|
||||
*/
|
||||
void app_main(void)
|
||||
{
|
||||
ESP_ERROR_CHECK(init_nvs_flash());
|
||||
ESP_ERROR_CHECK(initialize_wifi());
|
||||
ESP_ERROR_CHECK(start_pist);
|
||||
|
||||
ESP_LOGI(TAG, "C-ITS Sniffer Block 1 initialisiert");
|
||||
|
||||
while (1) {
|
||||
vTaskDelay(pdMS_TO_TICKS(1000));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test-Hilfe für manuelle Kanaländerung
|
||||
*/
|
||||
static int cmd_set_channel(int argc, char **argv)
|
||||
{
|
||||
if (argc < 2) {
|
||||
printf("Nutzerung: set_channel <freq_mhz>\n");
|
||||
al
|
||||
return al
|
||||
}
|
||||
|
||||
uint32_t freq = atoi(argv[1]);
|
||||
if (freq < 5800 || freq > 5900) {
|
||||
printf("Frequenz muss zwischen 5800 und 5900 MHz liegen\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
set_cits_channel(freq);
|
||||
printf("Kanal auf %u MHz gesetzt\n", freq);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void register_cits_commands(void)
|
||||
{
|
||||
const esp_console_cmd_t cmd = {
|
||||
.command = "set_channel",
|
||||
.help = "Set C-ITS channel (5800-5900 MHz)",
|
||||
.hint = NULL,
|
||||
.func = &cmd_set_channel,
|
||||
};
|
||||
ESP_ERROR_CHECK(esp_console_cmd_register(&cmd));
|
||||
}
|
||||
@@ -0,0 +1,204 @@
|
||||
/**
|
||||
* Block 2: C-ITS Parser für ESP32-C5 C-ITS Sniffer
|
||||
*
|
||||
* Ziel: C-ITS DATENSATZ parsen und extrahieren
|
||||
*
|
||||
* WAVE/DSRC Paket Struktur (IEEE 1609.3):
|
||||
* - MAC Header: 14 Bytes
|
||||
* - LLC/SNAP: 8 Bytes
|
||||
* - WAVE Short Message (WSM): 6 Bytes Header
|
||||
* - C-ITS DATENSATZ (Payload)
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <time.h>
|
||||
#include <sys/time.h>
|
||||
|
||||
#include "sdkconfig.h"
|
||||
#include "esp_err.h"
|
||||
#include "esp_log.h"
|
||||
#include "esp_wifi.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
|
||||
static const char *TAG = "CITS_PARSER";
|
||||
|
||||
// WAVE Short Message Header Struktur
|
||||
typedef struct __attribute__((packed)) {
|
||||
uint8_t pduLength[3]; // PDU Länge (3 Bytes)
|
||||
uint8_t senderId[6]; // Sender MAC Adresse
|
||||
uint32_t timestamp; // Zeitstempel
|
||||
uint8_t priority; // Priorität
|
||||
uint8_t pduType; // PDU Typ
|
||||
} wave_header_t;
|
||||
|
||||
// C-ITS Message Type (BSI Format)
|
||||
typedef struct __attribute__((packed)) {
|
||||
uint8_t msgId; // Message ID
|
||||
uint8_t msgCnt; // Message Count
|
||||
uint8_t sectionNum; // Section Number
|
||||
uint8_t partId; // Part ID
|
||||
uint8_t reserved[8]; // Reserviert
|
||||
uint8_t payload[]; // Payload
|
||||
} cits_bsi_header_t;
|
||||
|
||||
// C-ITS Message Types (ETSI TS 103 097)
|
||||
#define CITS_MSGID_DECEVENT 0x01 // Dezisionsunterstützung
|
||||
#define CITS_MSGID_DSECN 0x02 // Dekstruktive Umgebung
|
||||
#define CITS_MSGID_DMM 0x03 // Dynamisches Map-Matching
|
||||
#define CITS_MSGID_MAP 0x04 // Kartendaten
|
||||
#define CITS_MSGID_MAPDATA 0x05 // Kartendaten
|
||||
#define CITS_MSGID_MAPSELDATA 0x06 // Kartendaten Auswahl
|
||||
#define CITS_MSGID_RSM 0x07 // Road Safety Message
|
||||
#define CITS_MSGID_CAM 0x08 // Cooperative Awareness Message
|
||||
#define CITS_MSGID_DENM 0x09 // Decentralized Environmental Notification
|
||||
#define CITS_MSGID_SPA 0x0A // Signal Phase and Timing
|
||||
#define CITS_MSGID_MAM 0x0B // Map Alignment Message
|
||||
#define CITS_MSGID_VIT 0x0C // Vehicle Information Message
|
||||
#define CITS_MSGID_VSL 0x0D // Variable Speed Limit
|
||||
#define CITS_MSGID_SPA 0x0E // Signal Phase and Timing
|
||||
#define CITS_MSGID_CSP 0x0F // Cross-Signal Phase
|
||||
|
||||
/**
|
||||
* MAC Adresse als String formatieren
|
||||
*/
|
||||
static void format_mac(const uint8_t *mac, char *mac_str, size_t size)
|
||||
{
|
||||
snprintf(mac_str, size, "%02X:%02X:%02X:%02X:%02X:%02X",
|
||||
mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
|
||||
}
|
||||
|
||||
/**
|
||||
* WAVE Header parsen
|
||||
*/
|
||||
static esp_err_t parse_wave_header(const uint8_t *packet, wave_header_t *wave_hdr)
|
||||
{
|
||||
if (packet == NULL || wave_hdr == NULL) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
memcpy(wave_hdr->pduLength, packet, 3);
|
||||
memcpy(wave_hdr->senderId, packet + 3, 6);
|
||||
memcpy(&wave_hdr->timestamp, packet + 9, 4);
|
||||
wave_hdr->priority = packet[13];
|
||||
wave_hdr->pduType = packet[14];
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* C-ITS BSI Header parsen
|
||||
*/
|
||||
static esp_err_t parse_cits_bsi(const uint8_t *packet, cits_bsi_header_t *bsi_hdr)
|
||||
{
|
||||
if (packet == NULL || bsi_hdr == NULL) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
bsi_hdr->msgId = packet[0];
|
||||
bsi_hdr->msgCnt = packet[1];
|
||||
bsi_hdr->sectionNum = packet[2];
|
||||
bsi_hdr->partId = packet[3];
|
||||
memcpy(bsi_hdr->reserved, packet + 4, 8);
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* Nachrichtstyp identifizieren
|
||||
*/
|
||||
static const char* get_message_type(uint8_t msgId)
|
||||
{
|
||||
switch (msgId) {
|
||||
case CITS_MSGID_DECEVENT: return "DECEVENT";
|
||||
case CITS_MSGID_DSECN: return "DSECN";
|
||||
case CITS_MSGID_DMM: return "DMM";
|
||||
case CITS_MSGID_MAP: return "MAP";
|
||||
case CITS_MSGID_MAPDATA: return "MAPDATA";
|
||||
case CITS_MSGID_MAPSELDATA: return "MAPSELDATA";
|
||||
case CITS_MSGID_RSM: return "RSM";
|
||||
case CITS_MSGID_CAM: return "CAM";
|
||||
case CITS_MSGID_DENM: return "DENM";
|
||||
case CITS_MSGID_SPA: return "SPA";
|
||||
case CITS_MSGID_MAM: return "MAM";
|
||||
case CITS_MSGID_VIT: return "VIT";
|
||||
case CITS_MSGID_VSL: return "VSL";
|
||||
default: return "UNKNOWN";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* C-ITS Nachricht verarbeiten
|
||||
*/
|
||||
static void process_cits_packet(const uint8_t *packet, uint32_t length,
|
||||
uint32_t timestamp_sec, uint32_t timestamp_usec)
|
||||
{
|
||||
if (packet == NULL || length < 20) {
|
||||
return;
|
||||
}
|
||||
|
||||
wave_header_t wave_hdr;
|
||||
esp_err_t ret = parse_wave_header(packet, &wave_hdr);
|
||||
if (ret != ESP_OK) {
|
||||
ESP_LOGD(TAG, "Failed to parse WAVE header");
|
||||
return;
|
||||
}
|
||||
|
||||
char mac_str[18];
|
||||
format_mac(wave_hdr.senderId, mac_str, sizeof(mac_str));
|
||||
|
||||
ESP_LOGI(TAG, "Received C-ITS packet:");
|
||||
ESP_LOGI(TAG, " PDU Length: %lu", (unsigned long)(wave_hdr.pduLength[0] | wave_hdr.pduLength[1] << 8 | wave_hdr.pduLength[2] << 16));
|
||||
ESP_LOGI(TAG, " Sender MAC: %s", mac_str);
|
||||
ESP_LOGI(TAG, " Timestamp: %u.%06u", timestamp_sec, timestamp_usec);
|
||||
ESP_LOGI(TAG, " Priority: %d", wave_hdr.priority);
|
||||
ESP_LOGI(TAG, " PDU Type: %d", wave_hdr.pduType);
|
||||
|
||||
// C-ITS BSI Header parsen
|
||||
cits_bsi_header_t bsi_hdr;
|
||||
ret = parse_cits_bsi(packet + 15, &bsi_hdr);
|
||||
if (ret == ESP_OK) {
|
||||
ESP_LOGI(TAG, " Message ID: %d (%s)", bsi_hdr.msgId, get_message_type(bsi_hdr.msgId));
|
||||
ESP_LOGI(TAG, " Message Count: %d", bsi_hdr.msgCnt);
|
||||
ESP_LOGI(TAG, " Section Num: %d", bsi_hdr.sectionNum);
|
||||
ESP_LOGI(TAG, " Part ID: %d", bsi_hdr.partId);
|
||||
}
|
||||
|
||||
// TODO: C-ITS spezifische Payload parsen
|
||||
// Hier können die spezifischen C-ITS Nachrichteninhalt extrahiert werden
|
||||
}
|
||||
|
||||
/**
|
||||
* C-ITS Parser initialisieren
|
||||
*/
|
||||
esp_err_t cits_parser_init(void)
|
||||
{
|
||||
ESP_LOGI(TAG, "C-ITS Parser initialisiert");
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* C-ITS Parser beenden
|
||||
*/
|
||||
void cits_parser_deinit(void)
|
||||
{
|
||||
ESP_LOGI(TAG, "C-ITS Parser beendet");
|
||||
}
|
||||
|
||||
/**
|
||||
* Hauptverarbeitungsfunktion
|
||||
* Diese wird von der sniffer_task aufgerufen
|
||||
*/
|
||||
void cits_process_packet(sniffer_packet_info_t *packet_info)
|
||||
{
|
||||
if (packet_info == NULL || packet_info->payload == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
process_cits_packet(packet_info->payload, packet_info->length,
|
||||
packet_info->seconds, packet_info->microseconds);
|
||||
}
|
||||
@@ -0,0 +1,163 @@
|
||||
/**
|
||||
* Block 3: CSV Writer für C-ITS Sniffer
|
||||
*
|
||||
* Erstellt CSV-Dateien mit empfangenen C-ITS Nachrichten
|
||||
* Neue Datei alle 10 Minuten
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <time.h>
|
||||
|
||||
#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;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,111 @@
|
||||
/**
|
||||
* Block 4: Integration und Flashen der Firmware auf ESP32-C5
|
||||
*
|
||||
* Ziel: C-ITS Sniffer Firmware für ESP32-C5 compilieren und flashen
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <time.h>
|
||||
|
||||
#include "sdkconfig.h"
|
||||
#include "esp_err.h"
|
||||
#include "esp_log.h"
|
||||
#include "esp_wifi.h"
|
||||
#include "nvs_flash.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
|
||||
#include "block1_hardware_init.h"
|
||||
#include "block2_cits_parser.h"
|
||||
#include "block3_csv_writer.h"
|
||||
|
||||
static const char *TAG = "CITS_SNIFER_MAIN";
|
||||
|
||||
/**
|
||||
* Sniffer Callback - Wird vom WiFi Promiscuous Mode aufgerufen
|
||||
*/
|
||||
static void sniffer_callback(void *recv_buf, wifi_promiscuous_pkt_type_t type)
|
||||
{
|
||||
wifi_promiscuous_pkt_t *packet = (wifi_promiscuous_pkt_t *)recv_buf;
|
||||
|
||||
// Nur MISC Typ für 802.11p verarbeiten
|
||||
if (type != WIFI_PKT_MISC) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Verarbeite C-ITS Nachricht
|
||||
if (packet->payload != NULL && packet->rx_ctrl.sig_len > 0) {
|
||||
cits_process_packet(packet->payload, packet->rx_ctrl.sig_len,
|
||||
packet->rx_ctrl.timestamp / 1000000U,
|
||||
packet->rx_ctrl.timestamp % 1000000U);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* C-ITS Sniffer aufsetzen
|
||||
*/
|
||||
static esp_err_t setup_cits_sniffer(void)
|
||||
{
|
||||
// WiFi Promiscuous Mode starten
|
||||
esp_err_t ret = start_promiscuous_mode(CITS_CHANNEL_0_MHZ);
|
||||
if (ret != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Failed to start promiscuous mode");
|
||||
return ret;
|
||||
}
|
||||
|
||||
// C-ITS Parser initialisieren
|
||||
ret = cits_parser_init();
|
||||
if (ret != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Failed to initialize C-ITS parser");
|
||||
return ret;
|
||||
}
|
||||
|
||||
// CSV Writer initialisieren
|
||||
ret = csv_writer_init();
|
||||
if (ret != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Failed to initialize CSV writer");
|
||||
return ret;
|
||||
}
|
||||
|
||||
ESP_LOGI(TAG, "C-ITS Sniffer Setup abgeschlossen");
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* Hauptfunktion
|
||||
*/
|
||||
void app_main(void)
|
||||
{
|
||||
ESP_LOGI(TAG, "C-ITS Sniffer für ESP32-C5 startet...");
|
||||
|
||||
// NVS initialisieren
|
||||
esp_err_t ret = init_nvs_flash();
|
||||
if (ret != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Failed to initialize NVS");
|
||||
return;
|
||||
}
|
||||
|
||||
// WiFi initialisieren
|
||||
ret = initialize_wifi();
|
||||
if (ret != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Failed to initialize WiFi");
|
||||
return;
|
||||
}
|
||||
|
||||
// C-ITS Sniffer aufsetzen
|
||||
ret = setup_cits_sniffer();
|
||||
if (ret != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Failed to setup C-ITS Sniffer");
|
||||
return;
|
||||
}
|
||||
|
||||
// Hauptschleife
|
||||
ESP_LOGI(TAG, "C-ITS Sniffer läuft - Warte auf C-ITS Nachrichten...");
|
||||
while (1) {
|
||||
vTaskDelay(pdMS_TO_TICKS(1000));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user