Skip to content

Constants and System Info (FmrbConst / FmrbHw)

FmrbConst

A module that provides constants referenced throughout the system.

Platform Information

Constant Value
FmrbConst::PLATFORM "linux" or "esp32"
FmrbConst::BOARD "tab5", "naryav4", "atom_display", "narya_v3" or "linux". Finer-grained than PLATFORM and CHIP_MODEL: use it to pick board-specific wiring
FmrbConst::HW_FAMILY "modern" or "retro". The coarsest of the three, and the one to ask when a feature exists on one family and not the other
FmrbConst::OS_VERSION OS version string
FmrbConst::GA_VERSION fmruby-graphics-audio version
FmrbConst::LINK_VERSION UART link protocol version
FmrbConst::IDF_VERSION ESP-IDF version
FmrbConst::BUILD_DATE When this firmware was compiled, as "Mmm dd yyyy hh:mm:ss"
FmrbConst::LANGUAGE The UI language from system_conf.toml, "en" or "ja". FmrbApp.language reads it through a call that works on both engines

Hardware Information

Constant Description
FmrbConst::MAC_ADDRESS MAC address string
FmrbConst::CHIP_MODEL e.g. "ESP32-S3"
FmrbConst::CHIP_REVISION Revision number
FmrbConst::CHIP_CORES Number of cores
FmrbConst::FLASH_SIZE_MB Flash capacity (MB)
FmrbConst::PSRAM_SIZE_MB PSRAM capacity (MB)
FmrbConst::RESET_REASON Why the machine last restarted, as a string: POWERON, EXT, SW, PANIC, INT_WDT, TASK_WDT, WDT, DEEPSLEEP, BROWNOUT, SDIO, USB, JTAG, EFUSE, PWR_GLITCH, CPU_LOCKUP or UNKNOWN
FmrbConst::HAS_WIFI true on a machine that can join a network. See Network
FmrbConst::WHEEL_LINES How many text rows one notch of the mouse wheel moves, from system_conf.toml

Process Management

Constant Purpose
FmrbConst::PROC_ID_KERNEL Kernel process ID
FmrbConst::PROC_ID_HOST Host process ID
FmrbConst::PROC_ID_SYSTEM_APP System app ID
FmrbConst::PROC_ID_USER_APP0 … USER_APP4 User app slots. There are five; how many fill depends on the memory the machine has

Process States

The state of each entry FmrbApp.ps returns:

Constant Value Meaning
PROC_STATE_FREE 0 The slot is empty
PROC_STATE_INIT 1 Allocated and its VM built, not started yet. The kernel announces a spawn at this point, so an app already has a window here
PROC_STATE_RUNNING 2 Running
PROC_STATE_SUSPENDED 3 Temporarily suspended — a fullscreen app parked by Ctrl + Tab is in this state, and still answers from the taskbar
PROC_STATE_STOPPING 4 Asked to stop, still winding down

Messaging

Constant Purpose
MSG_TYPE_APP_CONTROL App control message
MSG_TYPE_APP_GFX Graphics message
MSG_TYPE_APP_AUDIO Audio message
MSG_TYPE_HID_EVENT HID event (keyboard, etc.)

App Control Commands

The subtype of an MSG_TYPE_APP_CONTROL message sent to the kernel:

Constant Value Meaning
APP_CTRL_SPAWN 1 Start an app
APP_CTRL_KILL 2 Stop one
APP_CTRL_SUSPEND 3 Suspend one
APP_CTRL_RESUME 4 Let it run again

An ordinary app rarely sends these itself: request_run, request_fullscreen and the rest of FmrbApp build the message for it.

Status LED

What the board's LED is showing. The kernel sets it; these name the patterns.

Constant Value Meaning
LED_ERR_NONE 0 Nothing wrong
LED_ERR_FATAL 1 Solid red. The system stopped
LED_ERR_VERSION_MISMATCH 2 Three quick red pulses, then a gap. The two chips are on different versions (Retro)

