Publish and Read Application Status with RobustOS USI

Display application status with the RobustOS USI API

Use the RobustOS USI API to publish live application values and read current device status. A status definition adds the presentation; your program supplies the current values.

Applies to: C applications built with a matching RobustOS SDK and deployed to the exact device model and firmware for that SDK target. Use the USI integration, librouter headers and libraries supplied with the selected SDK.

UCI describes chosen settings; USI describes runtime state. Publishing status does not change a service's configuration. Use the UCI API for settings, and use USI for values such as a running counter or observed device information. Keep credentials, keys and other sensitive data out of user-visible status.

Define a status tab

Start with the SDK's sample_uci package and preserve an original copy. Install a separate USI XML definition at /etc/router/usi/<package>.xml, following the package's installation rules. The following definition places a counter on a Status tab under Services > SDK Sample Uci:

<sample_uci cli_help="status of SDK Sample Uci"
            group="Services" group_weight="40"
            menu="SDK Sample Uci" menu_weight="901">
    <counter desc="Running Counter" tab="Status" tab_weight="20"
             area="SDK Example Status" />
</sample_uci>

The corresponding tag is sample_uci.counter. Keep its root and menu names aligned with the application's configuration page. The Web interface integration guide explains navigation and layout attributes.

Adding the XML does not run a counter. Build and install the package, then publish the value from the application using usi_update() or usi_printf() as shown below. The C examples are excerpts, so retain the headers and linking used by the matching SDK sample.

Discover available status tags

On the device command-line interface (CLI), inspect status with:

status sample_uci
status system
status lan
status cellular

Use Tab completion after status to explore available items. Examples of tags include system.device_model, lan.mac, lan.interface_status[1].rx_bytes and cellular.status[1].imei; confirm their availability against your device's output. List IDs start at 1 and an absent entry can occur before a higher populated ID.

Device identifiers and cellular account information can appear in these responses. Redact them before sharing a troubleshooting transcript.

Handle return values and memory

Use the types and constants provided by the selected SDK headers. status_t operations below return OK (0) or ERROR (-1). Predicates return TRUE (1) or FALSE (0) for the stated test; do not assume a separate error result.

usi_get() and usi_list_get() return allocated strings. Check each result for NULL, use it, and then call free() on every non-NULL allocation, including error and early-exit paths in your own code. This differs from the borrowed pointer returned by uci_get().

Read scalar status

char *usi_get(const char *tag);
bool_t usi_match(const char *tag, const char *value);

usi_get() reads the status item at tag and returns an allocated string, or NULL on error. usi_match() compares that item's value with the string value, returning TRUE for a match or FALSE otherwise.

For example, this device-side reading fragment obtains the model status and releases the string:

char *model = usi_get("system.device_model");
if (model != NULL) {
    printf("Device Model = %s\n", model);
    free(model);
}

Update and clear status

status_t usi_update(const char *tag, const char *status);
status_t usi_printf(const char *tag, const char *fmt, ...);
status_t usi_clear(const char *tag);
Function Action and result
usi_update Write the string status to tag; create the status item if the tag is not defined. Returns OK or ERROR.
usi_printf Update tag using a printf-style fmt and its arguments. Returns OK or ERROR.
usi_clear Clear a status file, all items in a list, or one item, depending on the supplied tag. Returns OK or ERROR. Confirm the scope of the exact tag before clearing.

For the same counter value, the following calls are alternatives:

usi_update("sample_uci.counter", "10");
/* Or, for an integer already held by the application: */
int counter = 10;
usi_printf("sample_uci.counter", "%d", counter);

Check the returned status in your application. Creating a status item does not by itself define a visible Web interface page; add the appropriate status definition and page integration separately.

Work with status lists

status_t usi_list_set(const char *list_tag, uint32_t id,
                      const char *member_name, const char *value);
status_t usi_list_printf(const char *list_tag, uint32_t id,
                         const char *member_name, const char *fmt, ...);
char *usi_list_get(const char *list_tag, uint32_t id,
                   const char *member_name);
status_t usi_list_delete(const char *list_tag, uint32_t id);
bool_t usi_list_match(const char *list_tag, uint32_t id,
                     const char *member_name, const char *value);
int32_t usi_list_get_max_entry_num(const char *tag);
bool_t usi_list_entry_empty(const char *tag, uint32_t id);

list_tag names the status list, id selects its one-based entry and member_name selects a field in it. These use the same tag notation as configuration; their values are status data.

Function Action or result
usi_list_set Set a member to string value; return OK or ERROR.
usi_list_printf Set a member using printf-style fmt and its arguments; return OK or ERROR.
usi_list_get Return the member's allocated string or NULL on error. The caller frees a successful result.
usi_list_delete Delete entry id; return OK or ERROR. Note the name ends in _delete, whereas the UCI equivalent is _del.
usi_list_match Compare the member with value; return TRUE for a match or FALSE otherwise.
usi_list_get_max_entry_num Return the list's maximum entry number, or 0 on error. Zero does not independently establish an empty list.
usi_list_entry_empty Return TRUE when entry id is empty, otherwise FALSE.

When iterating, use list IDs rather than an assumed count of occupied entries. Check for empty entries and NULL reads, and release each allocated value before moving to the next entry. Do not assume that the write functions provide an undocumented list-allocation or persistence policy.

Select the correct cellular status entry

usi_get("cellular.status[1].imei") addresses entry 1 directly. usi_list_get("cellular.status", entry_id, "imei") reads the same member using a variable entry ID. Inspect the actual status layout before choosing that ID.

The SDK example reads renv_get_int("cellular_current_sim"), but the relationship between that environment value, a physical SIM, a modem and the cellular.status list entry is device-specific. Confirm the mapping for the selected firmware before using it as a list index.

Verify the complete status workflow

  1. Install the package containing the USI XML and confirm that its Status tab appears.
  2. Publish a known counter value from the application and check the function's return value.
  3. Open the Status tab and run status sample_uci on the device CLI. Both should show the value most recently published by the application.
  4. Change the counter in the application and repeat the comparison. The displayed value is only as current as the last successful update.
  5. For lists, test a populated entry and an empty entry. Confirm that missing data is handled without reading a NULL pointer.
  6. For repeated reads, verify that every allocated result is freed.
Symptom Check first
Status tab is missing USI XML installation path, root/menu/tab names and package installation result
Counter is absent or stale Correct status tag, successful application update and whether the application is running
Read returns NULL Exact tag, valid list ID and whether the value has been published
Configuration API cannot find a status value Use usi_* for status; uci_* reads configuration
Memory use grows during repeated reads Cleanup for every usi_get() and usi_list_get() result

Return to the RobustOS SDK guide for the remaining development workflows.