/** * V2X-Display Driver - ST7735 SPI (T-Dongle-C5) * * Verwendet den ESP-IDF nativen ST7735 Treiber (aus LilyGO T-Dongle-C5 Demo) * * Display: ST7735, 80x160 Pixel * GPIO: CS=10, DC=3, RST=1, BL=0, MOSI=2, SCK=6 * * Rotation: 3 (invertiert 90°) * Offset: x=26, y=1 (nicht-Zentriert) */ #include "esp_log.h" #include "v2x_display.h" #include "st7735.h" #include "driver/gpio.h" #include "freertos/FreeRTOS.h" #include "freertos/task.h" #include "esp_timer.h" #include static const char *TAG = "v2x-display"; static void *s_dev = NULL; static bool s_initialized = false; /* Globale Variablen */ bool g_disp_initialized = false; void *g_disp_panel = NULL; esp_err_t v2x_display_init(void) { esp_err_t ret; ESP_LOGI(TAG, "Initialisiere ST7735 Display via eigenem ESP-IDF Treiber..."); ESP_LOGI(TAG, "GPIO: CS=%d, DC=%d, RST=%d, BL=%d, MOSI=%d, SCK=%d", DISP_GPIO_CS, DISP_GPIO_DC, DISP_GPIO_RST, DISP_GPIO_BL, DISP_GPIO_SDA, DISP_GPIO_SCK); /* GPIO-Konfiguration mit eigenem Treiber */ st7735_gpio_config_t gpio_cfg = { .cs_gpio = DISP_GPIO_CS, .dc_gpio = DISP_GPIO_DC, .rst_gpio = DISP_GPIO_RST, .bl_gpio = DISP_GPIO_BL, .mosi_gpio = DISP_GPIO_SDA, .sck_gpio = DISP_GPIO_SCK, }; /* ST7735 initialisieren - Rotation 3 (invertiert, 90° gedreht) */ ret = st7735_init(&gpio_cfg, 3, (void **)&s_dev); if (ret != ESP_OK) { ESP_LOGE(TAG, "ST7735 Init fehlgeschlagen: %s", esp_err_to_name(ret)); return ret; } /* Display ausschalten (Backlight an, Panel aus) */ st7735_display_off((void *)s_dev); /* Backlight an (aktiv LOW bei LilyGO) */ gpio_set_level(DISP_GPIO_BL, 0); vTaskDelay(pdMS_TO_TICKS(50)); /* Display einschalten */ st7735_display_on((void *)s_dev); /* Vollbild weiß */ st7735_fill_screen((void *)s_dev, DISP_COLOR_WHITE); s_initialized = true; g_disp_initialized = true; g_disp_panel = (void *)s_dev; ESP_LOGI(TAG, "ST7735 Display bereit (80x160, SPI, Rot=3)"); return ESP_OK; } esp_err_t v2x_display_clear(uint16_t color) { if (!s_initialized || !s_dev) return ESP_ERR_INVALID_STATE; st7735_fill_screen((void *)s_dev, color); return ESP_OK; } esp_err_t v2x_display_rect(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color, bool filled) { if (!s_initialized || !s_dev) return ESP_ERR_INVALID_STATE; if (filled) { /* Gefülltes Rechteck zeichnen */ for (int16_t py = 0; py < h; py++) { for (int16_t px = 0; px < w; px++) { st7735_draw_pixel((void *)s_dev, x + px, y + py, color); } } } else { /* Nur Rahmen zeichnen */ for (int16_t px = 0; px < w; px++) { st7735_draw_pixel((void *)s_dev, x + px, y, color); st7735_draw_pixel((void *)s_dev, x + px, y + h - 1, color); } for (int16_t py = 0; py < h; py++) { st7735_draw_pixel((void *)s_dev, x, y + py, color); st7735_draw_pixel((void *)s_dev, x + w - 1, y + py, color); } } return ESP_OK; } esp_err_t v2x_display_line(int16_t x0, int16_t y0, int16_t x1, int16_t y1, uint16_t color) { if (!s_initialized || !s_dev) return ESP_ERR_INVALID_STATE; return st7735_draw_line((void *)s_dev, x0, y0, x1, y1, color); } esp_err_t v2x_display_off(void) { if (!s_initialized || !s_dev) return ESP_ERR_INVALID_STATE; st7735_display_off((void *)s_dev); gpio_set_level(DISP_GPIO_BL, 1); /* Backlight aus */ return ESP_OK; } esp_err_t v2x_display_progress_bar(int16_t x, int16_t y, int16_t w, int16_t h, float progress, uint16_t fg_color, uint16_t bg_color) { progress = (progress < 0.0f) ? 0.0f : (progress > 1.0f) ? 1.0f : progress; for (int16_t py = 0; py < h; py++) { for (int16_t px = 0; px < w; px++) { st7735_draw_pixel((void *)s_dev, x + px, y + py, bg_color); } } int16_t fw = (int16_t)(w * progress); if (fw > 0) { for (int16_t py = 0; py < h; py++) { for (int16_t px = 0; px < fw; px++) { st7735_draw_pixel((void *)s_dev, x + px, y + py, fg_color); } } } for (int i = 0; i < w; i++) { st7735_draw_pixel((void *)s_dev, x + i, y, DISP_COLOR_BLACK); st7735_draw_pixel((void *)s_dev, x + i, y + h - 1, DISP_COLOR_BLACK); } for (int i = 0; i < h; i++) { st7735_draw_pixel((void *)s_dev, x, y + i, DISP_COLOR_BLACK); st7735_draw_pixel((void *)s_dev, x + w - 1, y + i, DISP_COLOR_BLACK); } return ESP_OK; } esp_err_t v2x_display_rssi_gauge(int8_t rssi) { if (rssi < -100) rssi = -100; if (rssi > -20) rssi = -20; float pct = (float)(rssi + 100) / 80.0f; uint16_t color = DISP_COLOR_RED; if (pct > 0.6f) color = DISP_COLOR_GREEN; else if (pct > 0.3f) color = DISP_COLOR_YELLOW; return v2x_display_progress_bar(0, 0, DISP_W, 3, pct, color, DISP_COLOR_BLACK); } esp_err_t v2x_display_render_frame_line(int16_t x, int16_t y, const disp_frame_info_t *info, uint16_t bg_color) { for (int16_t py = 0; py < 12; py++) { for (int16_t px = 0; px < DISP_W; px++) { st7735_draw_pixel((void *)s_dev, x + px, y + py, bg_color); } } if (info->rssi != 0) { int8_t r = info->rssi; if (r < -100) r = -100; if (r > -20) r = -20; float pct = (float)(r + 100) / 80.0f; uint16_t bar_color = DISP_COLOR_RED; if (pct > 0.6f) bar_color = DISP_COLOR_GREEN; else if (pct > 0.3f) bar_color = DISP_COLOR_YELLOW; for (int16_t py = 1; py < 11; py++) { for (int16_t px = 0; px < 5; px++) { st7735_draw_pixel((void *)s_dev, x + px, y + py, bar_color); } } } (void)x; (void)y; return ESP_OK; }