emulator working

This commit is contained in:
Adolfo Reyna
2026-01-30 23:40:10 -05:00
parent c1423b66aa
commit 76a74477a7
5 changed files with 45 additions and 65 deletions

View File

@@ -1,25 +0,0 @@
## Plan: Computer Emulator Board Option
Add an SFML-based computer emulator as a new board configuration to enable developing and testing the bare-metal application on a desktop computer. This creates a "virtual board" that emulates the display hardware using SFML graphics, following the existing display driver architecture.
### Steps
1. **Create [display/low_level_display_sfml.cpp](display/low_level_display_sfml.cpp) and [display/low_level_display_sfml.h](display/low_level_display_sfml.h)** - Implement `LowLevelDisplaySFML` class inheriting from `LowLevelDisplay`, with `init()` creating an SFML window, `draw_buffer()` converting the 1-bit buffer to RGBA pixels (similar to lines 105-112 in the example), and `refresh()` updating the SFML texture and handling window events.
2. **Create [board_configs/board_emulator.h](board_configs/board_emulator.h)** - Define `BOARD_NAME` as "Computer Emulator (SFML)", set `DISPLAY_WIDTH`/`DISPLAY_HEIGHT` (400x300 or configurable), define `DISPLAY_TYPE_EMULATOR_VAL` constant, set `DISPLAY_TYPE_SELECTED` to emulator type, set `TOUCH_TYPE_SELECTED` to `TOUCH_TYPE_NONE_VAL` initially, and stub out all hardware pin defines (`DISPLAY_SPI_PORT`, GPIO pins) as unused/invalid values.
3. **Update [display/low_level_display_factory.cpp](display/low_level_display_factory.cpp)** - Add `DISPLAY_TYPE_EMULATOR` to the `DisplayType` enum, add new case in `LowLevelDisplay::create()` switch statement to return `new LowLevelDisplaySFML(width, height)` when emulator type is selected, bypassing pin configuration struct since no hardware GPIO is needed.
4. **Modify [CMakeLists.txt](CMakeLists.txt)** - Add conditional compilation: detect if `BOARD_EMULATOR` is defined, if so, find and link SFML libraries (`sfml-graphics`, `sfml-window`, `sfml-system`), add [display/low_level_display_sfml.cpp](display/low_level_display_sfml.cpp) to sources, exclude Pico SDK hardware dependencies (multicore, GPIO, SPI), and compile for native host architecture instead of ARM.
5. **Update [board_config.h](board_config.h)** - Add `// #define BOARD_EMULATOR` to the board selection list with descriptive comment explaining it's for desktop testing, ensure conditional include adds `#elif defined(BOARD_EMULATOR)` case that includes [board_configs/board_emulator.h](board_configs/board_emulator.h).
6. **Create [build_emulator.sh](build_emulator.sh)** - Script to temporarily enable `BOARD_EMULATOR` define in [board_config.h](board_config.h), configure CMake for host architecture (remove `-DPICO_BOARD=` flags), build in `build_emulator/` directory, and produce a native executable `basic1_emulator` instead of `.uf2` file.
### Further Considerations
1. **Hardware abstraction for Pico SDK functions** - The code uses `multicore_launch_core1()`, `gpio_init()`, `spi_init()`, etc. Should we create stub implementations for the emulator, conditionally compile out hardware-specific code with `#ifndef BOARD_EMULATOR`, or refactor hardware initialization into a separate HAL layer? Recommend **Option A**: stub implementations that no-op for simplicity.
2. **Touch/mouse input support** - Extend later by creating [display/low_level_touch_sfml.cpp](display/low_level_touch_sfml.cpp) that inherits from `LowLevelTouch`, capture `sf::Event::MouseButtonPressed` events in `refresh()`, translate mouse coordinates to touch coordinates, and update `TOUCH_TYPE_SELECTED` in [board_configs/board_emulator.h](board_configs/board_emulator.h) to use the SFML touch driver.
3. **Keyboard input for hardware buttons** - The example shows console keyboard input (lines 56-89). Should we map specific keys (arrow keys, space, enter) to emulate the hardware buttons like `BUTTON_KEY0_PIN` found on the e-ink board, or implement a command-line interface like the example? Recommend **Option A**: map keys to button events for consistency with hardware boards.

View File

