Skip to content

Latest commit

 

History

History
322 lines (239 loc) · 13.4 KB

c_development_guide.md

File metadata and controls

322 lines (239 loc) · 13.4 KB

Developing C Applications for Flashiibo Pro Gen3 ("FEB Runner")

Warning

BETA & EXPERIMENTAL NOTICE: The Flashiibo Executable Binary (.feb) format, C SDK (feb.h), build tooling, and runtime environment are currently in Beta & Experimental status. APIs, header specifications, and runtime behavior are under active development and breaking changes might happen without warning.

Document Version: 1.0 (Beta)
Target Platform: Flashiibo Pro Gen3 (Firmware >= 26.10.6)
Host Applet: FEB Runner
Runtime Environment: Flashiibo Executable Binary (.feb) Virtual Machine


1. Introduction & Overview

Flashiibo Pro Gen3 features a sandboxed virtual runtime for user-installable applications and games called FEB Runner (.feb, requires firmware >= 26.10.6). With the Flashiibo C SDK, developers can write applications in idiomatic C, compile them into self-contained .feb binary packages, and distribute them without modifying or reflashing the MCU firmware.

1.1 Key Technical Specifications

Resource Specification Notes
Target Platform Flashiibo Pro Gen3 Requires firmware >= 26.10.6 (Sandboxed VM)
Language C (C99 / C11) / Assembly Standard types from <stdint.h> and <stdbool.h>
Display 128×64 (default Super-CHIP) or 64×32 (legacy) Monochrome OLED 1-bit per pixel (XOR sprite drawing)
Frame Rate 60 Hz Hardware timer-driven execution cycle
Memory Limit 4,096 Bytes total address space Sandboxed from system radio and kernel
Input Controls 4 Physical buttons UP, DOWN, BACK (Left), OK (Right)
Container Format .feb (Flashiibo Executable Binary) 100-byte metadata header + binary bytecode
Distribution VFS /feb/*.feb on SPI NOR Flash Loaded using Flashiibo Pro Tools on Web or Mobile

2. Flashiibo Gen3 Hardware Contract

2.1 Fixed Deterministic 4-Button Mapping

Flashiibo devices feature four physical buttons on the device body. In FEB Runner, these map to deterministic virtual key constants:

                  ┌──────────────┐
                  │    [ UP ]    │
                  │ (FEB_KEY_UP) │
                  │   Key: 0x2   │
  ┌───────────────┴──────────────┴───────────────┐
  │   [ BACK ]                         [ OK ]    │
  │ (FEB_KEY_LEFT)                (FEB_KEY_RIGHT)│
  │   Key: 0x4                       Key: 0x6    │
  └───────────────┬──────────────┬───────────────┘
                  │   [ DOWN ]   │
                  │(FEB_KEY_DOWN)│
                  │   Key: 0x8   │
                  └──────────────┘
Physical Button C Constant Hex Code Primary App Role
UP FEB_KEY_UP 0x2 Move cursor up / Jump / Rotate
DOWN FEB_KEY_DOWN 0x8 Move cursor down / Crouch / Soft drop
BACK FEB_KEY_LEFT / FEB_KEY_BACK 0x4 Move cursor left / Navigate back
OK FEB_KEY_RIGHT / FEB_KEY_OK 0x6 Move cursor right / Select / Action

2.2 System Exit Contract (UP + DOWN Chord)

Important

Pressing UP and DOWN simultaneously is intercepted at both the OS and virtual machine engine level to guarantee an immediate, safe exit back to the "FEB Runner" main menu.

Long press on BACK is deliberately not an exit trigger, ensuring that BACK (Key 0x4 / Left) is completely safe to hold down for continuous gameplay movement or action charging without accidental termination.


3. C SDK API Reference (feb.h)

Include the C SDK header in your application:

#include "feb.h"

3.1 Display & Drawing Modes

void feb_clear_screen(void);

Clears the entire display buffer (turns off all pixels).

void feb_set_draw_mode(uint8_t mode);

Sets the active drawing mode for all subsequent graphics operations:

  • FEB_DRAW_MODE_XOR (0): Inverts existing pixels (standard CHIP-8 blitting).
  • FEB_DRAW_MODE_SET (1): Solid write (turns pixels ON).
  • FEB_DRAW_MODE_CLEAR (2): Eraser (turns pixels OFF).
  • FEB_DRAW_MODE_OPAQUE (3): Sets pixels ON with a solid black background bounding box (erases whatever is behind glyphs/shapes).
  • FEB_DRAW_MODE_INVERTED_OPAQUE (4): Clears pixels OFF inside a solid white bounding box.

bool feb_draw_sprite(uint8_t x, uint8_t y, const uint8_t *sprite, uint8_t height);

Draws an 8-pixel wide bitmap sprite of height height (1 to 15 rows) at coordinate (x, y).

  • Sprites use XOR blitting. If a pixel is drawn where a pixel is already turned on, it will invert (turn off).
  • Erase a sprite: Call feb_draw_sprite a second time with the exact same coordinates and data.
  • Return value: Returns true if any drawn pixel collided with an already active pixel on screen.

bool feb_draw_sprite16(uint8_t x, uint8_t y, const uint8_t *sprite);

Draws a 16×16 pixel sprite in 128×64 mode (32 bytes). Returns true if collision occurred.

void feb_draw_digit(uint8_t x, uint8_t y, uint8_t digit);

Renders a built-in single-digit hexadecimal glyph (0x0 through 0xF, 5 pixels high by 4 pixels wide) at (x, y).

3.2 Fast Geometric Primitives

Flashiibo firmware >= 26.10.6 includes hardware-accelerated drawing primitives executed directly by the VM:

  • void feb_draw_pixel(uint8_t x, uint8_t y);: Plots single pixel using active draw mode.
  • void feb_draw_line(uint8_t x0, uint8_t y0, uint8_t x1, uint8_t y1);: Draws line between endpoints using Bresenham's algorithm.
  • void feb_draw_hline(uint8_t x, uint8_t y, uint8_t len);: Draws fast horizontal line.
  • void feb_draw_vline(uint8_t x, uint8_t y, uint8_t len);: Draws fast vertical line.
  • void feb_draw_rect(uint8_t x, uint8_t y, uint8_t w, uint8_t h);: Draws unfilled outline rectangle.
  • void feb_fill_rect(uint8_t x, uint8_t y, uint8_t w, uint8_t h);: Draws filled solid rectangle.
  • void feb_draw_rrect(uint8_t x, uint8_t y, uint8_t w, uint8_t h);: Draws unfilled outline rounded rectangle with 1px corner radius.
  • void feb_fill_rrect(uint8_t x, uint8_t y, uint8_t w, uint8_t h);: Draws filled solid rounded rectangle with 1px corner radius.
  • void feb_draw_triangle(uint8_t x0, uint8_t y0, uint8_t x1, uint8_t y1, uint8_t x2, uint8_t y2);: Draws unfilled outline triangle connecting 3 vertices.
  • void feb_draw_circle(uint8_t x, uint8_t y, uint8_t r);: Draws unfilled circle outline centered at (x, y).
  • void feb_fill_circle(uint8_t x, uint8_t y, uint8_t r);: Draws filled solid circle centered at (x, y).

3.3 Zero-RAM Collision Detection

bool feb_test_pixel(uint8_t x, uint8_t y);

Inspects whether the pixel at (x, y) is currently lit without modifying the display buffer or requiring shadow collision arrays in memory. Returns true if lit, false otherwise.

3.4 Typography & Number Formatting

Built-in typography functions render text using high-legibility u8g2 bitmap fonts:

  • FEB_FONT_4X6 (0): Compact 4×6 numeric & ASCII font.
  • FEB_FONT_6X10 (1): Standard UI 6×10 font.
  • FEB_FONT_RETRO_8X8 (2): Blocky 8×8 retro arcade font.

Functions:

  • uint8_t feb_draw_string(uint8_t x, uint8_t y, const char *str, uint8_t font_id);: Renders null-terminated ASCII string; returns advanced X coordinate.
  • uint8_t feb_draw_char(uint8_t x, uint8_t y, char ch, uint8_t font_id);: Renders single ASCII character; returns advanced X coordinate.
  • uint8_t feb_string_width(const char *str, uint8_t font_id);: Calculates pixel width of string without drawing.
  • uint8_t feb_draw_number(uint8_t x, uint8_t y, uint16_t num, uint8_t font_id);: Formats and renders 16-bit unsigned integer (0..65535) directly from register I; returns advanced X coordinate.

3.5 Input Polling

uint8_t feb_get_keys(void);

Non-blocking poll of the instantaneous 4-button hardware bitmask:

  • Bit 0 (0x01): FEB_BTN_UP
  • Bit 1 (0x02): FEB_BTN_DOWN
  • Bit 2 (0x04): FEB_BTN_LEFT (FEB_BTN_BACK)
  • Bit 3 (0x08): FEB_BTN_RIGHT (FEB_BTN_OK)

Allows detecting multi-button simultaneous presses and chord combinations with zero latency.

uint8_t feb_wait_key(void);

Blocks execution until a physical button is pressed, and returns the key code (0x2, 0x8, 0x4, or 0x6).

bool feb_is_key_down(uint8_t key);

Non-blocking check to determine if the specified key code is currently held down.

3.6 Timing & Randomness

uint8_t feb_rand(uint8_t mask);

Returns an 8-bit pseudo-random integer masked with mask (e.g., feb_rand(0x07) produces 0..7).

void feb_set_delay_timer(uint8_t val);

Sets the 60 Hz delay timer register. It automatically decrements by 1 every 16.6 ms until it reaches 0.

uint8_t feb_get_delay_timer(void);

Returns the current value of the 60 Hz delay timer register.

void feb_delay_frames(uint8_t frames);

Blocks execution for frames screen frames (~16.6 ms per frame).

3.7 Persistent Storage (Sidecar .sav)

Executable .feb files are strictly read-only. User save data, high scores, and settings are automatically persisted to /feb/saves/<app_name>.sav upon exit.

void feb_save_flags(const uint8_t *data, uint8_t len);

Saves up to 16 bytes of persistent application state (mapped to Super-CHIP RPL user flags). Flushed to the companion .sav file when the app closes.

void feb_load_flags(uint8_t *data, uint8_t len);

Loads up to 16 bytes of persistent application state previously saved by feb_save_flags.

3.8 Lifecycle & Programmatic Exit

void feb_exit(void);

Immediately halts execution of the FEB application, flushes any dirty RPL persistent flags, and returns cleanly to the device's "FEB Runner" menu.

  • Alias: feb_quit()
  • Bytecode: Emits standard Super-CHIP 00FD opcode.

4. Examples & Architectural Patterns

4.1 Real-Time Action Pattern (examples/features_demo)

For smooth, flicker-free movement in single-buffered CHIP-8, use non-blocking feb_get_keys() and XOR in-place erasing rather than clearing the whole screen every frame:

#include "feb.h"

int main(void) {
    uint8_t x = 60, y = 30;
    feb_set_high_res(true);
    feb_clear_screen();

    /* Render static background once */
    feb_draw_string(4, 2, "ACTION DEMO", FEB_FONT_6X10);
    feb_draw_rect(x, y, 6, 6);

    while (1) {
        /* Poll instantaneous input */
        uint8_t keys = feb_get_keys();
        if (keys != 0) {
            feb_draw_rect(x, y, 6, 6); /* XOR erase old position */
            if (keys & FEB_BTN_UP)    y--;
            if (keys & FEB_BTN_DOWN)  y++;
            if (keys & FEB_BTN_LEFT)  x--;
            if (keys & FEB_BTN_RIGHT) x++;
            feb_draw_rect(x, y, 6, 6); /* XOR draw new position */
        }
    }
    return 0;
}

