BMCLI Message Command: CAN, CAN FD and LIN I/O
Reference version: BMCLI 1.6.5. Command names, parameters and machine-readable fields retain their source spelling.
message send
Section titled “message send”Send CAN/CAN FD or LIN messages. --type selects CAN data/remote or LIN
master-write/master-read/sync-break. CAN supports raw data, repeated
sends, and DBC signal encoding. LIN supports IDs 0x00..0x3F and payloads up to
8 bytes.
# Single standard CAN framebmcli message send --channel=0 --message=0x123 --data="AA BB CC"
# CAN FD with bitrate switchingbmcli message send --channel=0 --message=0x100 --data="11 22" --flags=fdf+brs
# Extended ID (29-bit)bmcli message send --channel=0 --message=0x18FEDC01 --flags=ide --data="01 02"
# Explicit zero-length Classic CAN frame (omitted data does not restore DLC 8)bmcli message send --channel=0 --message=0x123 --dlc=0 --format=json
# Batch: 100 asynchronous writes at 10ms intervals (waits for the loop, not bus completion)bmcli message send --channel=0 --message=0x100 --count=100 --cycle=10
# DBC signal encoding (uses globally loaded DBC, see `database load`)bmcli message send --channel=0 --message=EngineStatus --signal=EngineSpeed:1500
# Multiple signalsbmcli message send --channel=0 --message=EngineStatus --signal=EngineSpeed:1500 --signal=CoolantTemp:85
# LIN master publishes a data framebmcli message send --channel=10356/4 --id=0x20 --type=master-write --data="01 02 03 04" --bitrate=19200
# LIN master read: payload+checksum response is requiredbmcli message send --channel=10356/4 --id=0x20 --type=master-read --dlc=8 --timeout=500 --format=json
# LIN sync break: a slave payload response is an errorbmcli message send --channel=10356/4 --id=0x21 --type=sync-break --timeout=500 --format=jsonStructured LIN transaction output distinguishes command attempts from bus
error flags. Top-level attempts is the number of attempted command records and
host_retry_count is currently 0; each result has one-based attempt,
result_error, and checksum_valid. The retained errors field inside a LIN
result is a firmware/BMAPI bit mask, duplicated as lin_error_flags with
errors_semantics="bitmask"; for example value 32 is a LIN timeout flag, not
32 retries. A header-only no-response result has checksum_valid=false and is
not counted in top-level received. A physical response with the wrong DLC is
counted in received but also in errors and has result_error=true.
--signal format — all of the following are accepted (separator interchangeable):
| Syntax | Example |
|---|---|
--signal=Name=Value |
--signal=EngineSpeed=1500 |
--signal=Name:Value |
--signal=EngineSpeed:1500 |
--signal Name=Value |
--signal EngineSpeed=1500 |
--signal Name:Value |
--signal EngineSpeed:1500 |
Repeat --signal for multiple signals. No spaces inside signal values.
BMCLI validates every DBC assignment before opening a standalone channel or
submitting a daemon send. An unknown message or signal, an out-of-range value,
or an invalid multiplexor selection fails without sending a frame. Structured
output uses the same typed DBC encode diagnostic described under dbc encode.
When a daemon client supplies a relative --dbc path, or a path-like relative
--database selector, it is resolved from that client’s current working
directory carried in structured IPC. A plain registered resource name is never
rewritten as a path. Resolution failures retain the requested selector, caller
directory, and resolved path in the structured error.
| Option | Default | Description |
|---|---|---|
--channel |
(required) | CAN or LIN channel; bus is inferred from capability |
--message / --id |
(required) | CAN ID/DBC message name, or LIN frame ID 0x00..0x3F |
--data |
CAN: 8 zero bytes; LIN: empty | Payload hex bytes; explicit empty --data= selects a zero-length CAN payload; LIN supports up to 8 and forbids data with header-only operations |
--type |
CAN data; LIN master-write |
CAN: data, remote. LIN: master-write, master-read, sync-break |
--dlc |
CAN: 8 when data is omitted; LIN master-read: 8 |
CAN DLC 0..15 explicitly selects the wire length before the omitted-data default; shorter payloads are zero padded and payloads longer than the selected DLC are rejected. LIN expected response length is 0..8; sync-break uses 0. |
--flags |
DBC metadata or none | CAN only: ide, fdf, brs, rtr (plus-separated) |
--checksum |
auto |
LIN only: auto, classic, or enhanced |
--count |
1 |
Number of frames (software-timed loop) |
--cycle |
0 |
Interval between frames in ms |
--timeout |
direct publish 0; LIN transaction 500 |
LIN master-read/sync-break total transaction deadline in ms, shared by all --count attempts. It is never passed to BMAPI as a write timeout. |
--signal |
— | CAN only: repeatable DBC signal assignment |
--bitrate |
CAN 500/2000; LIN 19200 |
Standalone CAN timing: one rate means nominal=data and N/D is explicit. LIN keeps its bps meaning; daemon channels keep their open-time configuration. |
Every BMCLI-owned BM_Write* call uses write-timeout 0 and BMCLI never sets
ECHO. A direct send result reports accepted, meaning BMAPI accepted the
write; it does not claim that the frame reached the bus. A later
event_kind=tx_complete is emitted only when the device returns a real TEF
through BM_Read. Immediate or partial rejection reports accepted,
failed_index, bmapi_status, and bmapi_status_name; it never creates a raw
event or log record.
Successful CAN JSON reports the stable physical channel, and daemon mode also
reports its separate channel_slot. dlc is the final wire DLC;
payload_length counts explicitly supplied/DBC-produced bytes;
padding_bytes and padded describe zero fill. Omitting both --data and
--dlc deterministically sends eight zero bytes. Explicit --dlc=0 sends no
payload in both Classic CAN and CAN FD. DLC 9..15 use the standard CAN FD
12/16/20/24/32/48/64-byte mapping.
--count/--cycle vs txtask: message send --count --cycle is a software-timed loop that keeps the command alive until all asynchronous writes have been attempted. txtask add is a hardware-timed task running on the device firmware — more precise, non-blocking, and persistent. Use message send for one-off batch tests; use txtask for long-running periodic messages.
For LIN header operations, accepted counts submitted headers and completed
counts outcomes that matched the selected intent. Each JSON results item has
an outcome. Master-read succeeds only with the expected DLC, payload/checksum,
and no LIN errors. Sync-break succeeds only for a header-only sync_break=true
event; a payload is reported as unexpected-response and returns nonzero.
message recv
Section titled “message recv”In daemon mode all selected channels must already be open. Run channel open
first; receive does not implicitly open a channel or replace its configuration.
Standalone receive retains its own open/receive/close lifecycle.
Receive CAN, CAN FD, or LIN frames. Blocks until --count is reached or
--duration elapses (or Ctrl+C in standalone). Standalone capture accepts
multiple channels only when they have the same bus type.
In daemon mode, omitting --channel receives from ALL open channels simultaneously. In standalone mode, --channel is required.
# Standalone: single channel, exit after 100 framesbmcli message recv --channel=10356/1 --count=100
# Standalone: multi-channel, 5-second capturebmcli message recv --channel=10356/0,10356/1 --duration=5
# Daemon: receive from all open channels for 10 secondsbmcli message recv --duration=10
# Daemon: preserve each raw CAN frame and add decoded data from a registered DBCbmcli message recv --channel=10356/1 --decode --database=vehicle --duration=5 --format=json
# Daemon: direct one-off DBC file, one decoded event per JSONL linebmcli message recv --channel=10356/1 --decode --dbc=network.dbc --duration=5 --format=jsonl
# With CAN ID filterbmcli message recv --channel=10356/1 --id=0x100 --mask=0x7FF --duration=5
# Passive LIN capturebmcli message recv --channel=10357/4 --mode=listen-only --bitrate=19200 --duration=5 --format=jsonl| Option | Default | Description |
|---|---|---|
--channel |
daemon: all open; standalone: required | Channel(s): SN/port, comma-separated list, or omit for all open (daemon only) |
--count |
0 (infinite) |
Max messages to receive. If a positive count is explicitly combined with duration, zero matching messages do not satisfy the count and the command fails. |
--duration |
0 (infinite, Ctrl+C to stop) |
Wall-clock capture duration in seconds. Daemon mode defaults to 10s if neither count nor duration is given; when duration is the only explicit stop condition, expiry is successful even with zero matching messages. |
--id |
none | CAN or LIN ID filter (software-filtered) |
--mask |
0x7FF |
ID filter mask |
--decode |
off | Decode matching CAN/CAN FD frames in standalone or daemon mode while retaining the raw frame |
--database |
sole loaded DBC | Registered DBC name or direct file used for receive decoding |
--dbc |
sole loaded DBC | Direct-file convenience alias for --database |
--format |
text |
text, json (array), jsonl (one JSON per line), csv |
--bitrate |
CAN 500/2000; LIN 19200 |
Standalone CAN timing: one rate means nominal=data and N/D is explicit. LIN keeps its bps meaning. |
--mode |
LIN listen-only |
Standalone LIN role |
With --decode, text keeps the existing raw line and prints the decoded
object after it. JSON and JSONL keep every existing raw field and add a
decoded object only when the selected DBC contains that CAN ID. Standard,
extended, and CAN FD frames use the same codec and decoded schema as standalone
receive. JSONL still emits one complete frame event per line.
Standalone JSONL makes the first complete event visible immediately. It then
batches later stdio flushes with a maximum 100 ms cadence so a low-rate tail is
visible without waiting for another frame or process exit, while high-rate
capture does not force one synchronous flush per event. Normal buffer-capacity
drain, the final summary, errors, and command completion remain flush
boundaries. Daemon JSONL likewise streams each complete frame, gap, and summary
record over the request socket as soon as it is formatted; it does not wait for
the aggregate response buffer or command completion. The short-lived client
flushes each received socket chunk to stdout. Client disconnect is checked at
the receive poll cadence and releases that request’s Broker cursors. Bounded
daemon --format=json deliberately keeps the existing one-document response.
An unmatched CAN ID remains a successful raw-only frame. A missing or
unparseable DBC also follows the current standalone receive oracle: the frame
remains raw-only rather than changing the receive command’s success result.
Receive decoding reports observed signal values; if a decoded physical value is
outside the DBC’s declared min/max, it is still returned exactly as standalone
receive returns it. Supplying --database or --dbc without --decode
does not load or decode the DBC and does not change raw output. These decode
options are CAN-only and do not alter LIN receive behavior.
Structured raw events classify device input explicitly as
event_kind=rx_frame or event_kind=tx_complete; direction is the derived
rx/tx view. Daemon events also carry the RxBroker source_sequence,
stream_epoch, extended timestamp_us, bus-specific flags/status and the
hardware SEQ where applicable. Identical hardware events remain distinct and
are never content-deduplicated. Every structured CAN frame reports stable
channel=UID/port (or SN fallback); daemon frames additionally carry a separate
numeric channel_slot, so a multi-channel consumer does not need enumeration
or daemon open order to identify its source.
For LIN master-read, the slave response payload can appear in a
tx_complete event for the master’s transaction. Consumers collecting LIN
responses must inspect both event kinds rather than filtering for rx_frame only.
Daemon and standalone bounded JSON return one object with status, messages, received,
channels, gaps, dropped, and completion_reason. JSONL emits one object
per frame and always terminates with an event=summary object containing the
same counters and completion reason. Text ends with the corresponding summary.
For a duration-only capture with no matching traffic, the result is successful:
received=0, gaps=0, dropped=0, and completion_reason=duration. A real
RxBroker gap, channel/hardware error, or an explicitly requested positive count
that expires at zero remains a nonzero failure; structured failures use the
canonical error.code, error.message, error.details, and
error.retryable envelope.
gaps and dropped measure only this command’s RxBroker observer link.
gaps counts retention discontinuity events, while dropped counts retained
events overwritten before this observer read them. They use the same source as
stat integrity fields broker_gaps and broker_dropped_frames; they do not
inspect DBC signals, E2E/application counters, or expected transmit cadence.
For example, an ECU counter changing from 4 to 6 can still produce
gaps=0,dropped=0 when every frame visible to RxBroker reached this observer.
Conversely, an RxBroker retention overrun reports nonzero gaps/dropped
even when the received payload counters themselves are consecutive. BMCLI does
not infer application-level missing frames from generic payload data.
Note: message send --timeout is an upper-layer LIN transaction deadline;
direct publish is always asynchronous. message recv --duration is a capture
window in seconds. Neither option changes the BMAPI write-timeout, which is 0.
Related practical workflow
Section titled “Related practical workflow”Source of truth: BMCLI 1.6.5 repository documentation. Run bmcli help <category> <action> --format=json for the exact contract of the installed version.