Skip to main content
Version: Matrix OS 4.0 🚧

Code Your Application (C++)

Native C++ apps are built into Matrix OS firmware. Use this path when your app needs native performance, direct Matrix OS APIs, deeper device integration, or C/C++ libraries that should run on-device.

For most app ideas, start in Matrix OS Developer Toolkit or Python first, then move to C++ when you need native behavior.

Matrix OS 4.0 beta

The examples on this page use the current Application, MatrixOS::Input, InputEvent, and KeypadInfo APIs.

What A Native App Contains​

A minimal native app usually has:

Applications/HelloNative/
HelloNative.h
HelloNative.cpp
CMakeLists.txt

Then the app folder is enabled from the target device family's ApplicationList.txt, such as Devices/MystrixSim/ApplicationList.txt.

Minimal Header​

#pragma once

#include "MatrixOS.h"
#include "Application.h"

class HelloNative : public Application {
public:
inline static Application_Info info = {
.name = "Hello Native",
.author = "Your Name",
.color = Color::Cyan,
.version = 1,
.visibility = true,
};

void Setup(const vector<string>& args) override;
void Loop() override;
void End() override;

private:
Color color = Color::Cyan;
};

Minimal Source​

#include "HelloNative.h"

void HelloNative::Setup(const vector<string>& args) {
(void)args;
MLOGI("HelloNative", "started");

MatrixOS::LED::Fill(Color::Black);
MatrixOS::LED::SetColor(Point(0, 0), color);
MatrixOS::LED::Update();
}

void HelloNative::Loop() {
InputEvent event;
while (MatrixOS::Input::Get(&event))
{
if (event.inputClass != InputClass::Keypad)
{
continue;
}

Point point;
bool hasPoint = MatrixOS::Input::GetPosition(event.id, &point);

if (hasPoint && event.keypad.state == KeypadState::Pressed)
{
MatrixOS::LED::SetColor(point, color);
MatrixOS::LED::Update();
}
else if (hasPoint && event.keypad.state == KeypadState::Released)
{
MatrixOS::LED::SetColor(point, Color::Black);
MatrixOS::LED::Update();
}
else if (event.id == InputId::FunctionKey() && event.keypad.state == KeypadState::Hold)
{
Exit();
}
}
}

void HelloNative::End() {
MatrixOS::LED::Fill(Color::Black);
MatrixOS::LED::Update();
MLOGI("HelloNative", "ended");
}

Expected behavior: when the app starts, LED (0, 0) turns cyan. Pressing a grid key lights that key cyan. Releasing it clears that LED. Holding the function key exits the app.

App Lifecycle​

MethodWhen it runsUse it for
Setup(const vector<string>& args)once when the app startsinitialize state, create layers, log startup, parse launch args
Loop()repeatedly while the app is activedrain input/MIDI queues and update app state
End()when the app exitsclear LEDs, release resources, stop background work
Exit()call from app coderequest Matrix OS to close the current app

Loop() should return regularly. Matrix OS calls it again, so do not block forever inside one call.

Input And LED Pattern​

Use MatrixOS::Input for physical controls:

InputEvent event;
while (MatrixOS::Input::Get(&event))
{
if (event.inputClass != InputClass::Keypad)
{
continue;
}

Point point;
if (MatrixOS::Input::GetPosition(event.id, &point))
{
MLOGD("HelloNative", "key %d %d state %d", point.x, point.y, (uint8_t)event.keypad.state);
}
}

For keypad input, event.keypad contains state, pressure, and velocity. Use MatrixOS::Input::GetPosition(...) when your logic needs a coordinate.

Use MatrixOS::LED for drawing:

MatrixOS::LED::SetColor(Point(0, 0), Color::Red);
MatrixOS::LED::Update();

Draw first, then call MatrixOS::LED::Update() to show the frame.

CMakeLists.txt​

file(GLOB_RECURSE HELLO_NATIVE_SOURCES "*.cpp" "*.c")
file(GLOB_RECURSE HELLO_NATIVE_HEADERS "*.h")

add_library(HelloNativeAPP ${HELLO_NATIVE_SOURCES} ${HELLO_NATIVE_HEADERS})

target_include_directories(HelloNativeAPP PUBLIC
${CMAKE_CURRENT_SOURCE_DIR}
)

target_link_libraries(HelloNativeAPP PUBLIC
MatrixOSInterface
MatrixOSAPPInterface
)

RegisterApplicationClass(HelloNative)

RegisterApplicationClass(HelloNative) records the class for the generated Applications.h file used by the firmware build.

Enable The App For A Device​

Add the app folder name to the target device family's application list.

For Matrix OS Developer Toolkit:

Devices/MystrixSim/ApplicationList.txt

Add:

HelloNative

Use [System]HelloNative only if the app should run with system-level privilege.

For hardware builds, edit the matching device family list, for example Devices/Mystrix1/ApplicationList.txt or Devices/Mystrix2/ApplicationList.txt.

Build And Test​

From the Matrix OS repository:

make DEVICE=MystrixSim build-dev
make DEVICE=MystrixSim run

For hardware, build the target device and upload using the Matrix OS build flow for that device.

UI Components​

Matrix OS UI components are owned by your app code while the UI is running. The current C++ API takes component pointers:

#include "UI/UI.h"

void HelloNative::OpenMenu() {
UI menu("Menu", Color::Cyan, true);

UIButton button;
button.SetName("Color");
button.SetColor(color);
button.OnPress([&]() {
color = Color::Magenta;
});

menu.AddUIComponent(&button, Point(0, 0));
menu.Start();
}

Keep UI component objects alive until menu.Start() returns.

Use The API Reference​

Start with these API pages while building native apps:

If you are updating older native app code, read Migration From 3.x to 4.x after you understand the current input model.

Native App Notes​

  • Keep long-running logic cooperative. Drain queues, update state, then return from Loop().
  • Store app state inside the application class instead of global variables when possible.
  • Clean up dynamic memory, extra tasks, mutexes, peripheral state, and LED output in End().
  • Test timing, USB, MIDI, HID, storage, and pressure-sensitive input on real hardware before release.

Comments