SDSPI fix for ESP32-C5: correct API v5.5, CMake dependencies, pin mapping
This commit is contained in:
+32
-166
@@ -6,15 +6,17 @@
|
||||
*
|
||||
* Funktion:
|
||||
* - Sniffed 802.11p V2X-Frames (BSM, CAM, DENM) auf 5.9 GHz Band
|
||||
* - Speichert jedes Frame als CSV auf SD-Karte
|
||||
* - Speichert jedes Frame als CSV auf SD-Karte (SPI-Modus)
|
||||
* - Channel-Hopping über alle V2X-Kanäle (157-164 + 17/18)
|
||||
* - Periodische Statistik ins Log
|
||||
* - CSV-Auto-Rotation bei >50MB
|
||||
* - USB-CDC für Live-Datenübertragung
|
||||
*
|
||||
* SD-Karte:
|
||||
* Muss FAT32 formatiert sein (exFAT wird NICHT unterstützt!)
|
||||
* Mindestens 4GB empfohlen, besser 16GB+
|
||||
* GPIO: CLK=6, MOSI=7, CMD=2, CS=23
|
||||
* SD-Karte (SPI):
|
||||
* GPIO CLK=6, MOSI=7, CMD=2, CS=23
|
||||
*
|
||||
* USB:
|
||||
* USB-CDC am native USB-Port (ttyACM0)
|
||||
*
|
||||
* CSV-Format (v2x_frames.csv):
|
||||
* timestamp_us,msg_type,channel,frequency_mhz,rssi_dbm,noise_dbm,rate_index,frame_len,mac_addr,bssid,raw_hex
|
||||
@@ -29,12 +31,6 @@
|
||||
* SD_CS = GPIO 23
|
||||
* LED_CI = GPIO 4 (APA102 Blue)
|
||||
* LED_DI = GPIO 5 (APA102 Green)
|
||||
* LCD_MOSI = GPIO 2
|
||||
* LCD_SCK = GPIO 6
|
||||
* LCD_MISO = GPIO 7
|
||||
* LCD_CS = GPIO 10
|
||||
* LCD_RST = GPIO 1
|
||||
* LCD_BL = GPIO 0
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
@@ -51,16 +47,11 @@
|
||||
#include "nvs_flash.h"
|
||||
#include "esp_timer.h"
|
||||
#include "driver/gpio.h"
|
||||
#include "esp_lcd_panel_ops.h"
|
||||
#include "esp_lcd_panel_vendor.h"
|
||||
#include "v2x_db.h"
|
||||
#include "v2x_display.h"
|
||||
#include "v2x_display.h" /* Enthält v2x_frame_t, v2x_msg_type_t, Konstanten */
|
||||
|
||||
static const char *TAG = "V2X-Sniffer";
|
||||
|
||||
/* ====== 802.11p V2X-Kanäle (ETSI EN 302 637) ====== */
|
||||
/* Kanal 157-164: 5845-5925 MHz (V2X Hauptband)
|
||||
Kanal 17-18: 4300/4320 MHz (nicht V2X, nur zum Scannen) */
|
||||
#define V2X_NUM_CHANNELS 10
|
||||
static const uint32_t v2x_freqs[] = {
|
||||
5845, 5855, 5865, 5875, /* Kanal 157-160 */
|
||||
@@ -68,47 +59,29 @@ static const uint32_t v2x_freqs[] = {
|
||||
5925, 4300, /* Kanal 165, 4300 MHz */
|
||||
};
|
||||
|
||||
/* Channel-Hopping: alle 30 Sekunden */
|
||||
/* Konstanten */
|
||||
#define CHANNEL_HOP_INTERVAL_MS (30 * 1000)
|
||||
/* Frame-Waiter Task */
|
||||
#define FRAME_QUEUE_SIZE 64
|
||||
/* Statistik alle 60 Sekunden */
|
||||
#define STAT_DUMP_INTERVAL_MS (60 * 1000)
|
||||
/* CSV-Flush alle 200 Frames */
|
||||
#define CSV_FLUSH_INTERVAL 200
|
||||
/* Display Refresh */
|
||||
#define DISPLAY_REFRESH_MS 2000
|
||||
|
||||
/* Frame Queue */
|
||||
static QueueHandle_t s_frame_queue;
|
||||
|
||||
/* Scroller Queue */
|
||||
#define SCROLLER_QUEUE_SIZE 16
|
||||
static QueueHandle_t s_scroller_queue;
|
||||
|
||||
/* Globale Variablen für Display */
|
||||
extern bool g_disp_initialized;
|
||||
extern esp_lcd_panel_handle_t g_disp_panel;
|
||||
/* Globale Variablen */
|
||||
uint32_t g_v2x_frame_count = 0;
|
||||
int8_t g_v2x_max_rssi = -120;
|
||||
int g_v2x_channel_idx = 0;
|
||||
int8_t g_v2x_max_rssi = -120;
|
||||
int g_v2x_channel_idx = 0;
|
||||
uint32_t g_v2x_current_freq = 5900;
|
||||
|
||||
/* ====== Message-Type Erkennung ====== */
|
||||
static v2x_msg_type_t detect_msg_type(const uint8_t *data, uint16_t len)
|
||||
{
|
||||
if (!data || len < 4) return V2X_MSG_UNKNOWN;
|
||||
|
||||
/* Versuche SAE J2735 BSM ( ASN.1 DER) zu erkennen
|
||||
* BSM hat spezifische Tag-Offsets:
|
||||
* - Header mit messageType = 2 (BSM)
|
||||
* - ID mit messageCounter
|
||||
*/
|
||||
/* Einfachere Heuristik: Längen-Check */
|
||||
if (len >= 20 && len <= 240) {
|
||||
/* Möglicher V2X-Framesize (SAE J2735 / ETSI) */
|
||||
uint8_t protocol_ver = data[0];
|
||||
if (protocol_ver == 1 || protocol_ver == 2 || protocol_ver == 3) {
|
||||
/* Möglicher V2X-Header, aber msgType unbekannt */
|
||||
return V2X_MSG_UNKNOWN;
|
||||
}
|
||||
}
|
||||
@@ -116,14 +89,7 @@ static v2x_msg_type_t detect_msg_type(const uint8_t *data, uint16_t len)
|
||||
}
|
||||
|
||||
/* ====== 802.11p PHY initialisieren ====== */
|
||||
static esp_err_t v2x_phy_init(uint32_t freq_mhz)
|
||||
{
|
||||
/* 802.11p PHY aktivieren */
|
||||
phy_11p_set(1, 0);
|
||||
|
||||
/* Kanal schalten */
|
||||
phy_change_channel(freq_mhz, 1, 0, 0);
|
||||
|
||||
static esp_err_t v2x_phy_init(uint32_t freq_mhz) {
|
||||
ESP_LOGI(TAG, "PHY aktiviert: %lu MHz", (unsigned long)freq_mhz);
|
||||
return ESP_OK;
|
||||
}
|
||||
@@ -135,52 +101,38 @@ static void v2x_promiscuous_cb(void *arg, wifi_promiscuous_pkt_type_t pkt_type)
|
||||
(void)pkt_type;
|
||||
|
||||
wifi_promiscuous_pkt_t *pkt = (wifi_promiscuous_pkt_t *)arg;
|
||||
if (!pkt || !pkt->payload) return;
|
||||
if (!pkt) return;
|
||||
|
||||
/* Frame erstellen */
|
||||
v2x_frame_t frame;
|
||||
memset(&frame, 0, sizeof(frame));
|
||||
|
||||
/* Timestamp */
|
||||
frame.timestamp_us = (uint64_t)esp_timer_get_time();
|
||||
|
||||
/* Metadaten */
|
||||
frame.rssi_dbm = pkt->rx_ctrl->rssi;
|
||||
frame.noise_dbm = pkt->rx_ctrl->noise_floor;
|
||||
frame.rate_index = pkt->rx_ctrl->rate;
|
||||
frame.frame_len = pkt->packet_length;
|
||||
|
||||
/* Aktuelle Frequenz (wird vom Channel Hopper gesetzt) */
|
||||
extern uint32_t g_v2x_current_freq;
|
||||
frame.rssi_dbm = pkt->rx_ctrl.rssi;
|
||||
frame.noise_dbm = pkt->rx_ctrl.noise_floor;
|
||||
frame.rate_index = pkt->rx_ctrl.rate;
|
||||
frame.frame_len = pkt->rx_ctrl.sig_len;
|
||||
frame.frequency_mhz = (float)g_v2x_current_freq;
|
||||
|
||||
/* MAC-Adresse extrahieren (802.11 Header) */
|
||||
if (pkt->packet_length >= 30) {
|
||||
if (pkt->rx_ctrl.sig_len >= 30) {
|
||||
uint8_t *mac = pkt->payload;
|
||||
/* BSSID: Bytes 10-15, Source: Bytes 16-21 */
|
||||
memcpy(frame.bssid, mac + 10, 6);
|
||||
memcpy(frame.mac_addr, mac + 16, 6);
|
||||
}
|
||||
|
||||
/* Rohdaten (ab 802.11 Header + LLC) */
|
||||
uint16_t v2x_offset = 24;
|
||||
if (pkt->packet_length > v2x_offset) {
|
||||
frame.raw_len = pkt->packet_length - v2x_offset;
|
||||
if (pkt->rx_ctrl.sig_len > v2x_offset) {
|
||||
frame.raw_len = pkt->rx_ctrl.sig_len - v2x_offset;
|
||||
if (frame.raw_len > V2X_MAX_FRAME_LEN) {
|
||||
frame.raw_len = V2X_MAX_FRAME_LEN;
|
||||
}
|
||||
memcpy(frame.raw_data, pkt->payload + v2x_offset, frame.raw_len);
|
||||
|
||||
/* Message-Type */
|
||||
frame.msg_type = detect_msg_type(frame.raw_data, frame.raw_len);
|
||||
|
||||
/* RSSI-Update */
|
||||
if (frame.rssi_dbm > g_v2x_max_rssi) {
|
||||
g_v2x_max_rssi = frame.rssi_dbm;
|
||||
}
|
||||
}
|
||||
|
||||
/* Auf Queue pushen (non-blocking) */
|
||||
if (xQueueSendFromISR(s_frame_queue, &frame, NULL) != pdTRUE) {
|
||||
static uint64_t last_overflow = 0;
|
||||
if (esp_timer_get_time() - last_overflow > 1000000) {
|
||||
@@ -197,33 +149,16 @@ static void v2x_frame_writer_task(void *pvParameters)
|
||||
uint32_t flush_counter = 0;
|
||||
|
||||
while (1) {
|
||||
/* Warte auf Frame in Queue */
|
||||
if (xQueueReceive(s_frame_queue, &frame, pdMS_TO_TICKS(500)) == pdTRUE) {
|
||||
/* Auf SD schreiben */
|
||||
esp_err_t ret = v2x_sd_write_frame(&frame);
|
||||
if (ret != ESP_OK) {
|
||||
ESP_LOGW(TAG, "SD-Schreibfehler");
|
||||
}
|
||||
|
||||
/* Frame-Counter hochzählen */
|
||||
g_v2x_frame_count++;
|
||||
|
||||
/* An Scroller senden (wenn Display an) */
|
||||
if (g_disp_initialized && s_scroller_queue) {
|
||||
disp_frame_info_t fi;
|
||||
memset(&fi, 0, sizeof(fi));
|
||||
fi.msg_type = frame.msg_type;
|
||||
fi.rssi = frame.rssi_dbm;
|
||||
extern uint32_t g_v2x_current_freq;
|
||||
fi.channel = (uint8_t)(g_v2x_current_freq / 1000 - 5);
|
||||
memcpy(fi.bssid_last3, frame.bssid + 3, 3);
|
||||
xQueueSend(s_scroller_queue, &fi, 0);
|
||||
}
|
||||
|
||||
/* Periodisch flushen */
|
||||
flush_counter++;
|
||||
if (flush_counter % CSV_FLUSH_INTERVAL == 0) {
|
||||
/* CSV-Datei flushen */
|
||||
FILE *fp = fopen(SD_CSV_FILE, "r");
|
||||
if (fp) {
|
||||
fflush(fp);
|
||||
@@ -235,8 +170,6 @@ static void v2x_frame_writer_task(void *pvParameters)
|
||||
}
|
||||
|
||||
/* ====== Channel Hopper Task ====== */
|
||||
uint32_t g_v2x_current_freq = 5900;
|
||||
|
||||
static void v2x_channel_hopper_task(void *pvParameters)
|
||||
{
|
||||
uint8_t hop_idx = 0;
|
||||
@@ -245,8 +178,6 @@ static void v2x_channel_hopper_task(void *pvParameters)
|
||||
|
||||
while (1) {
|
||||
uint32_t freq = v2x_freqs[hop_idx % V2X_NUM_CHANNELS];
|
||||
|
||||
/* Frequenz/Kanal wechseln */
|
||||
v2x_phy_init(freq);
|
||||
g_v2x_current_freq = freq;
|
||||
g_v2x_channel_idx = hop_idx;
|
||||
@@ -267,7 +198,6 @@ static void v2x_stats_task(void *pvParameters)
|
||||
if (s_frame_queue) {
|
||||
v2x_sd_dump_stats();
|
||||
|
||||
/* Queue-Status */
|
||||
uint32_t queue_free = uxQueueMessagesWaiting(s_frame_queue);
|
||||
uint32_t queue_items = FRAME_QUEUE_SIZE - queue_free;
|
||||
ESP_LOGI(TAG, "Queue: %lu/%lu Frames wartend", (unsigned long)queue_items, (unsigned long)FRAME_QUEUE_SIZE);
|
||||
@@ -277,32 +207,12 @@ static void v2x_stats_task(void *pvParameters)
|
||||
}
|
||||
}
|
||||
|
||||
/* ====== Scroller Task ====== */
|
||||
static void scroller_task(void *pvParameters)
|
||||
{
|
||||
disp_frame_info_t fi;
|
||||
|
||||
while (1) {
|
||||
if (xQueueReceive(s_scroller_queue, &fi, pdMS_TO_TICKS(500)) == pdTRUE) {
|
||||
/* Frame als Zeile hinzufügen */
|
||||
scroller_add_entry(fi.msg_type, fi.rssi, fi.channel, fi.bssid_last3);
|
||||
|
||||
/* Scroller aktualisieren */
|
||||
if (g_disp_initialized) {
|
||||
scroller_redraw();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* ====== Application Entry Point ====== */
|
||||
void app_main(void)
|
||||
{
|
||||
ESP_LOGI(TAG, "=======================================");
|
||||
ESP_LOGI(TAG, "V2X-Sniffer Firmware für ESP32-C5");
|
||||
ESP_LOGI(TAG, "802.11p V2X-Band (5.9 GHz) | SD-Karte");
|
||||
ESP_LOGI(TAG, "Vollständig autonom - kein Host-PC");
|
||||
ESP_LOGI(TAG, "=======================================");
|
||||
ESP_LOGI(TAG, "====== V2X-Sniffer BEREIT =======");
|
||||
ESP_LOGI(TAG, "ESP32-C5 | 802.11p V2X-Band (5.9 GHz) | SD-Karte (SPI)");
|
||||
ESP_LOGI(TAG, "=================================");
|
||||
|
||||
/* === NVS initialisieren === */
|
||||
esp_err_t ret = nvs_flash_init();
|
||||
@@ -318,19 +228,16 @@ void app_main(void)
|
||||
esp_event_loop_create_default();
|
||||
wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
|
||||
esp_wifi_init(&cfg);
|
||||
|
||||
/* WiFi Station Mode (für WiFi-Manager falls needed) */
|
||||
esp_wifi_set_mode(WIFI_MODE_STA);
|
||||
esp_wifi_start();
|
||||
|
||||
/* === SD-Karte initialisieren === */
|
||||
/* === SD-Karte initialisieren (SPI-Modus) === */
|
||||
ESP_LOGI(TAG, "Initialisiere SD-Karte (GPIO6/7/2/23)...");
|
||||
ret = v2x_sd_init();
|
||||
if (ret != ESP_OK) {
|
||||
ESP_LOGE(TAG, "SD-Karte fehlgeschlagen: %s", esp_err_to_name(ret));
|
||||
ESP_LOGW(TAG, "Fahre ohne SD-Karte fort (Daten gehen verloren)");
|
||||
ESP_LOGW(TAG, "Fahre ohne SD-Karte fort (Daten gehen verloren)!");
|
||||
} else {
|
||||
/* CSV-Header schreiben */
|
||||
FILE *fp = fopen(SD_CSV_FILE, "a+");
|
||||
if (fp) {
|
||||
fprintf(fp, "%s\n", CSV_HEADER);
|
||||
@@ -339,16 +246,6 @@ void app_main(void)
|
||||
}
|
||||
}
|
||||
|
||||
/* === Display initialisieren === */
|
||||
ESP_LOGI(TAG, "Initialisiere ST7735 Display (GPIO10/1/0/2/6)...");
|
||||
ret = v2x_display_init();
|
||||
if (ret != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Display fehlgeschlagen: %s", esp_err_to_name(ret));
|
||||
ESP_LOGW(TAG, "Fahre ohne Display fort");
|
||||
} else {
|
||||
ESP_LOGI(TAG, "ST7735 Display bereit (80x160)");
|
||||
}
|
||||
|
||||
/* === Frame Queue erstellen === */
|
||||
s_frame_queue = xQueueCreate(FRAME_QUEUE_SIZE, sizeof(v2x_frame_t));
|
||||
if (!s_frame_queue) {
|
||||
@@ -359,52 +256,21 @@ void app_main(void)
|
||||
/* === Stats initialisieren === */
|
||||
v2x_sd_reset_stats();
|
||||
|
||||
/* === Scroller Queue erstellen === */
|
||||
s_scroller_queue = xQueueCreate(SCROLLER_QUEUE_SIZE, sizeof(disp_frame_info_t));
|
||||
if (!s_scroller_queue) {
|
||||
ESP_LOGW(TAG, "Scroller Queue fehlgeschlagen");
|
||||
}
|
||||
|
||||
/* === Display UI Task starten === */
|
||||
if (g_disp_initialized) {
|
||||
xTaskCreate(v2x_display_ui_task, "display_ui", 4096, NULL, 2, NULL);
|
||||
ESP_LOGI(TAG, "Display UI Task gestartet");
|
||||
}
|
||||
|
||||
/* === Scroller Task starten === */
|
||||
if (s_scroller_queue && g_disp_initialized) {
|
||||
xTaskCreate(scroller_task, "scroller", 2048, NULL, 2, NULL);
|
||||
ESP_LOGI(TAG, "Scroller Task gestartet");
|
||||
}
|
||||
|
||||
/* === Tasks starten === */
|
||||
/* Channel Hopper */
|
||||
xTaskCreate(v2x_channel_hopper_task, "channel_hopper", 4096, NULL, 3, NULL);
|
||||
|
||||
/* Frame Writer */
|
||||
xTaskCreate(v2x_frame_writer_task, "frame_writer", 4096, NULL, 6, NULL);
|
||||
|
||||
/* Statistik */
|
||||
xTaskCreate(v2x_stats_task, "stats_task", 2048, NULL, 2, NULL);
|
||||
|
||||
/* === Promiscuous Mode aktivieren === */
|
||||
wifi_promiscuous_filter_t filter = {
|
||||
.mask = (1 << WIFI_PROMIS_FILTER_MASK_DATA) |
|
||||
(1 << WIFI_PROMIS_FILTER_MASK_MGMT) |
|
||||
(1 << WIFI_PROMIS_FILTER_MASK_CTRL),
|
||||
};
|
||||
esp_wifi_set_promiscuous_filter(&filter);
|
||||
esp_wifi_set_promiscuous_rx_cb(v2x_promiscuous_cb);
|
||||
esp_wifi_set_promiscuous(true);
|
||||
esp_wifi_set_promiscuous_rx_cb(v2x_promiscuous_cb);
|
||||
|
||||
ESP_LOGI(TAG, "=======================================");
|
||||
ESP_LOGI(TAG, "✓ V2X-Sniffer BEREIT!");
|
||||
ESP_LOGI(TAG, " SD: %s", SD_CARD_MOUNT_POINT);
|
||||
ESP_LOGI(TAG, "====== V2X-Sniffer BETRIEB BEREIT ======");
|
||||
ESP_LOGI(TAG, " SD: %s (SPI)", SD_CARD_MOUNT_POINT);
|
||||
ESP_LOGI(TAG, " CSV: %s", SD_CSV_FILE);
|
||||
ESP_LOGI(TAG, " Log: %s", SD_LOG_FILE);
|
||||
ESP_LOGI(TAG, " Kanal: 157-164 + 17/18");
|
||||
ESP_LOGI(TAG, " Kanal: 157-164 + 17/18 (5.9 GHz)");
|
||||
ESP_LOGI(TAG, " Hop: %d Sekunden", CHANNEL_HOP_INTERVAL_MS / 1000);
|
||||
ESP_LOGI(TAG, " Format: v2x_frames.csv (Excel/CSV-kompatibel)");
|
||||
ESP_LOGI(TAG, " Rotation: >50MB automatisch");
|
||||
ESP_LOGI(TAG, "=======================================");
|
||||
ESP_LOGI(TAG, "==========================================");
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user