4.2 Turn-Based Event Loop Pattern (examples/template)

A minimal moving sprite demo using 4-button directional keys:

#include "../../include/feb.h"

static const uint8_t player_sprite[8] = {
    0x3C, 0x7E, 0xDB, 0xFF, 0xFF, 0xDB, 0x7E, 0x3C
};

int main(void) {
    uint8_t x = 60, y = 28;
    feb_set_high_res(true);
    feb_clear_screen();
    feb_draw_sprite(x, y, player_sprite, 8);

    while (1) {
        uint8_t key = feb_wait_key();
        feb_draw_sprite(x, y, player_sprite, 8); /* XOR erase */

        if (key == FEB_KEY_UP && y >= 2) y -= 2;
        else if (key == FEB_KEY_DOWN && y <= 54) y += 2;
        else if (key == FEB_KEY_LEFT && x >= 2) x -= 2;
        else if (key == FEB_KEY_RIGHT && x <= 118) x += 2;

        feb_draw_sprite(x, y, player_sprite, 8); /* redraw */
    }
    return 0;
}

4.2 Full Game: 2048 Puzzle (examples/2048)

The repository includes a complete, fully playable 2048 game in examples/2048/main.c.


5. Build System & Packaging

5.1 Project Layout

feb-sdk/
├── include/
│   └── feb.h              <-- Flashiibo SDK header
├── tools/
│   ├── feb_build.py       <-- Build orchestrator
│   ├── make_feb.py        <-- .feb container packager
│   └── assemble_chip8.py  <-- Bytecode assembler
└── examples/
    └── my_app/
        ├── Makefile       <-- App build script
        └── main.c         <-- Your C application

