Read RobustOS Device Status, Hardware, and Service I/O

Read device status and access hardware from a RobustOS application

Use this guide when your application needs device status, a serial interface, digital or analog I/O, Bluetooth Low Energy (BLE), or notification services. Select the interface for the exact device before writing code that reads or changes it.

Applies to: RobustOS Devices with the hardware option and SDK target required by the task. The path examples are specific to the named hardware interfaces. Check the SDK overview for the supported model and target selection. The BLE procedure is limited to the R2110 module described here; the analog-input example is for R1520. Confirm firmware, hardware variant, and available interfaces on the development device.

Choose the interface before implementing the feature

Keep three kinds of information separate:

Information you need Where to obtain it
A configured value or a device/application status field The UCI configuration API or USI status API
Bytes from a serial port, an analog measurement, or a digital output control The matching device node or sysfs path on your exact hardware variant
A notification that an input, connection, or system state changed The event API in SDK API reference

A device node describes a software interface. It does not establish the connector pinout, electrical limits, availability of an optional module, or the encoding of values returned by that interface. Obtain those details for your device before connecting test equipment.

Before testing, record the device model and variant, firmware version, selected build target, interface path, and the expected observation. Run the hardware commands in this guide in an authorized device shell, not on the host or in the SDK container.

Read system status

Use status system in the RobustOS CLI (command-line interface) to inspect system values. From a C application, read the corresponding USI tags:

char *model = usi_get("system.device_model");
char *version = usi_get("system.firmware_version");

if (model != NULL) {
    printf("Model: %s\n", model);
    free(model);
}
if (version != NULL) {
    printf("Firmware: %s\n", version);
    free(version);
}

usi_get() returns an allocated string that your application must free. Check for NULL before using it. The sample_uci and sample_gps packages provide starting points for status and GPS-related access when included in your SDK. See the USI status API reference for the complete call contracts.

Check a value against the corresponding device Web interface or a controlled state change. An empty or missing value is a reason to check the tag, firmware, and service state; it is not evidence of a particular hardware reading.

Read and write serial data

RobustOS serial applications use the Linux serial programming model. Start from the SDK's sample_serial package and replace its port selection with the interface confirmed for your device. Match the baud rate, framing, and physical interface to the peer device; these settings are not interchangeable between RS232 and RS485.

The following examples distinguish port names that can otherwise look identical:

Device or variant Serial paths and their role
R3000 Lite /dev/ttyCOM1 is the first serial port; /dev/ttyCOM2 is the second. Confirm their physical modes for the variant.
R3000, including the variant with four digital inputs /dev/ttyCOM1 and /dev/ttyCOM2 are the first and second serial ports; /dev/ttyGPS is the GPS data port.
R3000-Quad /dev/ttyCOM1 is RS232; /dev/ttyCOM2 is RS485.
R2110 and R5020 /dev/ttyCOM1 is RS232; /dev/ttyCOM2 is RS485; /dev/ttyGPS is the GPS data port when that hardware feature is present.
M1200 /dev/ttyCOM1 is RS232; /dev/ttyCOM2 is RS485.
R1511 /dev/ttyCOM1 is the RS232/RS485 serial interface. Confirm the device's physical-mode configuration.
R1520 /dev/ttyCOM1 is RS232; /dev/ttyCOM2 is RS485; /dev/ttyGPS is optional.
R2010 and R2120 /dev/ttyCOM1 is RS485.
R5020-Lite /dev/ttyCOM1 is RS232/RS485 with software selection.

Open the correct interface, apply the peer's settings, and test transmission and reception with a known payload. Preserve the received bytes and the port configuration in your test record. If the port opens but no data arrives, compare the physical mode and serial settings before changing the application protocol.

For development devices that expose removable storage, /mnt/usb is the USB-disk mount point in the R3000 Lite, R3000, R2110/R5020, and R1520 examples. /mnt/sd is the SD-card mount point in the R3000 and R2110/R5020 examples. A path in this list does not mean that media is inserted, mounted, or writable.

Respond to digital-input changes

Digital input (DI) notifications are events. The sample_dido pattern subscribes to di1_on and di1_off, receives the message, checks that its cmd field is report, and then uses the event field to distinguish the transition.

  1. Confirm that the target exposes the required DI channel. For example, R3000 has /dev/DI1 and /dev/DI2; its four-DI variant adds /dev/DI3 and /dev/DI4. R2120 has /dev/DI1 and /dev/DI2. R2110, R5020, R1510, R1520, and R5030 examples use /dev/DI1.
  2. In the application, check the DIDO capability before starting the listener. The sample uses uci_check_bool("devcfg.dido_support").
  3. Initialize message reception with rmsg_init() and register its descriptor with the event loop.
  4. Subscribe to the required channel's events, then keep the event loop running.
  5. Change the input under controlled test conditions and confirm the corresponding event reaches the callback.

