Reload OS

API reference

Everything in ros.h that an app can use: 250 functions and variables the firmware exports, and the header's types, constants and macros - from the app kit of Reload OS 1.4.0 (app interface 2). The descriptions are the header's own comments.

Threading: every LVGL call happens inside an LVGL callback (event, timer - they run on the LVGL task) or between ros_lock() / ros_unlock(). Nothing that waits belongs on the LVGL task - see the rules.

#Screen, theme and the LVGL lock

A big static variable in PSRAM instead of the scarce internal RAM (CONFIG_SPIRAM_ALLOW_BSS_SEG_EXTERNAL_MEMORY). Only for what tasks use: never something an interrupt handler touches, nothing needed before app_main(). It starts as zeros like any other and cannot have an initialiser.

#define ROS_BIG_BSS EXT_RAM_BSS_ATTR
#define ROS_NAME        "Reload OS"

ROS_VERSION: the release, from version.txt (main/CMakeLists.txt) - also the app descriptor's version

#ifndef ROS_VERSION
#define ROS_VERSION     "dev"
#endif

Screen geometry: the panel is 1024x600 (JC4880P443: 480x800, scanned vertically). Mounted the panel's own way it is used as it is; the other way (setting "orientation", Settings > Display, applied at the next start) the display pipeline turns the UI (main.c): 600x1024 on a 7" board vertical, 800x480 on the JC4880P443 horizontal. ROS_SCR_W / ROS_SCR_H are therefore values, not constants.

#define ROS_PANEL_W     ROS_BOARD_PANEL_W  /* the panel as it scans (its frame buffer); the UI may be turned */
#define ROS_PANEL_H     ROS_BOARD_PANEL_H
ros_scr_hvariable
extern int ros_scr_w, ros_scr_h;
#define ROS_SCR_W       (ros_scr_w)
#define ROS_SCR_H       (ros_scr_h)
#define ROS_PORTRAIT    (ros_scr_h > ros_scr_w)
#define ROS_NARROW      (ros_scr_w < 560)   /* the JC4880P443 vertical (480 px): one control a line, short texts */
#define ROS_DLG_W(w)    ((w) < ros_scr_w - 24 ? (w) : ros_scr_w - 24)     /* a dialog width that fits either way */

A pointer position as the UI sees it -> what a pointer device must report: LVGL turns every pointer's coordinates for a turned display, so one that is already in UI coordinates (remote desktop, USB mouse, probe) has to be turned back first.

void ros_pointer_raw(int32_t *x, int32_t *y);
enum { ROS_ORIENT_HORIZONTAL, ROS_ORIENT_VERTICAL, ROS_ORIENT_VERTICAL_FLIPPED, ROS_ORIENT_COUNT };
#define ROS_BAR_H       44

Theme: dark or light (setting "theme", Settings > Display; applied at the next start). The ROS_C_* names read the palette in use, so they are values, not constants: no static initialisers.

typedef struct {
    uint32_t bg, surface, surface2, border, text, muted, dim, accent, accent2, ok, warn, err;
} ros_palette_t;
extern const ros_palette_t *ros_pal;
void ros_theme_apply(int light);         /* before the UI is built */
#define ROS_C_BG        (ros_pal->bg)
#define ROS_C_SURFACE   (ros_pal->surface)
#define ROS_C_SURFACE2  (ros_pal->surface2)
#define ROS_C_BORDER    (ros_pal->border)
#define ROS_C_TEXT      (ros_pal->text)
#define ROS_C_MUTED     (ros_pal->muted)
#define ROS_C_DIM       (ros_pal->dim)       /* status icons that are off */
#define ROS_C_ACCENT    (ros_pal->accent)
#define ROS_C_ACCENT2   (ros_pal->accent2)
#define ROS_C_OK        (ros_pal->ok)
#define ROS_C_WARN      (ros_pal->warn)
#define ROS_C_ERR       (ros_pal->err)

LVGL lock for code outside LVGL event/timer callbacks (recursive). timeout_ms = 0 waits forever. Returns false on timeout.

bool ros_lock(uint32_t timeout_ms);
void ros_unlock(void);

#Apps

typedef struct ros_app {
    const char *name;
    const char *icon;                 /* LV_SYMBOL_* glyph */
    uint32_t color;                   /* launcher tile colour */
    const void *(*image)(void);       /* optional: a picture for the tile instead of the glyph */
    bool image_on_white;              /* the picture is a logo: white tile instead of the colour */
    void (*create)(lv_obj_t *body);   /* build UI inside `body` */
    void (*destroy)(void);            /* optional: stop timers / free memory */
    bool (*back)(void);               /* optional: handle "back" (edge swipe) in-app; false = go home */
} ros_app_t;

Apps on the SD card (ros_elfapp.c): an ELF file in /sdcard/apps/ whose main(argc, argv) stores a pointer to its ros_elfapp_t in *(const ros_elfapp_t **)argv[0]. ROS_ELFAPP_ABI changes whenever ros_app_t, the meaning of the exported API, or the layout of a struct of this header an app uses changes (new struct fields go at the end instead); an app made for another number is refused. Template: elfapps/hello/; build: tools/elfapp.sh <name>.

#define ROS_ELFAPP_ABI 2

What the launcher shows for an app on the SD card - read from the file at start, without loading the app: a section ".ros_meta" holding one of these. Without it the tile is named after the file.

typedef struct {
    char magic[4];                        /* "ROSM" */
    uint32_t version;                     /* ROS_ELFAPP_META_VERSION */
    char name[24];                        /* the tile's name; an app with a built-in app's name replaces it */
    char icon[16];                        /* an LV_SYMBOL_* glyph, or "@name" for a drawn icon (ros_icon()) */
    uint32_t color;                       /* the tile's colour */
    uint32_t flags;                       /* ROS_ELFAPP_ON_WHITE */
} ros_elfapp_meta_t;
#define ROS_ELFAPP_META_VERSION 2
#define ROS_ELFAPP_ON_WHITE     1u        /* the tile's picture (ROS_ELFAPP_TILE) is a logo: a white tile */
#define ROS_ELFAPP_META_FLAGS(name_, icon_, color_, flags_) \
    __attribute__((section(".ros_meta"))) const ros_elfapp_meta_t ros_elfapp_meta = \
        { { 'R', 'O', 'S', 'M' }, ROS_ELFAPP_META_VERSION, name_, icon_, color_, flags_ }
#define ROS_ELFAPP_META(name_, icon_, color_) ROS_ELFAPP_META_FLAGS(name_, icon_, color_, 0)

Optional: a picture for the tile instead of the glyph. The PNG (at most 64 KB) goes into the file's section ".ros_tile", which is not loaded with the app - the launcher reads it at start. file_ is its path as a string, from the app's CMakeLists.txt.

#define ROS_ELFAPP_TILE(file_) \
    __asm__(".pushsection .ros_tile, \"\", @progbits\n.incbin \"" file_ "\"\n.popsection")
