Hardware-first focus: This project centers on robust UCI control of real hardware; the simulator only supports protocol validation and debugging.
An interactive shell to communicate with a UWB (Ultra-Wideband) device using the UCI (Ultra-wideband Communication Interface) protocol.
This project provides an interactive shell interface for testing and communicating with UWB devices using the UCI protocol. The UCI protocol is used in Ultra-Wideband communication systems, particularly in mobile and IoT devices for ranging and positioning applications.
To build the project, simply run:
makeOptional integration target:
make tcp-simulator-integration-testTo run the interactive shell:
./uci-shellOnce the shell is running, you can use the following commands:
help– Discover commands and their usage (now backed by the typed framework, so the output always mirrors the active command tables)analyze_packet [--verbose] [--tlv] [--compare] [--examples] [--help] <bytes...>– Run the enhanced packet analyzer on hex inputquit– Exit the shell
get_device_info,device_resetget_caps_info,get_device_stateset_config <config> <value>,get_config <config>set_device_active,set_device_ready,device_on,device_off,device_suspend
session_init <id> <type>,session_deinit <id>session_start <id>,session_stop <id>,get_session_state <id>set_app_config <id> <param> <value>,get_app_config <id> [param ...]session_update_multicast_list <id> <action> <short> <subsession>session_update_dt_tag_rounds <id> [round_index ... | hex_bytes]session_data_transfer_phase_config <id> <repetition> <control> <size> [payload...]session_query_data_size_in_ranging <id>session_set_hybrid_controller_config <id> [hex-config]session_set_hybrid_controlee_config <id> [hex-config]session_send_data <id> <dest> <seq> <payload>
simulate_ranging,simulate_multi_target_rangingsimulate_notification,simulate_session_status,simulate_data_creditdemo_session_flow
mode_hw <device_path>,hw_init <device_path>(aliashw_connect)mode_tcp <host> <port>(aliastcp_mode)mode_sim/mode_info– switch modes and display active transporthw_send <mt> <pbf> <gid> <oid> [payload...]– stream raw hex to the connected device- After connecting, reuse the standard device/session commands (e.g.
get_device_info,session_start 1) to operate on the active external transport.
- Get device information:
get_device_infoordevice_info - Reset device:
device_reset - Get capabilities:
get_caps_info - Get/set device state:
get_device_state,set_device_active,set_device_ready - Device power control:
device_on(alias for set_device_active),device_off(alias for set_device_ready)
- Initialize a session:
session_init 1 fira_ranging - Configure session parameters:
set_app_config 1 channel 5 - Update DT-Tag rounds:
session_update_dt_tag_rounds 1 0 1 2(orsession_update_dt_tag_rounds 1 000102for hex bytes) - Configure data transfer:
session_data_transfer_phase_config 1 1 0x02 4 AA BB CC DD - Start ranging:
session_start 1 - Get session status:
get_session_state 1 - Stop ranging:
session_stop 1 - Deinitialize session:
session_deinit 1
- Discover device configs (supports both modern and legacy syntax):
show_device_configs filter=state detail=fullshow_device_configs --filter state --fullshow_device_configs id=0x25
- Discover application configs for a particular session:
show_app_configs filter=channelshow_app_configs id=0x00 detail=summaryshow_app_configs --id 0x00 --filter device
- Set device configuration:
set_config device_state active - Get device configuration:
get_config device_state - Set application configuration:
set_app_config 1 device_type responder - Get one application configuration:
get_app_config 1 device_type - Get multiple application configurations:
get_app_config 1 device_type multi_node_mode - Get all returned application configurations:
get_app_config 1
- Connect to hardware:
mode_hw /dev/ttyUSB0(aliashw_init) - Connect to a TCP simulator:
mode_tcp 127.0.0.1 9000 - Inspect active transport:
mode_info - Send raw command:
hw_send 01 00 00 02(MT=1, PBF=0, GID=0, OID=2 for CORE_DEVICE_INFO) - Once connected, issue any standard command (
get_device_info,session_start 1, etc.) to act on the active external endpoint. - Build the sibling simulator and run an end-to-end shell check:
cd ../uci_device_simulator && make uci-device-sim && cd ../uci_interactive_shell && make tcp-simulator-integration-test
- Simulate ranging notification:
simulate_ranging - Simulate multi-target ranging:
simulate_multi_target_ranging - Run session demo:
demo_session_flow - Simulate other notifications:
simulate_notification,simulate_session_status,simulate_data_credit
The UCI protocol is a communication interface used for Ultra-Wideband (UWB) devices, particularly defined by the FiRa Consortium and is also used in some Android devices for UWB applications. This shell simulates communication with a UWB controller.
The shell is in consolidation mode. The active architecture is the declarative
command framework in src/uci_cmd_framework_* and src/uci_command_framework.c.
Help text, completion, validation, and dispatch now read from those shared
command tables. External transport selection now has three explicit modes:
simulation, hardware chardev, and TCP simulator.
- Standard UCI message, group, status, and opcode definitions are pinned to the
Android UWB code definitions in
include/uci_pdl.h, with Qorvo vendor-group values cross-checked against the Cherry C headers inuci_analysis/uwb/Samples/Cherry/uci/uci_core/include/uci. - Qorvo vendor groups and opcodes are pinned to QM SDK values in
include/uci_opcode_constants.h. GID 0x0Enow follows the Cherry C-header basis asQORVO_MAC; the Python Qorvo tools still exposeConfigManagerat0x0E, but this repository does not treat that alias as the authoritative protocol-group definition.- Shared enum decoding helpers in
include/uci_packet_utils.hown the plain CLI/analyzer mapping for status, device-state, session-state, and session-reason values. - Shared protocol lookup entries in
include/uci_packet_utils.hnow also back the richer UI decoder labels/descriptions for status, device state, session state, session reason, and data-transfer status, so those semantics are not duplicated inuci_ui_packet_decoder.c. - Session and simulation command tables now bind directly to typed handlers in
src/uci_cmd_handlers_session.candsrc/uci_cmd_handlers_simulation.c; the framework wrapper adapter layer has been removed. - Shared plain-text decode output now lives in
include/uci_decode_utils.h, souci.canduci_packet_analyzer.cdo not maintain separate status/state printing logic. - Plain response decoders in
src/uci_plain_decoders.cnow also use those shared decode helpers for UCI status and data-transfer status lines, so the plain CLI output no longer carries its own repeated status switch blocks. - Plain payload response/notification decoding now lives in
src/uci_plain_decoders.c, which removes the bulk decoder table fromuci.cwhile keeping shared measurement helpers available to the live session-notification path. - Control commands now flow through a single canonical packet-construction path before either simulation or hardware transport handles them.
- Tests in
tests/test_protocol_definitions.candtests/test_protocol_fixtures.cenforce those mappings, the command metadata that depends on them, and representative byte-level packet fixtures. tests/test_cherry_alignment.cnow reads the local Cherry headers and client sources directly, pinning the standard GIDs/OIDs, QorvoEXT2opcodes, the CherryQORVO_MAC/QORVO_CALIBgroup assignments, and the current explicitGID 0x0Ebasis choice against the Python-toolConfigManageroverlap.SESSION_CONTROL + SESSION_INFO_NTFis now presented through the CherryRANGE_DATA_NTFsemantic surface in analyzer and decoder output, while keeping the wire opcode and constant names unchanged. The checked-in Cherry alignment tests also pin the 25-byte fixed header, the session-handle meaning of the second 32-bit field, andmeasurement_countat byte 24.- The shared packet-header helpers now follow Cherry's payload-length split:
COMMAND/RESPONSE/NOTIFICATIONkeep the 8-bit length in byte 3, whileDATApackets use bytes 2-3 as a 16-bit little-endian payload length. The unit tests now pin both header encodings and aDATA_MESSAGE_SNDpayload path above 255 bytes. - The hardware transport now also follows Cherry's normal
DATApacket flow more closely: outboundDATAmessages fragment into 255-byte wire packets, while inboundDATAfragments are forwarded packet-by-packet instead of being merged through the control-packet reassembly buffer. - Segmented non-
DATAmessages are now reassembled inparse_uci_packet()before decode/analyzer routing, so hardware-mode receive loops can consume raw wire fragments while still presenting one logical control packet to the existing decoder surface.tests/test_uci_functions.cnow pins both successful reassembly and mismatch-drop behavior for segmentedSESSION_CONTROLcommands. tests/test_uci_functions.cnow includes analyzer-dispatch regressions for live packet routing, so duplicate or unreachableMT/GID/OIDdecode branches are caught even when individual decoder helpers still pass in isolation.tests/test_analyzer_dispatch.cprovides a table-driven analyzer dispatch suite for representative command, response, and notification packets across the currently supported CORE and SESSION families, plus family-specific unsupported-opcode fallback coverage for CORE, SESSION, and Android routing. The same suite now also audits the analyzer source for unique top-level dispatch routes so duplicateMT/GIDbranches are caught before they become unreachable runtime behavior.tests/test_transport_parity.cverifies that the same command handlers emit identical control-packet bytes in simulation mode and hardware mode before any hardware response is involved.tests/test_uci_functions.cnow also pins semantic parity between plain and UI decode paths for representative CORE and SESSION packets, so richer UI formatting cannot silently drift away from the underlying plain-protocol interpretation.tests/test_command_framework_validation.cnow runs real simulation commands through framework dispatch and asserts that their emitted notification bytes reach the expected analyzer path, closing the gap between command handlers and decode fixtures.tests/test_analyzer_dispatch.cnow also exercises malformed analyzer entrypoint cases, including too-short headers and truncated payloads, so header/data mismatches are clamped safely before any decoder sees them.
- Keep protocol constants centralized and remove local literal fallbacks.
- Route typed command handlers through validated parsed parameters instead of
reparsing
argv. - Expand regression coverage for constant mappings, command definitions, and hardware/simulation parity now that all framework command families use one typed handler model.
- Protocol Compliance: Fully aligned with Android UWB specification
- Enhanced Response Handling: Complete parsing of all UCI responses
- Comprehensive TLV Support: Full Type-Length-Value configuration management
- Session Management: Complete session lifecycle with persistent state
- Notification Handling: Human-readable display of all UCI notifications
- Ranging Support: Full UWB ranging notification parsing with distance/angle measurements
- Hardware Communication: Real UWB device support via character device files (/dev/ttyUSB*)
The UCI Interactive Shell can communicate with real UWB hardware through character device files:
./uci-shell
> mode_hw /dev/ttyUSB0
> hw_send 01 00 00 02 # Send CORE_DEVICE_INFO commandAn opt-in hardware integration suite is available and safe for CI/local runs when no device is attached.
# Builds and runs; auto-skips if UCI_HW_DEVICE is not set.
make hardware-integration-test
# Run against real hardware
UCI_HW_DEVICE=/dev/ttyUSB0 make hardware-integration-test
# Optional destructive reset coverage
UCI_HW_DEVICE=/dev/ttyUSB0 UCI_HW_INCLUDE_RESET=1 make hardware-integration-testA minimal user-facing hardware acceptance smoke script is also available:
# Non-destructive CLI bring-up flow
UCI_HW_DEVICE=/dev/ttyUSB0 make hardware-acceptance-smoke
# Include session_start only when the target device already has a known-good
# app-config baseline for the chosen session profile.
UCI_HW_DEVICE=/dev/ttyUSB0 UCI_HW_INCLUDE_SESSION_START=1 make hardware-acceptance-smokeEnvironment variables:
UCI_HW_DEVICE(required to run real-hardware checks)UCI_HW_TIMEOUT_MS(optional, default1500)UCI_HW_VERBOSE(optional,1enables transport debug logs)UCI_HW_INCLUDE_RESET(optional,1enablesCORE_DEVICE_RESETtest)UCI_HW_SCRIPT_TIMEOUT_SEC(optional, smoke-script timeout, default20)UCI_HW_SESSION_IDandUCI_HW_SESSION_TYPE(optional, smoke-script session settings)UCI_HW_INCLUDE_SESSION_START(optional,1includessession_startin the smoke script)
./uci-shell
> get_device_info
> device_reset
> get_device_state
> set_device_active
> session_init 1 fira_ranging
> set_app_config 1 device_type responder
> set_app_config 1 channel 5
> session_start 1
> simulate_ranging
> get_session_state 1
> session_stop 1
> session_deinit 1
> quit./uci-shell
> get_device_info # Get basic device info
> get_caps_info # Get device capabilities
> device_reset # Reset the device
> get_device_state # Check current state
> set_device_active # Set to active state
> session_init 1 fira_ranging # Initialize session with ID 1
> set_app_config 1 device_type responder # Set device as responder
> set_app_config 1 channel 5 # Set to channel 5
> set_app_config 1 ranging_usage ranging # Set ranging usage
> session_update_multicast_list 1 add 0x1234 0x00000001
> session_update_dt_tag_rounds 1 0 1 # or session_update_dt_tag_rounds 1 0001
> session_data_transfer_phase_config 1 1 0x02 0
> session_start 1 # Start the session
> simulate_ranging # Simulate ranging measurement
> get_session_state 1 # Check session state
> session_stop 1 # Stop the session
> session_deinit 1 # Deinitialize session
> set_device_ready # Set back to ready state
> quit # Exit shell./uci-shell
> mode_hw /dev/ttyUSB0 # Connect to the hardware transport
> mode_info # Confirm we are in HARDWARE mode
> get_device_info # Query the device over hardware
> device_reset # Reset the controller
> set_device_active # Bring the device to ACTIVE
> session_init 1 fira_ranging # Create a ranging session on hardware
> set_app_config 1 device_type responder
> set_app_config 1 channel 5
> session_start 1 # Begin ranging on hardware
> get_session_state 1 # Observe live session state
> session_stop 1
> session_deinit 1
> mode_sim # Return to simulation mode when finished
> quit./uci-shell
> hw_send 01 00 00 02 # Send CORE_DEVICE_INFO (MT=0x01, GID=0x00, OID=0x02)
> hw_send 01 00 00 04 01 00 01 02 # Send SET_CONFIG to set device to ACTIVE (num_tlvs=1, cfg_id=0, len=1, value=2)
> hw_send 01 00 00 05 01 00 # Request GET_CONFIG for device_stateFor complete technical details of all improvements, see:
docs/PROJECT_STATUS.md- Current branch snapshot, recent commits, and next stepsdocs/UCI_STATE_OF_THE_ART_SECURITY_FINAL_SUMMARY.md- End-to-end security hardening summaryuci_analysis/UCI_PROTOCOL_ANALYSIS.md- Detailed UCI protocol specificationuci_analysis/SUMMARY.md- Deep dive into protocol elementsuci_analysis/uci_packet_generator.py- Python script for generating UCI packets
src/main.c- Main interactive shell implementationsrc/uci.c- UCI packet processing, simulation flow, and live notification handlingsrc/uci_plain_decoders.c- Plain-text payload response/notification decoders shared by CLI pathssrc/uci.h- UCI data structuressrc/uci_functions.h- Function declarationssrc/uci_pdl.h- UCI protocol definitions and constantssrc/uci_hw_interface.h/c- Hardware interface layersrc/uci_hw_chardev.h/c- Character device communication layersrc/uci_command_framework.c- Parameter validation and unified dispatcher shared by simulation/hardware modessrc/uci_cmd_framework_{bridge,device,session,simulation}.c- Declarative command definition tables that power CLI help, completion, and handlers
For a comprehensive analysis of the UCI protocol based on the Android Open Source Project implementation, see:
uci_analysis/UCI_PROTOCOL_ANALYSIS.md- Detailed comparison with Android UWB implementationuci_analysis/SUMMARY.md- Deep dive summary of protocol elementsuci_analysis/uci_packet_generator.py- Python script to generate proper UCI packetsuci_analysis/uwb/- Full Android UWB repository for reference
The Android repository provides the complete UCI specification in Protocol Definition Language (PDL) format in uci_analysis/uwb/src/rust/uwb_uci_packets/uci_packets.pdl