some cleanup

This commit is contained in:
2025-10-11 11:15:39 +02:00
parent 5b75ff28e0
commit 535b0078e5
25 changed files with 359 additions and 368 deletions

View File

@@ -1,21 +1,14 @@
idf_component_register(SRCS
src/app_main.cpp
../sdk/apps/menu_app.cpp
../sdk/apps/clock_app.cpp
../sdk/apps/tetris_app.cpp
../sdk/apps/gameboy_app.cpp
src/display.cpp
src/bat_mon.cpp
src/spi_global.cpp
src/i2c_global.cpp
src/disp_tools.cpp
src/disp_tty.cpp
src/shutdowner.cpp
src/buttons.cpp
src/power_helper.cpp
src/buzzer.cpp
src/fs_helper.cpp
../sdk/src/app_system.cpp
PRIV_REQUIRES spi_flash esp_driver_i2c driver sdk-esp esp_timer nvs_flash littlefs
INCLUDE_DIRS "include" "../sdk/include"
EMBED_FILES "roms/builtin_demo1.gb" "roms/builtin_demo2.gb")

View File

@@ -11,9 +11,6 @@ using AppButtonEvent = cardboy::sdk::AppButtonEvent;
using AppTimerEvent = cardboy::sdk::AppTimerEvent;
using AppEvent = cardboy::sdk::AppEvent;
template<typename FramebufferT, typename InputT, typename ClockT>
using BasicAppContext = cardboy::sdk::BasicAppContext<FramebufferT, InputT, ClockT>;
using AppContext = cardboy::sdk::AppContext;
using IApp = cardboy::sdk::IApp;

View File

