check macro

This commit is contained in:
2025-10-11 20:36:43 +02:00
parent 961453e28a
commit 9a392d6aec
8 changed files with 114 additions and 33 deletions

View File

@@ -21,6 +21,7 @@ idf_component_register(
nvs_flash
)
add_subdirectory("${CMAKE_CURRENT_LIST_DIR}/../../sdk/utils" cardboy_utils_esp)
add_subdirectory("${CMAKE_CURRENT_LIST_DIR}/../../sdk/backend_interface" backend_interface_from_backend_esp)
add_library(cardboy_backend_esp INTERFACE)

View File

@@ -6,6 +6,7 @@
#define CB_DISPLAY_HPP
#include "cardboy/backend/esp/config.hpp"
#include "cardboy/utils/utils.hpp"
#include "driver/spi_master.h"
// (Async memcpy removed for debugging simplification)
@@ -34,7 +35,7 @@ void frame_ready();
bool frame_transfer_in_flight(); // optional diagnostic: is a frame transfer still in flight?
__attribute__((always_inline)) static void set_pixel(int x, int y, bool value) {
assert(x >= 0 && x < DISP_WIDTH && y >= 0 && y < DISP_HEIGHT);
CARDBOY_CHECK(x >= 0 && x < DISP_WIDTH && y >= 0 && y < DISP_HEIGHT);
unsigned lineIdx = 2 + kLineMultiSingle * y + (x / 8);
unsigned bitIdx = 1 << (7 - (x % 8)) % 8;
@@ -47,8 +48,8 @@ __attribute__((always_inline)) static void set_pixel(int x, int y, bool value) {
}
__attribute__((always_inline)) static void set_pixel_8(int x, int y, std::uint8_t value) {
assert(x >= 0 && x < DISP_WIDTH && y >= 0 && y < DISP_HEIGHT);
assert((x % 8) == 0);
CARDBOY_CHECK(x >= 0 && x < DISP_WIDTH && y >= 0 && y < DISP_HEIGHT);
CARDBOY_CHECK((x % 8) == 0);
unsigned lineIdx = 2 + kLineMultiSingle * y + (x / 8);
dma_buf[lineIdx] = ~value;
}

View File

@@ -16,10 +16,12 @@ class EspFramebuffer final : public cardboy::sdk::FramebufferFacade<EspFramebuff
public:
EspFramebuffer() = default;
[[nodiscard]] int width_impl() const { return cardboy::sdk::kDisplayWidth; }
[[nodiscard]] int height_impl() const { return cardboy::sdk::kDisplayHeight; }
void drawPixel_impl(int x, int y, bool on) { SMD::set_pixel(x, y, on); }
void drawBits8_impl(int x, int y, std::uint8_t bits) { SMD::set_pixel_8(x, y, bits); }
[[nodiscard]] int width_impl() const { return cardboy::sdk::kDisplayWidth; }
[[nodiscard]] int height_impl() const { return cardboy::sdk::kDisplayHeight; }
void __attribute__((always_inline)) drawPixel_impl(int x, int y, bool on) { SMD::set_pixel(x, y, on); }
void __attribute__((always_inline)) drawBits8_impl(int x, int y, std::uint8_t bits) {
SMD::set_pixel_8(x, y, bits);
}
void clear_impl(bool on);
void frameReady_impl();
void sendFrame_impl(bool clearAfterSend);

View File

@@ -5,6 +5,8 @@ set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD_REQUIRED YES)
set(CMAKE_CXX_EXTENSIONS NO)
add_subdirectory(utils)
add_subdirectory(backend_interface)
set(CARDBOY_SDK_BACKEND_LIBRARY "" CACHE STRING "Backend implementation library for Cardboy SDK")

View File

