Skip to content

BMCLI replay

Reference version: BMCLI 1.6.3. Command names, parameters and machine-readable fields retain their source spelling.

Online (host-side) replay of an ASC or uncompressed BLF log file. CAN/CAN FD works in standalone and daemon modes; LIN ASC/BLF replay uses a daemon-opened LIN channel so its role, electrical setup and schedule ownership remain explicit. For on-device replay from the device’s flash, use offline replay start (see offline).

For BLF input, consecutive uncompressed LOG_CONTAINER payloads form one logical object stream. An object header, body, or alignment padding may cross a container boundary; container headers and their physical alignment padding are not exposed as object bytes. Empty containers are allowed. Compressed, truncated, or structurally invalid containers fail explicitly rather than silently dropping or truncating frames.

In daemon mode the list is an ordered subset of already-open channels. Every listed target and every explicit map target is validated before the worker starts; an unopened target fails the whole start without sending. List position is independent of physical port and daemon slot. Numeric channel selectors retain the existing enumeration-index-first/slot-fallback rule; closing another channel does not renumber the running replay.

One worker reads the file on one timeline and tracks transmit completions per destination. Start/status JSON adds target_channels (ordered daemon slots), channel_mappings (recorded_channel, destination channel slot), and channel_mask (union of all destinations). Legacy channel is the first listed target. Closing any destination stops the remaining whole replay at a safe point; completed frames remain sent, with partial counters retained.

Terminal window
bmcli replay start --channel=0 --file=logfile.asc
bmcli replay start --channel=10356/0 --file=logfile.asc --loop --speed=2
# Replay a file recorded on a different channel as-is:
bmcli replay start --channel=10356/0 --file=recorded_on_ch2.asc --ignore-channel
# Fixed 20ms inter-frame gap instead of original timestamps:
bmcli replay start --channel=0 --file=logfile.asc --msg-delay=20
# As fast as possible (back-to-back):
bmcli replay start --channel=0 --file=logfile.asc --ignore-timestamp
# Loop with 500ms gap between iterations:
bmcli replay start --channel=0 --file=logfile.asc --loop --cycle-delay=500
Option Default Description
--channel (required) Channel list (comma-separated SN/port, UID/port, or legacy index). Selected in listed order (opened by standalone, pre-opened for daemon); list position i is routing position i (1-based). Single channel = position 1 only.
--file (required) ASC or uncompressed BLF log file path
--speed 1.0 Speed multiplier in (0, 100] (2 = twice as fast). Only meaningful in retain-timestamp mode. Invalid text, NaN and out-of-range values fail before replay starts.
--loop off Loop cyclically
--ignore-channel off Send every frame to the first opened channel (single-channel dump), bypassing positional routing.
--map-channel=<asc_ch>:<spec> (none) Override: route ASC channel <asc_ch> to physical channel <spec>. Repeatable. See routing rules below.
--map-strict off Only ASC channels with an explicit --map-channel entry are sent; all others are skipped (and counted as errors). Disables positional default.
--msg-delay=<ms> (off) Fixed inter-frame spacing in [0, 60000) ms, overrides original timestamps. 0 = back-to-back. First frame is always sent immediately.
--ignore-timestamp off Semantic alias for --msg-delay=0: send frames back-to-back with no inter-frame delay.
--cycle-delay=<ms> 0 Interruptible gap in [0, 60000) ms applied only between loop iterations.

Channel routing (per frame, highest-precedence first). The hardware port number is not consulted — ASC channel numbers are purely positional:

  1. explicit --map-channel=N:spec match → mapped channel
  2. --map-strict → skip + count as error
  3. --ignore-channel → first opened channel (--channel position 1)
  4. positional: ASC channel N → the N-th opened channel (if N is within the opened list)
  5. otherwise → skip

So with --channel=A,B,C opened, ASC ch1→A, ch2→B, ch3→C by default. ASC ch4 (no position 4) is skipped unless --ignore-channel or mapped. With a single --channel=A, only ASC ch1 is sent by default — use --ignore-channel to dump all frames onto A, or --map-channel=N:A to route a specific channel there.

Terminal window
# Multi-channel recording -> multi-channel hardware (purely positional)
bmcli replay start --file=multi.asc --channel=10356/0,10356/1,10357/0
# ASC ch1->10356/0, ch2->10356/1, ch3->10357/0
# Override specific channels (map on top of positional)
bmcli replay start --file=multi.asc --channel=10356/0 \
--map-channel=1:10356/2 --map-channel=3:10357/0 --map-strict
# ch1->10356/2, ch3->10357/0; everything else skipped (strict)
# Single channel, dump entire file onto it
bmcli replay start --channel=10356/0 --file=recorded_on_ch5.asc --ignore-channel

--map-channel resolves its spec independently of the --channel list (it opens the target channel). Do not list the same physical port in both --channel and --map-channel (the device-port open will fail — ports are exclusive).

