Display UI: ST7735 Treiber + Frame-Scroller + Speicheranzeige

- ST7735 SPI-Treiber für 0.96 Zoll Display (80x160 Pixel)
- ASCII-Font 6x8 mit Text-Ausgabe
- Frame-Counter (gross, rot)
- SD-Speicher-Balken (grün/gelb/rot)
- Frame-Scroller: rollende Liste der letzten 7 Frames
  - RSSI-Farbbalken (rot/gelb/grün)
  - Message-Type (B=BSM, C=CAM, D=DENM)
  - BSSID Hex + Kanal/RSSI
- Display UI Task aktualisiert alle 2 Sekunden
- Frame Writer sendet Frames an Scroller Queue
- Channel Hopper aktualisiert g_v2x_channel_idx
This commit is contained in:
Clawdia
2026-05-09 11:47:55 +02:00
parent 874dd969b6
commit 240a374148
7 changed files with 896 additions and 3 deletions
+83 -1
View File
@@ -51,8 +51,10 @@
#include "nvs_flash.h"
#include "esp_timer.h"
#include "driver/gpio.h"
#include "esp_codec_dev.h"
#include "esp_lcd_panel_ops.h"
#include "esp_lcd_panel_vendor.h"
#include "v2x_db.h"
#include "v2x_display.h"
static const char *TAG = "V2X-Sniffer";
@@ -74,10 +76,23 @@ static const uint32_t v2x_freqs[] = {
#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;
uint32_t g_v2x_frame_count = 0;
int8_t g_v2x_max_rssi = -120;
int g_v2x_channel_idx = 0;
/* ====== Message-Type Erkennung ====== */
static v2x_msg_type_t detect_msg_type(const uint8_t *data, uint16_t len)
{
@@ -158,6 +173,11 @@ static void v2x_promiscuous_cb(void *arg, wifi_promiscuous_pkt_type_t pkt_type)
/* 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) */
@@ -185,6 +205,21 @@ static void v2x_frame_writer_task(void *pvParameters)
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) {
@@ -214,6 +249,7 @@ static void v2x_channel_hopper_task(void *pvParameters)
/* Frequenz/Kanal wechseln */
v2x_phy_init(freq);
g_v2x_current_freq = freq;
g_v2x_channel_idx = hop_idx;
ESP_LOGI(TAG, "CH %d: %lu MHz", hop_idx, (unsigned long)freq);
@@ -241,6 +277,24 @@ 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)
{
@@ -285,6 +339,16 @@ 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) {
@@ -295,6 +359,24 @@ 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);