AkiraOS’s AkiraSDK/wasm_apps/ folder contains advanced sample applications functioning as reference architecture for deeply embedded mathematical interfaces, high-speed input logic, networking, and HID routing. These examples demonstrate best practices for WASM app development on resource-constrained devices.

1. Hello World (hello_world/main.c)

Minimal starter app demonstrating the printf() logging API. Shows basic WASM execution flow and output formatting.

int main(void) {
    printf("=================================");
    printf("  Hello from AkiraOS WASM!      ");
    printf("=================================");
    printf("");
    printf("[INFO]  This is an info message");
    printf("[WARN]  This is a warning message");
    printf("[ERROR] This is an error message");
    return 0;
}

2. IMU Orientation Visualizer (imu_3d/main.c)

Retrieves accelerometer data, computes pitch/roll, and renders a 3D wireframe bounding box showing device orientation. Key Takeaway: Uses Q14 fixed-point math (no floating-point) for matrix transformations. Derives sine/cosine directly from normalized accelerometer ratios without lookup tables.

// 1. Helper converts raw accelerometer value to Q14 normalized coordinate
static int to_q14(int raw, int mag) {
    return (mag != 0) ? (int)(((int64_t)raw << 14) / mag) : 0;
}

// 2. Normalize accelerometer vector and extract pitch sine/cosine
int mag = isqrt64(ax*ax + ay*ay + az*az);
int sp = to_q14(-ax, mag);  // sin(pitch) derived from gravity vector
int cp = to_q14(cross, mag); // cos(pitch) from cross product

// 3. Apply 3×3 rotation matrix with Q14 fixed-point multiply
int x_rot = (x * m00 + y * m01 + z * m02) >> 14;
int y_rot = (x * m10 + y * m11 + z * m12) >> 14;

// 4. Project to orthogonal display coordinates
int proj_x = center_x + ((x_rot * SCALE) >> 14);
int proj_y = center_y - ((y_rot * SCALE) >> 14);

// 5. Draw filled triangles with painter's algorithm (back-to-front)
display_triangle_fill(x0, y0, x1, y1, x2, y2, color);

3. Macro Pad Keyboard Configurator (macro_pad/main.c)

Showcases the power of abstracting Bluetooth LE HID into standardized akira bindings over 60Hz polling delays. Validates button edges utilizing hardware bitmasks and immediately translates them into Consumer/Media and standard Keycode streams without blocking.

// Button logic polled continuously inside thread logic at 16.6ms intervals
int edge_mask = buttons_edge();
if (edge_mask) {
    if (edge_mask & (1 << BTN_UP)) {
        // Fire custom OS registry string into target device over BLE
        hid_type_string("akira_run_script\n");
    }
    if (edge_mask & (1 << BTN_LEFT)) {
        // Multimedia / Consumer interface control 
        hid_consumer_send(HID_CONSUMER_PLAY_PAUSE);
    }
    if (edge_mask & (1 << BTN_A)) {
        // Absolute HID state manipulation
        hid_key_press(HID_KEY_A);
        delay(50);
        hid_key_release_all();
    }
}

4. Logic Analyzer (logic_analyzer/main.c)

A fast GPIO polling engine executing array bit-packing methodologies to construct high-density logic waves on the display subsystem without causing out-of-bounds heap overflows. The interface maps state-tracking via ring buffers.

// Pre-mapping array pointer write-indexes 
#define SAMPLES 272
static uint8_t smp[4][SAMPLES];

// Sample buffer injection with rollover boundary
smp[0][wr] = gpio_read(PIN_0);
smp[1][wr] = gpio_read(PIN_1);

// Redraw logic signals based on previous-state checks avoiding duplicate paint routines
if (prev_state != current_state) {
    display_rect(x, wave_y, 1, h, COLOR_YELLOW);
}
wr = (wr + 1) % SAMPLES; // Advance ring pointer logically

5. 3D Spinning Cube (cube3d/main.c)

Real-time 3D renderer with perspective projection, back-face culling, and diffuse shading. Gyroscope controls spin speed dynamically — flick the board to accelerate rotation.

// 1. Interpolated sin/cos using 64-entry Q14 lookup table
static int32_t sin_a(int ang) {
    int idx  = ang >> 6;          // Integer LUT index [0..63]
    int frac = ang & 63;          // Fractional sub-step [0..63]
    int32_t s0 = s64[idx];
    int32_t s1 = s64[(idx + 1) & 63];
    return s0 + ((s1 - s0) * frac >> 6); // Linear interpolation
}