Theme Colors (System-wide Color Scheme)

Constant Purpose
THEME_DESKTOP_BG Desktop background
THEME_MENU_BG Menu background
THEME_WINDOW_BG Window background
THEME_TEXT Normal text
THEME_TEXT_LIGHT Light text
THEME_HIGHLIGHT Highlight
THEME_BORDER Border
THEME_BUTTON Button
THEME_DIR_COLOR Directory names, where a file list distinguishes them from files

These are all RGB332 values. Use them when you want your app's UI to match the OS color scheme.

Input Device: Keyboard (KEY_*)

USB HID Usage IDs. Compare with ev[:scancode] in on_event(ev).

Category Constants
Letters KEY_A .. KEY_Z
Numbers KEY_1 .. KEY_9, KEY_0
Control KEY_ENTER, KEY_ESC, KEY_BACKSPACE, KEY_TAB, KEY_SPACE
Symbols KEY_MINUS, KEY_EQUAL, KEY_LBRACKET, KEY_RBRACKET, KEY_BACKSLASH, KEY_SEMICOLON, KEY_QUOTE, KEY_GRAVE, KEY_COMMA, KEY_PERIOD, KEY_SLASH
Locks KEY_CAPSLOCK, KEY_SCROLLLOCK, KEY_NUMLOCK
Function KEY_F1 .. KEY_F12
Editing KEY_INSERT, KEY_HOME, KEY_PGUP, KEY_DELETE, KEY_END, KEY_PGDN
Arrow KEY_LEFT, KEY_RIGHT, KEY_UP, KEY_DOWN
Other KEY_PRINTSCREEN, KEY_PAUSE
Modifier keys (individual) KEY_LCTRL, KEY_LSHIFT, KEY_LALT, KEY_LMETA, KEY_RCTRL, KEY_RSHIFT, KEY_RALT, KEY_RMETA

Input Device: Modifier Key Masks (MOD_*)

Use bitwise AND with ev[:modifier] in on_event(ev) to check modifier state.

Constant Bit Meaning
MOD_LSHIFT 0x01 Left Shift
MOD_RSHIFT 0x02 Right Shift
MOD_LCTRL 0x04 Left Ctrl
MOD_RCTRL 0x08 Right Ctrl
MOD_LALT 0x10 Left Alt
MOD_RALT 0x20 Right Alt
MOD_SHIFT 0x03 Either Shift
MOD_CTRL 0x0C Either Ctrl
MOD_ALT 0x30 Either Alt

These are this firmware's own bits, not the USB HID modifier byte, so do not write the numbers out by hand — 0x01 is Left Shift here and Left Ctrl in the HID standard.

There is no mask for the Meta (Windows / Command) key: the modifier byte the firmware delivers has six bits and Meta is not one of them. A press still arrives as an ordinary key event with scancode KEY_LMETA or KEY_RMETA.

ev_ctrl?(ev) / ev_shift?(ev) / ev_alt?(ev)

You can also check modifiers using FmrbApp helpers. Using MOD_* directly is only needed for special cases; normally use the helpers instead.

Input Device: Gamepad (GP_*)

In on_event(ev), when ev[:type] == :gamepad_down / :gamepad_up, ev[:button] holds the button number. When ev[:type] == :gamepad_axis, ev[:axis] holds the axis number.

Buttons

Constant Value Meaning
GP_SQUARE 0 Square
GP_CROSS 1 Cross
GP_CIRCLE 2 Circle
GP_TRIANGLE 3 Triangle
GP_L1 4 Left shoulder
GP_R1 5 Right shoulder
GP_L2 6 Left trigger
GP_R2 7 Right trigger
GP_SELECT 8 Select
GP_START 9 Start
GP_L3 10 Left stick press
GP_R3 11 Right stick press
GP_UP 12 D-pad up
GP_DOWN 13 D-pad down
GP_LEFT 14 D-pad left
GP_RIGHT 15 D-pad right

Axes

