Pure C library for reading and writing Vector CANoe/CANalyzer ASC log files,
with no external dependencies. C11, header include/asc_parser/asc_parser.h.
Reader
- Classic CAN: data / remote / error frames, standard & extended IDs
- CAN-FD: 12–64 byte payloads, BRS/ESI flags, signal (symbolic) names
base hex/base dec,timestamps absolute/relative- Begin/End TriggerBlock, status & statistic lines, UTF-8 BOM
- US (am/pm) and 24h dates, English + German month names
- Locale-independent number parsing (safe under de-DE comma locales)
- Hardened against corrupt input: bounds-checked DLC/length, invalid tokens, channel underflow, 29-bit ID range, over-long lines
- Lenient (default: skip & count malformed lines) or strict mode (abort with
line number); per-instance stats via
asc_parser_get_frames_parsed()/asc_parser_get_lines_skipped()
Writer
- CANoe-compatible output (same field layout as python-can's ASCWriter)
- Automatic header/TriggerBlock,
End TriggerBlockon destroy - Sticky write-error reporting (
asc_writer_get_error()), UTF-8 paths on Windows
Performance (reference machine, 1M-frame mixed classic/FD file):
read ~377k frames/s (65 MB/s); see tests/README.md for benchmark usage.
cmake -B build && cmake --build build
cd build && ctest # unit + golden + round-trip + bench smoke tests
./build/asc_demo file.asc # parse and pretty-print a logCross-validation against python-can (optional, needs Python):
./tests/run_tests.sh
#include "asc_parser/asc_parser.h"
char err[256];
asc_parser_t* p = asc_parser_create_ex("log.asc", err, sizeof err);
if (!p) { /* err has the reason */ }
asc_parser_set_strict(p, true); // optional
asc_can_frame_t f;
while (asc_parser_read_frame(p, &f)) {
// f.timestamp, f.frame_id, f.payload_length, f.payload[], ...
}
printf("%ld parsed, %ld skipped\n",
asc_parser_get_frames_parsed(p), asc_parser_get_lines_skipped(p));
asc_parser_destroy(p);
asc_writer_t* w = asc_writer_create("copy.asc");
asc_writer_write_frame(w, &f); // header written automatically
asc_writer_destroy(w); // writes "End TriggerBlock"Instances are independent and share no global state. Use one asc_parser_t /
asc_writer_t per thread; no function is re-entrant on the same instance.
- Classic frames with DLC > 8 (
d 40,d D): every logged data byte is kept on read (the scan stops at trailing fields such asLength = ...), and the writer round-trips them all.payload_lengthstores the byte count actually present, so a raw DLC 9..15 with only 8 bytes normalizes to 8 (raw DLC codes are not preserved; python-can keeps them). - Error frames: the classic
N ErrorFrameline carries no direction bit; FD error frames keep theirs via a CANFD-style line. timestamps absolutesemantics follow python-can (header date + logged time).
tests/data/ fixtures (except canoe.asc) originate from the
python-can test suite (GPL v3).
They are used for development/CI validation only; replace them before
redistributing this repository under a non-GPL license. canoe.asc is a
real CANoe 12 export kept for FD-format coverage. canoe14_fd.asc is a
synthetic CANoe 14-style log built from samples posted in python-can issues
#1786/#1315 (version 14 header, CANFD Start of measurement line,
six-digit-millisecond date).