MCPcopy Index your code
hub / github.com/I-CAN-hack/automotive

github.com/I-CAN-hack/automotive @v0.4.0

Chat with this repo
repository ↗ · DeepWiki ↗ · release v0.4.0 ↗ · + Follow
361 symbols 849 edges 45 files 85 documented · 24%
What it actually does AI analysis from the code graph — generated when you open this
loading…
README

The Automotive Crate

crates.io docs.rs

Welcome to the automotive crate documentation. The purpose of this crate is to help you with all things automotive related. Most importantly, it provides a fully async CAN interface supporting multiple adapters.

Async CAN Example

The following adapter opens the first available adapter on the system, and then receives all frames. Note how the sent frame is awaited, which waits until the message is ACKed on the CAN bus.

use automotive::StreamExt;
async fn can_example() -> automotive::Result<()> {
    let adapter = automotive::can::get_adapter()?;
    let mut stream = adapter.recv();

    let frame = automotive::can::Frame::new(0, 0x541.into(), &[0xff; 8])?;
    adapter.send(&frame).await;

    while let Some(frame) = stream.next().await {
        let id: u32 = frame.id.into();
        println!("[{}]\t0x{:x}\t{}", frame.bus, id, hex::encode(frame.data));
    }
    Ok(())
}

UDS Example

The automotive crate also supplies interfaces for various diagnostic protocols such as UDS. The adapter is first wrapped to support the ISO Transport Layer, then a UDS Client is created. All methods are fully async, making it easy to communicate with multiple ECUs in parallel. See automotive#21 for progress on the supported SIDs.

 async fn uds_example() -> automotive::Result<()> {
    let adapter = automotive::can::get_adapter()?;
    let isotp = automotive::isotp::IsoTPAdapter::from_id(&adapter, 0x7a1);
    let uds = automotive::uds::UDSClient::new(&isotp);

    uds.tester_present().await.unwrap();
    let response = uds.read_data_by_identifier(automotive::uds::DataIdentifier::ApplicationSoftwareIdentification as u16).await?;

    println!("Application Software Identification: {}", hex::encode(response));
    Ok(())
 }

CAN Adapters

The following CAN adapters are supported.

Supported CAN adapters

  • SocketCAN (Linux only, enable with the socketcan feature)
  • comma.ai panda (all platforms using rusb, enable with the panda feature)
  • J2534 PassThru Devices (Windows only, enable with the j2534 feature)
  • Vector Devices (Windows x64 only, enable with the vector-xl feature)

Adapter support is opt-in. The default feature set does not enable any hardware adapters.

Known limitations / Notes

This library has some unique features that might expose (performance) issues in drivers you wouldn't otherwise notice, so check the list of known limitations below.

This library supports awaiting a sent frame and waiting for the ACK on the CAN bus. This requires receiving these ACKs from the adapter, and matching them to the appropriate sent frame. This requires some level of hardware support that is not offered by all adapters/drivers. If this is not supported by the driver, an ACK will be simulated as soon as the frame is transmitted, but this can cause issues if precise timing is needed.

  • SocketCAN Devices
  • SocketCAN drivers without IFF_ECHO: This class of SocketCAN drivers has no hardware support for notifying the driver when a frame was ACKed. This is instead emulated by the Linux kernel. Due to transmitted frames immediately being received again this can cause the receive queue to fill up if more than 476 (default RX queue size on most systems) are transmitted in one go. To solve this we implement emulated ACKs ourself, instead of relying on the ACKs from the kernel.
  • PCAN-USB: The Peak CAN adapters have two drivers:
    • Kenel built in driver (peak_usb). The kernel driver properly implements IFF_ECHO, but has a rather small TX queue. This should not cause any issues, but it can be increased with ifconfig can0 txqueuelen <size>.
    • Out-of-tree driver (pcan) that can be downloaded from Peak System's website. The out-of-tree driver is not recommended as it does not implement IFF_ECHO.
  • neoVI/ValueCAN: Use of Intrepid Control System's devices is not recommended due to issues in their SocketCAN driver. If many frames are transmitted simultaneously it will cause the whole system/kernel to hang. intrepid-socketcan-kernel-module#20 tracks this issue.
  • comma.ai panda
  • The panda does not retry frames that are not ACKed, and drops them instead. This can cause panics in some internal parts of the library when frames are dropped. panda#1922 tracks this issue.
  • J2534 PassThru Devices are supported through the j2534 feature. The library provides J2534CanAdapter for raw CAN access, and J2534NativeIsoTpTransport to offload ISO-TP framing, flow-control, and timing to the adapter. It is recommended to use J2534CanAdapter unless you have specific speed or latency requirements.
  • Vector Devices are supported through the Vector XL Driver Library, and support can be enabled using the vector-xl feature. Make sure to distribute vxlapi64.dll alongside your application.

Implementing a New Adapter

Implementing a new adapter is done by implementing the CanAdapter Trait. Hardware implementations can be blocking, as the AsyncCanAdapter takes care of presenting an async interface to the user. The library makes some assumptions around sending/receiving frames. These assumption are also verified by the tests in tests/adapter_tests.rs.

  • The send function takes a &mut VecDequeue of frames. Frames to be sent are taken from the front of this queue. If there is no space in the hardware or driver buffer to send out all messages it's OK to return before the queue is fully empty. If an error occurs make sure to put the message back at the beginning of the queue and return.
  • The hardware or driver is free to prioritize sending frames with a lower Arbitration ID to prevent priority inversion. However frames with the same Arbitration ID need to be send out on the CAN bus in the same order as they were queued. This assumption is needed to match a received ACK to the correct frame.
  • Once a frame is ACKed it should be put in the receive queue with the loopback flag set. The AsyncCanAdapter wrapper will take care of matching it against the right transmit frame and resolving the Future. If this is not supported by the underlying hardware, this can be faked by looping back all transmitted frames immediately.

## Roadmap Features I'd like to add in the future. Also check the issues page. - CCP/XCP Client - Update file extraction (e.g. .frf and .odx) - VIN Decoding - More device support - WebUSB support - Python bindings

Extension points exported contracts — how you extend this code

CanAdapter (Interface)
Trait for a Blocking CAN Adapter [6 implementers]
src/can/mod.rs
TransportLayer (Interface)
Abstraction over anything that can exchange diagnostic PDUs over a transport layer. Two implementations ship with this [2 …
src/isotp/mod.rs

Core symbols most depended-on inside this repo

build
called by 32
src/can/bitrate.rs
bitrate
called by 30
src/can/bitrate.rs
sample_point
called by 18
src/can/bitrate.rs
send
called by 15
src/can/async_can.rs
vxlapi64
called by 13
src/vector/vxlapi.rs
request
called by 12
src/uds/mod.rs
recv
called by 9
src/can/async_can.rs
data_bitrate
called by 8
src/can/bitrate.rs

Shape

Method 155
Function 138
Class 34
Enum 32
Interface 2

Languages

Rust99%
Python1%

Modules by API surface

src/can/bitrate.rs60 symbols
src/isotp/mod.rs29 symbols
src/panda/mod.rs27 symbols
src/j2534/common.rs26 symbols
src/uds/mod.rs19 symbols
tests/adapter_tests.rs18 symbols
src/socketcan/socket.rs16 symbols
tests/isotp_tests.rs15 symbols
src/j2534/isotp_adapter.rs15 symbols
src/vector/vxlapi.rs14 symbols
src/j2534/can_adapter.rs11 symbols
src/can/mod.rs10 symbols

For agents

$ claude mcp add automotive \
  -- python -m otcore.mcp_server <graph>

⬇ download graph artifact

Ask about this repo answers extend the page