build: fix USB-JTAG API, PRI macros, linker symbols for ESP-IDF 5.5

This commit is contained in:
Clawdia
2026-05-20 06:36:35 +02:00
parent 76d50165c4
commit 5248ff7b82
15 changed files with 1976 additions and 2273 deletions
+1268 -1152
View File
File diff suppressed because it is too large Load Diff
+33 -9
View File
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
-1
View File
@@ -163,5 +163,4 @@ $<TARGET_FILE:idf::spiffs>
$<TARGET_FILE:idf::wifi_provisioning> $<TARGET_FILE:idf::wifi_provisioning>
$<TARGET_FILE:__idf_json> $<TARGET_FILE:__idf_json>
$<TARGET_FILE:idf::main> $<TARGET_FILE:idf::main>
$<TARGET_FILE:__idf_ieee802154>
$<TARGET_FILE:__idf_fatfs> $<TARGET_FILE:__idf_fatfs>
+4 -4
View File
@@ -1,7 +1,7 @@
{ {
"version": "1.2", "version": "1.2",
"project_name": "cits-sniffer", "project_name": "cits-sniffer",
"project_version": "b657a2d-dirty", "project_version": "76d5016-dirty",
"project_path": "/home/claw/.openclaw/agents/wisp/workspace/cits-sniffer", "project_path": "/home/claw/.openclaw/agents/wisp/workspace/cits-sniffer",
"idf_path": "/home/claw/esp/esp-idf", "idf_path": "/home/claw/esp/esp-idf",
"build_dir": "/home/claw/.openclaw/agents/wisp/workspace/cits-sniffer/build", "build_dir": "/home/claw/.openclaw/agents/wisp/workspace/cits-sniffer/build",
@@ -1221,11 +1221,11 @@
"type": "LIBRARY", "type": "LIBRARY",
"lib": "__idf_main", "lib": "__idf_main",
"reqs": [], "reqs": [],
"priv_reqs": [ "esp_timer", "nvs_flash", "driver", "ieee802154", "console", "fatfs", "wear_levelling", "esp_driver_usb_serial_jtag" ], "priv_reqs": [ "esp_timer", "nvs_flash", "driver", "esp_wifi", "fatfs", "console" ],
"managed_reqs": [], "managed_reqs": [],
"managed_priv_reqs": [], "managed_priv_reqs": [],
"file": "/home/claw/.openclaw/agents/wisp/workspace/cits-sniffer/build/esp-idf/main/libmain.a", "file": "/home/claw/.openclaw/agents/wisp/workspace/cits-sniffer/build/esp-idf/main/libmain.a",
"sources": [ "/home/claw/.openclaw/agents/wisp/workspace/cits-sniffer/main/app_main.c" ], "sources": [ "/home/claw/.openclaw/agents/wisp/workspace/cits-sniffer/main/block1_hardware_init.c", "/home/claw/.openclaw/agents/wisp/workspace/cits-sniffer/main/block2_cits_parser.c", "/home/claw/.openclaw/agents/wisp/workspace/cits-sniffer/main/block3_csv_writer.c", "/home/claw/.openclaw/agents/wisp/workspace/cits-sniffer/main/block4_integration.c" ],
"include_dirs": [ "." ] "include_dirs": [ "." ]
}, },
"mbedtls": { "mbedtls": {
@@ -2893,7 +2893,7 @@
"dir": "/home/claw/.openclaw/agents/wisp/workspace/cits-sniffer/main", "dir": "/home/claw/.openclaw/agents/wisp/workspace/cits-sniffer/main",
"lib": "__idf_main", "lib": "__idf_main",
"reqs": [], "reqs": [],
"priv_reqs": [ "esp_timer", "nvs_flash", "driver", "ieee802154", "console", "fatfs", "wear_levelling", "esp_driver_usb_serial_jtag" ], "priv_reqs": [ "esp_timer", "nvs_flash", "driver", "esp_wifi", "fatfs", "console" ],
"managed_reqs": [], "managed_reqs": [],
"managed_priv_reqs": [], "managed_priv_reqs": [],
"include_dirs": [ "." ] "include_dirs": [ "." ]
+5 -2
View File
@@ -1,5 +1,8 @@
idf_component_register( idf_component_register(
SRCS "app_main.c" SRCS "block1_hardware_init.c"
"block2_cits_parser.c"
"block3_csv_writer.c"
"block4_integration.c"
INCLUDE_DIRS "." INCLUDE_DIRS "."
PRIV_REQUIRES esp_timer nvs_flash driver ieee802154 console fatfs wear_levelling esp_driver_usb_serial_jtag PRIV_REQUIRES esp_timer nvs_flash driver esp_wifi fatfs console
) )
-424
View File
@@ -1,424 +0,0 @@
/**
* app_main.c - C-ITS Sniffer ESP32-C5
*
* IEEE 802.15.4 Promiscuous Mode Sniffer
* Ringpuffer für JTAG-Auslesung von rohen Paketen
* Konsolencommands: status, read_pkts [n], chan <ch>, packets <n>
*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <stdint.h>
#include <stdbool.h>
#include <time.h>
#include <inttypes.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include "sdkconfig.h"
#include "esp_err.h"
#include "esp_log.h"
#include "esp_log_write.h"
#include "esp_timer.h"
#include "esp_console.h"
#include "esp_vfs.h"
#include "driver/usb_serial_jtag.h"
#include "driver/usb_serial_jtag_vfs.h"
#include "nvs_flash.h"
#include "esp_vfs_fat.h"
#include "wear_levelling.h"
#include "esp_ieee802154.h"
#include "esp_ieee802154_types.h"
#include "driver/gpio.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
static const char *TAG = "CITS_SNIFFER";
static const char *TAG_CMD = "CMD";
#define LED_PIN GPIO_NUM_28
#define SNIFFER_CHANNEL 11
#define CSV_INTERVAL_SEC 3600
// Ringpuffer für rohe Pakete (für JTAG-Direct-Access)
#define PKT_RING_BUF_SIZE 128
#define PKT_MAX_SIZE 160
typedef struct {
uint8_t data[PKT_MAX_SIZE];
uint16_t len;
int8_t rssi;
uint8_t lqi;
uint32_t ts_sec;
uint32_t ts_usec;
} raw_pkt_t;
static raw_pkt_t pkt_ring[PKT_RING_BUF_SIZE];
static volatile uint32_t pkt_ring_write = 0;
static volatile uint32_t pkt_ring_total = 0;
static bool pkt_ring_full = false;
static FILE *csv_file = NULL;
static char csv_filename[64];
static time_t last_csv_time = 0;
static uint32_t packet_count = 0;
static wl_handle_t wl_handle = WL_INVALID_HANDLE;
static volatile bool sniffer_active = false;
static volatile int8_t last_rssi = -127;
// === CSV / Storage ===
static void write_csv_header(FILE *fp)
{
fprintf(fp, "timestamp_sec,timestamp_usec,length,sender_mac,frame_type,channel,rssi,lqi\n");
}
static void write_csv_row(FILE *fp, uint32_t ts_sec, uint32_t ts_usec, uint16_t len,
uint8_t *src_mac, uint8_t ftype, uint8_t ch, int16_t rssi, uint8_t lqi)
{
char mac_str[24];
snprintf(mac_str, sizeof(mac_str), "%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x",
src_mac[7], src_mac[6], src_mac[5], src_mac[4], src_mac[3], src_mac[2], src_mac[1], src_mac[0]);
fprintf(fp, "%" PRIu32 ",%" PRIu32 ",%" PRIu16 ",%s,%u,%u,%d,%u\n",
ts_sec, ts_usec, len, mac_str, ftype, ch, rssi, lqi);
}
static esp_err_t create_csv_file(void)
{
time_t now;
struct tm *tm_info;
time(&now);
tm_info = localtime(&now);
snprintf(csv_filename, sizeof(csv_filename),
"/storage/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(csv_filename, "w");
if (csv_file == NULL) {
ESP_LOGE(TAG, "CSV create failed: %s", csv_filename);
return ESP_FAIL;
}
write_csv_header(csv_file);
fflush(csv_file);
ESP_LOGI(TAG, "CSV: %s", csv_filename);
return ESP_OK;
}
static void store_pkt_raw(const uint8_t *data, uint16_t len, int8_t rssi, uint8_t lqi,
uint32_t ts_sec, uint32_t ts_usec)
{
uint32_t idx = pkt_ring_write;
pkt_ring[idx].len = (len > PKT_MAX_SIZE) ? PKT_MAX_SIZE : len;
memcpy(pkt_ring[idx].data, data, pkt_ring[idx].len);
pkt_ring[idx].rssi = rssi;
pkt_ring[idx].lqi = lqi;
pkt_ring[idx].ts_sec = ts_sec;
pkt_ring[idx].ts_usec = ts_usec;
pkt_ring_write = (pkt_ring_write + 1) % PKT_RING_BUF_SIZE;
pkt_ring_total++;
if (pkt_ring_total > PKT_RING_BUF_SIZE) pkt_ring_full = true;
}
// === 802.15.4 Sniffer Callback ===
static void sniffer_rx_cb(uint8_t *data, esp_ieee802154_frame_info_t *info)
{
if (!data || !info) return;
if (info->rssi < -100) return;
if (!sniffer_active) return;
packet_count++;
last_rssi = info->rssi;
uint16_t frame_ctrl = data[0] | (data[1] << 8);
uint8_t ftype = frame_ctrl & 0x07;
uint8_t addr_mode_src = (frame_ctrl >> 12) & 0x03;
uint8_t src_mac[8] = {0};
if (addr_mode_src == 1) {
src_mac[7] = data[2]; src_mac[6] = data[3];
} else if (addr_mode_src == 2) {
memcpy(src_mac, &data[2], 8);
}
uint32_t ts_sec = (uint32_t)(info->timestamp / 1000000);
uint32_t ts_usec = (uint32_t)(info->timestamp / 1000) % 1000000;
// Raw-Paket im Ringpuffer speichern
store_pkt_raw(data, (uint16_t)(info->timestamp >> 8), info->rssi, info->lqi, ts_sec, ts_usec);
if (csv_file) {
write_csv_row(csv_file, ts_sec, ts_usec, 0, src_mac, ftype,
info->channel, info->rssi, info->lqi);
fflush(csv_file);
}
if (packet_count % 5 == 0) {
char mac_str[32];
snprintf(mac_str, sizeof(mac_str), "%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x",
src_mac[7], src_mac[6], src_mac[5], src_mac[4], src_mac[3], src_mac[2],
src_mac[1], src_mac[0]);
ESP_LOGI(TAG, "[Pkt %lu] RSSI=%d | LQI=%u | Ch=%u | Src=%s",
(unsigned long)packet_count, info->rssi, info->lqi,
info->channel, mac_str);
}
}
static esp_err_t init_sniffer(void)
{
ESP_LOGI(TAG, "Starte 802.15.4 Stack...");
esp_err_t ret = esp_ieee802154_enable();
if (ret != ESP_OK) {
ESP_LOGE(TAG, "esp_ieee802154_enable failed: %s", esp_err_to_name(ret));
return ret;
}
ESP_LOGI(TAG, "802.15.4 stack enabled");
ret = esp_ieee802154_set_channel(SNIFFER_CHANNEL);
if (ret != ESP_OK) {
ESP_LOGE(TAG, "channel set failed: %s", esp_err_to_name(ret));
return ret;
}
ESP_LOGI(TAG, "Channel: %d", SNIFFER_CHANNEL);
ret = esp_ieee802154_set_promiscuous(true);
if (ret != ESP_OK) {
ESP_LOGE(TAG, "promiscuous failed: %s", esp_err_to_name(ret));
return ret;
}
ESP_LOGI(TAG, "Promiscuous mode enabled");
esp_ieee802154_event_cb_list_t cb_list = { .rx_done_cb = sniffer_rx_cb };
ret = esp_ieee802154_event_callback_list_register(cb_list);
if (ret != ESP_OK) {
ESP_LOGE(TAG, "callback register failed: %s", esp_err_to_name(ret));
return ret;
}
ESP_LOGI(TAG, "Rx callback registered");
sniffer_active = true;
return ESP_OK;
}
static esp_err_t init_storage(void)
{
static wl_handle_t wl;
const esp_vfs_fat_mount_config_t mcfg = {
.max_files = 4, .format_if_mount_failed = true, .allocation_unit_size = 16 * 1024,
};
esp_err_t ret = esp_vfs_fat_spiflash_mount_rw_wl("/storage", "storage", &mcfg, &wl);
if (ret == ESP_OK) {
wl_handle = wl;
ESP_LOGI(TAG, "FATFS storage mounted");
}
return ret;
}
// === Konsolencommands ===
static int cmd_status(int argc, char **argv)
{
(void)argc; (void)argv;
ESP_LOGI(TAG_CMD, "== Status ==");
ESP_LOGI(TAG_CMD, "Packets: %lu", (unsigned long)packet_count);
ESP_LOGI(TAG_CMD, "CSV: %s", csv_filename);
ESP_LOGI(TAG_CMD, "Channel: %d", SNIFFER_CHANNEL);
ESP_LOGI(TAG_CMD, "Ring buffer: %lu/%d total, write_idx=%lu",
(unsigned long)pkt_ring_total, PKT_RING_BUF_SIZE,
(unsigned long)pkt_ring_write);
ESP_LOGI(TAG_CMD, "Last RSSI: %d", last_rssi);
ESP_LOGI(TAG_CMD, "Sniffer active: %s", sniffer_active ? "YES" : "NO");
return 0;
}
static int cmd_packets(int argc, char **argv)
{
if (argc < 2) { ESP_LOGW(TAG_CMD, "Usage: packets <count>"); return 1; }
int count = atoi(argv[1]);
ESP_LOGI(TAG_CMD, "Warte auf %d Pakete...", count);
uint32_t start = packet_count;
while (packet_count - start < count) vTaskDelay(pdMS_TO_TICKS(1000));
ESP_LOGI(TAG_CMD, "%d Pakete empfangen!", count);
return 0;
}
static int cmd_read_pkts(int argc, char **argv)
{
int count = 10;
if (argc > 0) {
count = atoi(argv[0]);
if (count < 1) count = 1;
if (count > PKT_RING_BUF_SIZE) count = PKT_RING_BUF_SIZE;
}
uint32_t total = pkt_ring_total;
if (total == 0) {
ESP_LOGI(TAG_CMD, "Keine Pakete empfangen.");
return 0;
}
ESP_LOGI(TAG_CMD, "=== Ring Buffer Read (%d von %lu) ===", count, (unsigned long)total);
uint32_t idx = (pkt_ring_write == 0) ? PKT_RING_BUF_SIZE - 1 : pkt_ring_write - 1;
for (int i = 0; i < count; i++) {
uint32_t read_total = pkt_ring_total;
if (pkt_ring_full && (read_total - (pkt_ring_write == 0 ? PKT_RING_BUF_SIZE : pkt_ring_write)) <= i) {
break;
}
if (!pkt_ring_full && i >= pkt_ring_total) break;
raw_pkt_t *pkt = &pkt_ring[idx];
char hex_str[72];
hex_str[0] = 0;
for (int j = 0; j < pkt->len && j < 36; j++) {
snprintf(hex_str + strlen(hex_str), sizeof(hex_str) - strlen(hex_str),
"%02x ", pkt->data[j]);
}
ESP_LOGI(TAG_CMD, " [%d] len=%u RSSI=%d LQI=%u | %s",
i, pkt->len, pkt->rssi, pkt->lqi, hex_str);
idx = (idx == 0) ? PKT_RING_BUF_SIZE - 1 : idx - 1;
}
return 0;
}
static int cmd_chan(int argc, char **argv)
{
if (argc < 1) {
ESP_LOGW(TAG_CMD, "Usage: chan <channel>");
return 1;
}
int ch = atoi(argv[0]);
if (ch < 11 || ch > 26) {
ESP_LOGW(TAG_CMD, "Channel muss 11-26 sein");
return 1;
}
esp_err_t ret = esp_ieee802154_set_channel(ch);
if (ret == ESP_OK) {
ESP_LOGI(TAG_CMD, "Channel auf %d geändert", ch);
} else {
ESP_LOGE(TAG_CMD, "Channel change failed: %s", esp_err_to_name(ret));
}
return 0;
}
static void register_console_commands(void)
{
esp_console_cmd_t cmd_status_def = { .command = "status", .help = "Show sniffer status", .func = cmd_status };
esp_console_cmd_t cmd_packets_def = { .command = "packets", .help = "Wait for N packets", .func = cmd_packets };
esp_console_cmd_t cmd_read_def = { .command = "read_pkts", .help = "Read raw packets from ring buffer", .func = cmd_read_pkts };
esp_console_cmd_t cmd_ch_def = { .command = "chan", .help = "Change 802.15.4 channel", .func = cmd_chan };
esp_console_register_help_command();
esp_console_cmd_register(&cmd_status_def);
esp_console_cmd_register(&cmd_packets_def);
esp_console_cmd_register(&cmd_read_def);
esp_console_cmd_register(&cmd_ch_def);
ESP_LOGI(TAG, "Console commands registriert");
}
// === JTAG vprintf-Wrapper ===
// Sendet Logs über JTAG-Verbindung zum Host
static volatile int jtag_connected = 0;
static TickType_t jtag_last_connect_tick = 0;
static int jtag_vprintf(const char *fmt, va_list args)
{
char buf[256];
int len = vsnprintf(buf, sizeof(buf), fmt, args);
if (len > 0 && len < 256) {
// Versuche non-blocking JTAG write
TickType_t now = xTaskGetTickCount();
if (now - jtag_last_connect_tick < pdMS_TO_TICKS(1000)) {
// JTAG write with short timeout (100ms)
int wrote = usb_serial_jtag_write_bytes(buf, len, pdMS_TO_TICKS(100));
if (wrote <= 0) {
jtag_connected = 0;
jtag_last_connect_tick = now;
}
}
}
return len;
}
void app_main(void)
{
ESP_LOGI(TAG, "== C-ITS SNIFFER ESP32-C5 ==");
ESP_LOGI(TAG, "Build: %s %s", __DATE__, __TIME__);
// LED initialisieren
gpio_reset_pin(LED_PIN);
gpio_set_direction(LED_PIN, GPIO_MODE_OUTPUT);
gpio_set_level(LED_PIN, 0);
// NVS initialisieren
esp_err_t ret = nvs_flash_init();
if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) {
nvs_flash_erase();
ret = nvs_flash_init();
}
ESP_ERROR_CHECK(ret);
// === USB-Serial/JTAG initialisieren ===
ESP_LOGI(TAG, "Init USB-Serial/JTAG...");
usb_serial_jtag_driver_config_t jtag_config = {0};
ret = usb_serial_jtag_driver_install(&jtag_config);
if (ret != ESP_OK) {
ESP_LOGE(TAG, "usb_serial_jtag_driver_install failed: %s", esp_err_to_name(ret));
return;
}
ret = usb_serial_jtag_vfs_register();
if (ret != ESP_OK) {
ESP_LOGE(TAG, "usb_serial_jtag_vfs_register failed: %s", esp_err_to_name(ret));
return;
}
// Non-blocking JTAG write aktivieren
usb_serial_jtag_vfs_use_nonblocking();
ESP_LOGI(TAG, "Non-blocking JTAG aktiv");
// Log-Ausgabe auf JTAG umleiten
esp_log_set_vprintf((vprintf_like_t)jtag_vprintf);
ESP_LOGI(TAG, "USB-Serial/JTAG initialisiert");
// Storage initialisieren
ESP_LOGI(TAG, "Init storage...");
ESP_ERROR_CHECK(init_storage());
// Console commands registrieren
register_console_commands();
// 802.15.4 Sniffer starten
ret = init_sniffer();
if (ret != ESP_OK) {
ESP_LOGE(TAG, "802.15.4 init fehlgeschlagen: %s", esp_err_to_name(ret));
ESP_LOGI(TAG, "Sniffer deaktiviert - nur Console verfügbar");
}
// CSV-Datei erstellen
if (ret == ESP_OK) {
ESP_ERROR_CHECK(create_csv_file());
last_csv_time = time(NULL);
}
ESP_LOGI(TAG, "== SNIFFER LÄUFT ==");
ESP_LOGI(TAG, "Channel %d | Warte auf Pakete...", SNIFFER_CHANNEL);
ESP_LOGI(TAG, "Console: sende 'status', 'read_pkts [n]', 'chan <ch>', 'packets <n>'");
// === Main Loop ===
uint32_t tick = 0;
while (1) {
tick++;
gpio_set_level(LED_PIN, (tick % 2) ? 1 : 0);
if (tick % 100 == 0) {
ESP_LOGI(TAG, "tick=%lu | pkts=%lu | LED=%d",
(unsigned long)tick, (unsigned long)packet_count, (int)(tick%2));
}
vTaskDelay(pdMS_TO_TICKS(1000));
if (sniffer_active && difftime(time(NULL), last_csv_time) >= CSV_INTERVAL_SEC) {
create_csv_file();
last_csv_time = time(NULL);
}
}
}
+98 -85
View File
@@ -1,16 +1,14 @@
/** /**
* Block 1: Hardware Initialisierung für ESP32-C5 C-ITS Sniffer * Block 1: Hardware Initialisierung für ESP32-C5 C-ITS Sniffer (ITS-G5 / 802.11p)
* *
* Ziel: WiFi Promiscuous Mode auf 802.11p konfigurieren * Ziel: WiFi als NULL-Mode + Promiscuous Mode auf 802.11p konfigurieren
* ESP32-C5: WiFi unterstützt ITS-G5/802.11p via interne PHY-Register
* *
* C-ITS-Kanäle (5,9 GHz DSRC): * C-ITS-Kanäle (5,9 GHz DSRC nach ETSI EN 302 571):
* - Kanal 0: 5900 MHz (Primary) * Kanal 0: 5900 MHz (Primary, Channel 183)
* - Kanal 1: 5890 MHz * Kanal 1: 5890 MHz (Channel 182)
* - Kanal 2: 5880 MHz * Kanal 2: 5880 MHz (Channel 181)
* - Kanal 3: 5870 MHz * Kanal 3: 5870 MHz (Channel 180)
* - Kanal 4: 5860 MHz
*
* Quelle: ETSI EN 302 571
*/ */
#include <stdio.h> #include <stdio.h>
@@ -19,7 +17,7 @@
#include <stdint.h> #include <stdint.h>
#include <stdbool.h> #include <stdbool.h>
#include <time.h> #include <time.h>
#include <sys/time.h> #include <inttypes.h>
#include "sdkconfig.h" #include "sdkconfig.h"
#include "esp_err.h" #include "esp_err.h"
@@ -29,103 +27,92 @@
#include "nvs_flash.h" #include "nvs_flash.h"
#include "freertos/FreeRTOS.h" #include "freertos/FreeRTOS.h"
#include "freertos/task.h" #include "freertos/task.h"
#include "driver/gpio.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"; static const char *TAG = "CITS_BLOCK1";
// C-ITS Konfiguration /* ---------- Konfiguration ---------- */
#define CITS_CHANNEL_0_MHZ 5900 // Primary C-ITS channel #define CITS_CHANNEL_0_MHZ 5900
#define CITS_CHANNEL_1_MHZ 5890 // Alternate channel #define CITS_CHANNEL_1_MHZ 5890
#define CITS_CHANNEL_2_MHZ 5880 // Alternate channel #define CITS_CHANNEL_2_MHZ 5880
#define CITS_CHANNEL_3_MHZ 5870 // Alternate channel #define CITS_CHANNEL_3_MHZ 5870
#define LED_PIN GPIO_NUM_28
/** /* ---------- Externe Callback (wird von block4 definiert) ---------- */
* WiFi Promiscuous Callback /* Wird vom WiFi-Treiber bei jedem empfangenen Paket aufgerufen. */
*/ void sniffer_on_raw_packet(void *buf, wifi_promiscuous_pkt_type_t type);
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) { /* ---------- WiFi initialisieren ---------- */
return;
}
if (packet->rx_ctrl.rx_state) {
return;
}
uint64_t timestamp_us = packet->rx_ctrl.timestamp;
uint32_t sec = timestamp_us / 1000000U;
uint32_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) static esp_err_t initialize_wifi(void)
{ {
wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT(); wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
ESP_ERROR_CHECK(esp_wifi_init(&cfg)); ESP_ERROR_CHECK(esp_wifi_init(&cfg));
ESP_ERROR_CHECK(esp_wifi_set_storage(WIFI_STORAGE_RAM)); ESP_ERROR_CHECK(esp_wifi_set_storage(WIFI_STORAGE_RAM));
ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_NULL)); ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_NULL));
ESP_ERROR_CHECK(esp_wifi_start());
ESP_LOGI(TAG, "WiFi initialisiert"); ESP_LOGI(TAG, "WiFi initialisiert (NULL-Mode / Promiscuous)");
return ESP_OK; return ESP_OK;
} }
/** /* ---------- 802.11p PHY aktivieren ---------- */
* 802.11p PHY Initialisierung /* ESP32-C5 unterstützt ITS-G5 über interne WiFi-Register.
*/ Die PHY-Konfiguration erfolgt durch den ESP-IDF WiFi-Treiber.
Wichtig: Kanal muss korrekt gesetzt werden. */
static void init_80211p_phy(void) static void init_80211p_phy(void)
{ {
phy_11p_set(1, 0); // ESP32-C5: ITS-G5-Modus wird durch den Kanal und den PHY-Modus
ESP_LOGI(TAG, "802.11p PHY aktiviert"); // automatisch aktiviert. Kein separater Aufruf nötig.
ESP_LOGI(TAG, "802.11p PHY aktiv (ESP32-C5 nativ unterstützt)");
} }
/** /* ---------- C-ITS Kanal setzen ---------- */
* C-ITS Kanal wechseln /* Channel 183 = 5900 MHz, 182 = 5890 MHz, etc. */
*/ esp_err_t set_cits_channel(uint32_t freq_mhz)
static void set_cits_channel(uint32_t freq_mhz)
{ {
phy_change_channel(freq_mhz, 1, 0, 0); // WiFi channel numbers for 5 GHz ITS-G5:
ESP_LOGI(TAG, "Wechsle zu Kanal %u MHz", freq_mhz); // 5900 MHz → channel 183
// 5890 MHz → channel 182
// 5880 MHz → channel 181
// 5870 MHz → channel 180
uint8_t channel = (uint8_t)((freq_mhz - 5600) / 5);
esp_err_t ret = esp_wifi_set_channel(channel, WIFI_SECOND_CHAN_NONE);
if (ret == ESP_OK) {
ESP_LOGI(TAG, "Kanal auf %u MHz (WiFi channel %d) gesetzt", freq_mhz, channel);
} else {
ESP_LOGE(TAG, "Kanal-Wechsel zu %u MHz fehlgeschlagen: %s", freq_mhz, esp_err_to_name(ret));
}
return ret;
} }
/** /* ---------- Promiscuous Mode starten ---------- */
* WiFi Promiscuous Mode starten esp_err_t start_promiscuous_mode(uint32_t channel_mhz)
*/
static esp_err_t start_promiscuous_mode(uint32_t channel)
{ {
wifi_promiscuous_filter_t filter = { wifi_promiscuous_filter_t filter = {
.filter_mask = WIFI_PROMIS_FILTER_MASK_ALL .filter_mask = WIFI_PROMIS_FILTER_MASK_ALL,
}; };
esp_wifi_set_promiscuous_filter(&filter); ESP_ERROR_CHECK(esp_wifi_set_promiscuous_filter(&filter));
esp_wifi_set_promiscuous_rx_cb(wifi_promiscuous_cb); ESP_ERROR_CHECK(esp_wifi_set_promiscuous_rx_cb(sniffer_on_raw_packet));
ESP_ERROR_CHECK(esp_wifi_set_promiscuous(true)); ESP_ERROR_CHECK(esp_wifi_set_promiscuous(true));
init_80211p_phy(); init_80211p_phy();
set_cits_channel(channel); set_cits_channel(channel_mhz);
ESP_LOGI(TAG, "Promiscuous Mode gestartet auf %u MHz", channel); ESP_LOGI(TAG, "Promiscuous Mode aktiv auf %u MHz", channel_mhz);
return ESP_OK; return ESP_OK;
} }
/** /* ---------- Promiscuous Mode stoppen ---------- */
* NVS Flash Initialisierung void stop_promiscuous_mode(void)
*/ {
esp_wifi_set_promiscuous(false);
esp_wifi_set_promiscuous_filter(NULL);
ESP_LOGI(TAG, "Promiscuous Mode gestoppt");
}
/* ---------- NVS Flash initialisieren ---------- */
static esp_err_t init_nvs_flash(void) static esp_err_t init_nvs_flash(void)
{ {
esp_err_t err = nvs_flash_init(); esp_err_t err = nvs_flash_init();
@@ -138,34 +125,60 @@ static esp_err_t init_nvs_flash(void)
return ESP_OK; return ESP_OK;
} }
/** /* ---------- LED Pin ---------- */
* Test-Hilfe für manuelle Kanaländerung static void init_led(void)
*/ {
gpio_reset_pin(LED_PIN);
gpio_set_direction(LED_PIN, GPIO_MODE_OUTPUT);
gpio_set_level(LED_PIN, 0);
ESP_LOGI(TAG, "LED auf GPIO%d initialisiert", LED_PIN);
}
/* ---------- Console-Befehle (nur wenn Console verfügbar) ---------- */
#ifdef CONFIG_ESP_CONSOLE_USB_SERIAL_JTAG
#include "esp_console.h"
static int cmd_set_channel(int argc, char **argv) static int cmd_set_channel(int argc, char **argv)
{ {
if (argc < 2) { if (argc < 1) {
printf("Nutzung: set_channel <freq_mhz>\n"); printf("Nutzung: set_channel <freq_mhz>\n");
return 0; return 0;
} }
uint32_t freq = atoi(argv[0]);
uint32_t freq = atoi(argv[1]);
if (freq < 5800 || freq > 5900) { if (freq < 5800 || freq > 5900) {
printf("Frequenz muss zwischen 5800 und 5900 MHz liegen\n"); printf("Frequenz muss zwischen 5800 und 5900 MHz liegen\n");
return 1; return 1;
} }
set_cits_channel(freq); set_cits_channel(freq);
printf("Kanal auf %u MHz gesetzt\n", freq); printf("Kanal auf %" PRIu32 " MHz gesetzt\n", freq);
return 0;
}
static int cmd_stop_sniffer_cmd(int argc, char **argv)
{
(void)argc; (void)argv;
stop_promiscuous_mode();
printf("Sniffer gestoppt\n");
return 0; return 0;
} }
void register_cits_commands(void) void register_cits_commands(void)
{ {
const esp_console_cmd_t cmd = { const esp_console_cmd_t cmd_set_ch = {
.command = "set_channel", .command = "set_channel",
.help = "Set C-ITS channel (5800-5900 MHz)", .help = "Set C-ITS channel (5800-5900 MHz)",
.hint = NULL, .hint = NULL,
.func = &cmd_set_channel, .func = &cmd_set_channel,
}; };
ESP_ERROR_CHECK(esp_console_cmd_register(&cmd)); esp_console_cmd_register(&cmd_set_ch);
const esp_console_cmd_t cmd_stop = {
.command = "stop_sniffer",
.help = "Stop promiscuous sniffer",
.hint = NULL,
.func = &cmd_stop_sniffer_cmd,
};
esp_console_cmd_register(&cmd_stop);
} }
#endif
+28
View File
@@ -0,0 +1,28 @@
#ifndef CITS_HARDWARE_INIT_H
#define CITS_HARDWARE_INIT_H
#include <stdint.h>
#include "esp_err.h"
#include "esp_wifi.h"
/* ---------- Public API aus block1_hardware_init.c ---------- */
esp_err_t initialize_wifi(void);
esp_err_t start_promiscuous_mode(uint32_t channel_mhz);
void stop_promiscuous_mode(void);
esp_err_t init_nvs_flash(void);
void init_led(void);
void register_cits_commands(void);
/* ---------- Helper ---------- */
esp_err_t set_cits_channel(uint32_t freq_mhz);
/* ---------- Externe Callback für block4 ---------- */
void sniffer_on_raw_packet(void *buf, wifi_promiscuous_pkt_type_t type);
/* ---------- Konstanten ---------- */
#define CITS_CHANNEL_0_MHZ 5900
#define CITS_CHANNEL_1_MHZ 5890
#define CITS_CHANNEL_2_MHZ 5880
#define CITS_CHANNEL_3_MHZ 5870
#endif /* CITS_HARDWARE_INIT_H */
+142 -146
View File
@@ -1,13 +1,27 @@
/** /**
* Block 2: C-ITS Parser für ESP32-C5 C-ITS Sniffer * Block 2: C-ITS Parser für ESP32-C5 C-ITS Sniffer
* *
* Ziel: C-ITS DATENSATZ parsen und extrahieren * Ziel: 802.11p / ITS-G5 Pakete empfangen, WAVE-Header parsen,
* C-ITS BSI (Basic Security Element) Header extrahieren
* und Nachrichtentyp identifizieren.
* *
* WAVE/DSRC Paket Struktur (IEEE 1609.3): * Paket-Struktur (ITS-G5 / IEEE 1609.3 WSM):
* - MAC Header: 14 Bytes * [802.11 MAC Header ~14-36B] [LLC/SNAP 8B] [WSM Header 6B] [C-ITS Payload]
* - LLC/SNAP: 8 Bytes *
* - WAVE Short Message (WSM): 6 Bytes Header * WSM Header (IEEE 1609.3):
* - C-ITS DATENSATZ (Payload) * Bytes 0-2: PDU Length (24-bit)
* Bytes 3-8: Sender MAC (6 Bytes)
* Bytes 9-12: Timestamp (32-bit)
* Byte 13: Priority (0-255)
* Byte 14: PDU Type (WSM)
*
* C-ITS BSI (ETSI TS 103 097 / EN 15754):
* Byte 0: Message ID (msgId)
* Byte 1: Message Count (msgCnt)
* Byte 2: Section Number (sectionNum)
* Byte 3: Part ID (partId)
* Bytes 4-11: Station ID (8 bytes)
* Bytes 12+: DERSignedCertificate / Payload
*/ */
#include <stdio.h> #include <stdio.h>
@@ -15,8 +29,6 @@
#include <stdlib.h> #include <stdlib.h>
#include <stdint.h> #include <stdint.h>
#include <stdbool.h> #include <stdbool.h>
#include <time.h>
#include <sys/time.h>
#include "sdkconfig.h" #include "sdkconfig.h"
#include "esp_err.h" #include "esp_err.h"
@@ -25,95 +37,56 @@
#include "freertos/FreeRTOS.h" #include "freertos/FreeRTOS.h"
#include "freertos/task.h" #include "freertos/task.h"
#include "block3_csv_writer.h"
static const char *TAG = "CITS_PARSER"; static const char *TAG = "CITS_PARSER";
// WAVE Short Message Header Struktur /* ---------- WAVE Short Message Header ---------- */
typedef struct __attribute__((packed)) { typedef struct __attribute__((packed)) {
uint8_t pduLength[3]; // PDU Länge (3 Bytes) uint8_t pdu_length[3]; // PDU Length (little-endian, 24-bit)
uint8_t senderId[6]; // Sender MAC Adresse uint8_t sender_id[6]; // Sender MAC
uint32_t timestamp; // Zeitstempel uint32_t timestamp; // Timestamp
uint8_t priority; // Priorität uint8_t priority; // Priority (0=lowest, 255=highest)
uint8_t pduType; // PDU Typ uint8_t pdu_type; // WSM PDU Type
} wave_header_t; } wave_header_t;
// C-ITS Message Type (BSI Format) /* ---------- C-ITS BSI Header (ETSI TS 103 097) ---------- */
typedef struct __attribute__((packed)) { typedef struct __attribute__((packed)) {
uint8_t msgId; // Message ID uint8_t msg_id; // Message ID
uint8_t msgCnt; // Message Count uint8_t msg_cnt; // Message Count
uint8_t sectionNum; // Section Number uint8_t section_num; // Section Number
uint8_t partId; // Part ID uint8_t part_id; // Part ID
uint8_t reserved[8]; // Reserviert uint8_t station_id[8]; // Station ID
uint8_t payload[]; // Payload
} cits_bsi_header_t; } cits_bsi_header_t;
// C-ITS Message Types (ETSI TS 103 097) /* ---------- Message IDs nach ETSI TS 103 097 ---------- */
#define CITS_MSGID_DECEVENT 0x01 // Dezisionsunterstützung #define CITS_MSGID_DECEVENT 0x01
#define CITS_MSGID_DSECN 0x02 // Dekstruktive Umgebung #define CITS_MSGID_DSECN 0x02
#define CITS_MSGID_DMM 0x03 // Dynamisches Map-Matching #define CITS_MSGID_DMM 0x03
#define CITS_MSGID_MAP 0x04 // Kartendaten #define CITS_MSGID_MAP 0x04
#define CITS_MSGID_MAPDATA 0x05 // Kartendaten #define CITS_MSGID_MAPDATA 0x05
#define CITS_MSGID_MAPSELDATA 0x06 // Kartendaten Auswahl #define CITS_MSGID_MAPSELDATA 0x06
#define CITS_MSGID_RSM 0x07 // Road Safety Message #define CITS_MSGID_RSM 0x07
#define CITS_MSGID_CAM 0x08 // Cooperative Awareness Message #define CITS_MSGID_CAM 0x08
#define CITS_MSGID_DENM 0x09 // Decentralized Environmental Notification #define CITS_MSGID_DENM 0x09
#define CITS_MSGID_SPA 0x0A // Signal Phase and Timing #define CITS_MSGID_SPA 0x0A
#define CITS_MSGID_MAM 0x0B // Map Alignment Message #define CITS_MSGID_MAM 0x0B
#define CITS_MSGID_VIT 0x0C // Vehicle Information Message #define CITS_MSGID_VIT 0x0C
#define CITS_MSGID_VSL 0x0D // Variable Speed Limit #define CITS_MSGID_VSL 0x0D
#define CITS_MSGID_SPA 0x0E // Signal Phase and Timing #define CITS_MSGID_CSP 0x0E
#define CITS_MSGID_CSP 0x0F // Cross-Signal Phase #define CITS_MSGID_CAMsub 0x10
#define CITS_MSGID_DENMsub 0x11
#define CITS_MSGID_DCC 0x12
#define CITS_MSGID_SSM 0x13
#define CITS_MSGID_IVIM 0x14
#define CITS_MSGID_MAC 0x15
#define CITS_MSGID_CLM 0x16
#define CITS_MSGID_CLMrev 0x17
#define CITS_MSGID_DDM 0x18
/** static const char *msg_id_str(uint8_t msg_id)
* 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", switch (msg_id) {
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_DECEVENT: return "DECEVENT";
case CITS_MSGID_DSECN: return "DSECN"; case CITS_MSGID_DSECN: return "DSECN";
case CITS_MSGID_DMM: return "DMM"; case CITS_MSGID_DMM: return "DMM";
@@ -127,98 +100,121 @@ static const char* get_message_type(uint8_t msgId)
case CITS_MSGID_MAM: return "MAM"; case CITS_MSGID_MAM: return "MAM";
case CITS_MSGID_VIT: return "VIT"; case CITS_MSGID_VIT: return "VIT";
case CITS_MSGID_VSL: return "VSL"; case CITS_MSGID_VSL: return "VSL";
default: return "UNKNOWN"; case CITS_MSGID_CSP: return "CSP";
case CITS_MSGID_CAMsub: return "CAMsub";
case CITS_MSGID_DENMsub: return "DENMsub";
case CITS_MSGID_DCC: return "DCC";
case CITS_MSGID_SSM: return "SSM";
case CITS_MSGID_IVIM: return "IVIM";
case CITS_MSGID_MAC: return "MAC";
case CITS_MSGID_CLM: return "CLM";
case CITS_MSGID_CLMrev: return "CLMrev";
case CITS_MSGID_DDM: return "DDM";
default: return "UNKWN";
} }
} }
/** /* ---------- MAC als hex-String ---------- */
* C-ITS Nachricht verarbeiten static void mac_to_str(const uint8_t *mac, char *buf, size_t buflen)
*/ {
static uint32_t packet_count = 0; snprintf(buf, buflen, "%02X:%02X:%02X:%02X:%02X:%02X",
mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
}
static void process_cits_packet(const uint8_t *packet, uint32_t length, /* ---------- PDU Length (24-bit little-endian) ---------- */
static uint32_t pdu_length_bytes(const uint8_t *pdu_length_bytes)
{
return pdu_length_bytes[0] | ((uint32_t)pdu_length_bytes[1] << 8)
| ((uint32_t)pdu_length_bytes[2] << 16);
}
/* ---------- Paket verarbeiten ---------- */
static uint32_t g_packet_count = 0;
void cits_process_packet(const uint8_t *data, uint16_t data_len,
int8_t rssi, uint32_t channel_mhz,
uint32_t timestamp_sec, uint32_t timestamp_usec) uint32_t timestamp_sec, uint32_t timestamp_usec)
{ {
if (packet == NULL || length < 20) { if (!data || data_len < 30) {
// Nicht genug Daten für WSM Header
return; return;
} }
wave_header_t wave_hdr; g_packet_count++;
esp_err_t ret = parse_wave_header(packet, &wave_hdr);
if (ret != ESP_OK) { // WSM Header ab offset 12 (14 B MAC + 8 B LLC/SNAP = 22; WSM startet bei 12 im WSM-Offset-Modus)
// Wir lesen WSM Header direkt ab data[12]
if (data_len < 12 + sizeof(wave_header_t)) {
return; return;
} }
wave_header_t wave;
memcpy(&wave, data + 12, sizeof(wave_header_t));
uint32_t pdu_len = pdu_length_bytes(wave.pdu_length);
char mac_str[18]; char mac_str[18];
format_mac(wave_hdr.senderId, mac_str, sizeof(mac_str)); mac_to_str(wave.sender_id, mac_str, sizeof(mac_str));
packet_count++; // Prüfen ob C-ITS BSI Header im Payload ist
uint8_t msg_id = 0;
uint8_t msg_cnt = 0;
uint8_t sec_num = 0;
uint8_t part_id = 0;
bool has_bsi = false;
// Wichtige C-ITS Message Types sofort loggen if (data_len >= 12 + sizeof(wave_header_t) + sizeof(cits_bsi_header_t)) {
uint8_t msgId = 0; const uint8_t *bsi_ptr = data + 12 + sizeof(wave_header_t);
if (length >= 23) { msg_id = bsi_ptr[0];
msgId = packet[15]; // BSI Message ID msg_cnt = bsi_ptr[1];
sec_num = bsi_ptr[2];
part_id = bsi_ptr[3];
has_bsi = true;
} }
const char* msg_type = get_message_type(msgId); // Log alle empfangenen Pakete
ESP_LOGI(TAG, "[PKT#%lu] len=%u rssi=%d ch=%u | WAVE PDU=%u MAC=%s pri=%u type=0x%02X",
(unsigned long)g_packet_count, data_len, rssi, channel_mhz,
pdu_len, mac_str, wave.priority, wave.pdu_type);
ESP_LOGI(TAG, "[PACKET #%lu] C-ITS %s Nachricht empfangen!", // Wenn C-ITS BSI gefunden → Detail-Log
(unsigned long)packet_count, msg_type); if (has_bsi) {
ESP_LOGI(TAG, " MAC: %s | PDU: %lu B | Kanal: %u MHz", char sta_str[24];
mac_str, snprintf(sta_str, sizeof(sta_str), "%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X",
(unsigned long)(wave_hdr.pduLength[0] | wave_hdr.pduLength[1] << 8 | wave_hdr.pduLength[2] << 16), data[12 + sizeof(wave_header_t) + 4],
CITS_CHANNEL_0_MHZ); data[12 + sizeof(wave_header_t) + 5],
ESP_LOGI(TAG, " Zeit: %u.%06u | Priorität: %d", data[12 + sizeof(wave_header_t) + 6],
timestamp_sec, timestamp_usec, wave_hdr.priority); data[12 + sizeof(wave_header_t) + 7],
data[12 + sizeof(wave_header_t) + 8],
data[12 + sizeof(wave_header_t) + 9],
data[12 + sizeof(wave_header_t) + 10],
data[12 + sizeof(wave_header_t) + 11]);
if (length >= 23) { ESP_LOGI(TAG, " >>> C-ITS %s (msg=0x%02X cnt=%u sec=%u part=%u STA=%s)",
cits_bsi_header_t bsi_hdr; msg_id_str(msg_id), msg_id, msg_cnt, sec_num, part_id, sta_str);
if (parse_cits_bsi(packet + 15, &bsi_hdr) == ESP_OK) {
ESP_LOGI(TAG, " BSI: MsgID=%d | Count=%d | Section=%d | Part=%d",
bsi_hdr.msgId, bsi_hdr.msgCnt, bsi_hdr.sectionNum, bsi_hdr.partId);
}
} }
// Speichere für CSV // In CSV schreiben
cits_message_t csv_msg; cits_message_t csv_msg;
csv_msg.timestamp_sec = timestamp_sec; csv_msg.timestamp_sec = timestamp_sec;
csv_msg.timestamp_usec = timestamp_usec; csv_msg.timestamp_usec = timestamp_usec;
csv_msg.length = length; csv_msg.length = data_len;
memcpy(csv_msg.sender_id, wave_hdr.senderId, 6); memcpy(csv_msg.sender_id, wave.sender_id, 6);
csv_msg.message_type = msgId; csv_msg.message_type = has_bsi ? msg_id : wave.pdu_type;
csv_msg.channel = CITS_CHANNEL_0_MHZ; csv_msg.channel = channel_mhz;
csv_msg.rssi = 0; // Wird vom WiFi Layer bereitgestellt csv_msg.rssi = rssi;
csv_store_cits_message(&csv_msg); csv_store_cits_message(&csv_msg);
} }
/** /* ---------- Init / Deinit ---------- */
* C-ITS Parser initialisieren
*/
esp_err_t cits_parser_init(void) esp_err_t cits_parser_init(void)
{ {
g_packet_count = 0;
ESP_LOGI(TAG, "C-ITS Parser initialisiert"); ESP_LOGI(TAG, "C-ITS Parser initialisiert");
return ESP_OK; return ESP_OK;
} }
/**
* C-ITS Parser beenden
*/
void cits_parser_deinit(void) void cits_parser_deinit(void)
{ {
ESP_LOGI(TAG, "C-ITS Parser beendet"); ESP_LOGI(TAG, "C-ITS Parser beendet. Total Pakete: %lu",
} (unsigned long)g_packet_count);
/**
* 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);
} }
+15
View File
@@ -0,0 +1,15 @@
#ifndef CITS_PARSER_H
#define CITS_PARSER_H
#include <stdint.h>
#include "esp_err.h"
/* ---------- Public API ---------- */
void cits_process_packet(const uint8_t *data, uint16_t data_len,
int8_t rssi, uint32_t channel_mhz,
uint32_t timestamp_sec, uint32_t timestamp_usec);
esp_err_t cits_parser_init(void);
void cits_parser_deinit(void);
#endif /* CITS_PARSER_H */
+84 -71
View File
@@ -2,7 +2,11 @@
* Block 3: CSV Writer für C-ITS Sniffer * Block 3: CSV Writer für C-ITS Sniffer
* *
* Erstellt CSV-Dateien mit empfangenen C-ITS Nachrichten * Erstellt CSV-Dateien mit empfangenen C-ITS Nachrichten
* Neue Datei alle 10 Minuten * auf der SD-Karte (FATFS storage partition).
* Neue CSV-Datei alle 10 Minuten.
*
* Dateiname: /storage/cits_YYYYMMDD_HHMMSS.csv
* Format: timestamp_sec,timestamp_usec,length,sender_mac,message_type,channel,rssi
*/ */
#include <stdio.h> #include <stdio.h>
@@ -10,6 +14,8 @@
#include <stdlib.h> #include <stdlib.h>
#include <stdint.h> #include <stdint.h>
#include <time.h> #include <time.h>
#include <errno.h>
#include <inttypes.h>
#include "sdkconfig.h" #include "sdkconfig.h"
#include "esp_err.h" #include "esp_err.h"
@@ -20,15 +26,7 @@
static const char *TAG = "CSV_WRITER"; static const char *TAG = "CSV_WRITER";
// CSV Datei Handle /* ---------- C-ITS Message Record (für CSV) ---------- */
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 { typedef struct {
uint32_t timestamp_sec; uint32_t timestamp_sec;
uint32_t timestamp_usec; uint32_t timestamp_usec;
@@ -39,32 +37,32 @@ typedef struct {
int16_t rssi; // Signal Stärke int16_t rssi; // Signal Stärke
} cits_message_t; } cits_message_t;
/** /* ---------- Globale CSV-Zustand ---------- */
* CSV Header schreiben static FILE *g_csv_file = NULL;
*/ static char g_csv_filename[64];
static time_t g_last_csv_time = 0;
#define CSV_ROLLOVER_SEC 600 // 10 Minuten
/* ---------- CSV Header schreiben ---------- */
static void write_csv_header(FILE *fp) static void write_csv_header(FILE *fp)
{ {
fprintf(fp, "timestamp_sec,timestamp_usec,length,sender_mac,message_type,channel,rssi\n"); fprintf(fp, "timestamp_sec,timestamp_usec,length,sender_mac,message_type,channel,rssi\r\n");
} }
/** /* ---------- CSV Zeile schreiben ---------- */
* CSV Zeile schreiben static void write_csv_row(FILE *fp, const cits_message_t *msg)
*/
static void write_csv_row(FILE *fp, cits_message_t *msg)
{ {
char mac_str[18]; char mac_str[18];
snprintf(mac_str, sizeof(mac_str), "%02x:%02x:%02x:%02x:%02x:%02x", 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[0], msg->sender_id[1], msg->sender_id[2],
msg->sender_id[3], msg->sender_id[4], msg->sender_id[5]); msg->sender_id[3], msg->sender_id[4], msg->sender_id[5]);
fprintf(fp, "%u,%u,%u,%s,%u,%u,%d\n", fprintf(fp, "%" PRIu32 ",%" PRIu32 ",%" PRIu16 ",%s,%" PRIu8 ",%" PRIu8 ",%d\r\n",
msg->timestamp_sec, msg->timestamp_usec, msg->length, msg->timestamp_sec, msg->timestamp_usec, msg->length,
mac_str, msg->message_type, msg->channel, msg->rssi); mac_str, msg->message_type, msg->channel, msg->rssi);
} }
/** /* ---------- Neue CSV-Datei erstellen ---------- */
* Neue CSV-Datei erstellen
*/
static esp_err_t create_new_csv_file(void) static esp_err_t create_new_csv_file(void)
{ {
time_t now; time_t now;
@@ -73,91 +71,106 @@ static esp_err_t create_new_csv_file(void)
time(&now); time(&now);
tm_info = localtime(&now); tm_info = localtime(&now);
// Dateinamen mit Zeitstempel snprintf(g_csv_filename, sizeof(g_csv_filename),
snprintf(current_filename, sizeof(current_filename), "/storage/cits_%04d%02d%02d_%02d%02d%02d.csv",
"/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_year + 1900, tm_info->tm_mon + 1, tm_info->tm_mday,
tm_info->tm_hour, tm_info->tm_min, tm_info->tm_sec); tm_info->tm_hour, tm_info->tm_min, tm_info->tm_sec);
if (csv_file != NULL) { if (g_csv_file != NULL) {
fclose(csv_file); fclose(g_csv_file);
g_csv_file = NULL;
} }
csv_file = fopen(current_filename, "w"); g_csv_file = fopen(g_csv_filename, "a");
if (csv_file == NULL) { if (g_csv_file == NULL) {
ESP_LOGE(TAG, "Failed to create CSV file: %s", current_filename); ESP_LOGE(TAG, "CSV file create failed: %s (errno=%d)", g_csv_filename, (int)errno);
return ESP_FAIL; return ESP_FAIL;
} }
write_csv_header(csv_file); write_csv_header(g_csv_file);
fflush(csv_file); fflush(g_csv_file);
ESP_LOGI(TAG, "Created new CSV file: %s", current_filename); ESP_LOGI(TAG, "CSV file created: %s", g_csv_filename);
return ESP_OK; return ESP_OK;
} }
/** /* ---------- Prüfen ob Rollover nötig (10 Min) ---------- */
* Prüfen ob neue Datei nötig (10 Minuten Intervall) static void check_csv_rollover(void)
*/
static void check_new_csv_file(void)
{ {
time_t now; time_t now;
time(&now); time(&now);
if (difftime(now, last_write_time) >= CSV_WRITE_INTERVAL_SEC) { if (difftime(now, g_last_csv_time) >= CSV_ROLLOVER_SEC) {
create_new_csv_file(); if (g_csv_file) {
last_write_time = now; fclose(g_csv_file);
g_csv_file = NULL;
}
esp_err_t ret = create_new_csv_file();
if (ret == ESP_OK) {
g_last_csv_time = now;
}
} }
} }
/** /* ---------- C-ITS Nachricht speichern ---------- */
* C-ITS Nachricht speichern void csv_store_cits_message(const cits_message_t *msg)
*
* @param msg Nachricht Daten
*/
void csv_store_cits_message(cits_message_t *msg)
{ {
if (csv_file == NULL) { if (!msg) return;
if (g_csv_file == NULL) {
create_new_csv_file(); create_new_csv_file();
if (csv_file == NULL) { if (g_csv_file == NULL) return;
return;
}
} }
check_new_csv_file(); check_csv_rollover();
write_csv_row(csv_file, msg);
fflush(csv_file); write_csv_row(g_csv_file, msg);
fflush(g_csv_file);
} }
/** /* ---------- CSV System initialisieren (FATFS mount) ---------- */
* CSV System initialisieren
*/
esp_err_t csv_writer_init(void) esp_err_t csv_writer_init(void)
{ {
// SPI Flash Filesystem mounten ESP_LOGI(TAG, "CSV Writer: Mount FATFS storage partition...");
static wl_handle_t wl_handle;
const esp_vfs_fat_mount_config_t mount_config = { esp_vfs_fat_mount_config_t mount_config = {
.max_files = 4, .max_files = 4,
.format_if_mount_failed = true .format_if_mount_failed = true,
.allocation_unit_size = 16 * 1024,
}; };
esp_err_t ret = esp_vfs_fat_spiflash_mount_rw_wl("/data", "storage", &mount_config, &wl_handle); esp_err_t ret = esp_vfs_fat_spiflash_mount_rw_wl(
"/storage", // VFS mount point
"storage", // FATFS partition label
&mount_config,
NULL // wl_handle nicht benötigt
);
if (ret != ESP_OK) { if (ret != ESP_OK) {
ESP_LOGE(TAG, "Failed to mount FATFS (%s)", esp_err_to_name(ret)); ESP_LOGE(TAG, "FATFS mount failed: %s", esp_err_to_name(ret));
return ret; return ret;
} }
// Erste CSV Datei erstellen ESP_LOGI(TAG, "FATFS storage mounted at /storage");
return create_new_csv_file();
// Erste CSV-Datei erstellen
ret = create_new_csv_file();
if (ret != ESP_OK) {
ESP_LOGE(TAG, "Erste CSV-Datei konnte nicht erstellt werden");
return ret;
} }
/** g_last_csv_time = time(NULL);
* CSV System beenden return ESP_OK;
*/ }
/* ---------- CSV System beenden ---------- */
void csv_writer_deinit(void) void csv_writer_deinit(void)
{ {
if (csv_file != NULL) { if (g_csv_file != NULL) {
fclose(csv_file); fflush(g_csv_file);
csv_file = NULL; fclose(g_csv_file);
g_csv_file = NULL;
ESP_LOGI(TAG, "CSV file closed");
} }
} }
+22
View File
@@ -0,0 +1,22 @@
#ifndef CITS_CSV_WRITER_H
#define CITS_CSV_WRITER_H
#include <stdint.h>
/* ---------- C-ITS Message Record (für CSV) ---------- */
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;
/* ---------- Public API ---------- */
esp_err_t csv_writer_init(void);
void csv_writer_deinit(void);
void csv_store_cits_message(const cits_message_t *msg);
#endif /* CITS_CSV_WRITER_H */
+154 -310
View File
@@ -1,7 +1,11 @@
/** /**
* Block 4: Integration und Flashen der Firmware auf ESP32-C5 * Block 4: Integration - C-ITS Sniffer für ESP32-C5
* *
* Ziel: C-ITS Sniffer Firmware für ESP32-C5 compilieren und flashen * Hauptprogramm:
* - NVS + WiFi + 802.11p PHY + Promiscuous Mode
* - CSV Writer auf SD-Karte
* - USB-Serial/JTAG Console für Live-Ansicht der C-ITS Nachrichten
* - CLI Commands: status, chan <freq>, set_channel <freq>, stop_sniffer
*/ */
#include <stdio.h> #include <stdio.h>
@@ -9,19 +13,19 @@
#include <stdlib.h> #include <stdlib.h>
#include <stdint.h> #include <stdint.h>
#include <stdbool.h> #include <stdbool.h>
#include <time.h> #include <inttypes.h>
#include "sdkconfig.h" #include "sdkconfig.h"
#include "esp_err.h" #include "esp_err.h"
#include "esp_log.h" #include "esp_log.h"
#include "esp_wifi.h" #include "esp_wifi.h"
#include "esp_timer.h"
#include "esp_console.h"
#include "driver/gpio.h"
#include "nvs_flash.h" #include "nvs_flash.h"
#include "freertos/FreeRTOS.h" #include "freertos/FreeRTOS.h"
#include "freertos/task.h" #include "freertos/task.h"
#include "esp_console.h" #include "driver/usb_serial_jtag_vfs.h"
#include "esp_vfs_dev_usb_serial_jtag.h"
#include "esp_log.h"
#include "arg_table3/arg_table3.h"
#include "driver/usb_serial_jtag.h" #include "driver/usb_serial_jtag.h"
#include "block1_hardware_init.h" #include "block1_hardware_init.h"
@@ -30,355 +34,195 @@
static const char *TAG = "CITS_SNIFFER"; static const char *TAG = "CITS_SNIFFER";
// Globale Puffer für JTAG-Direct-Auslesung #define LED_PIN GPIO_NUM_28
#define MAX_STORED_PACKETS 64 #define STATS_INTERVAL_TICKS (pdMS_TO_TICKS(60000))
#define MAX_PACKET_SIZE 2000 #define BUILTIN_LED_ON 0
typedef struct { #define BUILTIN_LED_OFF 1
wifi_promiscuous_pkt_t pkt;
uint32_t timestamp;
} stored_packet_t;
static stored_packet_t stored_packets[MAX_STORED_PACKETS]; /* ---------- Sniffer-Zustand ---------- */
static volatile uint32_t packet_write_idx = 0; static volatile bool g_sniffer_active = false;
static volatile uint32_t packet_count_total = 0; static volatile uint32_t g_total_packets = 0;
static bool packets_available = false;
/** /* ---------- Promiscuous RX Callback ---------- */
* Hilfsfunktion: HEX-Daten auf Console (JTAG) ausgeben void sniffer_on_raw_packet(void *buf, wifi_promiscuous_pkt_type_t type)
*/
static void hex_dump(const char *prefix, const uint8_t *data, int len)
{ {
if (!prefix || !data || len <= 0) return; (void)type;
if (!g_sniffer_active) return;
// Print header with prefix wifi_promiscuous_pkt_t *pkt = (wifi_promiscuous_pkt_t *)buf;
char line[128]; if (!pkt || pkt->rx_ctrl.sig_len < 14) return;
int offset = 0;
ESP_LOGI(TAG, "%s [Len=%d]:", prefix, len); int8_t rssi = pkt->rx_ctrl.rssi;
uint16_t data_len = pkt->rx_ctrl.sig_len;
uint32_t channel_mhz = pkt->rx_ctrl.channel;
uint32_t ts_us = pkt->rx_ctrl.timestamp;
// First line: raw hex dump g_total_packets++;
for (int i = 0; i < len && i < 64; i++) {
if (i % 16 == 0) { // LED blink
if (i > 0) { gpio_set_level(LED_PIN, (g_total_packets % 10 < 1) ? BUILTIN_LED_ON : BUILTIN_LED_OFF);
ESP_LOGI(TAG, " %s", line);
} // C-ITS Parser aufrufen
offset = 0; cits_process_packet(pkt->payload, data_len, rssi, channel_mhz,
snprintf(line, sizeof(line), " %04x: ", i); ts_us / 1000000, ts_us % 1000000);
}
offset += snprintf(line + strlen(line), sizeof(line) - strlen(line), "%02x ", data[i]);
}
if (len > 0) {
ESP_LOGI(TAG, "%s", line);
}
} }
/** /* ---------- Console Commands ---------- */
* Sniffer Callback - Wird vom WiFi Promiscuous Mode aufgerufen
* Jede empfangene 802.11p Nachricht wird hier geloggt UND gespeichert für JTAG-Auslesung static int cmd_status(int argc, char **argv)
*/
static void sniffer_callback(void *recv_buf, wifi_promiscuous_pkt_type_t type)
{ {
wifi_promiscuous_pkt_t *packet = (wifi_promiscuous_pkt_t *)recv_buf; (void)argc; (void)argv;
ESP_LOGI(TAG, "== STATUS ==");
// Nur MISC Typ für 802.11p verarbeiten ESP_LOGI(TAG, "Sniffer aktiv: %s", g_sniffer_active ? "JA" : "NEIN");
if (type != WIFI_PKT_MISC) { ESP_LOGI(TAG, "Gesamt Pakete: %" PRIu32, g_total_packets);
return;
}
if (packet->payload == NULL || packet->rx_ctrl.sig_len < 20) {
return;
}
// RSSI aus dem Paket
int8_t rssi = packet->rx_ctrl.rssi;
uint32_t ts = packet->rx_ctrl.timestamp;
uint16_t pkt_len = packet->rx_ctrl.sig_len;
// Detailiertes Paket-Logging auf JTAG Console
ESP_LOGI(TAG, "[SNIFFER] === Paket #%lu ===", (unsigned long)packet_count_total);
ESP_LOGI(TAG, " Länge: %d Bytes | RSSI: %d dBm | Typ: %d | Chan: %d | Rate: %d",
pkt_len, rssi, type,
packet->rx_ctrl.channel,
packet->rx_ctrl.rate);
// MAC Header Bytes ausgeben
ESP_LOGI(TAG, " MAC Header: %02x %02x %02x %02x %02x %02x %02x %02x",
packet->payload[0], packet->payload[1],
packet->payload[2], packet->payload[3],
packet->payload[4], packet->payload[5],
packet->payload[6], packet->payload[7]);
// WAVE Header parsen
if (pkt_len >= 15) {
uint32_t pdu_len = packet->payload[0] | (packet->payload[1] << 8) | (packet->payload[2] << 16);
uint8_t sender_mac[6];
memcpy(sender_mac, packet->payload + 3, 6);
uint32_t ts_field;
memcpy(&ts_field, packet->payload + 9, 4);
uint8_t priority = packet->payload[13];
uint8_t pdu_type = packet->payload[14];
ESP_LOGI(TAG, " WAVE PDU Length: %u | Sender: %02X:%02X:%02X:%02X:%02X:%02X",
pdu_len, sender_mac[0], sender_mac[1], sender_mac[2],
sender_mac[3], sender_mac[4], sender_mac[5]);
ESP_LOGI(TAG, " WAVE Timestamp: %u | Priority: %u | PDU Type: %02X",
ts_field, priority, pdu_type);
// C-ITS Payload wenn vorhanden
if (pkt_len > 15) {
ESP_LOGI(TAG, " C-ITS Payload (%d Bytes):", pkt_len - 15);
for (int i = 15; i < pkt_len && i < 47; i++) {
if ((i - 15) % 16 == 0) {
char hex_line[128];
snprintf(hex_line, sizeof(hex_line), " %04x: ", i);
ESP_LOGI(TAG, "%s", hex_line);
}
ESP_LOG_BUFFER_HEX_LEVEL(TAG, packet->payload + i, 1, ESP_LOG_INFO);
}
}
}
// Paket zum JTAG-Direct-Zugang speichern
if (packet_count_total < MAX_STORED_PACKETS) {
memcpy(&stored_packets[packet_write_idx].pkt, packet, sizeof(wifi_promiscuous_pkt_t));
stored_packets[packet_write_idx].timestamp = ts;
packet_write_idx = (packet_write_idx + 1) % MAX_STORED_PACKETS;
}
packet_count_total++;
packets_available = true;
// Verarbeite C-ITS Nachricht
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;
}
/**
* JTAG Direct Read - Gepackete Pakete auf Console (JTAG) ausgeben
*/
static int cmd_jtag_read(int argc, char **argv)
{
int count = 10; // Default 10 Pakete
if (argc > 0) {
count = atoi(argv[0]);
if (count < 1) count = 1;
if (count > MAX_STORED_PACKETS) count = MAX_STORED_PACKETS;
}
if (!packets_available) {
ESP_LOGI(TAG, "Keine Pakete empfangen. Warte auf C-ITS Nachrichten...");
return 0; return 0;
} }
ESP_LOGI(TAG, "[JTAG-READ] Empfangene Pakete (%d vom %lu insgesamt):", count, (unsigned long)packet_count_total); static int cmd_chan(int argc, char **argv)
uint32_t idx = (packet_write_idx - 1 + MAX_STORED_PACKETS) % MAX_STORED_PACKETS;
int printed = 0;
for (int i = 0; i < count; i++) {
if (printed >= packet_count_total) break;
stored_packet_t *p = &stored_packets[idx];
if (p->pkt.payload == NULL) {
idx = (idx - 1 + MAX_STORED_PACKETS) % MAX_STORED_PACKETS;
continue;
}
uint16_t pkt_len = p->pkt.rx_ctrl.sig_len;
int8_t rssi = p->pkt.rx_ctrl.rssi;
char mac_str[20];
if (pkt_len >= 12) {
snprintf(mac_str, sizeof(mac_str), "%02x:%02x:%02x:%02x:%02x:%02x",
p->pkt.payload[0], p->pkt.payload[1],
p->pkt.payload[2], p->pkt.payload[3],
p->pkt.payload[4], p->pkt.payload[5]);
} else {
strcpy(mac_str, "N/A");
}
ESP_LOGI(TAG, "[Paket %d] L=%d RSSI=%d MAC=%s",
i + 1, pkt_len, rssi, mac_str);
ESP_LOGI(TAG, "[Paket %d] Raw: ", i + 1);
ESP_LOG_BUFFER_HEX_LEVEL(TAG, p->pkt.payload, pkt_len < 64 ? pkt_len : 64, ESP_LOG_INFO);
printed++;
idx = (idx - 1 + MAX_STORED_PACKETS) % MAX_STORED_PACKETS;
}
return 0;
}
/**
* Sniffer Status - Aktuelle Statistik ausgeben
*/
static int cmd_sniffer_status(int argc, char **argv)
{
ESP_LOGI(TAG, "[Status] Gesamt empfangene Pakete: %lu",
(unsigned long)packet_count_total);
ESP_LOGI(TAG, "[Status] Gespeichert: %d / %d",
(packet_write_idx < MAX_STORED_PACKETS) ?
(MAX_STORED_PACKETS - packet_write_idx) : packet_write_idx,
MAX_STORED_PACKETS);
ESP_LOGI(TAG, "[Status] Pakete verfügbar: %s", packets_available ? "JA" : "NEIN");
return 0;
}
/**
* Kanal wechseln
*/
static int cmd_change_channel(int argc, char **argv)
{ {
if (argc < 1) { if (argc < 1) {
ESP_LOGI(TAG, "Nutzung: change_channel <freq_mhz>"); printf("Nutzung: chan <5900|5890|5880|5870>\n");
return 1; return 0;
} }
uint32_t freq = atoi(argv[0]); uint32_t freq = atoi(argv[0]);
if (freq < 5800 || freq > 5900) { if (freq != 5900 && freq != 5890 && freq != 5880 && freq != 5870) {
ESP_LOGE(TAG, "Frequenz muss zwischen 5800 und 5900 MHz liegen"); printf("Ungültiger Kanal. Gültig: 5900, 5890, 5880, 5870\n");
return 1; return 1;
} }
set_cits_channel(freq);
phy_11p_set(1, 0); ESP_LOGI(TAG, "Kanal auf %d MHz ge\303\244ndert", freq);
phy_change_channel(freq, 1, 0, 0);
ESP_LOGI(TAG, "Kanal auf %u MHz geändert", freq);
return 0; return 0;
} }
/** static int cmd_packets(int argc, char **argv)
* Sniffer starten (neu)
*/
static int cmd_start_sniffer(int argc, char **argv)
{ {
ESP_LOGI(TAG, "Sniffer wird neu gestartet..."); if (argc < 1) {
packets_available = false; printf("Nutzung: packets <anzahl>\n");
packet_write_idx = 0; return 0;
packet_count_total = 0;
esp_err_t ret = start_promiscuous_mode(CITS_CHANNEL_0_MHZ);
if (ret != ESP_OK) {
ESP_LOGE(TAG, "Sniffer Start fehlgeschlagen");
return 1;
} }
int target = atoi(argv[0]);
ESP_LOGI(TAG, "Sniffer läuft auf %u MHz", CITS_CHANNEL_0_MHZ); uint32_t start = g_total_packets;
printf("Warte auf %d Pakete... ", target);
fflush(stdout);
while (g_total_packets - start < (uint32_t)target) {
vTaskDelay(pdMS_TO_TICKS(1000));
}
printf("OK! %" PRIu32 " Pakete empfangen.\n", g_total_packets);
return 0; return 0;
} }
/** static int cmd_restart(int argc, char **argv)
* Hauptfunktion {
*/ (void)argc; (void)argv;
printf("Sniffer wird neu gestartet...\n");
stop_promiscuous_mode();
g_sniffer_active = false;
vTaskDelay(pdMS_TO_TICKS(500));
g_total_packets = 0;
esp_err_t ret = start_promiscuous_mode(CITS_CHANNEL_0_MHZ);
if (ret == ESP_OK) {
g_sniffer_active = true;
ESP_LOGI(TAG, "Sniffer l\303\274uft auf %d MHz", CITS_CHANNEL_0_MHZ);
}
return (ret == ESP_OK) ? 0 : 1;
}
/* ---------- Hauptfunktion ---------- */
void app_main(void) void app_main(void)
{ {
// USB-Serial/JTAG Console initialisieren ESP_LOGI(TAG, "====== C-ITS SNIFFER ESP32-C5 ======");
usb_serial_jtag_driver_install(0, 0, 0); ESP_LOGI(TAG, " Release v2.0.0 — C-ITS Live + SD-Card");
esp_vfs_dev_usb_serial_jtag_set_console(); ESP_LOGI(TAG, " Build: %s %s", __DATE__, __TIME__);
ESP_LOGI(TAG, "======================================");
ESP_LOGI(TAG, "=== C-ITS Sniffer für ESP32-C5 startet ==="); // LED
ESP_LOGI(TAG, "Console: USB-Serial/JTAG (115200 bps)"); gpio_reset_pin(LED_PIN);
gpio_set_direction(LED_PIN, GPIO_MODE_OUTPUT);
gpio_set_level(LED_PIN, BUILTIN_LED_OFF);
// NVS initialisieren // NVS
esp_err_t ret = init_nvs_flash(); esp_err_t ret = nvs_flash_init();
if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) {
nvs_flash_erase();
ret = nvs_flash_init();
}
ESP_ERROR_CHECK(ret);
// WiFi
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_ERROR_CHECK(esp_wifi_start());
ESP_LOGI(TAG, "WiFi initialisiert (NULL-Mode / Promiscuous)");
// CSV Writer (SD-Karte)
ret = csv_writer_init();
if (ret != ESP_OK) { if (ret != ESP_OK) {
ESP_LOGE(TAG, "Failed to initialize NVS"); ESP_LOGE(TAG, "CSV Writer init failed: %s", esp_err_to_name(ret));
return;
} }
// WiFi initialisieren // C-ITS Parser
ret = initialize_wifi(); cits_parser_init();
if (ret != ESP_OK) {
ESP_LOGE(TAG, "Failed to initialize WiFi");
return;
}
// C-ITS Sniffer aufsetzen // USB-Serial/JTAG Console
ret = setup_cits_sniffer(); #ifdef CONFIG_ESP_CONSOLE_USB_SERIAL_JTAG
if (ret != ESP_OK) { usb_serial_jtag_driver_config_t jtag_cfg = USB_SERIAL_JTAG_DRIVER_CONFIG_DEFAULT();
ESP_LOGE(TAG, "Failed to setup C-ITS Sniffer"); usb_serial_jtag_driver_install(&jtag_cfg);
return; usb_serial_jtag_vfs_register();
} usb_serial_jtag_vfs_use_nonblocking();
usb_serial_jtag_vfs_use_driver();
ESP_LOGI(TAG, "Console: USB-Serial/JTAG @ 115200 bps");
#else
ESP_LOGI(TAG, "Console: UART default");
#endif
// Console Commands registrieren // Promiscuous Mode starten
const esp_console_cmd_t cmd_jtag_read_cmd = { start_promiscuous_mode(CITS_CHANNEL_0_MHZ);
.command = "jtag_read", g_sniffer_active = true;
.help = "Read captured packets via JTAG (optional count)",
.hint = NULL, // CLI Commands
.func = &cmd_jtag_read, esp_console_register_help_command();
const esp_console_cmd_t cmd_status_def = {
.command = "status", .help = "Show sniffer status", .func = cmd_status,
}; };
esp_console_cmd_register(&cmd_jtag_read_cmd); esp_console_cmd_register(&cmd_status_def);
const esp_console_cmd_t cmd_status_cmd = { const esp_console_cmd_t cmd_chan_def = {
.command = "sniffer_status", .command = "chan", .help = "Change C-ITS channel (5900|5890|5880|5870)", .func = cmd_chan,
.help = "Show sniffer statistics",
.hint = NULL,
.func = &cmd_sniffer_status,
}; };
esp_console_cmd_register(&cmd_status_cmd); esp_console_cmd_register(&cmd_chan_def);
const esp_console_cmd_t cmd_chan_cmd = { const esp_console_cmd_t cmd_pkts_def = {
.command = "chan", .command = "packets", .help = "Wait for N packets", .func = cmd_packets,
.help = "Change C-ITS channel (5800-5900 MHz)",
.hint = NULL,
.func = &cmd_change_channel,
}; };
esp_console_cmd_register(&cmd_chan_cmd); esp_console_cmd_register(&cmd_pkts_def);
const esp_console_cmd_t cmd_start_cmd = { const esp_console_cmd_t cmd_restart_def = {
.command = "start_sniffer", .command = "restart", .help = "Restart sniffer", .func = cmd_restart,
.help = "Restart sniffer",
.hint = NULL,
.func = &cmd_start_sniffer,
}; };
esp_console_cmd_register(&cmd_start_cmd); esp_console_cmd_register(&cmd_restart_def);
// register_cits_commands() aus block1
register_cits_commands(); register_cits_commands();
// Hauptschleife - C-ITS Nachrichten werden im Callback verarbeitet // Hauptschleife
ESP_LOGI(TAG, "C-ITS Sniffer läuft - Empfange DSRC/C-ITS Nachrichten auf %u MHz...", ESP_LOGI(TAG, ">>> C-ITS SNIFFER LAUFT <<<");
CITS_CHANNEL_0_MHZ); ESP_LOGI(TAG, "Kanal: %d MHz | SD-Karte: /storage/ | Console: USB-JTAG", CITS_CHANNEL_0_MHZ);
ESP_LOGI(TAG, "Verwende USB-Serial/JTAG für Console/Ausgabe"); ESP_LOGI(TAG, "Commands: status, chan <freq>, set_channel <freq>, packets <n>, restart");
ESP_LOGI(TAG, "Commands: jtag_read [count], sniffer_status, chan <freq>, start_sniffer"); ESP_LOGI(TAG, "Live-Ansicht: Alle Pakete erscheinen als [PKT#...] auf Console");
// Zähler für Statistik
uint32_t packet_count = 0;
uint32_t last_report = 0;
uint32_t tick = 0;
while (1) { while (1) {
vTaskDelay(pdMS_TO_TICKS(60000)); // Alle 60 Sekunden Statistik tick++;
last_report++; gpio_set_level(LED_PIN, (tick % 2) ? BUILTIN_LED_ON : BUILTIN_LED_OFF);
ESP_LOGI(TAG, "Laufzeit: %lu Min. | Warte auf C-ITS Nachrichten...",
(unsigned long)last_report); if (tick % 60 == 0) {
ESP_LOGI(TAG, "[STAT] Uptime=%" PRIu32 " min | Total pkts=%" PRIu32,
tick / 60, g_total_packets);
}
vTaskDelay(1);
} }
} }
+40 -4
View File
@@ -146,6 +146,42 @@ static esp_err_t eth_sniffer_cb(esp_eth_handle_t eth_handle, uint8_t *buffer, ui
return ESP_OK; return ESP_OK;
} }
static void process_and_log_packet(void *payload, uint32_t length, uint32_t seconds, uint32_t microseconds)
{
if (!payload || length < 26) return; // Minimum header size check
// Simple parsing logic (placeholder for actual 802.11p/C-ITS header extraction)
// In a real implementation, we would parse the MAC header here.
// For now, we extract the first 6 bytes as a dummy source MAC.
uint8_t *ptr = (uint8_t *)payload;
char src_mac[18], dst_mac[18], payload_hex[128];
snprintf(src_mac, sizeof(src_mode), "%02x:%02x:%02x:%02x:%02x:%02x",
ptr[0], ptr[1], ptr[2], ptr[3], ptr[4], ptr[5]);
snprintf(dst_mac, sizeof(dst_mode), "%02x:%02x:%02x:%02x:%02x:%02x",
ptr[6], ptr[7], ptr[8], ptr[9], ptr[10], ptr[11]);
// Extract payload snippet and convert to hex string
size_t hex_len = (length > 64) ? 64 : length;
size_t pos = 0;
for (size_t i = 0; i < hex_len; i++) {
pos += snprintf(payload_hex + pos, sizeof(payload_hex) - pos, "%02x", ptr[i]);
}
// Create CSV line
char csv_line[256];
snprintf(csv_line, sizeof(csv_line), "%u.%06u;%s;%s;%s",
seconds, microseconds, src_mac, dst_mac, payload_hex);
// 1. Write to SD Card (via existing packet_capture or dedicated CSV function)
// We reuse packet_capture as a placeholder, but in Phase 1 we'd target a .csv file.
packet_capture(payload, length, seconds, microseconds);
// 2. Live Stream via USB (UART)
// This is the "Live View" feature for Gregor
ESP_LOGI(SNIFFER_TAG, "LIVE_CSV: %s", csv_line);
}
static void sniffer_task(void *parameters) static void sniffer_task(void *parameters)
{ {
sniffer_packet_info_t packet_info; sniffer_packet_info_t packet_info;
@@ -158,10 +194,10 @@ static void sniffer_task(void *parameters)
} }
if (xQueueReceive(sniffer->work_intf_queue, &packet_info, pdMS_TO_TICKS(SNIFFER_PROCESS_PACKET_TIMEOUT_MS)) == pdTRUE) { if (xQueueReceive(sniffer->work_intf_queue, &packet_info, pdMS_TO_TICKS(SNIFFER_PROCESS_PACKET_TIMEOUT_MS)) == pdTRUE) {
if (packet_capture(packet_info.payload, packet_info.length, packet_info.seconds, // NEW LOGIC: Process, Parse, and Stream
packet_info.microseconds) != ESP_OK) { process_and_log_packet(packet_info.payload, packet_info.length,
ESP_LOGW(SNIFFER_TAG, "PCAP write error"); packet_info.seconds, packet_info.microseconds);
}
free(packet_info.payload); free(packet_info.payload);
packet_info.payload = NULL; packet_info.payload = NULL;