// 2. Read gyroscope channels and accumulate rotation angles
int32_t gx = sensor_read(SENSOR_CHAN_GYRO_X);
int32_t gy = sensor_read(SENSOR_CHAN_GYRO_Y);
int32_t gz = sensor_read(SENSOR_CHAN_GYRO_Z);
int dx = (gx != AKIRA_SENSOR_ERROR) ? gx / GYRO_SCALE : 0;
int dy = (gy != AKIRA_SENSOR_ERROR) ? gy / GYRO_SCALE : 0;
ang_x = (ang_x + AUTO_X + dx) & ANG_MASK;
ang_y = (ang_y + AUTO_Y + dy) & ANG_MASK;

// 3. Build 3×3 rotation matrix from euler angles
int sx = sin_a(ang_x), cx = cos_a(ang_x);
int sy = sin_a(ang_y), cy = cos_a(ang_y);
int m00 = (cy * cz) >> 14;
int m01 = (cy * sz) >> 14;
// ... (9 matrix elements)

// 4. Transform cube vertices, perform perspective divide
int xr = (x * m00 + y * m01 + z * m02) >> 14;
int yr = (x * m10 + y * m11 + z * m12) >> 14;
int zr = (x * m20 + y * m21 + z * m22) >> 14;
int xs = center_x + ((xr * FOCAL) / (zr + FOCAL));
int ys = center_y - ((yr * FOCAL) / (zr + FOCAL));

// 5. Back-face culling, depth sort, then fill with diffuse shading
if (dot_product > 0) continue; // Back face — skip
qsort(face_depths, 6, sizeof(face_t), depth_compare);
for (int i = 0; i < 6; i++) {
    int shade = calculate_diffuse(normal, light_dir);
    display_triangle_fill(v0, v1, v2, shade_color(PIECE_COLOR[i], shade));
}

6. Supervisor App Launcher (supervisor/main.c)

Foreground app launcher displaying scrollable list of installed apps with state badges (RUNNING/STOPPED/ERROR). Uses Lifecycle IPC to reactively update status.

// 1. Query installed apps via lifecycle API (returns "name:STATE\n" format)
char list_buf[LIST_BUF];
int count = app_list((uint8_t *)list_buf, sizeof(list_buf));

// 2. Parse app list buffer into local arrays
char *p = list_buf;
for (int i = 0; i < count; i++) {
    char *col = strchr(p, ':');
    int name_len = col - p;
    strncpy(apps[i].name, p, name_len);
    apps[i].state = parse_state(col + 1); // Parse "RUNNING", "STOPPED", etc.
    p = strchr(col, '\n') + 1;
}

// 3. Handle button input for navigation and control
if (btn_up_edge())   sel = (sel > 0) ? sel - 1 : count - 1;
if (btn_down_edge()) sel = (sel + 1) % count;
if (btn_a_edge()) {
    app_switch(apps[sel].name); // Launch selected app
    return 0; // Supervisor exits cleanly
}
if (btn_b_edge()) {
    app_stop(apps[sel].name); // Stop selected app
}

// 4. Subscribe to lifecycle topic and poll for events (non-blocking)
msg_subscribe("akira.lifecycle");
akira_lifecycle_event_t ev;
while (msg_try_recv("akira.lifecycle", (uint8_t *)&ev, sizeof(ev)) > 0) {
    // Update app state badges reactively
    for (int i = 0; i < count; i++) {
        if (strcmp(apps[i].name, ev.name) == 0) {
            apps[i].state = ev.state;
            break;
        }
    }
}

7. TCP Echo Client (net_echo/main.c)

TCP networking example connecting to echo server, sending data, and receiving reply. Uses shared-memory ring buffers for zero-copy I/O.

// 1. Open TCP socket and bind TX/RX ring buffers
int h = net_open(NET_TYPE_TCP);
net_tx_bind(h, tx_ring, sizeof(tx_ring));
net_rx_bind(h, rx_ring, sizeof(rx_ring));

// 2. Async connect to server (DNS + TCP handshake in background)
net_connect(h, "127.0.0.1", 7);

// 3. Poll for NET_EVT_CONNECTED event
uint8_t evt[4];
while (!connected) {
    if (net_event_pop(evt, sizeof(evt)) > 0) {
        if (evt[0] == NET_EVT_CONNECTED) connected = 1;
    }
    delay_ms(10);
}

// 4. Write to TX ring (zero-copy), then flush
net_ring_write(tx_ring, sizeof(tx_ring), (uint8_t *)"Hello AkiraOS!\n", 15);
net_tx_flush(h);

