Added render loop function and print overloads with cleared flag to avoid blocking

This commit is contained in:
2026-03-23 16:51:01 +01:00
parent 9c8280c829
commit b6a14c6b14

View File

@@ -1,26 +1,100 @@
#pragma once
#define MOD "modules/lcd/lcd.h"
#include "flags.h"
#include "modules/logger/system_logger.h"
#include "modules/gps/gps.h"
#include <LiquidCrystal_I2C.h>
#define MOD "modules/lcd/lcd.h"
namespace screen
{
typedef enum lcd_screen {
blank,
gps_debug,
};
} // namespace screen
class lcd {
private:
LiquidCrystal_I2C *_display;
bool _dispaly_cleared;
system_logger *_logger = nullptr;
screen::lcd_screen _screen;
unsigned long _last_render;
unsigned long _frame_duration;
gps *_gps;
void clear();
void print(const String& msg);
void print(char);
void print(const char []);
void print(double val, int digits);
void print(unsigned long val, int base);
void print(long val, int base);
void print(unsigned int val, int base);
void print(int val, int base);
public:
lcd();
lcd(system_logger *logger);
~lcd();
int init();
int set_gps(gps *gps);
int print_message(String message);
int switch_screen(screen::lcd_screen new_screen);
int render_task();
};
lcd::lcd() { _display = new LiquidCrystal_I2C(0x27, 20, 4); }
void lcd::clear() {
if (!_dispaly_cleared) {
_display->clear();
_dispaly_cleared = true;
}
}
lcd::lcd(system_logger *logger) {
void lcd::print(const String& msg) {
_display->print(msg);
_dispaly_cleared = false;
}
void lcd::print(char c) {
_display->print(c);
_dispaly_cleared = false;
}
void lcd::print(const char c[]) {
_display->print(c);
_dispaly_cleared = false;
}
void lcd::print(double d, int digits=2) {
_display->print(d, digits);
_dispaly_cleared = false;
}
void lcd::print(unsigned long l, int base=10) {
_display->print(l, base);
_dispaly_cleared = false;
}
void lcd::print(long l, int base=10) {
_display->print(l, base);
_dispaly_cleared = false;
}
void lcd::print(unsigned int i, int base=10) {
_display->print(i, base);
_dispaly_cleared = false;
}
void lcd::print(int i, int base=10) {
_display->print(i, base);
_dispaly_cleared = false;
}
lcd::lcd(): _logger(nullptr), _screen(screen::blank), _last_render(0), _frame_duration(500), _dispaly_cleared(false), _gps(nullptr) { _display = new LiquidCrystal_I2C(0x27, 20, 4); }
lcd::lcd(system_logger *logger): _logger(logger), _screen(screen::blank), _last_render(0), _frame_duration(500), _dispaly_cleared(false), _gps(nullptr) {
_display = new LiquidCrystal_I2C(0x27, 20, 4);
_logger = logger;
}
lcd::~lcd() {}
@@ -32,8 +106,9 @@ int lcd::init() {
}
#endif
_display->init();
Wire.setClock(400000);
_display->backlight();
_display->clear();
this->clear();
_display->setCursor(0, 0);
#ifdef DEEP_DEBUG
if (_logger != nullptr) {
@@ -43,26 +118,146 @@ int lcd::init() {
return 0;
}
int lcd::set_gps(gps *gps) {
_gps = gps;
}
int lcd::print_message(String message) {
#ifdef DEEP_DEBUG
if (_logger != nullptr) {
_logger->deep_debug(String(MOD) + ": print_message: Begin");
}
#endif
_display->clear();
_display->setCursor(0, 0);
_display->print(message);
String original = message;
this->clear();
if (message.length() > 80) {
message = message.substring(0, 80);
}
String lines[4] = {"", "", "", ""};
int lineIndex = 0;
while (message.length() > 0 && lineIndex < 4) {
if (message.length() <= 20) {
lines[lineIndex++] = message;
break;
}
int splitIndex = message.lastIndexOf(' ', 20);
if (splitIndex == -1 || splitIndex == 0) {
splitIndex = 20;
}
lines[lineIndex++] = message.substring(0, splitIndex);
if (splitIndex < message.length() && message.charAt(splitIndex) == ' ') {
message = message.substring(splitIndex + 1);
} else {
message = message.substring(splitIndex);
}
}
int usedLines = 0;
for (int i = 0; i < 4; i++) {
if (lines[i].length() > 0) usedLines++;
}
int startRow = 0;
if (usedLines == 1) startRow = 1;
else if (usedLines == 2) startRow = 1;
else startRow = 0;
int currentRow = startRow;
for (int i = 0; i < 4; i++) {
if (lines[i].length() == 0) continue;
int col = (20 - lines[i].length()) / 2;
if (col < 0) col = 0;
_display->setCursor(col, currentRow++);
this->print(lines[i]);
}
#ifdef INFO
if (_logger != nullptr) {
_logger->info(message);
_logger->info(original);
}
#endif
#ifdef DEEP_DEBUG
if (_logger != nullptr) {
_logger->deep_debug(String(MOD) + ": print_message: End");
}
#endif
return 0;
}
int lcd::switch_screen(screen::lcd_screen new_screen) {
_screen = new_screen;
return 0;
}
int lcd::render_task() {
unsigned long now = millis();
if (now < _last_render + _frame_duration) {
return 1;
}
switch (_screen)
{
case screen::blank:
this->clear();
break;
case screen::gps_debug:
this->clear();
if (_gps == nullptr) {
this->print_message("No GPS Found");
break;
}
gps_data data = _gps->get_data();
_display->setCursor(0,0);
this->print("Alt: ");
if (data.altitude.valid) {
this->print(data.altitude.value, 5);
} else {
this->print("not valid");
}
_display->setCursor(0,1);
this->print("Lat: ");
if (data.lat.valid) {
this->print(data.lat.value, 5);
} else {
this->print("not valid");
}
_display->setCursor(0,2);
this->print("Lng: ");
if (data.lng.valid) {
this->print(data.lng.value, 5);
} else {
this->print("not valid");
}
_display->setCursor(0,3);
this->print("Spd: ");
if (data.speed.valid) {
this->print(data.speed.value, 5);
} else {
this->print("not valid");
}
break;
default:
break;
}
_last_render = millis();
return 1;
}
#undef MOD