This is the subscription portion of the sample_dido pattern, not a complete application:

sd = rmsg_init("sample_dido");
event_init();

event_set(&event, sd, EV_READ | EV_PERSIST, di_event_msg_proc, NULL);
event_add(&event, NULL);

event_subscribe("di1_on");
event_subscribe("di1_off");
event_dispatch();

The surrounding application must provide sd, the event object, the callback, capability checks, and error handling. Use a suitable application-specific socket name without a path; the example uses sample_dido. Stop initialization if rmsg_init() returns -1, before registering the descriptor or subscribing. In the callback, check the result of rmsg_recv() before parsing. Check pointers returned by rmsg_get() and release the allocated values when finished. See the IPC and event reference for the documented ownership boundaries.

The sample also daemonizes and checks /var/run/sample_dido.pid with daemon_check_running() to avoid a second instance. These choices belong to that application's lifecycle; coordinate them with your selected lifecycle integration.

A transition event is not a documented initial-state snapshot. If your application must know the level immediately after startup, confirm the supported initial-state read method for that firmware. Do not assume that subscribing immediately produces the current input state.

Change a digital output

Digital output (DO) control uses the Linux LED subsystem.

Warning: These writes change a physical output. Establish a safe test state for the connected equipment before running either command. Confirm the electrical meaning of 0 and 1 for the device and connected circuit; do not infer contact or actuator behavior from the word brightness.

For a device that provides DO1 at this path, choose the one value needed for your test. To write 0 in the device shell:

echo 0 > /sys/class/leds/do1/brightness

Alternatively, to write 1:

echo 1 > /sys/class/leds/do1/brightness

DO1 is listed for the R3000, R2110/R5020, M1200, R1510, R1520, R2120, and R5030 interface examples. R3000 and R2120 also list DO2 at /sys/class/leds/do2/. The four-DI R3000 variant has a separate resource definition; do not copy the two-DI variant's DO assumptions into it.

Confirm the physical result independently of command completion. If the path is absent, verify the exact variant before trying a different output path.

Read an analog input or subscribe to thresholds

For the R1520 analog input (AI), choose between a measurement and a threshold notification:

Requirement Interface
Obtain the measured value Read /dev/AI1 using the sample_ai example and convert the numeric reading to volts or milliamps.
React when voltage or current crosses a configured threshold Subscribe to the corresponding AI event using the same receive loop as the DI example.

The AI event names are:

  • ai1_voltage_low and ai1_voltage_high: voltage reaches the lower or upper threshold.
  • ai1_current_low and ai1_current_high: current reaches the lower or upper threshold.
  • ai1_recovery: voltage or current returns to normal.

Configure the AI mode and thresholds on the device, and test threshold events with a controlled input. For R1520, SDK 5.0.3 sample_ai reads numeric text from /dev/AI1 and converts the raw value: voltage (V) = raw * 2.985 * 13 / 4095; current (mA) = raw * 2.985 * 13 * 1000 / (4095 * 1200). The sample uses sample_ai.type to select voltage or current and sample_ai.interval for the sampling interval in seconds.

Send an SMS message

The device provides the sms command for sending a message. In a device shell, replace the recipient placeholder and use a test message:

sms <RECIPIENT_PHONE_NUMBER> "hello world"

An application can invoke the same command. The following C fragment shows a fixed-message call after replacing the example number:

system("sms 123456789 \"hello world\"");

This fragment is not a complete application and the example number is not a test destination. Confirm that SMS service is available on the device's cellular configuration. Record both the application/command result and whether the intended recipient receives the message. Do not construct shell command text directly from untrusted recipient or message input.

For event-driven handling, the event catalogue includes sms_received, sms_sent, and sms_cmd_executed. They describe different events; a command execution notification is not the same event as a received or sent message.

Send email through the device service