// 5. Poll for NET_EVT_DATA_READY, then read from RX ring
while (net_event_pop(evt, sizeof(evt)) > 0) {
    if (evt[0] == NET_EVT_DATA_READY && evt[1] == (uint8_t)h) {
        char buf[64];
        int n = net_ring_read(rx_ring, sizeof(rx_ring), (uint8_t *)buf, sizeof(buf));
        printf("Echo reply: %.*s", n, buf);
    }
}

8. Inclinometer (inclinometer/main.c)

Accelerometer-based tilt sensor displaying direction and angle on compass-style rose. No magnetometer required — pure gravity vector analysis.

// 1. Read accelerometer gravity vector (separate channels)
int32_t ax = sensor_read(SENSOR_CHAN_ACCEL_X);
int32_t ay = sensor_read(SENSOR_CHAN_ACCEL_Y);
int32_t az = sensor_read(SENSOR_CHAN_ACCEL_Z);
if (ax == AKIRA_SENSOR_ERROR) { ax = 0; ay = 0; az = 9812; }

// 2. Calculate total magnitude and horizontal tilt component
int32_t mag = isqrt64((int64_t)ax*ax + (int64_t)ay*ay + (int64_t)az*az);
int32_t horiz = isqrt64((int64_t)ax*ax + (int64_t)ay*ay);
int32_t tilt_q14 = (int32_t)((int64_t)horiz * 16384 / mag); // sin(tilt) in Q14

// 3. Compute tilt direction with integer atan2 (0-3600 tenths of degrees)
int tilt_dir = atan2_dd((int)ax, (int)ay); // CCW from +Y axis

// 4. Convert tilt angle to needle length and draw compass
int tilt_deg = (int32_t)((int64_t)tilt_q14 * 90 >> 14); // 0-90 degrees
int needle_len = (tilt_q14 * RADIUS) >> 14; // Scale to display radius
int lut_idx = (tilt_dir * 64) / 3600; // Map to 64-entry LUT
int nx = center_x + ((needle_len * COS64(lut_idx)) >> 14);
int ny = center_y - ((needle_len * SIN64(lut_idx)) >> 14);
display_line(center_x, center_y, nx, ny, COLOR_RED);

9. Tetris (tetris/main.c)

Full-featured Tetris implementation with classic gameplay, scoring, and level progression. Demonstrates efficient game state management and incremental rendering.

// 1. Piece collision detection using bit-packed 4×4 shapes
static int collides(int piece, int rot, int x, int y) {
    uint16_t shape = SHAPES[piece][rot];
    for (int r = 0; r < 4; r++) {
        for (int c = 0; c < 4; c++) {
            if (shape & (0x8000 >> (r * 4 + c))) {
                int bx = x + c, by = y + r;
                if (bx < 0 || bx >= BOARD_WIDTH || by >= BOARD_HEIGHT)
                    return 1;
                if (by >= 0 && g.board[by][bx]) return 1;
            }
        }
    }
    return 0;
}

// 2. Line clear detection and board compaction
int lines_cleared = 0;
for (int y = BOARD_HEIGHT - 1; y >= 0; y--) {
    int full = 1;
    for (int x = 0; x < BOARD_WIDTH; x++) {
        if (!g.board[y][x]) { full = 0; break; }
    }
    if (full) {
        lines_cleared++;
        // Shift all rows above down by one
        for (int yy = y; yy > 0; yy--) {
            for (int x = 0; x < BOARD_WIDTH; x++) {
                g.board[yy][x] = g.board[yy - 1][x];
            }
        }
        // Clear top row
        for (int x = 0; x < BOARD_WIDTH; x++) g.board[0][x] = 0;
        y++; // Re-check this row (shifted down)
    }
}

// 3. Score calculation: pts[1]=100, pts[2]=300, pts[3]=500, pts[4]=800
static const uint32_t pts[5] = {0, 100, 300, 500, 800};
g.score += pts[lines_cleared] * g.level;

// 4. Incremental rendering — only redraw changed cells
if (g.piece_moved || g.board_changed) {
    for (int y = 0; y < BOARD_HEIGHT; y++) {
        for (int x = 0; x < BOARD_WIDTH; x++) {
            if (g.board[y][x] != prev_board[y][x]) {
                draw_block(x, y, PIECE_COLOR[g.board[y][x] - 1]);
            }
        }
    }
    g.piece_moved = 0;
    g.board_changed = 0;
}

Additional sample apps available in AkiraSDK/wasm_apps/: ble_led, compass, display_test, gpio, imu_timer_test, net_server, storage_test. Refer to each app’s main.c for implementation details and required capabilities.


Copyright © 2025-2026 AkiraOS Project. Licensed under GNU GPL v3.