blf_asc
A small Rust library for reading and writing Vector BLF and ASC (CAN log) files, modeled after python-can behavior.

Documentation: docs.rs/blf_asc
Features
- BLF reader with
Iterator<Item = Message>
- BLF writer with
on_message_received (python-can-like)
- ASC (Vector) reader/writer
- Supports CAN classic, CAN FD, and error frames
- Zlib compression for BLF (default level = -1, same intent as python-can)
Installation
[dependencies]
blf_asc = "0.2"
Usage
Read BLF
use blf_asc::{BlfReader, Result};
fn main() -> Result<()> {
let mut reader = BlfReader::open("input.blf")?;
for msg in reader.by_ref() {
println!("id={} dlc={} data={:?}", msg.arbitration_id, msg.dlc, msg.data);
}
if let Some(err) = reader.take_error() {
eprintln!("reader error: {err}");
}
Ok(())
}
Note: msg.data is DataBytes (hex-friendly). println!("{:?}", msg.data) prints hex. The helper msg.data_hex() returns a hex string, and msg.arbitration_id_hex() prints the ID as hex.
Write BLF (python-can style)
use blf_asc::{BlfWriter, Message, Result};
fn main() -> Result<()> {
let mut writer = BlfWriter::create("output.blf")?;
let msg = Message {
timestamp: 0.0,
arbitration_id: 0x123.into(),
is_extended_id: false,
is_remote_frame: false,
is_rx: true,
is_error_frame: false,
is_fd: false,
bitrate_switch: false,
error_state_indicator: false,
dlc: 3,
data: vec![0x11, 0x22, 0x33].into(),
channel: 0, };
writer.on_message_received(&msg)?;
writer.finish()?;
Ok(())
}
Read ASC
use blf_asc::{AscReader, Result};
fn main() -> Result<()> {
let mut reader = AscReader::open("input.asc")?; for msg in reader.by_ref() {
println!("id={} dlc={} data={:?}", msg.arbitration_id, msg.dlc, msg.data);
}
if let Some(err) = reader.take_error() {
eprintln!("reader error: {err}");
}
Ok(())
}
Write ASC
use blf_asc::{AscWriter, Message, Result};
fn main() -> Result<()> {
let mut writer = AscWriter::create("output.asc")?;
let msg = Message {
timestamp: 1710000000.123,
arbitration_id: 0x123.into(),
is_extended_id: false,
is_remote_frame: false,
is_rx: true,
is_error_frame: false,
is_fd: false,
bitrate_switch: false,
error_state_indicator: false,
dlc: 3,
data: vec![0x11, 0x22, 0x33].into(),
channel: 0,
};
writer.on_message_received(&msg)?;
writer.finish()?;
Ok(())
}
Convert BLF <-> ASC
use blf_asc::{AscReader, AscWriter, BlfReader, BlfWriter, Result};
fn blf_to_asc(input: &str, output: &str) -> Result<()> {
let reader = BlfReader::open(input)?;
let mut writer = AscWriter::create(output)?;
for msg in reader {
writer.on_message_received(&msg)?;
}
writer.finish()?;
Ok(())
}
fn asc_to_blf(input: &str, output: &str) -> Result<()> {
let reader = AscReader::open_with_options(input, "hex", false)?;
let mut writer = BlfWriter::create(output)?;
for msg in reader {
writer.on_message_received(&msg)?;
}
writer.finish()?;
Ok(())
}
Notes
Message::channel is 0-based. It is serialized as channel+1 in BLF/ASC, matching python-can conventions.
- BLF object types supported: CAN_MESSAGE, CAN_MESSAGE2, CAN_ERROR_EXT, CAN_FD_MESSAGE, CAN_FD_MESSAGE_64.
- ASC timestamp precision is milliseconds. A BLF -> ASC -> BLF roundtrip will lose sub-millisecond precision.
License
Licensed under either of
- Apache License, Version 2.0
- MIT license
at your option.
Release
This repo includes release.toml for cargo-release.
Typical flow:
- cargo release patch