Timing modes (evaluated in this order):

  1. --ignore-timestamp → back-to-back, no delay
  2. --msg-delay=<ms> → fixed delay between every frame
  3. default → retain original inter-frame timestamps (scaled by 1/speed)

The first frame of the initial iteration is sent immediately. Fixed-delay deadlines are derived from the loop origin and frame index, so transmit completion time does not accumulate into the requested spacing. At every loop boundary an explicit --cycle-delay takes priority and is applied once. Without an explicit cycle delay, retained-timestamp mode preserves the trace’s bounded zero-to-first-frame interval. If that interval is zero, BMCLI applies a 1 ms minimum loop guard; this keeps a one-frame retained trace from becoming an unbounded busy loop. All timing and loop-boundary waits check stop state in bounded slices.

Host replay submits CAN/CAN FD/LIN frames with BMAPI timeout 0, so the USB transport and device queue provide their normal NAK/queue-full backpressure without a one-second completion round trip on every frame. Each accepted frame leases one nonzero six-bit hardware sequence identity. The replay completion reader counts it as sent only after a matching real TX-completion event for the same bus type, message ID, sequence and Broker generation. accepted therefore means queued by BMAPI; sent means physically completed, and the two may differ while replay is active.

If either the BMAPI host queue or the finite completion-identity window is full, BMCLI pumps completions and retries the same frame without changing its source order or deadline. A finite replay performs a data-driven EOF drain and does not report success until every accepted frame has a matched completion. Five seconds with no completion progress is a hard failure, as are write, reader and completion errors. A valid completion that reports a hardware TX error increments failed but remains a consumed event, so it does not suppress the following input record. Cancellation remains interruptible and reports pending accepted frames instead of presenting them as sent. Later frames still reference the original absolute replay origin, so transient backpressure can catch up without accumulating relative delays.

Daemon replay rejects a CAN channel configured in NoACK mode because BMAPI does not publish a real transmit-completion event in that mode; queue acceptance is not eligible to increase sent.

For retained timing, BMCLI honors the ASC header: with timestamps absolute, the input timestamps remain absolute; with timestamps relative, record delays are accumulated by the input layer. BLF timestamps are absolute. After this normalization, each loop records one monotonic clock origin and the first source timestamp. Every frame deadline is calculated directly as origin + (timestamp - first_timestamp) / speed; actual wait completion and send time never become the next frame’s origin. A late frame skips its expired wait and subsequent frames continue along that same absolute timeline. Daemon timing statistics are published and serialized from one synchronized snapshot, including on start/reset and worker exit, so 32-bit builds cannot expose torn or mixed-generation lateness counters.

ASC format support: Both classic CAN and CAN FD messages. Classic format supports old (Ext/Std + R/T) and new Vector (Rx/Tx) styles. Frame-shaped records are validated before transmission: channel/direction, standard versus extended ID range, DLC/data-length agreement, exact payload bytes, and the eight CAN FD tail fields must all be complete, with no trailing tokens. Malformed records stop replay with an input error; unsupported non-frame event records are skipped.

Historical Classic rows in the explicit directionless RTR form timestamp channel id r [dlc] are accepted. Since the source has no direction, BMCLI normalizes it to Rx; direction remains mandatory for data frames.

Terminal window
bmcli replay stop

In standalone mode, use Ctrl+C.

Survey of all replay-capable entities (mirror of logging status). Does NOT require --channel.

$ bmcli replay status
[host] active=yes channels=10356/0 file=x.asc accepted=1260 sent=1234 failed=2 pending=24
[dev 10356] replay=off
[dev 10357] replay=on mode=always_on channels=0x0001 path=stored.asc cyclic=yes
  • [host] — host-side (online) replay, tracked by the daemon.
  • [dev SN] — each USB device’s on-device replay state via BM_GetReplay.

Host replay likewise reports terminal errors/last_error for invalid input, read, timing, write, or close failures instead of remaining deceptively active. Standalone replay results and the daemon CLI/Web host status report accepted, sent, failed, and pending. The counters reconcile as accepted = sent + failed + pending; errors includes every failed completion. They also report current_lateness_ms, last_lateness_ms, max_lateness_ms, average_lateness_ms, late_frames, late_threshold_ms, send_failures, and dropped. late_threshold_ms is 2; late_frames counts only attempts whose scheduling lateness is strictly greater than 2 ms. This measurement ends at the first send attempt and does not include transmit-completion time. Lateness is measured at the first send attempt relative to the absolute frame deadline. A temporary full transmit queue is neither a send failure nor a drop; the expected dropped value is therefore zero.

Optional --channel=<spec> filters to the matching entity.

In daemon mode, replay start, replay stop, and replay status honor the global --format=json output contract. Status returns one object containing a host object and a devices array; it never prefixes or appends human-readable survey lines to JSON stdout. Daemon start and host status include the effective timing_mode (retain_timestamp, fixed_delay, or back_to_back), message_delay_ms, and cycle_delay_ms.



Source of truth: BMCLI 1.6.3 repository documentation. Run bmcli help <category> <action> --format=json for the exact contract of the installed version.