5.2 Compiling with feb_build.py

Compile your C application into a distributable .feb container:

python3 tools/feb_build.py examples/my_app/main.c -o examples/my_app/my_app.feb \
    --title "My App" \
    --author "Developer" \
    --ver "1.0.0"

5.3 Sample Makefile

PYTHON ?= python3
BUILD_TOOL = ../../tools/feb_build.py

APP_TITLE = My App
APP_AUTHOR = Developer
APP_VER = 1.0.0
TARGET = my_app.feb

all: $(TARGET)

$(TARGET): main.c ../../include/feb.h
	$(PYTHON) $(BUILD_TOOL) main.c -o $(TARGET) \
		--title "$(APP_TITLE)" \
		--author "$(APP_AUTHOR)" \
		--ver "$(APP_VER)"

clean:
	rm -f $(TARGET)

6. Deploying to Flashiibo Pro Gen3 Hardware

Note

Running .feb applications requires Flashiibo Pro Gen3 firmware >= 26.10.6.

  1. Connect your Flashiibo Pro Gen3 to your computer or phone via USB or Web Bluetooth.
  2. In the Flashiibo companion application or Web Tool, open the File Manager.
  3. Upload your .feb file into the /feb/ folder on the device flash storage.
  4. On your Flashiibo device, enter FEB Runner from the main menu, select your game, and press OK to launch!