134 lines
4.1 KiB
C++
134 lines
4.1 KiB
C++
#include "low_level_display_st7796.h"
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
|
|
// RGB565 color definitions
|
|
#define COLOR_BLACK 0x0000
|
|
#define COLOR_WHITE 0xFFFF
|
|
|
|
LowLevelDisplayST7796::LowLevelDisplayST7796(const st7796_config* cfg, int w, int h, bool invert)
|
|
: config(cfg), width(w), height(h), initialized(false), rgb_buffer(nullptr), invert_color(invert) {
|
|
}
|
|
|
|
LowLevelDisplayST7796::~LowLevelDisplayST7796() {
|
|
if (rgb_buffer) {
|
|
free(rgb_buffer);
|
|
rgb_buffer = nullptr;
|
|
}
|
|
}
|
|
|
|
bool LowLevelDisplayST7796::init() {
|
|
if (initialized) {
|
|
return true;
|
|
}
|
|
|
|
st7796_init(config, width, height);
|
|
|
|
// Allocate RGB565 buffer once (reused for all draw operations)
|
|
size_t buffer_size = width * height * sizeof(uint16_t);
|
|
rgb_buffer = (uint16_t *)malloc(buffer_size);
|
|
if (!rgb_buffer) {
|
|
printf("Error: Failed to allocate %zu bytes for RGB buffer\n", buffer_size);
|
|
return false;
|
|
}
|
|
printf("ST7796 display initialized: %dx%d (RGB buffer: %zu bytes)\n", width, height, buffer_size);
|
|
|
|
initialized = true;
|
|
return true;
|
|
}
|
|
|
|
void LowLevelDisplayST7796::clear(bool white) {
|
|
bool out_white = invert_color ? !white : white;
|
|
st7796_fill(out_white ? COLOR_WHITE : COLOR_BLACK);
|
|
}
|
|
|
|
void LowLevelDisplayST7796::draw_pixel(int x, int y, bool white) {
|
|
bool out_white = invert_color ? !white : white;
|
|
st7796_draw_pixel(x, y, out_white ? COLOR_WHITE : COLOR_BLACK);
|
|
}
|
|
|
|
void LowLevelDisplayST7796::draw_buffer(const uint8_t* bit_buffer) {
|
|
if (!bit_buffer || !rgb_buffer) return;
|
|
// Convert 1-bit buffer to RGB565 using persistent buffer
|
|
for (int y = 0; y < height; y++) {
|
|
for (int x = 0; x < width; x++) {
|
|
int byte_index = (y * width + x) / 8;
|
|
int bit_index = 7 - (x % 8);
|
|
bool pixel_white = (bit_buffer[byte_index] >> bit_index) & 0x01;
|
|
bool out_white = invert_color ? !pixel_white : pixel_white;
|
|
rgb_buffer[y * width + x] = out_white ? COLOR_WHITE : COLOR_BLACK;
|
|
}
|
|
}
|
|
// Draw entire buffer at once
|
|
st7796_set_cursor(0, 0);
|
|
// Use raw write for speed.
|
|
// Since we only use 0x0000 (Black) and 0xFFFF (White), endianness doesn't matter.
|
|
// 0x0000 -> 0x00, 0x00 (LE) -> Display sees 0x00, 0x00 (0x0000 correct)
|
|
// 0xFFFF -> 0xFF, 0xFF (LE) -> Display sees 0xFF, 0xFF (0xFFFF correct)
|
|
st7796_write_raw((const uint8_t*)rgb_buffer, width * height * 2);
|
|
}
|
|
|
|
void LowLevelDisplayST7796::refresh() {
|
|
// ST7796 updates immediately, no refresh needed
|
|
}
|
|
|
|
void LowLevelDisplayST7796::set_backlight(bool on) {
|
|
// Use brightness control: on = 100%, off = 0%
|
|
st7796_set_brightness(on ? 100 : 0);
|
|
}
|
|
|
|
void LowLevelDisplayST7796::set_brightness(uint8_t brightness) {
|
|
st7796_set_brightness(brightness);
|
|
}
|
|
|
|
uint8_t LowLevelDisplayST7796::get_brightness() const {
|
|
return st7796_get_brightness();
|
|
}
|
|
|
|
void LowLevelDisplayST7796::sleep() {
|
|
st7796_sleep();
|
|
}
|
|
|
|
void LowLevelDisplayST7796::wake() {
|
|
st7796_wake();
|
|
}
|
|
|
|
void LowLevelDisplayST7796::set_rotation(uint8_t rotation) {
|
|
// ST7796 driver doesn't have rotation control yet
|
|
// TODO: Add MADCTL register manipulation for rotation
|
|
(void)rotation;
|
|
}
|
|
|
|
void LowLevelDisplayST7796::on_idle_2min() {
|
|
if (!is_dimmed && !is_sleeping) {
|
|
saved_brightness = get_brightness();
|
|
set_brightness(5); // Dim to 5%
|
|
is_dimmed = true;
|
|
printf("TFT: Dimmed to 5%%\n");
|
|
}
|
|
}
|
|
|
|
void LowLevelDisplayST7796::on_idle_10min() {
|
|
if (!is_sleeping) {
|
|
sleep();
|
|
is_sleeping = true;
|
|
is_dimmed = true; // Sleep implies dimmed
|
|
printf("TFT: Entered sleep mode\n");
|
|
}
|
|
}
|
|
|
|
void LowLevelDisplayST7796::on_user_interaction() {
|
|
if (is_sleeping) {
|
|
wake();
|
|
// Restore brightness if we have a saved value, or default to 100
|
|
set_brightness(saved_brightness > 0 ? saved_brightness : 100);
|
|
is_sleeping = false;
|
|
is_dimmed = false;
|
|
printf("TFT: Woke from sleep\n");
|
|
} else if (is_dimmed) {
|
|
set_brightness(saved_brightness > 0 ? saved_brightness : 100);
|
|
is_dimmed = false;
|
|
printf("TFT: Restored brightness\n");
|
|
}
|
|
}
|