Everything works as intended. For now

This commit is contained in:
Rasmus Rasmussen 2026-01-09 16:05:26 +01:00
parent 4b283e0139
commit 9b118b2d80
8 changed files with 80 additions and 39 deletions

View File

@ -26,6 +26,22 @@ void setup() {
Serial.begin(115200); Serial.begin(115200);
Serial.println("Initializing..."); Serial.println("Initializing...");
CALIBRATION_IDLE _calibration_idle;
// Calibration phase, measure idle baseline over 3 seconds
Serial.println("Calibrating CPU baseline... please wait 3 seconds");
uint32_t calibration_start = xTaskGetIdleRunTimeCounter();
vTaskDelay(pdMS_TO_TICKS(3000));
uint32_t calibration_end = xTaskGetIdleRunTimeCounter();
// Calculate average idle iterations per millisecond during calibration
_calibration_idle.max_idle_iterations = (calibration_end - calibration_start) / 3000;
Serial.print("Baseline calibrated. Max idle iterations per ms: ");
Serial.println(_calibration_idle.max_idle_iterations);
_calibration_idle.idle_count_last = xTaskGetIdleRunTimeCounter();
// Create shared state // Create shared state
_display_state = new DISPLAY_STATE(); _display_state = new DISPLAY_STATE();
_display_state->update_display.store(false); _display_state->update_display.store(false);
@ -43,7 +59,7 @@ void setup() {
EventManager::getInstance().init(); EventManager::getInstance().init();
// Initialize system manager with shell and tft references // Initialize system manager with shell and tft references
sm->init(_display_state, _shell, th); sm->init(_display_state, _shell, th, _calibration_idle);
// Initialize components (they subscribe to events) // Initialize components (they subscribe to events)
im->init(_display_state, th); im->init(_display_state, th);

View File

@ -40,3 +40,8 @@ struct APPLICATION_EVENT {
struct DISPLAY_STATE { struct DISPLAY_STATE {
std::atomic<bool> update_display; std::atomic<bool> update_display;
}; };
struct CALIBRATION_IDLE {
uint32_t max_idle_iterations = 0;
uint32_t idle_count_last = 0;
};

View File

@ -52,10 +52,7 @@ public:
// You have full access to the window and can draw to it // You have full access to the window and can draw to it
while (_running) { while (_running) {
// Handle text editing logic here vTaskDelay(pdMS_TO_TICKS(1));
// Draw to the window content area using _tft
vTaskDelay(pdMS_TO_TICKS(100));
} }
} }
}; };
@ -68,7 +65,7 @@ public:
while (_running) { while (_running) {
// Calculator logic here // Calculator logic here
vTaskDelay(pdMS_TO_TICKS(100)); vTaskDelay(pdMS_TO_TICKS(1));
} }
} }
}; };
@ -81,40 +78,43 @@ public:
while (_running) { while (_running) {
// Game logic and rendering // Game logic and rendering
vTaskDelay(pdMS_TO_TICKS(50)); // 20 FPS vTaskDelay(pdMS_TO_TICKS(1)); // 20 FPS
} }
} }
}; };
// Example Program 5: Settings // Example Program 5: Settings
class SettingsProgram : public Program { class SettingsProgram : public Program {
private:
uint32_t max_idle_iterations;
public: public:
void run() override { void run() override {
Serial.println("Settings started!"); _window->x += 150;
_window->width -= 50;
//_window->sprite.setPsram(true);
//_window->sprite.createSprite(10, 10);
//_window->sprite.setColorDepth(16);
Serial.println("Settings started!");
WindowContentText ram_usage; WindowContentText ram_usage;
WindowContentText ram_usage_label; WindowContentText ram_usage_label;
WindowContentText cpu_usage; WindowContentText cpu_usage;
WindowContentText cpu_usage_label; WindowContentText cpu_usage_label;
ram_usage_label.size = 2; ram_usage_label.size = 2;
ram_usage_label.text = "RAM usage"; ram_usage_label.text = "RAM usage";
ram_usage_label.x = _window->x + 10; ram_usage_label.x = _window->x + 10;
ram_usage_label.y = _window->y + 50; ram_usage_label.y = _window->y + 50;
ram_usage.size = 2; ram_usage.size = 2;
ram_usage.x = _window->x + 10; ram_usage.x = _window->x + 10;
ram_usage.y = _window->y + 70; ram_usage.y = _window->y + 70;
cpu_usage_label.size = 2; cpu_usage_label.size = 2;
cpu_usage_label.text = "CPU usage:"; cpu_usage_label.text = "CPU usage:";
cpu_usage_label.x = _window->x + 10; cpu_usage_label.x = _window->x + 10;
cpu_usage_label.y = _window->y + 90; cpu_usage_label.y = _window->y + 90;
cpu_usage.size = 2; cpu_usage.size = 2;
cpu_usage.x = _window->x + 10; cpu_usage.x = _window->x + 10;
cpu_usage.y = _window->y + 110; cpu_usage.y = _window->y + 110;
_window->window_content_text.push_back(ram_usage_label); _window->window_content_text.push_back(ram_usage_label);
_window->window_content_text.push_back(ram_usage); _window->window_content_text.push_back(ram_usage);
_window->window_content_text.push_back(cpu_usage_label); _window->window_content_text.push_back(cpu_usage_label);
@ -125,14 +125,15 @@ public:
size_t free_ram; size_t free_ram;
size_t used_ram; size_t used_ram;
float ram_percent; float ram_percent;
float cpu_percent; float cpu_percent = 0.0f;
// For CPU calculation // For CPU calculation
uint32_t idle_count_last = 0; uint32_t idle_count_last = _calibration_idle.idle_count_last;
max_idle_iterations = _calibration_idle.max_idle_iterations;
Serial.printf("idle_count_last: %i\n", idle_count_last);
uint32_t idle_count_current = 0; uint32_t idle_count_current = 0;
uint counter = 0; uint counter = 0;
while (_running) { while (_running) {
counter++; counter++;
@ -141,7 +142,6 @@ public:
size_t internal_free = heap_caps_get_free_size(MALLOC_CAP_INTERNAL); size_t internal_free = heap_caps_get_free_size(MALLOC_CAP_INTERNAL);
size_t psram_total = heap_caps_get_total_size(MALLOC_CAP_SPIRAM); size_t psram_total = heap_caps_get_total_size(MALLOC_CAP_SPIRAM);
size_t psram_free = heap_caps_get_free_size(MALLOC_CAP_SPIRAM); size_t psram_free = heap_caps_get_free_size(MALLOC_CAP_SPIRAM);
total_ram = internal_total + psram_total; total_ram = internal_total + psram_total;
free_ram = internal_free + psram_free; free_ram = internal_free + psram_free;
used_ram = total_ram - free_ram; used_ram = total_ram - free_ram;
@ -150,26 +150,40 @@ public:
// CPU Usage - measure idle task iterations // CPU Usage - measure idle task iterations
idle_count_current = xTaskGetIdleRunTimeCounter(); idle_count_current = xTaskGetIdleRunTimeCounter();
if (idle_count_last > 0) { if (idle_count_last > 0 && max_idle_iterations > 0) {
uint32_t idle_delta = idle_count_current - idle_count_last; uint32_t idle_delta = idle_count_current - idle_count_last;
// The more idle iterations, the less CPU is used
// Scale based on your measurement interval (100ms) // Calculate idle percentage based on baseline
// Tune the divisor based on your specific system // We're measuring over 1ms, so compare to max_idle_iterations
cpu_percent = 100.0f - (idle_delta / 10000.0f); float idle_percent = ((float)idle_delta / (float)max_idle_iterations) * 100.0f;
// Cap at 100%
if (idle_percent > 100.0f) idle_percent = 100.0f;
// CPU usage is inverse of idle
cpu_percent = 100.0f - idle_percent;
if (cpu_percent < 0) cpu_percent = 0; if (cpu_percent < 0) cpu_percent = 0;
if (cpu_percent > 100) cpu_percent = 100;
} else { } else {
cpu_percent = 0.0f; cpu_percent = 0.0f;
} }
idle_count_last = idle_count_current; idle_count_last = idle_count_current;
_window->window_content_text[1].text = std::to_string(used_ram); _window->window_content_text[1].text = std::to_string(ram_percent);
_window->window_content_text[3].text = std::to_string(cpu_percent); _window->window_content_text[3].text = std::to_string((int)cpu_percent) + "%";
vTaskDelay(pdMS_TO_TICKS(5));
vTaskDelay(pdMS_TO_TICKS(1));
if (counter == 1000) { if (counter == 1000) {
Serial.printf("internal_total %i\n", internal_total);
Serial.printf("internal_free %i\n", internal_free);
Serial.printf("psram_total %i\n", psram_total);
Serial.printf("psram_free %i\n", psram_free);
Serial.printf("total_ram %i\n", total_ram);
Serial.printf("free_ram %i\n", free_ram);
Serial.printf("used_ram %i\n", used_ram);
Serial.printf("ram_percent %f.2\n", ram_percent);
Serial.printf("cpu_percent %f.2\n", cpu_percent);
Serial.println("===============");
_display_state->update_display.store(true); _display_state->update_display.store(true);
counter = 0; counter = 0;
} }

View File

@ -12,7 +12,7 @@ Program::~Program() {
close(); close();
} }
void Program::init(int id, std::string name, Window* window, Shell* shell, TFT_Handler* tft, DISPLAY_STATE* display_state) { void Program::init(int id, std::string name, Window* window, Shell* shell, TFT_Handler* tft, DISPLAY_STATE* display_state, CALIBRATION_IDLE calibration_idle) {
_id = id; _id = id;
_name = name; _name = name;
_window = window; _window = window;
@ -20,6 +20,7 @@ void Program::init(int id, std::string name, Window* window, Shell* shell, TFT_H
_tft = tft; _tft = tft;
_display_state = display_state; _display_state = display_state;
_running = true; _running = true;
_calibration_idle = calibration_idle;
// Create the task // Create the task
xTaskCreatePinnedToCore(task_wrapper, _name.c_str(), 4096, this, 1, &_task_handle, 0); xTaskCreatePinnedToCore(task_wrapper, _name.c_str(), 4096, this, 1, &_task_handle, 0);

View File

@ -4,6 +4,7 @@
#include "GLOBALS.h" #include "GLOBALS.h"
#include <string> #include <string>
#include <vector> #include <vector>
#include <LovyanGFX.hpp>
// Forward declarations // Forward declarations
class Shell; class Shell;
@ -66,6 +67,7 @@ struct Window {
std::string title; std::string title;
std::vector<WindowDecoration> window_decorations; std::vector<WindowDecoration> window_decorations;
std::vector<WindowContentText> window_content_text; std::vector<WindowContentText> window_content_text;
LGFX_Sprite sprite;
}; };
// Base Program class - all programs inherit from this // Base Program class - all programs inherit from this
@ -79,6 +81,7 @@ protected:
int _id; int _id;
std::string _name; std::string _name;
bool _running; bool _running;
CALIBRATION_IDLE _calibration_idle;
static void task_wrapper(void* pvParameters); static void task_wrapper(void* pvParameters);
@ -87,7 +90,7 @@ public:
virtual ~Program(); virtual ~Program();
// Initialize the program with its window and shell reference // Initialize the program with its window and shell reference
void init(int id, std::string name, Window* window, Shell* shell, TFT_Handler* tft, DISPLAY_STATE* display_state); void init(int id, std::string name, Window* window, Shell* shell, TFT_Handler* tft, DISPLAY_STATE* display_state, CALIBRATION_IDLE calibration_idle);
// Override this in your specific programs // Override this in your specific programs
virtual void run() = 0; virtual void run() = 0;

View File

@ -256,8 +256,6 @@ void Shell::draw_task_bar(int color) {
// Button // Button
tft->draw_box(6, 298, 50, 18, color); tft->draw_box(6, 298, 50, 18, color);
Serial.println(task_bar_items.size());
for (TaskBarItem item : task_bar_items) { for (TaskBarItem item : task_bar_items) {
if (item.focused) { if (item.focused) {
tft->draw_box(item.place_x - 2, item.place_y - 2, item.width + 3, item.height + 3, COL_BLACK); tft->draw_box(item.place_x - 2, item.place_y - 2, item.width + 3, item.height + 3, COL_BLACK);
@ -373,6 +371,7 @@ int Shell::handle_desktop_click(CLICK_EVENT event) {
win->minimized = false; win->minimized = false;
win->title = item.name; win->title = item.name;
win->window_content_text = {}; win->window_content_text = {};
win->sprite = LGFX_Sprite(&tft->tft);
// Spawn program using the program_class // Spawn program using the program_class
bool result = _system_manager->spawn_program(win, item.program_class); bool result = _system_manager->spawn_program(win, item.program_class);

View File

@ -4,10 +4,11 @@
#include "example_programs.h" #include "example_programs.h"
#include <Arduino.h> #include <Arduino.h>
void SystemManager::init(DISPLAY_STATE* display_state, Shell* shell, TFT_Handler* tft) { void SystemManager::init(DISPLAY_STATE* display_state, Shell* shell, TFT_Handler* tft, CALIBRATION_IDLE calibration_idle) {
_display_state = display_state; _display_state = display_state;
_shell = shell; _shell = shell;
_tft = tft; _tft = tft;
_calibration_idle = calibration_idle;
// Register all available programs // Register all available programs
register_program<CounterProgram>("CounterProgram"); register_program<CounterProgram>("CounterProgram");
@ -37,7 +38,7 @@ bool SystemManager::spawn_program(Window* window, const std::string& program_cla
// Assign ID and initialize // Assign ID and initialize
window->id = _next_program_id; window->id = _next_program_id;
program->init(_next_program_id, window->title, window, _shell, _tft, _display_state); program->init(_next_program_id, window->title, window, _shell, _tft, _display_state, _calibration_idle);
_next_program_id++; _next_program_id++;
_programs.push_back(program); _programs.push_back(program);

View File

@ -4,6 +4,7 @@
#include <unordered_map> #include <unordered_map>
#include <string> #include <string>
#include <functional> #include <functional>
#include "GLOBALS.h"
// Forward declarations // Forward declarations
class Shell; class Shell;
@ -15,6 +16,7 @@ private:
Shell* _shell; Shell* _shell;
TFT_Handler* _tft; TFT_Handler* _tft;
int _next_program_id = 1; int _next_program_id = 1;
CALIBRATION_IDLE _calibration_idle;
// Factory function type: creates a new instance of a Program // Factory function type: creates a new instance of a Program
using ProgramFactory = std::function<Program*()>; using ProgramFactory = std::function<Program*()>;
@ -25,7 +27,7 @@ private:
public: public:
std::vector<Program*> _programs; std::vector<Program*> _programs;
void init(DISPLAY_STATE* display_state, Shell* shell, TFT_Handler* tft); void init(DISPLAY_STATE* display_state, Shell* shell, TFT_Handler* tft, CALIBRATION_IDLE calibration_idle);
// Register a program type with a factory function // Register a program type with a factory function
template<typename T> template<typename T>