Everything works as intended. For now
This commit is contained in:
parent
4b283e0139
commit
9b118b2d80
@ -26,6 +26,22 @@ void setup() {
|
||||
Serial.begin(115200);
|
||||
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
|
||||
_display_state = new DISPLAY_STATE();
|
||||
_display_state->update_display.store(false);
|
||||
@ -43,7 +59,7 @@ void setup() {
|
||||
EventManager::getInstance().init();
|
||||
|
||||
// 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)
|
||||
im->init(_display_state, th);
|
||||
|
||||
@ -39,4 +39,9 @@ struct APPLICATION_EVENT {
|
||||
|
||||
struct DISPLAY_STATE {
|
||||
std::atomic<bool> update_display;
|
||||
};
|
||||
|
||||
struct CALIBRATION_IDLE {
|
||||
uint32_t max_idle_iterations = 0;
|
||||
uint32_t idle_count_last = 0;
|
||||
};
|
||||
@ -49,13 +49,10 @@ class TextEditorProgram : public Program {
|
||||
public:
|
||||
void run() override {
|
||||
Serial.println("Text editor started!");
|
||||
|
||||
|
||||
// You have full access to the window and can draw to it
|
||||
while (_running) {
|
||||
// Handle text editing logic here
|
||||
// Draw to the window content area using _tft
|
||||
|
||||
vTaskDelay(pdMS_TO_TICKS(100));
|
||||
vTaskDelay(pdMS_TO_TICKS(1));
|
||||
}
|
||||
}
|
||||
};
|
||||
@ -68,7 +65,7 @@ public:
|
||||
|
||||
while (_running) {
|
||||
// Calculator logic here
|
||||
vTaskDelay(pdMS_TO_TICKS(100));
|
||||
vTaskDelay(pdMS_TO_TICKS(1));
|
||||
}
|
||||
}
|
||||
};
|
||||
@ -81,67 +78,70 @@ public:
|
||||
|
||||
while (_running) {
|
||||
// Game logic and rendering
|
||||
vTaskDelay(pdMS_TO_TICKS(50)); // 20 FPS
|
||||
vTaskDelay(pdMS_TO_TICKS(1)); // 20 FPS
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// Example Program 5: Settings
|
||||
class SettingsProgram : public Program {
|
||||
private:
|
||||
uint32_t max_idle_iterations;
|
||||
|
||||
public:
|
||||
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_label;
|
||||
WindowContentText cpu_usage;
|
||||
WindowContentText cpu_usage_label;
|
||||
|
||||
ram_usage_label.size = 2;
|
||||
ram_usage_label.text = "RAM usage";
|
||||
ram_usage_label.x = _window->x + 10;
|
||||
ram_usage_label.y = _window->y + 50;
|
||||
|
||||
ram_usage.size = 2;
|
||||
ram_usage.x = _window->x + 10;
|
||||
ram_usage.y = _window->y + 70;
|
||||
|
||||
cpu_usage_label.size = 2;
|
||||
cpu_usage_label.text = "CPU usage:";
|
||||
cpu_usage_label.x = _window->x + 10;
|
||||
cpu_usage_label.y = _window->y + 90;
|
||||
|
||||
cpu_usage.size = 2;
|
||||
cpu_usage.x = _window->x + 10;
|
||||
cpu_usage.y = _window->y + 110;
|
||||
|
||||
_window->window_content_text.push_back(ram_usage_label);
|
||||
_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);
|
||||
|
||||
|
||||
// Variables for metrics
|
||||
size_t total_ram;
|
||||
size_t free_ram;
|
||||
size_t used_ram;
|
||||
float ram_percent;
|
||||
float cpu_percent;
|
||||
float cpu_percent = 0.0f;
|
||||
|
||||
// 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;
|
||||
|
||||
uint counter = 0;
|
||||
|
||||
while (_running) {
|
||||
counter++;
|
||||
|
||||
|
||||
// RAM Calculation (Internal + PSRAM)
|
||||
size_t internal_total = heap_caps_get_total_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_free = heap_caps_get_free_size(MALLOC_CAP_SPIRAM);
|
||||
|
||||
total_ram = internal_total + psram_total;
|
||||
free_ram = internal_free + psram_free;
|
||||
used_ram = total_ram - free_ram;
|
||||
@ -150,26 +150,40 @@ public:
|
||||
// CPU Usage - measure idle task iterations
|
||||
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;
|
||||
// The more idle iterations, the less CPU is used
|
||||
// Scale based on your measurement interval (100ms)
|
||||
// Tune the divisor based on your specific system
|
||||
cpu_percent = 100.0f - (idle_delta / 10000.0f);
|
||||
|
||||
// Calculate idle percentage based on baseline
|
||||
// We're measuring over 1ms, so compare to max_idle_iterations
|
||||
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 > 100) cpu_percent = 100;
|
||||
} else {
|
||||
cpu_percent = 0.0f;
|
||||
}
|
||||
|
||||
idle_count_last = idle_count_current;
|
||||
|
||||
_window->window_content_text[1].text = std::to_string(used_ram);
|
||||
_window->window_content_text[3].text = std::to_string(cpu_percent);
|
||||
|
||||
vTaskDelay(pdMS_TO_TICKS(5));
|
||||
|
||||
|
||||
_window->window_content_text[1].text = std::to_string(ram_percent);
|
||||
_window->window_content_text[3].text = std::to_string((int)cpu_percent) + "%";
|
||||
|
||||
vTaskDelay(pdMS_TO_TICKS(1));
|
||||
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);
|
||||
counter = 0;
|
||||
}
|
||||
|
||||
@ -12,7 +12,7 @@ Program::~Program() {
|
||||
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;
|
||||
_name = name;
|
||||
_window = window;
|
||||
@ -20,6 +20,7 @@ void Program::init(int id, std::string name, Window* window, Shell* shell, TFT_H
|
||||
_tft = tft;
|
||||
_display_state = display_state;
|
||||
_running = true;
|
||||
_calibration_idle = calibration_idle;
|
||||
|
||||
// Create the task
|
||||
xTaskCreatePinnedToCore(task_wrapper, _name.c_str(), 4096, this, 1, &_task_handle, 0);
|
||||
|
||||
@ -4,6 +4,7 @@
|
||||
#include "GLOBALS.h"
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <LovyanGFX.hpp>
|
||||
|
||||
// Forward declarations
|
||||
class Shell;
|
||||
@ -66,6 +67,7 @@ struct Window {
|
||||
std::string title;
|
||||
std::vector<WindowDecoration> window_decorations;
|
||||
std::vector<WindowContentText> window_content_text;
|
||||
LGFX_Sprite sprite;
|
||||
};
|
||||
|
||||
// Base Program class - all programs inherit from this
|
||||
@ -79,6 +81,7 @@ protected:
|
||||
int _id;
|
||||
std::string _name;
|
||||
bool _running;
|
||||
CALIBRATION_IDLE _calibration_idle;
|
||||
|
||||
static void task_wrapper(void* pvParameters);
|
||||
|
||||
@ -87,7 +90,7 @@ public:
|
||||
virtual ~Program();
|
||||
|
||||
// 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
|
||||
virtual void run() = 0;
|
||||
|
||||
@ -256,8 +256,6 @@ void Shell::draw_task_bar(int color) {
|
||||
// Button
|
||||
tft->draw_box(6, 298, 50, 18, color);
|
||||
|
||||
Serial.println(task_bar_items.size());
|
||||
|
||||
for (TaskBarItem item : task_bar_items) {
|
||||
if (item.focused) {
|
||||
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->title = item.name;
|
||||
win->window_content_text = {};
|
||||
win->sprite = LGFX_Sprite(&tft->tft);
|
||||
|
||||
// Spawn program using the program_class
|
||||
bool result = _system_manager->spawn_program(win, item.program_class);
|
||||
|
||||
@ -4,10 +4,11 @@
|
||||
#include "example_programs.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;
|
||||
_shell = shell;
|
||||
_tft = tft;
|
||||
_calibration_idle = calibration_idle;
|
||||
|
||||
// Register all available programs
|
||||
register_program<CounterProgram>("CounterProgram");
|
||||
@ -37,7 +38,7 @@ bool SystemManager::spawn_program(Window* window, const std::string& program_cla
|
||||
|
||||
// Assign ID and initialize
|
||||
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++;
|
||||
_programs.push_back(program);
|
||||
|
||||
@ -4,6 +4,7 @@
|
||||
#include <unordered_map>
|
||||
#include <string>
|
||||
#include <functional>
|
||||
#include "GLOBALS.h"
|
||||
|
||||
// Forward declarations
|
||||
class Shell;
|
||||
@ -15,6 +16,7 @@ private:
|
||||
Shell* _shell;
|
||||
TFT_Handler* _tft;
|
||||
int _next_program_id = 1;
|
||||
CALIBRATION_IDLE _calibration_idle;
|
||||
|
||||
// Factory function type: creates a new instance of a Program
|
||||
using ProgramFactory = std::function<Program*()>;
|
||||
@ -25,7 +27,7 @@ private:
|
||||
public:
|
||||
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
|
||||
template<typename T>
|
||||
|
||||
Loading…
Reference in New Issue
Block a user