typedef struct {
    uint32_t abi;                         /* ROS_ELFAPP_ABI it was built with */
    ros_app_t app;
    const char *board;                    /* ROS_BOARD_SHORT it was built for: the pins are the board's */
    volatile int *tasks;                  /* its tasks still running (NULL: none). The code is unloaded
                                           * only when this is 0 - end them with ros_task_end(). */
    void (*unload)(void);                 /* optional: right before the code goes (no task of it left) -
                                           * free what it keeps across opens (queues, mutexes ...): every
                                           * load starts with fresh variables, so that would leak */
    const ros_elfapp_meta_t *meta;        /* &ros_elfapp_meta (ROS_ELFAPP_META): keeps the section in the file */
} ros_elfapp_t;
ros_task_endfunction

The end of a task that counts itself in *live (an app on the SD card must, see ros_elfapp_t.tasks): the count goes down here, in the firmware, so the task never returns into code that may be gone. caps: the task was made with xTaskCreate...WithCaps. Does not return.

void ros_task_end(volatile int *live, bool caps) __attribute__((noreturn));

The product this firmware is built as (products/<product>/product.c; -D ROS_PRODUCT=..., see products/README.md): its name and the apps on its launcher, in their built-in order (at most 16 - the shell keeps 8 places for the SD card's apps).

extern const char *const ros_product_name;
extern const ros_app_t *const ros_product_apps[];
extern const int ros_product_app_count;

In ros.h for the firmware itself, not exported to apps: app_settings, app_wifi, app_monitor, app_files, app_ethernet, app_camera, app_recorder, app_usb, app_idcard, app_factory, ros_factory_log, ros_elfapp_merge, ros_elfapp_release.

#Shell

int ros_app_count(void);                    /* launcher apps, for the auto-start choice */
const ros_app_t *ros_app_at(int i);
void ros_open_app(const ros_app_t *app);

An app screen shown inside another app (Settings pages): counts as active for ros_app_is_active(). NULL when it goes away.

void ros_app_embed(const ros_app_t *app);

Settings pages (Android-style: every driver's settings in one app)

enum {
    ROS_SETTINGS_WIFI, ROS_SETTINGS_ETHERNET, ROS_SETTINGS_HOTSPOT, ROS_SETTINGS_BLUETOOTH, ROS_SETTINGS_REMOTE,
    ROS_SETTINGS_DISPLAY, ROS_SETTINGS_SOUND, ROS_SETTINGS_STORAGE, ROS_SETTINGS_USB,
    ROS_SETTINGS_TIME, ROS_SETTINGS_ABOUT,
    /* Tools (1.4): apps that were on the launcher - their screen inside Settings */
    ROS_SETTINGS_CAMERA, ROS_SETTINGS_MONITOR, ROS_SETTINGS_RECORDER, ROS_SETTINGS_IDCARD,
};
void ros_open_settings(int page);       /* -1 = the category list */
void ros_go_home(void);
bool ros_app_is_active(const ros_app_t *app);
void ros_toast(const char *fmt, ...);
void ros_statusbar_show(bool show);   /* hidden = no redraws at all (full-screen video overlay) */

Small UI helpers so apps look consistent

lv_obj_t *ros_ui_card(lv_obj_t *parent);
lv_obj_t *ros_ui_round_corners(lv_obj_t *box, int radius, uint32_t outside_color);  /* cheap clip_corner */
lv_obj_t *ros_ui_button(lv_obj_t *parent, const char *text, uint32_t color);
ros_ui_pngfunction

An embedded PNG decoded once (kept for good; RGBA -> LVGL's ARGB8888). NULL if it can't be.

const void *ros_ui_png(const uint8_t *start, const uint8_t *end);
ros_iconfunction

a drawn icon by name (main/assets/icons, tools/mkicons.py), e.g. "sun"; NULL if there is none

const void *ros_icon(const char *name);

that icon as an lv_image tinted to `color` (white drawings)

lv_obj_t *ros_ui_icon(lv_obj_t *parent, const char *name, uint32_t color);
lv_obj_t *ros_ui_list_note(lv_obj_t *list, const char *text);   /* a muted text line in a list */

put a drawn icon in front of a button's text (tinted like the text)

void ros_ui_button_icon(lv_obj_t *btn, const char *name);
lv_obj_t *ros_ui_keyboard(lv_obj_t *parent);    /* the OS keyboard: big keys, digit row, key preview, click */
void ros_ui_keyboard_light(lv_obj_t *kb);       /* its colours for a light screen */
lv_obj_t *ros_ui_label(lv_obj_t *parent, const lv_font_t *font, uint32_t color, const char *text);

In ros.h for the firmware itself, not exported to apps: ros_shell_start.

#Settings (NVS)

IPv4 configuration: on = static address, else DHCP. Strings are dotted quads ("" = unset).

typedef struct {
    bool on;
    char ip[16], mask[16], gw[16], dns[16];
} ros_ipv4_t;

Shared "IP settings" dialog (Ethernet and Wi-Fi pages). `current` pre-fills the fields when nothing is saved yet (the DHCP lease). on_save runs in the LVGL task after validation.

typedef void (*ros_ipv4_save_cb_t)(const ros_ipv4_t *cfg);
void ros_ipv4_dialog(const char *title, const ros_ipv4_t *saved, const ros_ipv4_t *current,
                     const char *note, ros_ipv4_save_cb_t on_save);
void ros_ipv4_dialog_close(void);
typedef struct {
    int brightness;     /* 5..100 % */
    int volume;         /* 0..100 % */
    int tz_index;       /* index into ros_timezones */
    bool wifi_enabled;
    bool remote_enabled;  /* browser remote desktop, restored at boot */
    int usb_port;         /* USB host port: 0 = USB Native (HS), 1 = USB_OTG (FS); applied at boot */
    bool usb_hub;         /* high-speed port runs at full speed so FS devices work behind a hub; at boot */
    ros_ipv4_t eth;       /* Ethernet: static address (on) or DHCP */
    ros_ipv4_t wifi;      /* Wi-Fi: static address, only on the network below */
    char wifi_static_ssid[33];
    int screen_timeout;   /* index into ros_screen_timeouts (0 = never) */
    int printer_lang;     /* ros_prn_lang_t; ROS_PRN_AUTO = from the printer's device ID */
    int printer_dots;     /* receipt printers: dots per line, 0 = auto (384 = 58 mm, 576 = 80 mm) */
    bool hotspot_on;      /* Wi-Fi access point (ros_wifi.c) */
    bool hotspot_share;   /* share the board's internet (Ethernet / Wi-Fi) with hotspot clients: NAT */
    char hotspot_ssid[33];
    char hotspot_pass[65];/* "" = open network; else 8..63 characters, WPA2 */
    int bp_baud;          /* serial speed of a blood-pressure monitor (a product app's setting) */
    char remote_user[25]; /* remote desktop login (ros_remote.c) */
    char remote_pass[33]; /* "" = not made yet: a random one is created when the remote desktop first starts */
    int theme;            /* 0 dark, 1 light (ros_pal) */
    char ntp_server[64];  /* SNTP server, "" = pool.ntp.org */
    char app_order[256];  /* launcher order: app names, comma separated (others follow); "" = built-in */
    char autostart[24];   /* app opened by itself after boot (its launcher name), "" = home screen */
    int orientation;      /* ROS_ORIENT_*: how the device is mounted; applied at the next start */
    bool bt_enabled;      /* Bluetooth LE (ros_bt.c): restored at boot */
    bool bt_visible;      /* advertise the name below, so phones and PCs see the device */
    char bt_name[25];     /* "" = not made yet: ReloadOS-XXXX (from the MAC) when Bluetooth is first switched on */
    bool ram_disk;        /* the 8 MB RAM disk in PSRAM (/ram, also a USB drive for a PC); applied at boot */
    uint8_t panel;        /* which panel a board sold with more than one has (ROS_BOARD_PANEL_VARIANTS; JC8012P4A1:
                           * 0 = the vendor's New_Panel, 1 = Old_Panel); applied at boot */
    /* New fields go HERE, at the end: SD card apps use this struct by offset (a product app reads bp_baud,
     * theme ...). A field in the middle moves the ones after it under every app built before - or
     * raise ROS_ELFAPP_ABI. The same for every struct of this header an app uses. */
} ros_settings_t;

Screen timeout choices (seconds, 0 = never) and labels for a dropdown

extern const int ros_screen_timeouts[];
extern const char *const ros_screen_timeout_labels;   /* "Never\n30 seconds\n..." */
#define ROS_SCREEN_TIMEOUT_COUNT 6
void ros_keep_awake(void);      /* call periodically while something should keep the screen on (video) */

Why the last boot happened. crash = panic / watchdog / brownout.

const char *ros_reset_reason(bool *crash);

In ros.h for the firmware itself, not exported to apps: ros_ipv4_valid, ros_ipv4_mask_valid, ros_back.

#Device health (ros_health.c)

For devices nobody watches: restart counters, what the last crash was, a crash-loop guard (safe mode: no auto start app) and a watchdog on the UI task.

typedef struct {
    uint32_t boots, crashes, brownouts;   /* since the first start of a release with this record (1.0.0) */
    uint8_t streak;                       /* crashes in a row, each soon after its start */
    bool crashed;                         /* this start follows a crash (panic / watchdog) */
    bool safe_mode;                       /* this start: a crash loop - the auto start app is not opened */
    char last[224];                       /* the last crash on record, one line; "" = none */
} ros_health_t;
void ros_health_ui_start(void);           /* LVGL context, when the shell is up: UI watchdog, "settled" timer */
const ros_health_t *ros_health(void);
void ros_health_app(const char *name);    /* the app on screen (NULL = home screen): goes into a crash record */
typedef struct {
    const char *label;
    const char *posix;
} ros_tz_t;
extern const ros_tz_t ros_timezones[];
extern const int ros_timezone_count;
void ros_settings_load(void);
void ros_settings_save(void);
ros_settings_t *ros_settings(void);
void ros_apply_brightness(int pct);
void ros_apply_timezone(int idx);

In ros.h for the firmware itself, not exported to apps: ros_health_init, ros_health_clear.

#Storage

Three FAT volumes, each usable locally or exposed to a PC over USB_OTG (ros_usbdev.c). While a PC has them, they are NOT available locally (ros_vol_available() == false).

#define ROS_SD_MOUNT   "/sdcard"
#define ROS_FFAT_MOUNT "/ffat"
#define ROS_RAM_MOUNT  "/ram"
typedef enum { ROS_VOL_SD, ROS_VOL_FFAT, ROS_VOL_RAM, ROS_VOL_COUNT } ros_vol_t;
bool ros_vol_present(ros_vol_t v);       /* the medium exists (card inserted, partition found) */
bool ros_vol_available(ros_vol_t v);     /* mounted in Reload OS right now */
const char *ros_vol_path(ros_vol_t v);
bool ros_vol_stats(ros_vol_t v, uint64_t *total, uint64_t *free_bytes);

Erase and re-create the volume's FAT (SD: FAT32, 32 KB clusters). Blocking - several seconds for the SD card; call from a task. Refused while a PC has the volumes.

esp_err_t ros_vol_format(ros_vol_t v);
esp_err_t ros_usbdev_start(void);        /* USB mass-storage device on USB_OTG */
bool ros_usbdev_pc_connected(void);      /* a PC currently owns the volumes */
bool ros_sd_mounted(void);
uint64_t ros_sd_total_bytes(void);
uint64_t ros_sd_free_bytes(void);

In ros.h for the firmware itself, not exported to apps: ros_usbdev_enabled, ros_usbdev_generation, ros_storage_init.

#Animations (ros_anim.c)

A looping animation made from a GIF by tools/mkanim.py. Returns an lv_image (NULL: bad data or no memory) that is paused until ros_anim_run(). The data must outlive the object. LVGL task only.

lv_obj_t *ros_anim_create(lv_obj_t *parent, const uint8_t *data, size_t len);

The same from a file: /ffat/anim/<name>, else /sdcard/anim/<name> (8.3 name), read into PSRAM. keep: the bytes stay loaded for the session (an app that is opened again and again).

lv_obj_t *ros_anim_create_file(lv_obj_t *parent, const char *name, bool keep);
void ros_anim_run(lv_obj_t *anim, bool run);    /* true: play from the first frame; false: pause */

#Audio

esp_err_t ros_audio_init(void);
bool ros_audio_ready(void);
void ros_audio_set_volume(int pct);
void ros_audio_tone(float freq_hz, int duration_ms);   /* non-blocking */
void ros_audio_click(void);
esp_err_t ros_audio_play_wav(const char *path);        /* 16-bit mono WAV, non-blocking */

A whole WAV file in memory, 16 kHz mono, 16-bit PCM or IMA ADPCM; non-blocking, replaces what plays. The memory must stay valid until it ends (built-in voice prompts).

esp_err_t ros_audio_play_mem(const void *wav, size_t len);

A sound file from a drive: MP3 (any bit rate, 32-48 kHz, mono / stereo) or WAV (PCM 8 / 16-bit, mono / stereo, any rate), decoded in its own task and played through the stream (16 kHz mono on the speaker). Non-blocking; replaces what plays; ros_audio_stop() ends it, ros_audio_playing() says whether it runs.

esp_err_t ros_audio_play_file(const char *path);
void ros_audio_stop(void);                             /* interrupt tone / WAV / file playback */
bool ros_audio_idle(void);                             /* nothing queued, nothing playing (memory a clip came from may go) */

PCM stream (video soundtracks): any rate, 8/16-bit, mono/stereo in; converted to the speaker's 16 kHz mono. UI click tones are ignored while a stream plays. The clock counts what has actually been played (minus output latency) - use it as the A/V master clock.

esp_err_t ros_audio_stream_start(int rate, int channels, int bits);   /* starts paused */
size_t ros_audio_stream_write(const void *pcm, size_t bytes);        /* never blocks; bytes taken */
int ros_audio_stream_buffered_ms(void);
void ros_audio_stream_pause(bool pause);
void ros_audio_stream_format(int rate, int channels, int bits);      /* change the input format, keep playing */
int64_t ros_audio_stream_clock_us(void);
void ros_audio_stream_reset(void);                                    /* drop buffer, clock to 0 */
void ros_audio_stream_stop(void);
bool ros_audio_playing(void);

In ros.h for the firmware itself, not exported to apps: ros_audio_stream_free_ms.

#Microphone

Called on the mic task with each 20 ms block (16 kHz, 16-bit mono)

typedef void (*ros_mic_cb_t)(const int16_t *samples, size_t count, void *user);
bool ros_mic_ready(void);
esp_err_t ros_mic_start(ros_mic_cb_t cb, void *user);  /* cb may be NULL (level meter only) */
void ros_mic_stop(void);                               /* also finalises any recording */
int ros_mic_level(void);                               /* 0..100, peak -60..0 dBFS */
void ros_mic_set_gain(float db);
esp_err_t ros_mic_record_start(const char *path);      /* WAV to SD; mic must be started */
uint32_t ros_mic_record_stop(void);                    /* returns recorded length in ms */
bool ros_mic_recording(void);
uint32_t ros_mic_record_ms(void);

#Wi-Fi

typedef enum {
    ROS_WIFI_STARTING,
    ROS_WIFI_UNAVAILABLE,   /* co-processor did not respond */
    ROS_WIFI_OFF,
    ROS_WIFI_IDLE,
    ROS_WIFI_CONNECTING,
    ROS_WIFI_CONNECTED,
} ros_wifi_state_t;
typedef struct {
    char ssid[33];
    int8_t rssi;
    bool secure;
} ros_wifi_ap_t;
void ros_wifi_start(void);                         /* spawns init task */
ros_wifi_state_t ros_wifi_state(void);
const char *ros_wifi_ssid(void);
const char *ros_wifi_ip(void);
int ros_wifi_rssi(void);
esp_err_t ros_wifi_set_enabled(bool on);
esp_err_t ros_wifi_scan(ros_wifi_ap_t *out, int max, int *found); /* blocking */
esp_err_t ros_wifi_connect(const char *ssid, const char *password);

Static IPv4 for Wi-Fi (Android-style, per network): ros_settings()->wifi applies only while connected to ros_settings()->wifi_static_ssid; any other network uses DHCP.

esp_err_t ros_wifi_apply_ip(void);          /* apply now (no reconnect) */
void ros_wifi_ip_info(ros_ipv4_t *out);     /* current address / mask / gateway / DNS; on = static */
void ros_wifi_disconnect(void);

Hotspot: the C6 as an access point (AP, or AP + station), 192.168.4.1/24 with DHCP; with sharing on, clients reach the internet through the board (lwIP NAPT over Ethernet or Wi-Fi)

#define ROS_HOTSPOT_IP "192.168.4.1"
esp_err_t ros_hotspot_set(bool on);                /* saved; LVGL or worker context */
esp_err_t ros_hotspot_config(const char *ssid, const char *pass, bool share);   /* saved, re-applied */
bool ros_hotspot_running(void);
int ros_hotspot_clients(void);
const char *ros_hotspot_uplink(void);              /* "Ethernet" / "Wi-Fi" / "" (no internet to share) */

#Bluetooth LE (ros_bt.c)

The controller is the ESP32-C6's, over the esp-hosted link; the host stack (NimBLE) runs on the P4. Nothing is started while it is off. No pairing and no profiles yet: the device is visible under its name and lists the devices nearby.

typedef enum {
    ROS_BT_OFF,
    ROS_BT_STARTING,
    ROS_BT_ON,
    ROS_BT_STOPPING,
    ROS_BT_UNAVAILABLE,     /* the C6 does not answer, or its firmware has no Bluetooth: ros_bt_status() */
} ros_bt_state_t;
typedef struct {
    uint8_t addr[6];        /* as NimBLE has it: least significant byte first */
    int8_t rssi;
    char name[30];          /* "" = the device did not send one */
} ros_bt_dev_t;
void ros_bt_start(void);                           /* boot: its task; on if the setting is */
bool ros_bt_supported(void);                       /* the C6's firmware has Bluetooth (known once the link is up) */
esp_err_t ros_bt_set_enabled(bool on);             /* saved; returns at once - watch ros_bt_state() */
ros_bt_state_t ros_bt_state(void);
const char *ros_bt_status(void);                   /* why it is unavailable, "" otherwise */
const char *ros_bt_address(void);                  /* "AA:BB:CC:DD:EE:FF" while on, else "" */
esp_err_t ros_bt_set_name(const char *name);       /* 1-24 printable ASCII characters; saved, applied at once */
void ros_bt_set_visible(bool on);                  /* saved, applied at once */
int ros_bt_connections(void);                      /* devices connected to this one */
esp_err_t ros_bt_scan(int seconds);                /* look for devices nearby (1-60 s) */
bool ros_bt_scanning(void);
int ros_bt_devices(ros_bt_dev_t *out, int max);    /* found so far: named ones first, then by signal. LVGL task */
uint32_t ros_bt_generation(void);                  /* changes with the state, the list, the connections */

#Display performance

typedef struct {
    const char *name;
    float fps;
    float avg_ms;       /* render + flush per refresh */
    float max_ms;
} ros_perf_result_t;
typedef void (*ros_perf_done_cb_t)(const ros_perf_result_t *results, int count);
void ros_perf_init(void);                          /* call once with the display lock held */
bool ros_perf_benchmark(ros_perf_done_cb_t done);  /* LVGL context; results also logged */
void ros_perf_counters(uint32_t *frames, uint64_t *us);   /* all LVGL refreshes so far, total time */
void ros_perf_overlay(bool show);                  /* FPS / refresh ms / CPU per core */
bool ros_perf_overlay_visible(void);

In ros.h for the firmware itself, not exported to apps: ros_perf_benchmark_running.

#Remote desktop

See and drive this screen from a browser (concept: RLD_Remote). MJPEG stream from the hardware JPEG encoder on port 81, page + touch on port 80. Plain HTTP, no login.

esp_err_t ros_remote_start(void);
void ros_remote_stop(void);
void ros_remote_set_enabled(bool on);   /* start/stop and remember the choice */

New login: user 1-24 of A-Z a-z 0-9 _ . -, password 6-32 printable characters without spaces. Everybody who is logged in is logged out. ESP_ERR_INVALID_ARG if they don't fit.

esp_err_t ros_remote_set_login(const char *user, const char *pass);
bool ros_remote_running(void);
const char *ros_remote_url(void);      /* "http://a.b.c.d/" once an interface has an IP */
int ros_remote_viewers(void);

In ros.h for the firmware itself, not exported to apps: ros_remote_frames, ros_remote_snapshot, ros_remote_snapshot_done, ros_remote_touch, ros_probe_start, ros_probe_put.

#JPEG codec (hardware)

void ros_jpeg_init(void);
jpeg_decoder_handle_t ros_jpeg_decoder(void);
esp_err_t ros_jpeg_encode(const jpeg_encode_cfg_t *cfg, const uint8_t *in, uint32_t in_size,
                          uint8_t *out, uint32_t out_size, uint32_t *out_len);

#Heap watch (ros_heap.c)

ESP32-C6 Wi-Fi co-processor firmware (ros_cpfw.c): version, update over SDIO from the SD card

#define ROS_CPFW_PATH "/sdcard/esp32c6_hosted.bin"
void ros_cpfw_start(void);                 /* asks the C6 for its version (background) */
const char *ros_cpfw_version(void);
bool ros_cpfw_file_present(void);
esp_err_t ros_cpfw_update(void);           /* starts the update; P4 restarts when done */
esp_err_t ros_cpfw_update_file(const char *path);   /* the same from any volume */
int ros_cpfw_progress(const char **msg);   /* 0..100, -1 = idle; msg: stage or error */

Battery-backed clock (ros_rtc.c): the P4's LP timer on VDD_BAT (MaTouch), or the RX8025T clock chip (JC1060P470C)

typedef enum { ROS_CLOCK_UNSET, ROS_CLOCK_BATTERY, ROS_CLOCK_NETWORK, ROS_CLOCK_MANUAL } ros_clock_src_t;
void ros_rtc_init(void);                   /* early in boot: restore / report the clock */
void ros_rtc_on_sync(struct timeval *tv);  /* SNTP sync callback */
void ros_rtc_tz_changed(void);
void ros_rtc_set_manual(time_t t);         /* set by hand (no internet): clock, backup, clock chip */
time_t ros_rtc_last_sync(void);            /* last network sync, 0 = none since boot */             /* after ros_apply_timezone() with a new zone */
ros_clock_src_t ros_rtc_source(void);
const char *ros_rtc_status(void);          /* one line for Settings */
bool ros_rtc_rc_ppm(float *ppm, int *minutes);   /* live: internal RC vs main crystal since boot */
const char *ros_rtc_drift(void);           /* accuracy at the last network sync after boot, "" if none */
void ros_heap_init(void);                  /* failed-allocation log + low-RAM watch */
void ros_heap_report(const char *why);     /* heaps and every task's stack, to the log */
void ros_lvmem_usage(size_t *bytes, size_t *blocks);   /* what LVGL holds now (ros_lvmem.c) */
void ros_cpu_report(int ms, char *out, size_t n);   /* per-task CPU over ms, to the log and out */

In ros.h for the firmware itself, not exported to apps: ros_rtc_save, ros_heap_failures.

#Images (ros_image.c)

Decode a JPEG / PNG / BMP file, scaled to fit bw x bh (at most max_scale up), into BGR888 (LVGL RGB888 order) in PSRAM; caller frees. iw/ih: the image's own size. Worker tasks only.

uint8_t *ros_image_decode(const char *path, int bw, int bh, float max_scale, int *ow, int *oh, int *iw, int *ih,
                          const char **err);
bool ros_ext_is(const char *name, const char *list);   /* list: "jpg,jpeg,png" */

Same, for a baseline JPEG already in memory (e.g. an ID card photo)

uint8_t *ros_image_decode_jpeg_mem(const uint8_t *data, size_t len, int bw, int bh, float max_scale, int *ow,
                                   int *oh, int *iw, int *ih, const char **err);

#MySQL client (ros_mysql.c)

typedef struct {
    char host[64];
    int port;                                  /* 0 = 3306 */
    char user[33], pass[65];
} ros_mysql_cfg_t;

Connect, log in (mysql_native_password), run one statement, quit. Plain TCP. err: a short reason on failure. Blocking with timeouts - worker tasks only.

esp_err_t ros_mysql_exec(const ros_mysql_cfg_t *cfg, const char *sql, char *err, size_t err_n);

#Firmware update (ros_ota.c)

typedef struct {
    char project[32], version[32], built[24], idf[32];
    uint32_t size;
    bool ours;                                 /* a Reload OS build */
    bool legacy;                               /* ... from before 1.0.0: it does not say which board it is for */
} ros_ota_info_t;
#define ROS_PROJECT_PREFIX "reload_os"         /* project name: reload_os_<board> (root CMakeLists.txt) */
#define ROS_OTA_PATH "/sdcard/reload_os.bin"   /* Settings > About > Update from SD looks here ... */
#define ROS_OTA_PATH_UPLOAD "/sdcard/update.bin" /* ... then here (where POST /ota stores it) */
void ros_ota_start(void);                      /* boot: report the slot, confirm a new image after 20 s */
const char *ros_ota_sd_file(void);             /* the update file on the SD card, NULL if none */
esp_err_t ros_ota_check_file(const char *path, ros_ota_info_t *info, const char **why);
esp_err_t ros_ota_install_file(const char *path);   /* starts it; the device restarts when done */
void ros_ota_offer(const char *path);          /* LVGL: check it and ask on screen before installing */
void ros_ota_offer_async(const char *path);    /* same, from any task */
void ros_ota_ui_tick(void);                    /* LVGL: install dialog + progress overlay */
int ros_ota_progress(const char **msg);        /* 0..100, -1 = idle; msg: stage or last error */
const char *ros_ota_running(void);             /* "1.0.0  (slot ota_0, built ...)" */

#File operations

Blocking - call from a worker task. Work across volumes and on whole folders. Name clashes in the destination get "name (2).ext". A cancelled or failed copy leaves nothing behind.

typedef struct {
    volatile bool cancel;
    volatile uint64_t total_bytes, done_bytes;
    volatile int total_files, done_files;
    char current[64];       /* name being processed */
} ros_fsop_progress_t;
bool ros_fs_valid_name(const char *name);
esp_err_t ros_fs_unique(const char *dir, const char *name, char *out, size_t n);
esp_err_t ros_fs_copy(const char *src, const char *dst_dir, bool move, ros_fsop_progress_t *p,
                      char *dst_out, size_t dst_n);                 /* move: rename on the same volume;
                      ESP_ERR_NOT_FINISHED: moved across volumes, but the original is not all gone */
esp_err_t ros_fs_delete(const char *path, ros_fsop_progress_t *p);

#License (ros_license.c)

A free device shows "Reloader Co.,Ltd." on every screen until it is activated: one payment per device through Reloader's license server (server/license/), or a license.txt on the SD card.

typedef enum { ROS_LIC_IDLE, ROS_LIC_BUSY, ROS_LIC_QR, ROS_LIC_DONE, ROS_LIC_ERROR } ros_license_state_t;
bool ros_license_active(void);
bool ros_license_configured(void);           /* this firmware has the public key (CONFIG_ROS_LICENSE_PUBKEY) */
bool ros_license_online_possible(void);      /* it can be paid for on the device: a license server
                                              * (CONFIG_ROS_LICENSE_SERVER), or its own Ksher account */
bool ros_license_direct(void);               /* paying goes straight to Ksher (no license server) */
const char *ros_license_device_id(void);     /* "RLD-" + the factory MAC: what a license is made for */
const char *ros_license_info(void);          /* "Activated 2026-10-05" / "Free version ..." */
const char *ros_license_lock_info(void);     /* what an activation is locked to: "MAC ... + chip ID ..." */
void ros_license_watermark(void);            /* LVGL: shows / removes the watermark to match */

Online, on its own task: order + QR + waiting for the payment, or (restore) the license of a device that paid before / with Ksher direct: asking about the order made before. The state is read with ros_license_online() (LVGL timer).

ros_license_state_t ros_license_online(char *msg, size_t mn, char *qr, size_t qn, uint32_t *qr_gen, char *amount,
                                       size_t an, int *secs_left);

In ros.h for the firmware itself, not exported to apps: ros_license_init, ros_license_ksher_import_sd, ros_license_install, ros_license_refusal, ros_license_import_sd, ros_license_online_start, ros_license_online_stop, ros_license_dialog.

#System log

All ESP_LOG output is also kept in a 64 KB PSRAM ring (viewer: Files -> Log).

void ros_log_init(void);
uint32_t ros_log_head(void);                          /* total bytes logged since boot */
size_t ros_log_read(uint32_t *pos, char *out, size_t max); /* from *pos (clamped to oldest), advances it */

#Time

esp_err_t ros_time_sync_now(void);   /* (re)start SNTP with ntp_server now; ESP_ERR_INVALID_STATE: no network */
bool ros_time_valid(void);     /* true once SNTP has synced */
void ros_time_sync_start(void); /* start SNTP once any interface is online */

#Ethernet

typedef enum {
    ROS_ETH_UNAVAILABLE,    /* driver/PHY failed to start */
    ROS_ETH_NO_LINK,        /* cable unplugged */
    ROS_ETH_LINK_UP,        /* link up, waiting for DHCP */
    ROS_ETH_CONNECTED,      /* has an IP address */
} ros_eth_state_t;
typedef struct {
    ros_eth_state_t state;
    int speed_mbps;
    bool full_duplex;
    uint8_t mac[6];
    char ip[16], gateway[16], netmask[16], dns[16];
} ros_eth_info_t;
esp_err_t ros_eth_start(void);
ros_eth_state_t ros_eth_state(void);
void ros_eth_info(ros_eth_info_t *out);

Apply ros_settings()->eth now (no reboot): static address, or back to DHCP. ESP_ERR_INVALID_ARG if the addresses don't parse.

esp_err_t ros_eth_apply_ip(void);

#Camera

Called on the camera task with each preview frame: w*h pixels in cf (RGB888 = the display's own format, drawn by LVGL without per-pixel conversion; RGB565 from sources that can't give RGB888)

typedef void (*ros_camera_frame_cb_t)(const void *pixels, int w, int h, lv_color_format_t cf, void *user);
esp_err_t ros_camera_start(int preview_w, int preview_h, ros_camera_frame_cb_t cb, void *user);
void ros_camera_stop(void);
bool ros_camera_running(void);
void ros_camera_snapshot(void);     /* next full-res frame is saved to SD as BMP */
void ros_camera_set_mirror(bool on);
float ros_camera_fps(void);

Overlay: frames go by PPA straight into the display frame buffers at this screen box (no CPU, no LVGL) - only while nothing is drawn on top of it. LVGL context.

void ros_camera_set_overlay(bool on, int x, int y, int w, int h, int radius, uint32_t outside_color);
bool ros_camera_overlay_active(void);
void ros_camera_preview_size(int *w, int *h);   /* the scaled picture, once started */

#USB host

High-speed USB-C port (always powered). One USB Host Library, four class drivers: MSC (FAT at ROS_USB_MOUNT), HID (keyboard -> LVGL keypad + default group, mouse -> pointer with cursor), VCP (CH34x / CP210x / FTDI / CDC-ACM), UVC (MJPEG webcams).

#define ROS_USB_MOUNT "/usb"
typedef enum {
    ROS_USB_MSC, ROS_USB_KEYBOARD, ROS_USB_MOUSE, ROS_USB_HID, ROS_USB_SERIAL, ROS_USB_CAMERA,
    ROS_USB_SMARTCARD, ROS_USB_PRINTER,
} ros_usb_kind_t;
typedef struct {
    ros_usb_kind_t kind;
    uint8_t addr;
    uint16_t vid, pid;
    char name[48];
} ros_usb_dev_t;
esp_err_t ros_usb_start(void);
int ros_usb_devices(ros_usb_dev_t *out, int max);
void ros_usb_list_add(ros_usb_kind_t kind, uint8_t addr, uint16_t vid, uint16_t pid, const char *name);  /* class drivers */
void ros_usb_list_remove(ros_usb_kind_t kind, uint8_t addr);

USB smart-card reader (CCID, what PC/SC uses) - ros_ccid.c. Blocking calls: worker tasks only.

typedef enum { ROS_SC_NO_READER, ROS_SC_NO_CARD, ROS_SC_CARD_PRESENT, ROS_SC_CARD_ACTIVE } ros_sc_state_t;
void ros_ccid_start(void);
ros_sc_state_t ros_sc_state(void);
uint32_t ros_sc_generation(void);          /* changes on reader / card events */
const char *ros_sc_reader_name(void);
const char *ros_sc_info(void);             /* exchange level + card protocol */
esp_err_t ros_sc_power_on(uint8_t *atr, size_t *atr_len);
esp_err_t ros_sc_power_off(void);
esp_err_t ros_sc_transmit(const uint8_t *apdu, size_t len, uint8_t *resp, size_t *resp_len);  /* resp ends with SW1 SW2 */

USB printer (printer class 0x07) - ros_printer.c. One job at a time, printed by its own task.

typedef enum { ROS_PRN_AUTO, ROS_PRN_ESCPOS, ROS_PRN_PCL, ROS_PRN_PS, ROS_PRN_ZPL, ROS_PRN_TSPL, ROS_PRN_TEXT,
               ROS_PRN_LANG_COUNT } ros_prn_lang_t;
extern const char *const ros_prn_lang_names;   /* dropdown options, in ros_prn_lang_t order */
typedef struct {
    bool active;
    uint32_t id;                   /* changes with every job */
    char name[64];
    uint32_t sent, total;          /* bytes; total 0 = not known yet */
    const char *stage;             /* "Sending", "Waiting for the printer", ... */
    esp_err_t result;              /* of the last finished job */
    const char *error;             /* short reason when result != ESP_OK */
} ros_prn_job_t;
void ros_printer_start(void);
bool ros_printer_present(void);
uint32_t ros_printer_generation(void);         /* printer attach / detach / status / job changes */
const char *ros_printer_name(void);
const char *ros_printer_device_id(void);       /* IEEE 1284 ID string, "" if none */
ros_prn_lang_t ros_printer_lang(void);         /* in use: the setting, or detected when AUTO */
int ros_printer_dots(void);                    /* receipt / label printers: dots per line in use */
const char *ros_printer_status_text(void);     /* "Ready", "Out of paper", "Offline", "Error", "" */
bool ros_printer_can_print(const char *path);  /* file type this printer can take */
esp_err_t ros_printer_print_file(const char *path);
esp_err_t ros_printer_print_text(const char *text);
esp_err_t ros_printer_test_page(void);
void ros_printer_cancel(void);
void ros_printer_job(ros_prn_job_t *out);

Smart card on plain GPIOs (ros_scgpio.c): ISO 7816 T=0, no reader chip, 3.3 V cards only. The pins are the board's: ROS_SCG_PIN_* in ros_board.h.

#define ROS_SCG_VCC_ACTIVE_LOW  0      /* 1 for a P-MOSFET high-side switch (gate low = on) */
#define ROS_SCG_UART            2      /* UART_NUM_2 */
#define ROS_SCG_LEDC_TIMER      2      /* backlight uses timer 1 / channel 1 */
#define ROS_SCG_LEDC_CHANNEL    2
bool ros_scg_present(void);                /* card-detect switch closed */
esp_err_t ros_scg_power_on(uint8_t *atr, size_t *atr_len);
void ros_scg_power_off(void);
esp_err_t ros_scg_transmit(const uint8_t *apdu, size_t len, uint8_t *resp, size_t *resp_len);

Thai national ID card (ros_thid.c) - over the USB reader or the direct GPIO socket

typedef struct {
    char cid[24];                          /* 1-2345-67890-12-3 */
    char name_th[200], name_en[200];
    char birth_th[48], birth_en[48];
    char gender_th[16], gender_en[16];
    char address[400];
    char issuer[200];
    char card_no[24];
    char issue_th[48], expiry_th[48];
    uint8_t *photo;                        /* JPEG, PSRAM (free()), NULL if not read */
    size_t photo_len;
    int fields_ok, fields_total;
    const char *reader;                    /* "USB: <name>" / "Direct GPIO" */
} ros_thid_t;
typedef enum { ROS_THID_NONE, ROS_THID_USB, ROS_THID_GPIO } ros_thid_port_t;
ros_thid_port_t ros_thid_card_port(void);  /* where a card is inserted now (USB first) */

Reads every field; progress(stage, user) is called between fields (from this task). Worker task only - a full read with the photo takes a few seconds.

esp_err_t ros_thid_read(ros_thid_port_t port, ros_thid_t *out, void (*progress)(const char *stage, void *user),
                        void *user);
void ros_thid_free(ros_thid_t *t);         /* photo buffer; wipes the fields */

Identification only: 13 digits + Thai name, under a second. Worker task.

esp_err_t ros_thid_read_id(ros_thid_port_t port, char cid[14], char *name_th, size_t name_n);
bool ros_thid_number_valid(const char *digits13);   /* check digit of a citizen number */
uint32_t ros_usb_generation(void);             /* changes whenever a device comes or goes */
const char *ros_usb_kind_name(ros_usb_kind_t k);
void ros_usb_ui_tick(void);                    /* LVGL context: mouse cursor visibility */
bool ros_usb_msc_mounted(void);
uint64_t ros_usb_msc_total_bytes(void);
uint64_t ros_usb_msc_free_bytes(void);
bool ros_usb_vcp_ready(void);
const char *ros_usb_vcp_name(void);
esp_err_t ros_usb_vcp_set_baud(uint32_t baud);
uint32_t ros_usb_vcp_baud(void);
esp_err_t ros_usb_vcp_write(const void *data, size_t len);
size_t ros_usb_vcp_read(void *buf, size_t max);  /* non-blocking */

Keyboard-style scanners (QR / barcode): characters are collected until Enter

const char *ros_usb_last_scan(void);
uint32_t ros_usb_scan_count(void);
int ros_usb_active_port(void);                 /* 0 = USB Native, 1 = USB_OTG */
bool ros_usb_uvc_present(void);
esp_err_t ros_usb_uvc_start(int w, int h, ros_camera_frame_cb_t cb, void *user);
void ros_usb_uvc_stop(void);
float ros_usb_uvc_fps(void);

In ros.h for the firmware itself, not exported to apps: ros_printer_detected_lang, ros_scg_active, ros_scg_info.

#Everything else an app can call

Besides ros.h, the firmware exports 340 names of LVGL 9.2.2, the C library, FreeRTOS and ESP-IDF - the ones the firmware itself uses. An app that calls a name not in reloados/api.txt is refused by build.sh, and by the device. Need one that is missing? Ask Reloader: the next firmware can export it.

LVGL (262)

lv_anim_init lv_anim_set_completed_cb lv_anim_set_delay lv_anim_set_duration lv_anim_set_exec_cb lv_anim_set_values lv_anim_set_var lv_anim_start lv_area_get_height lv_area_get_width lv_async_call lv_bar_create lv_bar_set_range lv_bar_set_value lv_button_create lv_buttonmatrix_clear_button_ctrl lv_buttonmatrix_create lv_buttonmatrix_get_button_text lv_buttonmatrix_get_selected_button lv_buttonmatrix_set_button_ctrl lv_buttonmatrix_set_button_ctrl_all lv_buttonmatrix_set_map lv_chart_add_series lv_chart_create lv_chart_set_all_value lv_chart_set_div_line_count lv_chart_set_next_value lv_chart_set_point_count lv_chart_set_range lv_chart_set_type lv_chart_set_update_mode lv_checkbox_create lv_checkbox_set_text lv_color_black lv_color_darken lv_color_format_get_size lv_color_hex lv_color_make lv_color_mix lv_color_to_u32 lv_color_white lv_display_add_event_cb lv_display_get_buf_active lv_display_get_default lv_display_get_inactive_time lv_display_get_rotation lv_display_remove_event_cb_with_user_data lv_display_set_theme lv_display_trigger_activity lv_draw_buf_destroy lv_draw_buf_width_to_stride lv_draw_rect lv_draw_rect_dsc_init lv_dropdown_add_option lv_dropdown_clear_options lv_dropdown_create lv_dropdown_get_selected lv_dropdown_set_options lv_dropdown_set_selected lv_event_get_code lv_event_get_current_target lv_event_get_layer lv_event_get_target lv_event_get_user_data lv_free_core lv_group_create lv_group_remove_obj lv_group_set_default lv_image_cache_drop lv_image_create lv_image_set_inner_align lv_image_set_scale lv_image_set_src lv_indev_active lv_indev_add_event_cb lv_indev_create lv_indev_get_next lv_indev_get_point lv_indev_get_type lv_indev_set_cursor lv_indev_set_display lv_indev_set_group lv_indev_set_read_cb lv_indev_set_type lv_keyboard_create lv_keyboard_get_textarea lv_keyboard_set_map lv_keyboard_set_mode lv_keyboard_set_popovers lv_keyboard_set_textarea lv_label_create lv_label_get_text lv_label_set_long_mode lv_label_set_text lv_label_set_text_fmt lv_label_set_text_static lv_layer_sys lv_layer_top lv_list_add_button lv_list_create lv_list_get_button_text lv_malloc_core lv_mem_deinit lv_mem_init lv_msgbox_add_close_button lv_msgbox_add_footer_button lv_msgbox_add_text lv_msgbox_add_title lv_msgbox_close lv_msgbox_create lv_obj_add_event_cb lv_obj_add_flag lv_obj_add_state lv_obj_align lv_obj_center lv_obj_clean lv_obj_create lv_obj_delete lv_obj_delete_async lv_obj_fade_in lv_obj_get_child lv_obj_get_child_count lv_obj_get_content_coords lv_obj_get_content_height lv_obj_get_content_width lv_obj_get_coords lv_obj_get_height lv_obj_get_index lv_obj_get_parent lv_obj_get_screen lv_obj_get_scroll_bottom lv_obj_get_scroll_y lv_obj_get_user_data lv_obj_get_width lv_obj_has_flag lv_obj_has_state lv_obj_invalidate lv_obj_invalidate_area lv_obj_is_visible lv_obj_move_to_index lv_obj_remove_event_cb_with_user_data lv_obj_remove_flag lv_obj_remove_state lv_obj_remove_style_all lv_obj_scroll_by_bounded lv_obj_scroll_to lv_obj_scroll_to_view lv_obj_scroll_to_view_recursive lv_obj_scroll_to_y lv_obj_set_ext_click_area lv_obj_set_flex_align lv_obj_set_flex_flow lv_obj_set_flex_grow lv_obj_set_height lv_obj_set_pos lv_obj_set_scroll_dir lv_obj_set_size lv_obj_set_state lv_obj_set_style_arc_color lv_obj_set_style_arc_width lv_obj_set_style_bg_color lv_obj_set_style_bg_grad_color lv_obj_set_style_bg_grad_dir lv_obj_set_style_bg_opa lv_obj_set_style_border_color lv_obj_set_style_border_opa lv_obj_set_style_border_side lv_obj_set_style_border_width lv_obj_set_style_clip_corner lv_obj_set_style_color_filter_opa lv_obj_set_style_image_opa lv_obj_set_style_image_recolor lv_obj_set_style_image_recolor_opa lv_obj_set_style_line_color lv_obj_set_style_line_width lv_obj_set_style_margin_bottom lv_obj_set_style_margin_left lv_obj_set_style_margin_right lv_obj_set_style_margin_top lv_obj_set_style_max_height lv_obj_set_style_min_height lv_obj_set_style_min_width lv_obj_set_style_opa lv_obj_set_style_pad_bottom lv_obj_set_style_pad_column lv_obj_set_style_pad_left lv_obj_set_style_pad_right lv_obj_set_style_pad_row lv_obj_set_style_pad_top lv_obj_set_style_radius lv_obj_set_style_shadow_color lv_obj_set_style_shadow_offset_y lv_obj_set_style_shadow_opa lv_obj_set_style_shadow_width lv_obj_set_style_text_align lv_obj_set_style_text_color lv_obj_set_style_text_font lv_obj_set_style_text_letter_space lv_obj_set_style_text_line_space lv_obj_set_style_text_opa lv_obj_set_style_transform_pivot_x lv_obj_set_style_transform_pivot_y lv_obj_set_user_data lv_obj_set_width lv_obj_update_flag lv_obj_update_layout lv_pct lv_qrcode_create lv_qrcode_set_dark_color lv_qrcode_set_light_color lv_qrcode_set_size lv_qrcode_update lv_realloc_core lv_roller_create lv_roller_get_selected lv_roller_set_options lv_roller_set_selected lv_roller_set_visible_row_count lv_screen_active lv_screen_load_anim lv_slider_create lv_slider_get_value lv_slider_set_range lv_slider_set_value lv_spinner_create lv_switch_create lv_table_create lv_table_set_cell_value lv_table_set_cell_value_fmt lv_table_set_column_count lv_table_set_column_width lv_table_set_row_count lv_tabview_add_tab lv_tabview_create lv_tabview_get_tab_active lv_tabview_get_tab_bar lv_tabview_set_tab_bar_size lv_text_get_width lv_textarea_add_text lv_textarea_create lv_textarea_delete_char lv_textarea_get_label lv_textarea_get_text lv_textarea_set_accepted_chars lv_textarea_set_cursor_click_pos lv_textarea_set_cursor_pos lv_textarea_set_max_length lv_textarea_set_one_line lv_textarea_set_password_mode lv_textarea_set_placeholder_text lv_textarea_set_text lv_theme_default_init lv_tick_elaps lv_tick_get lv_timer_create lv_timer_delete lv_timer_get_user_data lv_timer_pause lv_timer_reset lv_timer_resume lv_timer_set_period lv_timer_set_repeat_count

Fonts (13)

lv_font_get_line_height lv_font_montserrat_12 lv_font_montserrat_14 lv_font_montserrat_16 lv_font_montserrat_20 lv_font_montserrat_24 lv_font_montserrat_28 lv_font_montserrat_32 lv_font_montserrat_40 lv_font_montserrat_48 rld_font_thai_30 rld_font_thai_bold_40 rld_font_thai_bold_56

FreeRTOS (15)

vQueueDelete vStreamBufferDelete vTaskDelay xQueueCreateMutex xQueueGenericCreate xQueueGenericReset xQueueGenericSend xQueueReceive xQueueSemaphoreTake xStreamBufferGenericCreateStatic xStreamBufferReceive xStreamBufferReset xStreamBufferSend xTaskCreatePinnedToCore xTaskCreatePinnedToCoreWithCaps

ESP-IDF (18)

esp_log esp_log_timestamp esp_timer_get_time gpio_pullup_en heap_caps_malloc nvs_close nvs_commit nvs_get_i32 nvs_get_str nvs_open nvs_set_i32 nvs_set_str uart_driver_delete uart_driver_install uart_param_config uart_read_bytes uart_set_baudrate uart_set_pin

C library (29)

atoi fclose fgets fopen fprintf free fwrite localtime_r lodepng_decode32 malloc memchr memcpy memmove memset mkdir remove rename ros_scr_w snprintf stat strchr strcmp strftime strlcpy strlen strncmp strspn strstr time

Embedded files (2)

_binary_lan_png_end _binary_lan_png_start

Compiler runtime (1)

__divdi3