Skip to main content

can_utils_rs/
lib.rs

1//! # can-utils-rs
2//!
3//! `can-utils-rs` is a Rust library and CLI utility for working with
4//! **Linux SocketCAN interfaces**. It provides an interactive workflow
5//! for creating CAN interfaces and inspecting CAN traffic with a
6//! colorized CAN dump.
7//!
8//! The tool currently supports:
9//!
10//! - Creating and managing Linux CAN interfaces
11//! - Automatic installation of required system prerequisites
12//! - Pretty, colorized CAN frame dumping
13//!- Easy CAN frame sending once or cyclically
14//!
15//! The goal of this project is to provide a **friendlier and more visual
16//! alternative to common Linux CAN tools** such as `candump`, while still
17//! integrating seamlessly with the standard SocketCAN ecosystem.
18//!
19//! ---
20//!
21//! # Features
22//!
23//! ## CAN Interface Setup
24//!
25//! The interactive wizard helps configure CAN interfaces without needing
26//! to remember the exact Linux commands.
27//!
28//! Supported interface types:
29//!
30//! - **Native CAN** (`can0`, `can1`, …)
31//! - **SLCAN serial adapters** (`slcan0` via `slcand`)
32//! - **Virtual CAN** (`vcan0`) for development and simulation
33//!
34//! The tool previews the commands before executing them so users can see
35//! exactly what will happen.
36//!
37//! Example native CAN configuration:
38//!
39//! ```text
40//! sudo ip link set can0 up type can bitrate 500000
41//! ```
42//!
43//! ---
44//!
45//! ## Pretty CAN Dump
46//!
47//! The project includes a **colorized CAN dump utility** similar to
48//! Linux `candump`, but optimized for readability.
49//!
50//! Example output:
51//!
52//! ```text
53//! (1773430351.545039) vcan0 7FF#00 11 22 33 44 55 66
54//! ```
55//!
56//! Enhancements include:
57//!
58//! - colored timestamps
59//! - highlighted interface name
60//! - colored CAN IDs
61//! - **per-byte coloring of payload data**
62//!
63//! This makes it significantly easier to visually scan CAN traffic.
64//!
65//! ---
66//!
67//! ## Automatic Prerequisite Detection
68//!
69//! On startup the tool checks whether required system utilities exist.
70//!
71//! Missing prerequisites are detected automatically and the user is
72//! offered an option to install them.
73//!
74//! Example prompt:
75//!
76//! ```text
77//! Missing prerequisites:
78//!   - can-utils / slcand
79//!
80//! ? Some required tools are missing. What do you want to do?
81//! ❯ Install prerequisites
82//!   Continue anyway
83//!   Exit
84//! ```
85//!
86//! Installation currently supports **APT-based systems** (Debian / Ubuntu).
87//!
88//! ---
89//!
90//! # Supported CAN Interface Types
91//!
92//! ## Native CAN
93//!
94//! Configures a hardware CAN controller via SocketCAN.
95//!
96//! ```text
97//! sudo ip link set can0 up type can bitrate 500000
98//! ```
99//!
100//! Typical hardware:
101//!
102//! - PCI CAN adapters
103//! - USB SocketCAN adapters
104//! - Raspberry Pi CAN HATs
105//! - embedded CAN controllers
106//!
107//! ---
108//!
109//! ## SLCAN (Serial CAN)
110//!
111//! Serial CAN adapters using the `slcand` daemon.
112//!
113//! Example command sequence:
114//!
115//! ```text
116//! sudo slcand -c -o -f -s6 -t hw -S 3000000 /dev/ttyUSB0 slcan0
117//! sudo ip link set up slcan0
118//! ```
119//!
120//! ---
121//!
122//! ## Virtual CAN
123//!
124//! Virtual CAN interfaces are extremely useful for development,
125//! testing, and CI environments.
126//!
127//! ```text
128//! sudo ip link add dev vcan0 type vcan
129//! sudo ip link set up vcan0
130//! ```
131//!
132//! ---
133//!
134//! # CLI
135//! ## Installation
136//!
137//! Install the CLI locally with Cargo:
138//!
139//! ```text
140//! cargo install --path .
141//! ```
142//!
143//! Or install it from crates.io without needing to build from source:
144//! ```text
145//! cargo install can-utils-rs
146//! ```
147//!
148//! Then run:
149//!
150//! ```text
151//! can-utils-rs
152//! ```
153//!
154//! ---
155//!
156//! ## Demo
157//! Set-up and CAN dump
158//!
159//! ![can-utils-rs dump demo](demo/setup-and-dump.gif)
160//!
161//!
162//! CAN send and CAN dump
163//!
164//! ![can-utils-rs send and dump demo](demo/dump_and_send.gif)
165//!
166//! ---
167//!
168//! ## CLI Usage
169//!
170//! Running the binary launches an interactive menu.
171//!
172//! ```text
173//! $ can-utils-rs
174//!
175//! ? What do you want to do?
176//! ❯ Create or manage a CAN interface
177//!   Start pretty CAN dump
178//!   Create/manage CAN interface then start dump
179//!   Send CAN frame(s)
180//! ```
181//!
182//! The setup workflow asks for:
183//!
184//! - interface type
185//! - interface name
186//! - CAN bitrate
187//! - serial device (for SLCAN)
188//!
189//! Before applying changes the tool prints the commands that will run.
190//!
191//! ---
192//!
193//! # Use as a Library
194//! ## Import
195//! ```bash
196//! cargo add anyhow
197//! cargo add can-utils-rs
198//! ```
199//!
200//! ## Example
201//! Example for native CAN interface `can0`
202//! ```no_run
203//! use can_utils_rs::{CanConfig, NativeConfig, CanBitrate, setup};
204//!
205//!fn main() -> anyhow::Result<()> {
206//!    let config = CanConfig::Native(NativeConfig::new("can0".to_string(), CanBitrate::B500K));
207//!    setup::setup(config)?;
208//!    Ok(())
209//!
210//!    // Use your CAN interface with SocketCAN via socketcan crate
211//! }
212//!```
213//!
214//! # Interface Safety
215//!
216//! If an interface already exists the user is asked how to proceed:
217//!
218//! ```text
219//! Interface 'can0' already exists.
220//!
221//! ❯ Replace existing interface
222//!   Enter another interface name
223//!   Keep existing and skip setup
224//!   Cancel
225//! ```
226//!
227//! When using this crate as a library an existing interface with the same name will be replaced.
228//!
229//! When replacing an interface the tool will:
230//!
231//! - bring the interface down
232//! - remove it if necessary (`vcan` or `slcan`)
233//! - recreate the interface with the selected configuration
234//!
235//! ---
236//!
237//! # Linux Requirements
238//!
239//! The following system packages are required:
240//!
241//! ```text
242//! iproute2
243//! can-utils
244//! kmod
245//! ```
246//!
247//! For virtual CAN interfaces:
248//!
249//! ```text
250//! sudo modprobe vcan
251//! ```
252//!
253//! The tool can optionally install these automatically on supported systems.
254//!
255//! ---
256//!
257//! # Design
258//!
259//! The project is structured into modular subsystems:
260//!
261//! ```text
262//! setup::models   - shared configuration types
263//! setup::prompt   - interactive setup wizard
264//! setup::plan     - command planning / preview generation
265//! setup::exec     - command execution helpers
266//! setup::prereqs  - prerequisite detection and installation
267//!
268//! dump::format    - colored frame formatting
269//! dump::live      - live SocketCAN frame reader
270//! dump::mod       - dump orchestration and interface selection
271//! ```
272//!
273//! This architecture keeps setup logic, CAN traffic handling, and CLI
274//! interaction clearly separated.
275//!
276//! ---
277//!
278//! # License
279//!
280//! MIT
281//!
282//! ---
283use anyhow::Result;
284use inquire::Select;
285use std::fmt;
286
287pub use crate::setup::models::{
288    CanBitrate, CanConfig, CanMode, ExistingIfaceAction, InterfaceResolution, NativeConfig,
289    SlcanConfig, SlcanSpeed, VirtualConfig,
290};
291pub mod dump;
292pub mod send;
293pub mod setup;
294
295#[derive(Debug, Clone, Copy)]
296enum ToolAction {
297    Setup,
298    Dump,
299    SetupAndDump,
300    Send,
301}
302
303impl fmt::Display for ToolAction {
304    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
305        match self {
306            ToolAction::Setup => write!(f, "Create or manage a CAN interface"),
307            ToolAction::Dump => write!(f, "Start pretty CAN dump"),
308            ToolAction::SetupAndDump => {
309                write!(f, "Create/manage CAN interface then start dump")
310            }
311            ToolAction::Send => write!(f, "Send CAN frame(s)"),
312        }
313    }
314}
315
316pub fn run_interactive() -> Result<()> {
317    let action = Select::new(
318        "What do you want to do?",
319        vec![
320            ToolAction::Setup,
321            ToolAction::Dump,
322            ToolAction::SetupAndDump,
323            ToolAction::Send,
324        ],
325    )
326    .prompt()?;
327
328    match action {
329        ToolAction::Setup => {
330            setup::run_setup_from_cli()?;
331        }
332
333        ToolAction::Dump => {
334            dump::run_dump_wizard()?;
335        }
336
337        ToolAction::SetupAndDump => {
338            if let Some(config) = setup::run_setup_from_cli_and_return_config()? {
339                dump::run_dump(config.iface())?;
340            }
341        }
342        ToolAction::Send => {
343            send::run_send_wizard()?;
344        }
345    }
346
347    Ok(())
348}