Email requests go to the emaild daemon through the SDK's inter-process communication (IPC) interface. First enable and configure email in Service > Email on the device Web interface. The application uses that service configuration rather than supplying mail-server settings in each request.

  1. Confirm that the email feature is configured for the development device.
  2. Initialize your application's IPC socket with rmsg_init() and check for failure.
  3. Send a request to emaild with the cmd, addresses, and content fields.
  4. Check the IPC send result, then confirm the intended message arrives at the test mailbox.
  5. Close IPC with rmsg_close() when the application no longer needs it.

The message payload below is an excerpt to use after successful IPC initialization. Replace the reserved example address with your test recipient:

char email_addresses[] = "recipient@example.com";
char buf[] = "from application";

rmsg_send("emaild", "cmd", "send",
          "addresses", email_addresses,
          "content", buf);

A successful IPC send means the request was sent through IPC; it is not, by itself, proof of email delivery. The exact variadic declaration and error-handling requirements must match the SDK headers used to build your application. See IPC API.

Scan and connect with the R2110 BLE module

This procedure applies to the R2110 BLE 5.0 module with scanning and connection modes. The CPU communicates with the module through /dev/ttyXRUSB1. The SDK's sample_ble package provides higher-level examples; the commands below are the module's low-level serial protocol.

Important: Send these commands to the opened serial port, not to the Linux shell. Confirm serial settings and command termination from the matching module/SDK example. The address token format and GATT identifiers are module-specific; do not replace them with assumptions from another BLE API.

Scan for advertisements

  1. Open /dev/ttyXRUSB1 with the serial settings required by the module.

  2. Send cmd to enter serial-command mode.

  3. Start a scan with a timeout in milliseconds and a whitelist value of 0:

    scan start 5000 0
    
  4. Read advertising records until the timeout. Each record has this structure:

    ADV:<mac_addr> <data> <num_of_data_discarded> <RSSI>
    
  5. To end the scan before the timeout, send:

    scan stop
    

For example, an advertising record can look like:

ADV:01E9FAEC7DCA51 020106070941455F424C4511079ECADC240EE5A9E093F3A3B50100406E 0 -51

Keep the returned address token intact. This protocol's example uses a 14-hex-character token. Confirm its exact interpretation with the matching module interface before constructing or converting addresses yourself.

Connect, inspect attributes, and read data

  1. Open /dev/ttyXRUSB1 and enter command mode with cmd, unless that session is already established.

  2. Send the connection request using the observed peer token:

    connect <mac_addr> <timeout_ms> <minConnInt_us> <maxConnInt_us> <linkSup_us>
    

    timeout_ms is the connection-attempt timeout in milliseconds. The minimum and maximum connection interval arguments are in microseconds, with a stated range of 7500 to 4000000 for each. linkSup_us is the supervision timeout in microseconds. Confirm the permitted combination for the peer and module.

    Example values:

    connect 01C1F755B9A7C2 5000 7500 20000 5000000
    
  3. Read the connection result and retain the returned session handle. A result may include handle=1; later commands must use your actual handle.

  4. Open GATT access, then request the table mapping:

    gattc open 0 0
    gattc tablemap <handle>
    
  5. Identify the required attribute from the returned mapping. For the example session, the mapping includes:

    S:1,(9),FE011800
     C:3,00000002,FE012A00,0
    
  6. Read with the returned handle, the appropriate ID from that mapping, and the data offset:

    gattc read <handle> <service_ID> <data_offset>
    

    The example gattc read 1 3 0 returns data such as 4C4149524420424C363534, representing LAIRD BL654. The example's 3 comes from its mapping; do not hard-code it for a different peer. Confirm the module's use of the term service_ID against its GATT table.

  7. Disconnect the session when finished:

    disconnect <handle>
    

Record the scan response, connection result, mapping, read result, and disconnect result separately. A successful scan does not establish that connection or attribute access succeeded.

Check the complete device interaction

Observation Next check
Interface path does not exist Exact model, hardware option, firmware, and resource mapping
Serial port opens but no expected data arrives Physical interface mode, serial settings, and peer protocol
No DI or AI event arrives Channel support, event name, message/event-loop initialization, and whether the controlled input actually crossed the expected state or threshold
DO write completes but the equipment does not behave as expected Device electrical behavior and wiring; stop testing until the output meaning is established
Email IPC call succeeds but no email arrives Service > Email configuration and the delivery observation; keep the IPC result separate
BLE scan succeeds but reading an attribute fails Connection handle, actual mapping, ID/offset, and module protocol

Keep hardware observations separate from build results. Compiling and exporting an RPK proves a build step; the serial exchange, physical I/O change, received notification, or BLE response proves the corresponding device interaction.