@@ -5,6 +5,7 @@
#include "cardboy/sdk/app_framework.hpp"
#include "cardboy/sdk/app_system.hpp"
#include "cardboy/sdk/services.hpp"
#include "cardboy/utils/utils.hpp"
#include <inttypes.h>
@@ -1039,23 +1040,21 @@ private:
if (!activeRomName.empty()) {
const std::string rotatedRomName(activeRomName.rbegin(), activeRomName.rend());
const auto textBounds =
font16x8::measureTextBounds(rotatedRomName, textScale, 1,
font16x8::Rotation::Clockwise90);
font16x8::measureTextBounds(rotatedRomName, textScale, 1, font16x8::Rotation::Clockwise90);
const int textHeight = textBounds.height;
const int maxOrigin = std::max(0, screenHeight - textHeight);
int leftX = 8;
int leftY = std::clamp((screenHeight - textHeight) / 2, 0, maxOrigin);
const int maxOrigin = std::max(0, screenHeight - textHeight);
int leftX = 8;
int leftY = std::clamp((screenHeight - textHeight) / 2, 0, maxOrigin);
font16x8::drawText(framebuffer, leftX, leftY, rotatedRomName, textScale, true, 1,
font16x8::Rotation::Clockwise90);
if (!statusMessage.empty()) {
const std::string rotatedStatusMessage(statusMessage.rbegin(), statusMessage.rend());
const auto statusBounds =
font16x8::measureTextBounds(rotatedStatusMessage, textScale, 1,
font16x8::Rotation::Clockwise90);
const int textHeight = statusBounds.height;
const int maxOrigin = std::max(0, screenHeight - textHeight);
leftX = leftX + 20;
leftY = std::clamp((screenHeight - textHeight) / 2, 0, maxOrigin);
const auto statusBounds = font16x8::measureTextBounds(rotatedStatusMessage, textScale, 1,
font16x8::Rotation::Clockwise90);
const int textHeight = statusBounds.height;
const int maxOrigin = std::max(0, screenHeight - textHeight);
leftX = leftX + 20;
leftY = std::clamp((screenHeight - textHeight) / 2, 0, maxOrigin);
font16x8::drawText(framebuffer, leftX, leftY, rotatedStatusMessage, textScale, true, 1,
font16x8::Rotation::Clockwise90);
}
@@ -1075,9 +1074,7 @@ private:
std::string rotated(text.rbegin(), text.rend());
if (totalRightHeight > 0)
totalRightHeight += gap;
const auto bounds =
font16x8::measureTextBounds(rotated, textScale, 1,
font16x8::Rotation::Clockwise90);
const auto bounds = font16x8::measureTextBounds(rotated, textScale, 1, font16x8::Rotation::Clockwise90);
totalRightHeight += bounds.height;
}
@@ -1093,10 +1090,8 @@ private:
if (text.empty())
continue;
std::string rotated(text.rbegin(), text.rend());
const auto bounds =
font16x8::measureTextBounds(rotated, textScale, 1,
font16x8::Rotation::Clockwise90);
rightY = screenHeight - bounds.height - 8;
const auto bounds = font16x8::measureTextBounds(rotated, textScale, 1, font16x8::Rotation::Clockwise90);
rightY = screenHeight - bounds.height - 8;
font16x8::drawText(framebuffer, rightX, rightY, rotated, textScale, true, 1,
font16x8::Rotation::Clockwise90);
rightX -= 20;
@@ -1193,8 +1188,7 @@ private:
}
static GameboyApp* fromGb(struct gb_s* gb) {
if (!gb)
return nullptr;
CARDBOY_CHECK_CODE(if (!gb) return nullptr;);
return static_cast<GameboyApp*>(gb->direct.priv);
}
@@ -1210,11 +1204,10 @@ private:
static uint8_t romRead(struct gb_s* gb, const uint_fast32_t addr) {
auto* self = fromGb(gb);
if (!self)
return 0xFF;
// ScopedCallbackTimer timer(self, PerfTracker::CallbackKind::RomRead);
if (!self->romDataView || addr >= self->romDataViewSize)
return 0xFF;
CARDBOY_CHECK_CODE(if (!self) return 0xFF;
if (!self->romDataView || addr >= self->romDataViewSize) return 0xFF;);
// ScopedCallbackTimer timer(self,
// PerfTracker::CallbackKind::RomRead);
return self->romDataView[static_cast<std::size_t>(addr)];
}

View File

@@ -1,5 +1,7 @@
add_library(cardboy_backend_interface INTERFACE)
target_link_libraries(cardboy_backend_interface INTERFACE cardboy_utils)
set_target_properties(cardboy_backend_interface PROPERTIES
EXPORT_NAME backend_interface
)

View File

@@ -0,0 +1,21 @@
add_library(cardboy_utils INTERFACE)
option(CARDBOY_MORE_CHECKS "More checks" OFF)
set_target_properties(cardboy_utils PROPERTIES
EXPORT_NAME utils
)
target_include_directories(cardboy_utils
INTERFACE
${CMAKE_CURRENT_SOURCE_DIR}/include
)
if(CARDBOY_MORE_CHECKS)
target_compile_definitions(cardboy_utils INTERFACE CARDBOY_MORE_CHECKS=1)
endif()
target_sources(cardboy_utils
INTERFACE
${CMAKE_CURRENT_SOURCE_DIR}/include/cardboy/utils/utils.hpp
)

View File

@@ -0,0 +1,59 @@
//
// Created by Stepan Usatiuk on 11.10.2025.
//
#ifndef CARDBOY_SDK_UTILS_HPP
#define CARDBOY_SDK_UTILS_HPP
#ifndef CARDBOY_MORE_CHECKS
#define CARDBOY_MORE_CHECKS 0
#endif
#if CARDBOY_MORE_CHECKS
#include <cstdio>
#include <cstdlib>
// Fails the program with a message. Internal use.
#define CARDBOY__CHECK_FAIL_IMPL(expr_str, file, line, func, msg_opt) \
do { \
std::fprintf(stderr, \
"CARDBOY_CHECK failed: %s\n at %s:%d in %s%s%s\n", \
(expr_str), (file), (line), (func), \
((msg_opt) ? "\n message: " : ""), \
((msg_opt) ? (msg_opt) : "")); \
std::fflush(stderr); \
std::abort(); \
} while (0)
// Runtime check that is active only when CARDBOY_MORE_CHECKS != 0.
// Evaluates the expression exactly once.
#define CARDBOY_CHECK(expr) \
do { \
if (!(expr)) { \
CARDBOY__CHECK_FAIL_IMPL(#expr, __FILE__, __LINE__, __func__, NULL); \
} \
} while (0)
// Same as CARDBOY_CHECK but allows providing a custom C-string message.
#define CARDBOY_CHECK_MSG(expr, msg) \
do { \
if (!(expr)) { \
CARDBOY__CHECK_FAIL_IMPL(#expr, __FILE__, __LINE__, __func__, (msg));\
} \
} while (0)
// Execute arbitrary code only when checks are enabled.
#define CARDBOY_CHECK_CODE(code) \
do { \
code; \
} while (0)
#else
// Checks compiled out when CARDBOY_MORE_CHECKS == 0.
#define CARDBOY_CHECK(expr) do { (void)sizeof(expr); } while (0)
#define CARDBOY_CHECK_MSG(expr, _) do { (void)sizeof(expr); } while (0)
#define CARDBOY_CHECK_CODE(code) do { } while (0)
#endif
#endif // CARDBOY_SDK_UTILS_HPP