191 lines
5.8 KiB
C
191 lines
5.8 KiB
C
/**
|
|
* 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 <stdio.h>
|
|
|
|
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;
|
|
}
|