Constant Value Meaning
GP_AXIS_LX 0 Left stick X
GP_AXIS_LY 1 Left stick Y
GP_AXIS_RX 2 Right stick X
GP_AXIS_RY 3 Right stick Y

Sample: Key Detection

def on_event(ev)
  super
  if ev[:type] == :key_down
    case ev[:scancode]
    when FmrbConst::KEY_LEFT  then @x -= 4
    when FmrbConst::KEY_RIGHT then @x += 4
    when FmrbConst::KEY_SPACE then shoot
    when FmrbConst::KEY_ESC   then stop
    end
    if (ev[:modifier] || 0) & FmrbConst::MOD_CTRL != 0 &&
       ev[:scancode] == FmrbConst::KEY_S
      save_state
    end
  elsif ev[:type] == :gamepad_down
    case ev[:button]
    when FmrbConst::GP_CROSS  then jump
    when FmrbConst::GP_START  then pause
    end
  end
end

Other

Constant Description
MAX_PATH_LEN Maximum path length

Sample: Display Version and Environment

class SysInfo < FmrbApp
  def on_create
    clear_user_area(FmrbGfx::WHITE)
    x = @user_area_x0 + 4
    y = @user_area_y0 + 4
    @gfx.draw_text(x, y,      "OS: #{FmrbConst::OS_VERSION}", FmrbGfx::BLACK)
    @gfx.draw_text(x, y + 10, "Chip: #{FmrbConst::CHIP_MODEL}", FmrbGfx::BLACK)
    @gfx.draw_text(x, y + 20, "PSRAM: #{FmrbConst::PSRAM_SIZE_MB}MB", FmrbGfx::BLACK)
    @gfx.draw_text(x, y + 30, "MAC: #{FmrbConst::MAC_ADDRESS}", FmrbGfx::BLACK)
    draw_window_frame
    @gfx.present
  end
end

SysInfo.new.start

FmrbHw

A module for querying the usage status of hardware resources (especially GPIO pins).

Method Return Value
FmrbHw.pin_status(pin) Pin usage state (Integer, 0 = unused, other = usage-specific identifier)
FmrbHw.pin_available?(pin) true if unused
FmrbHw.pin_status_all Array<Integer> (index = pin number, value = status)
FmrbHw.pin_count Total number of pins

What pin_status returns is one of these, and they are constants on FmrbHw:

Constant Value Meaning
FmrbHw::PIN_UNUSED 0 Free
FmrbHw::PIN_SYSTEM_EXCLUSIVE 1 Reserved by the system and never available — USB, PSRAM, the display link
FmrbHw::PIN_USER_GPIO 2 Taken by an app as a GPIO
FmrbHw::PIN_USER_I2C 3 Taken by an I2C
FmrbHw::PIN_USER_RMT 4 Taken by an RMT
FmrbHw::PIN_USER_SPI 5 Taken by SPI
FmrbHw::PIN_USER_PWM 6 Taken by PWM
FmrbHw::PIN_USER_UART 7 Taken by a UART

The I2C buses the system itself uses are named too, so an app can talk on one without hardcoding a board's numbers (ESP32 only):

Constant
FmrbHw::PIN_I2C1_SDA / PIN_I2C1_SCL The first bus
FmrbHw::PIN_I2C2_SDA / PIN_I2C2_SCL The second

Sample: Display All Pins

status = FmrbHw.pin_status_all
status.each_with_index do |s, i|
  Log.info("pin #{i}: #{s == 0 ? 'free' : 'used'}")
end

Sample: Check Before Use

PIN = 10
unless FmrbHw.pin_available?(PIN)
  Log.error("Pin #{PIN} is in use (status=#{FmrbHw.pin_status(PIN)})")
  return
end
gpio = GPIO.new(PIN, GPIO::OUT)

There is a sample in tool/gpio_viewer.app.rb that visualizes pin states with a GUI.

  • For pin specifications (electrical characteristics, external connections), see Hardware
  • For GPIO usage, see Hardware Control