@@ -2,31 +2,31 @@
#include <cmath>
#include <algorithm>
#include <vector>
#include "./fonts/5x5_font.h"
#include "./fonts/BMplain_font.h"
#include "./fonts/Blokus_font.h"
#include "./fonts/HISKYF21_font.h"
#include "./fonts/Minimum_font.h"
#include "./fonts/SUPERDIG_font.h"
#include "./fonts/acme_5_outlines_font.h"
#include "./fonts/aztech_font.h"
#include "./fonts/crackers_font.h"
#include "./fonts/haiku_font.h"
#include "./fonts/sloth_font.h"
#include "./fonts/zxpix_font.h"
#include "./fonts/Commo-Monospaced_font.h"
#include "./fonts/7linedigital_font.h"
#include "./fonts/BMSPA_font.h"
#include "./fonts/HUNTER_font.h"
#include "./fonts/Raumsond_font.h"
#include "./fonts/bubblesstandard_font.h"
#include "./fonts/formplex12_font.h"
#include "./fonts/homespun_font.h"
#include "./fonts/Minimum_1_font.h"
#include "./fonts/m38_font.h"
#include "./fonts/pzim3x5_font.h"
#include "./fonts/renew_font.h"
#include "./fonts/tama_mini02_font.h"
#include "../fonts/5x5_font.h"
#include "../fonts/BMplain_font.h"
#include "../fonts/Blokus_font.h"
#include "../fonts/HISKYF21_font.h"
#include "../fonts/Minimum_font.h"
#include "../fonts/SUPERDIG_font.h"
#include "../fonts/acme_5_outlines_font.h"
#include "../fonts/aztech_font.h"
#include "../fonts/crackers_font.h"
#include "../fonts/haiku_font.h"
#include "../fonts/sloth_font.h"
#include "../fonts/zxpix_font.h"
#include "../fonts/Commo-Monospaced_font.h"
#include "../fonts/7linedigital_font.h"
#include "../fonts/BMSPA_font.h"
#include "../fonts/HUNTER_font.h"
#include "../fonts/Raumsond_font.h"
#include "../fonts/bubblesstandard_font.h"
#include "../fonts/formplex12_font.h"
#include "../fonts/homespun_font.h"
#include "../fonts/Minimum_1_font.h"
#include "../fonts/m38_font.h"
#include "../fonts/pzim3x5_font.h"
#include "../fonts/renew_font.h"
#include "../fonts/tama_mini02_font.h"
// Font object definitions
Font font_5x5_obj(reinterpret_cast<const unsigned char*>(font_5x5), 96, 6, 8);
@@ -547,19 +547,27 @@ void LowLevelRenderer::draw_filled_circle(int x, int y, int radius, bool on)
int LowLevelRenderer::draw_char_vcol(int x, int y, char c)
{
if (!current_font) return 0;
// The font table starts at space (ASCII 32)
if (c < 32 || c > 127)
if (!current_font) {
fprintf(stderr, "[draw_char_vcol] current_font is null!\n");
return 0;
}
// The font table starts at space (ASCII 32)
if (c < 32 || c > 127) {
fprintf(stderr, "[draw_char_vcol] char out of range: %d\n", (int)c);
return 0;
}
int font_idx = c - 32;
if (font_idx < 0 || font_idx >= current_font->get_num_chars()) {
fprintf(stderr, "[draw_char_vcol] font_idx out of range: %d\n", font_idx);
return 0;
}
const unsigned char* char_data = current_font->get_char_data(font_idx);
if (!char_data) return 0;
if (!char_data) {
fprintf(stderr, "[draw_char_vcol] char_data is null for idx %d\n", font_idx);
return 0;
}
int bytes_per_char = current_font->get_bytes_per_char();
int char_height = current_font->get_char_height();
// Find the actual width by skipping trailing empty columns
int actual_width = 0;
for (int col = bytes_per_char - 1; col >= 0; col--)
@@ -570,12 +578,10 @@ int LowLevelRenderer::draw_char_vcol(int x, int y, char c)
break;
}
}
// Draw only up to the actual width
for (int col = 0; col < actual_width; col++)
{
unsigned char column_byte = char_data[col];
for (int row = 0; row < char_height; row++)
{
// Check if the bit for this row is set
@@ -585,7 +591,6 @@ int LowLevelRenderer::draw_char_vcol(int x, int y, char c)
}
}
}
return actual_width;
}

View File

@@ -6,7 +6,7 @@
#ifndef DEMO_GAME_H
#define DEMO_GAME_H
#include "game.h"
#include "../lib/game.h"
/**
* @brief Demo Game - Simple test game for launcher

View File

@@ -6,7 +6,7 @@
#ifndef TIC_TAC_TOE_H
#define TIC_TAC_TOE_H
#include "game.h"
#include "../lib/game.h"
/**
* @brief Tic-Tac-Toe game implementation

View File

@@ -9,8 +9,8 @@
#include <stdint.h>
#include "input_event.h"
#include "display/low_level_render.h"
#include "display/low_level_gui.h"
#include "../display/low_level_render.h"
#include "../display/low_level_gui.h"
// Forward declaration
class InputManager;