CANParser is a robust, Rust-based CAN parsing library, designed with speed and accuracy in mind. Developed in Rust for its efficiency, direct bit-level manipulation, and vast compatibility with various architectures and languages. It aims to parse CAN (Controller Area Network) log files, decode them based on provided specifications, and produce meaningful output. Additionally, it provides a command-line interface utility for effortless integration into terminal-based workflows.
- Features
- Repository Structure
- Library Features
- Data Variables
- Main Functions
- Getting Started
- Benchmarking Statistics
- Memory Estimates and Limitations
- Examples
- Future Work
- Blazing Fast: Optimized for speed, providing parse times as low as ~700ns per line on modern systems.
- Versatile Input: Support for all text-based CAN logs. Specification files can be in JSON, XLSX, or DBC formats.
- Diverse Output Options: Output can be formatted in JSON, CSV, or as an SQLite database.
- Broad Compatibility: With included wrappers, it supports integration with Python and web clients through WebAssembly.
can_parser/
: Contains the Rust-based CAN parsing utility.can_parser_python/
: Features a pyo3 wrapper, allowing the utility to be compiled into a Python library.can_parser_wasm/
: Contains a wasm_bindgen wrapper, permitting compilation into web assembly for client-side web integrations.can_parser_cli
: Provides a Rust-based CLI utility, which also serves as a Rust example for utilizing the CAN parsing library.examples/
: Includes Python and Next.js usage samples.
parallel
: Enables multi-threaded parsing.debug
: Activates debug output, including benchmarking.xlsx
: Support for Microsoft XLSX document specifications.sqlite
: Enables SQLite database output.python
: PyO3 support for Python versions 3.7 and above.wasm
: Enables wasm-bindgen support. (Note: multi-threaded support for WASM requires the nightly unstable std, resulting in potential instability).
messages
: Array ofCANMessages
where parsed data values reside.filtered_spec
: A filtered specification for items in the CAN logs.flags
: Boolean flags indicating detected protocols in the CAN log.
NOTE: Multi-line parsing functions don't return data directly to avoid unnecessary data copy when using wrapper libraries. They return success status; to access data, refer to class variables.
(For brevity, not all functions are detailed here. Refer to the library documentation for full details.)
-
Constructor: Initializes a
CANParser
instance. Excerpt:pub fn new( error_handling: String, line_regex: Option<String>, specs_annexes: Option<HashMap<String, String>>, ) -> Result<Self, CANParserError>;
-
parse_file: Parses a file, returning the operation's success status.
-
parse_lines: Parses an array of lines.
-
parse_line: Parses a single CAN message and directly returns the parsed message.
-
to_json: Outputs
filtered_spec
,flags
, andmessages
as a JSON string or saves them to a specified file. -
to_csv: Converts data to multiple CSVs.
-
to_sqlite: Stores data in an SQLite database, the most memory-efficient option.
Before diving into the core functionalities of CANParser, it's essential to set up your development environment. Follow these steps to get started:
- Git: To clone the repository, ensure that you have Git installed on your machine. If not, you can download and install it from the official Git website.
- Open your terminal or command prompt.
- Navigate to the directory where you want to clone the CANParser repository.
- Execute the following command:
git clone https://github.com/systemscyber/CANParser.git
- Change to the cloned directory:
cd CANParser
Rust provides excellent documentation for setting up the language on various operating systems. Here's a quick guide:
- Open your terminal.
- Download and install Rust using the rustup script:
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
- The above command will download a script and start the installation of the rustup toolchain installer. Follow the on-screen instructions.
- Once completed, restart your terminal or run the following command to update your path:
source $HOME/.cargo/env
- Verify the installation by executing:
rustc --version
- Visit the official Rust downloads page.
- Download the
rustup-init.exe
for Windows. - Run the downloaded executable and follow the on-screen instructions.
- After installation, restart your computer.
- Open a new Command Prompt and verify the installation:
rustc --version
Building CANParser involves compiling and setting up different components, namely the CLI, Python library, and the WASM library. Here’s a detailed guide for each component:
The CLI provides a command-line interface to interact with the CANParser library.
-
Navigate to the
can_parser_cli
directory:cd can_parser_cli
-
Using the Makefile (Recommended for Unix-like systems):
-
Compile the binary for your system in release mode:
make
-
To compile for multiple targets (Windows, Linux, Raspberry Pi, and BeagleBone):
make all
-
-
Manual Compilation:
If you are on Windows or don’t prefer using the Makefile, you can compile manually using Cargo.
- Compile the binary in release mode:
cargo build --release
- Compile the binary in release mode:
-
First, ensure you have Python installed. For this library, we're targeting Python 3.7 and higher.
-
Create and activate a virtual environment:
python3 -m venv canparser_env source canparser_env/bin/activate
python -m venv canparser_env .\canparser_env\Scripts\activate
-
Install
maturin
, a tool to build and publish Rust projects with Python bindings:pip install maturin
-
Navigate to the
can_parser_python
directory and build the library:cd can_parser_python maturin build --release
-
To automatically compile and install the Python wheel in the current environment, use:
maturin develop --release
-
Install
wasm-pack
, a toolchain for building WebAssembly with Rust:cargo install wasm-pack
-
Navigate to the
can_parser_wasm
directory:cd can_parser_wasm
-
Build the package targeting web platforms:
wasm-pack build --target web
After these steps, you've successfully built the various components of CANParser. Now, you can proceed to use them in your applications or further development. Always refer back to the provided examples for practical implementation insights.
To view the benchmark statistics enabled the "debug" feature and then recompile.
Detailed benchmarking stats help users get a sense of the library's performance. For instance, parsing a 230MB candump log on a modern four-core system with multi-threaded support took 3.26 seconds, averaging 704 ns per line.
Debug Information:
------------------
File Parsing Duration: 3.26 seconds
Total Lines Parsed: 4630148
Average Time per Line: 704 ns
Average Message Size: 144.00 bytes
------------------
At the time of writing this here are some other statistics (as of 8/2023) on a relatively modern machine across a few different can logs:
- Single threaded average time per line: ~2us (micro seconds)
- Single threaded Firefox average time per line: 2us
- Single threaded Chrome average time per line: 16us
- Single threaded Edge average time per line: 32us
As shown in the debug information above a decoded CANMessage in memory takes about 144 bytes. The typical can message in an ascii candump log file takes around 50 bytes. As such for text based log files you'll need roughly around 6x the size of the file free space in memory:
Ex: size of the file = 1
the_file(1) + the_spec_file_in_memory(1) + the_decoded_messages(3) + filtered_spec_in_memory(1) = 6 (Again its a rough estimate)
You'll also need more space to write the results to disk. How much will largely depend on your method of output.
As mentioned before the multithreaded version of the wasm wrapper requires the nightly unstable std library. This appears to work well for can logs under 10MB but it starts getting memory errors and exceptions for larger logs. As such its recommended to use the single threaded version. The single threaded version is still limited by the browser at least compared to native performance. It has successfully parsed files hundreds of MBs in size running in the browser but depending on the system, browser, and browser settings it may perform differently.
In the examples folder there is a python example showing python using the parsing library. Be sure to have compiled and installed the can_parser_python wheel before running the example. In addition there is a simple nextjs example project showing the wasm wrapper being used on a website. In this example the parser is ran in a separate web worker so that its not running it in the same worker that the graphics are being run on. This is not a requirement (it is for the multithreaded version) but it is a recommendation.
Features like OpenDBC support, UDS Parsing, Transport Session parsing, binary log parsing, and efficient chunk based parsing that can handle files that are too large to fit into memory are under consideration.
Contributions, suggestions, and insights are always welcome.