@@ -5,37 +5,37 @@
#include "config.hpp"
#include <buttons.hpp>
#include <disp_tools.hpp>
#include <display.hpp>
#include <power_helper.hpp>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
class PlatformFramebuffer final : public cardboy::sdk::IFramebuffer {
class PlatformFramebuffer final : public cardboy::sdk::FramebufferFacade<PlatformFramebuffer> {
public:
int width() const override { return cardboy::sdk::kDisplayWidth; }
int height() const override { return cardboy::sdk::kDisplayHeight; }
[[nodiscard]] int width_impl() const { return cardboy::sdk::kDisplayWidth; }
[[nodiscard]] int height_impl() const { return cardboy::sdk::kDisplayHeight; }
void drawPixel(int x, int y, bool on) override {
__attribute__((always_inline)) void drawPixel_impl(int x, int y, bool on) {
if (x < 0 || y < 0 || x >= width() || y >= height())
return;
DispTools::set_pixel(x, y, on);
SMD::set_pixel(x, y, on);
}
void clear(bool on) override {
void clear_impl(bool on) {
for (int y = 0; y < height(); ++y)
for (int x = 0; x < width(); ++x)
DispTools::set_pixel(x, y, on);
SMD::set_pixel(x, y, on);
}
void beginFrame() override { DispTools::draw_to_display_async_wait(); }
void endFrame() override { DispTools::draw_to_display_async_start(); }
bool isFrameInFlight() const override { return DispTools::draw_to_display_async_busy(); }
__attribute__((always_inline)) void frameReady_impl() { SMD::frame_ready(); }
__attribute__((always_inline)) void sendFrame_impl(bool clear) { SMD::send_frame(clear); }
__attribute__((always_inline)) [[nodiscard]] bool frameInFlight_impl() const { return SMD::frame_transfer_in_flight(); }
};
class PlatformInput final : public cardboy::sdk::IInput {
class PlatformInput final : public cardboy::sdk::InputFacade<PlatformInput> {
public:
cardboy::sdk::InputState readState() override {
cardboy::sdk::InputState readState_impl() {
cardboy::sdk::InputState state{};
const uint8_t pressed = Buttons::get().get_pressed();
if (pressed & BTN_UP)
@@ -58,14 +58,14 @@ public:
}
};
class PlatformClock final : public cardboy::sdk::IClock {
class PlatformClock final : public cardboy::sdk::ClockFacade<PlatformClock> {
public:
std::uint32_t millis() override {
std::uint32_t millis_impl() {
TickType_t ticks = xTaskGetTickCount();
return static_cast<std::uint32_t>((static_cast<std::uint64_t>(ticks) * 1000ULL) / configTICK_RATE_HZ);
}
void sleep_ms(std::uint32_t ms) override {
void sleep_ms_impl(std::uint32_t ms) {
if (ms == 0)
return;
PowerHelper::get().delay(static_cast<int>(ms), static_cast<int>(ms));

View File

@@ -0,0 +1,14 @@
#pragma once
#include "app_platform.hpp"
#include "cardboy/sdk/platform.hpp"
namespace cardboy::backend {
struct EspBackend {
using Framebuffer = PlatformFramebuffer;
using Input = PlatformInput;
using Clock = PlatformClock;
};
} // namespace cardboy::backend

View File

@@ -1,53 +0,0 @@
//
// Created by Stepan Usatiuk on 02.03.2025.
//
#ifndef CB_DISP_TOOLS_HPP
#define CB_DISP_TOOLS_HPP
#include <display.hpp>
namespace DispTools {
static void clear() {
for (int y = 0; y < DISP_HEIGHT; y++) {
for (int x = 0; x < DISP_WIDTH; x++) {
SMD::set_pixel(x, y, true);
}
}
}
static bool get_pixel(int x, int y) {
if (x < 0 || x >= DISP_WIDTH || y < 0 || y >= DISP_HEIGHT)
assert(false);
assert(false); // Not implemented
return true;
// return disp_frame[y][x];
}
static void reset_pixel(int x, int y) {
if (x < 0 || x >= DISP_WIDTH || y < 0 || y >= DISP_HEIGHT)
assert(false);
SMD::set_pixel(x, y, false);
}
static void set_pixel(int x, int y) {
if (x < 0 || x >= DISP_WIDTH || y < 0 || y >= DISP_HEIGHT)
assert(false);
SMD::set_pixel(x, y, true);
}
static void set_pixel(int x, int y, bool on) {
if (on) {
set_pixel(x, y);
} else {
reset_pixel(x, y);
}
}
// New simplified async pipeline wrappers
static void async_frame_start() { SMD::async_draw_wait(); } // call at frame start
static void async_frame_end() { SMD::async_draw_start(); } // call after rendering
// Legacy names (temporary) mapped to new API in case of straggling calls
static void draw_to_display_async_start() { SMD::async_draw_start(); }
static void draw_to_display_async_wait() { SMD::async_draw_wait(); }
static bool draw_to_display_async_busy() { return SMD::async_draw_busy(); }
};
#endif // DISP_TOOLS_HPP

View File

@@ -1,42 +0,0 @@
//
// Created by Stepan Usatiuk on 02.03.2025.
//
#ifndef DISP_TTY_HPP
#define DISP_TTY_HPP
#include <array>
#include <cstddef>
#include "config.hpp"
#include <format>
class FbTty {
public:
void putchar(char c);
void putstr(const char* str);
void reset();
template<typename... Args>
auto fmt(std::format_string<Args...> fmt, Args&&... args) {
auto str = std::format(fmt, std::forward<Args>(args)...);
putstr(str.c_str());
}
private:
void draw_char(int col, int row);
int _cur_col = 0;
int _cur_row = 0;
static constexpr size_t _max_col = DISP_WIDTH / 8;
static constexpr size_t _max_row = DISP_HEIGHT / 16;
std::array<std::array<char, _max_row>, _max_col> _buf = {};
void next_col();
void next_row();
};
#endif // DISP_TTY_HPP

View File

@@ -24,15 +24,15 @@ extern uint8_t* dma_buf;
void init();
// Double-buffered asynchronous frame pipeline:
// Usage pattern each frame:
// SMD::async_draw_wait(); // (start of frame) waits for previous transfer & ensures draw buffer is ready/synced
// SMD::frame_ready(); // (start of frame) waits for previous transfer & ensures draw buffer is ready/synced
// ... write pixels into dma_buf via set_pixel / surface ...
// SMD::async_draw_start(); // (end of frame) queues SPI DMA of current framebuffer; once SPI finishes the sent buffer
// // is asynchronously cleared so the alternate buffer is ready for the next frame
void async_draw_start();
void async_draw_wait();
bool async_draw_busy(); // optional diagnostic: is a frame transfer still in flight?
// SMD::send_frame(); // (end of frame) queues SPI DMA of current framebuffer; once SPI finishes the sent buffer
// // is optionally cleared so the alternate buffer is ready for the next frame
void send_frame(bool clear_after_send = true);
void frame_ready();
bool frame_transfer_in_flight(); // optional diagnostic: is a frame transfer still in flight?
static void set_pixel(int x, int y, bool value) {
__attribute__((always_inline)) static void set_pixel(int x, int y, bool value) {
assert(x >= 0 && x < DISP_WIDTH && y >= 0 && y < DISP_HEIGHT);
unsigned lineIdx = 2 + kLineMultiSingle * y + (x / 8);

View File

@@ -6,6 +6,7 @@
#define POWER_HELPER_HPP
#include "freertos/FreeRTOS.h"
#include "freertos/event_groups.h"
class PowerHelper {
public:

View File

@@ -14,7 +14,6 @@
#include <bat_mon.hpp>
#include <buttons.hpp>
#include <buzzer.hpp>
#include <disp_tools.hpp>
#include <display.hpp>
#include <fs_helper.hpp>
#include <i2c_global.hpp>
@@ -299,8 +298,6 @@ extern "C" void app_main() {
BatMon::get();
SpiGlobal::get();
SMD::init();
DispTools::clear();
Buzzer::get().init();
FsHelper::get().mount();

View File

@@ -1,10 +0,0 @@
//
// Created by Stepan Usatiuk on 02.03.2025.
//
#include "disp_tools.hpp"
#include <cmath>
#include <display.hpp>

View File

@@ -1,62 +0,0 @@
//
// Created by Stepan Usatiuk on 26.04.2024.
//
#include "disp_tty.hpp"
#include <disp_tools.hpp>
#include "cardboy/gfx/Fonts.hpp"
void FbTty::draw_char(int col, int row) {
for (int x = 0; x < 8; x++) {
for (int y = 0; y < 16; y++) {
bool color = fonts_Terminess_Powerline[_buf[col][row]][y] & (1 << (8 - x));
if (color)
DispTools::set_pixel(col * 8 + x, row * 16 + y);
else
DispTools::reset_pixel(col * 8 + x, row * 16 + y);
}
}
}
void FbTty::reset() {
_cur_col = 0;
_cur_row = 0;
}
void FbTty::putchar(char c) {
if (c == '\n') {
next_row();
return;
}
_buf[_cur_col][_cur_row] = c;
draw_char(_cur_col, _cur_row);
next_col();
}
void FbTty::putstr(const char* str) {
while (*str != 0) {
putchar(*str);
str++;
}
}
void FbTty::next_col() {
_cur_col++;
_cur_col = _cur_col % _max_col;
if (_cur_col == 0) {
next_row();
} else {
_buf[_cur_col][_cur_row] = ' ';
draw_char(_cur_col, _cur_row);
}
}
void FbTty::next_row() {
_cur_col = 0;
_cur_row++;
_cur_row = _cur_row % _max_row;
for (int i = 0; i < _max_col; i++) {
_buf[i][_cur_row] = ' ';
draw_char(i, _cur_row);
}
}

View File

@@ -4,7 +4,6 @@
#include <cassert>
#include <cstring>
#include <driver/gpio.h>
#include "disp_tools.hpp"
#include "driver/spi_master.h"
#include "esp_async_memcpy.h"
#include "esp_timer.h"
@@ -27,6 +26,7 @@ static bool _vcom = false;
static TaskHandle_t s_clearTaskHandle = nullptr;
static SemaphoreHandle_t s_clearReqSem = nullptr;
static SemaphoreHandle_t s_bufferSem[2] = {nullptr, nullptr};
static bool s_clearPending[2] = {true, true};
static async_memcpy_config_t config = ASYNC_MEMCPY_DEFAULT_CONFIG();
// update the maximum data stream supported by underlying DMA engine
@@ -58,8 +58,17 @@ static void clear_task(void*) {
ESP_ERROR_CHECK(spi_device_get_trans_result(SMD::_spi, &r, 0));
int bufIdx = (int) r->user;
xSemaphoreGive(_txSem);
ESP_ERROR_CHECK(esp_async_memcpy(driver, s_dma_buffers[bufIdx], dma_buf_template, 12480U,
my_async_memcpy_cb, static_cast<void*>(s_bufferSem[bufIdx])));
const bool shouldClear = s_clearPending[bufIdx];
s_clearPending[bufIdx] = true;
if (shouldClear) {
constexpr unsigned alignedSize = SMD::kLineDataBytes - (SMD::kLineDataBytes % 4);
static_assert(SMD::kLineDataBytes - alignedSize < 8); // Last byte is zero anyway
ESP_ERROR_CHECK(esp_async_memcpy(driver, s_dma_buffers[bufIdx], dma_buf_template, alignedSize,
my_async_memcpy_cb, static_cast<void*>(s_bufferSem[bufIdx])));
} else {
if (!xSemaphoreGive(s_bufferSem[bufIdx]))
assert(false);
}
}
}
}
@@ -101,9 +110,9 @@ void SMD::init() {
xTaskCreate(clear_task, "fbclr", 1536, nullptr, tskIDLE_PRIORITY + 1, &s_clearTaskHandle);
}
bool SMD::async_draw_busy() { return uxSemaphoreGetCount(s_bufferSem[s_drawBufIdx]) == 0; }
bool SMD::frame_transfer_in_flight() { return uxSemaphoreGetCount(s_bufferSem[s_drawBufIdx]) == 0; }
void SMD::async_draw_start() {
void SMD::send_frame(bool clear_after_send) {
assert(driver != nullptr);
if (!xSemaphoreTake(_txSem, portMAX_DELAY))
assert(false);
@@ -115,7 +124,8 @@ void SMD::async_draw_start() {
if (!xSemaphoreTake(sem, 0))
assert(false);
const int nextDrawIdx = sendIdx ^ 1;
const int nextDrawIdx = sendIdx ^ 1;
s_clearPending[sendIdx] = clear_after_send;
_vcom = !_vcom;
_tx = {};
@@ -129,7 +139,7 @@ void SMD::async_draw_start() {
dma_buf = s_dma_buffers[nextDrawIdx];
}
void SMD::async_draw_wait() {
void SMD::frame_ready() {
SemaphoreHandle_t sem = s_bufferSem[s_drawBufIdx];
// uint64_t waitedUs = 0;
if (!uxSemaphoreGetCount(sem)) {