A cross-platform crate with FFI bindings to allow for complex vehicle ECU diagnostics.

Overview

ecu_diagnostics

Documentation Crates.io License

A cross-platform crate with FFI bindings to allow for complex vehicle ECU diagnostics.

IMPORTANT

Currently this crate is not 100% ready for use. Check the feature matrix below for each diagnostic server's checklist

Features

  • Easy to use (Check the examples folder for UDS server usage with SocketCAN)
  • Implements UDS, KWP2000 and OBD2
  • FFI bindings for use in C/C++ projects! (Check the examples folder)
  • Safe to use (Cannot inadvertently send incorrect requests to the ECU)
  • Parsing support - Where possible, data is returned in data structures, being interpreted from the ECU's response, rather than just bytes which have to be manually interpreted
  • ISO-TP transport layer, LIN, J1850 and DoIP is work in progress at this time
  • Diagnostic servers (For KWP2000 and UDS) automatically handle disconnects from ECU
  • Optional diagnostic server event receiving for logging internal server events

A quick overview of diagnostic servers used by ECUs

On-board diagnostics (OBD2)

ISO9141 - OBD2 is a legal requirement on all vehicles produced from 2002, allowing for reading of sensor data, reading and clearing standard DTCs, and reading basic vehicle information. OBD2 is designed to be safe and simple, and does not write data to the ECU.

Keyword protocol 2000 (KWP2000)

ISO14230 - KWP2000 is a advanced diagnostic protocol utilized by many vehicle manufacturers from 2000-2006 (Superseded by UDS). Unlike OBD2, KWP2000 allows for much more complex operations, which could potentially cause damage to a vehicle if used incorrectly.
A few examples of features allowed by KWP2000 are

  • ECU flashing
  • Clearing and reading of permanent DTCs
  • Manipulation of ECU communication parameters
  • Low level manipulation of ECU's EEPROM or RAM
  • Gateway access in vehicles which have them

The specification implemented in this crate is v2.2, dated 05-08-2002

Unified diagnostic services (UDS)

ISO14429 - UDS is an advanced diagnostic protocol utilized by almost all vehicle manufacturers from 2006 onwards. Like KWP2000, this protocol allows for reading/writing directly to the ECU, and should therefore be used with caution.

The specification implemented in this crate is the second edition, dated 01-12-2006.

Diagnostic server checklist

OBD2

TBA

KWP2000

Custom service support: YES

Working specification services:

  • StartDiagnosticSession
  • ECUReset
  • ReadDTCByStatus
  • ReadECUIdentification
  • ReadStatusOfDTC
  • ClearDiagnosticInformation

UDS

Custom service support: YES

Working specification services:

  • DiagnosticSessionControl
  • ECUReset
  • ReadDTCInformation
  • SecurityAccess
Comments
  • Hardware support

    Hardware support

    I'm assuming this currently only supports the Macchina A0/M2 for OSX/Linux usage?

    The M2 seems to be out of stock everywhere unfortunately which makes using this library a bit difficult.

    opened by tayler-king 3
  • Feature gate hardware implementations

    Feature gate hardware implementations

    👋 Hey,

    I'm trying to use this crate on a embedded device, and we don't have support for libloading.

    This PR hides the hardware implementations behind feature flags so that they can be enabled conditionally.

    Additionally it removes the env_logger dependency, but that's just because its not used anywhere in the project.

    opened by afonso360 1
  • the project does not compile

    the project does not compile

    this language is new to me, build error is -

    warning: unused imports:BorrowMut,Borrow,LockResult,cell::RefCell,convert::TryInto,default--> src\hardware\passthru\mod.rs:22:14 | 22 | borrow::{Borrow, BorrowMut}, | ^^^^^^ ^^^^^^^^^ 23 | cell::RefCell, | ^^^^^^^^^^^^^ 24 | convert::TryInto, | ^^^^^^^^^^^^^^^^ 25 | default, | ^^^^^^^ 26 | ffi::c_void, 27 | sync::{Arc, LockResult, Mutex, PoisonError}, | ^^^^^^^^^^ | = note:#[warn(unused_imports)]` on by default

    warning: unused import: RegValue --> src\hardware\passthru\mod.rs:35:22 | 35 | use winreg::{RegKey, RegValue}; | ^^^^^^^^

    warning: unused import: RwLock --> src\hardware\passthru\lib_funcs.rs:5:22 | 5 | use std::sync::{Arc, RwLock}; | ^^^^^^

    warning: unused import: winreg::enums::* --> src\hardware\passthru\lib_funcs.rs:9:5 | 9 | use winreg::enums::*; | ^^^^^^^^^^^^^^^^

    warning: unused imports: RegKey, RegValue --> src\hardware\passthru\lib_funcs.rs:12:14 | 12 | use winreg::{RegKey, RegValue}; | ^^^^^^ ^^^^^^^^

    warning: unused variable: x --> src\hardware\passthru\mod.rs:811:13 | 811 | fn from(x: PoisonError) -> Self { | ^ help: if this is intentional, prefix it with an underscore: _x | = note: #[warn(unused_variables)] on by default

    warning: unused variable: x --> src\hardware\passthru\mod.rs:820:13 | 820 | fn from(x: PoisonError) -> Self { | ^ help: if this is intentional, prefix it with an underscore: _x

    warning: variable does not need to be mutable --> src\kwp2000\read_dtc_by_status.rs:90:9 | 90 | let mut res: Vec = Vec::new(); | ----^^^ | | | help: remove this mut | = note: #[warn(unused_mut)] on by default

    warning: associated function is never used: get_version --> src\hardware\passthru\lib_funcs.rs:291:12 | 291 | pub fn get_version(&self, dev_id: u32) -> PassthruResult { | ^^^^^^^^^^^ | = note: #[warn(dead_code)] on by default

    warning: associated function is never used: stop_msg_filter --> src\hardware\passthru\lib_funcs.rs:439:12 | 439 | pub fn stop_msg_filter(&self, channel_id: u32, filter_id: u32) -> PassthruResult<()> { | ^^^^^^^^^^^^^^^

    warning: unused Result that must be used --> src\hardware\passthru\mod.rs:464:17 | 464 | self.close(); | ^^^^^^^^^^^^^ | = note: #[warn(unused_must_use)] on by default = note: this Result may be an Err variant, which should be handled

    warning: unused Result that must be used --> src\hardware\passthru\mod.rs:636:17 | 636 | self.close(); | ^^^^^^^^^^^^^ | = note: this Result may be an Err variant, which should be handled

    warning: 12 warnings emitted`

    opened by carik-car 1
  • Software ISOTP channels

    Software ISOTP channels

    This is a specific fix for Passthru devices.

    This allows for a software based ISO-TP channel to be used, allowing for both CAN+ISOTP communication protocols to be used at the same time.

    This is because with the Passthru J2534 API, ISOTP and CAN are listed as conflicting channels, meaning both cannot be run at the same time

    opened by rnd-ash 0
  • Software based ISO-TP channel

    Software based ISO-TP channel

    Taking inspiration from the D-PDU API, It is probably best to convert the Passthru ISO-TP methodology to software driven.

    Currently, Passthru device opens a dedicated ISO-TP channel at a hardware level. This is good for performance, but it means that a dedicated CAN Channel cannot be opened at the same time as they conflict one another.

    One down side to this method is it means it is impossible for the tester to send keep alive CAN messages to other ECUs in a vehicle whilst trying to maintain an ISO-TP channel with a target ECU.

    Therefore, it is best to create a software ISO-TP channel, which uses a PT CAN channel to operate on. This will allow both ISO-TP messages and regular CAN messages to be exchanged at the same time.

    opened by rnd-ash 0
  • Add global bus session control for KWP

    Add global bus session control for KWP

    On some older cars that utilize KWP, the ECU will never respond to session control operations, instead, it is required that the tester sends session control on the global bus can ID, which puts EVERY ECU on the network into the specified session mode

    opened by rnd-ash 0
  • UDSCommand missing services

    UDSCommand missing services

    Going based off Wikipedia (again, sorry I don't have access to the official standard), it appears the UDSCommand enum is missing SID 0x29 (Authentication) and 0x38 (Request File Transfer). If you have access to the standard, can you please check it to see if these are actually missing standard services?

    opened by camercu 1
  • OBD2 CAN IDs not matching spec

    OBD2 CAN IDs not matching spec

    Background

    According to Wikipedia (sorry I don't have access to the actual OBD-II specification):

    The PID query and response occurs on the vehicle's CAN bus. Standard OBD requests and responses use functional addresses. The diagnostic reader initiates a query using CAN ID 7DFh, which acts as a broadcast address, and accepts responses from any ID in the range 7E8h to 7EFh. ECUs that can respond to OBD queries listen both to the functional broadcast ID of 7DFh and one assigned ID in the range 7E0h to 7E7h. Their response has an ID of their assigned ID plus 8 e.g. 7E8h through 7EFh.

    This approach allows up to eight ECUs, each independently responding to OBD queries. The diagnostic reader can use the ID in the ECU response frame to continue communication with a specific ECU. In particular, multi-frame communication requires a response to the specific ECU ID rather than to ID 7DFh.

    This library's current code has you specify a sid/did (tx_id, rx_id) for OBD messages, and uses a single socket (socketCAN ISO-TP kernel interface) to handle sending/receiving messages on just those addresses. However, this causes problems when running against vehicles that follow the spec.

    Observed Behavior

    On a 2020 Toyota Camry, I tested Service_09::get_vin(), but it causes a timeout error. The reason is that if I set the tx_id to 0x7df, I get the first frame back from the ECU (with CAN ID 0x7e8), but the ECU pauses and waits for a FlowControl frame to be sent with CAN ID 0x7e0 (8 less than the ECU's transmit ID). The ISO-TP kernel sends flow control using the original broadcast address, 0x7df, which the ECU ignores. If I set the tx_id to 0x7e0 and request the VIN, the ECU completely ignores the request.

    Other Implementations

    I have a scan tool that sends the OBD messages properly, and I looked at the example code for Comma.ai's Panda, and they also send the request to 0x7df and listen on 0x7e8 (which sends the FC frame using ID 0x7e0). Their handling of UDS protocol does similar filtering to ensure the tx addr is changed from 0x7df to something in the range 0x7e0-0x7e7 (based on the first response received).

    Proposed Design

    The OBD code should have a single transmit socket with tx_id = 0x7df, and eight listening sockets with rx_id in the range 0x7e8 - 0x7ef (and tx_id for FC frames set to a value that is 8 less than the rx_id). This would follow the specification, allowing 8 ECUs to respond to OBD queries simultaneously. If it is a simple request, like to get the VIN, then that function can just take the first response and return it. In order for this to be possible, you will first have to implement the suggestion in Issue #11 to have a software-based ISO-TP channel. The socketcan-isotp crate definitely supports this, as demonstrated in their examples.

    bug 
    opened by camercu 3
  • J2534-2 API version 05.00 support

    J2534-2 API version 05.00 support

    Currently, this crate only supports version 04.04 of the J2534-2 API.

    There is a recent addition to the J2534-2 API version 05.00: SAE documentation link

    enhancement 
    opened by rnd-ash 0
  • J2534-2 implement CAN_MIXED_FORMAT

    J2534-2 implement CAN_MIXED_FORMAT

    Needed for some J2534 devices for ISO-TP.

    When an ECU responds with an ISO-TP frame that is not padded with 00 eg:

    01A4: [02 10 20 76 54 32 10 99]
    

    The adapter will reject this frame as ISO-TP as it expected the following formatted message:

    01A4: [02 10 20 00 00 00 00 00]
    

    Sending an IOCTL SET_CONFIG request of CAN_MIXED_FORMAT to the adapters ISO-TP channel will allow it to read and accept these ISO-TP frames

    bug 
    opened by rnd-ash 0
Owner
Ashcon Mohseninia
Undergraduate student at University of Reading
Ashcon Mohseninia
Automatically generates Rust FFI bindings to C (and some C++) libraries.

bindgen bindgen automatically generates Rust FFI bindings to C (and some C++) libraries. For example, given the C header doggo.h: typedef struct Doggo

The Rust Programming Language 3.2k Jan 4, 2023
libc - Raw FFI bindings to platforms' system libraries

libc provides all of the definitions necessary to easily interoperate with C code (or "C-like" code) on each of the platforms that Rust supports. This includes type definitions (e.g. c_int), constants (e.g. EINVAL) as well as function headers (e.g. malloc).

The Rust Programming Language 1.5k Jan 1, 2023
Handy macro to generate C-FFI bindings to Rust for Haskell

hs-bindgen Handy macro to generate C-FFI bindings to Rust for Haskell. This library intended to work best in a project configured by cargo-cabal. N.B.

Yvan Sraka 32 Feb 16, 2023
Rust in Haskell FFI Example

Provides an example for using Rust in Haskell. To use this you'll need cargo, rustc, cabal and GHC installed. To execute the example run the following

Michael Gattozzi 21 Oct 1, 2022
A safe Rust FFI binding for the NVIDIA® Tools Extension SDK (NVTX).

NVIDIA® Tools Extension SDK (NVTX) is a C-based Application Programming Interface (API) for annotating events, code ranges, and resources in your applications. Official documentation for NVIDIA®'s NVTX can be found here.

Spencer Imbleau 78 Jan 2, 2023
Rust Attribute-Based Encryption library rabe's C FFI binding , support CP-ABE and KP-ABE encrypt and decrypt, submodule of Rabe.Core c# library.

Rabe-ffi Rust Attribute-Based Encryption library rabe's C FFI binding , support CP-ABE and KP-ABE encrypt and decrypt, submodule of Rabe.Core c# libra

Aya0wind 2 Oct 10, 2022
A simple library to allow for easy use of python from rust.

Rustpy A simple library to allow for easy use of python from rust. Status Currently this library has not received much love (pull requests welcome for

Luke 74 Jun 20, 2022
🐱‍👤 Cross-language static library for accessing the Lua state in Garry's Mod server plugins

gmserverplugin This is a utility library for making Server Plugins that access the Lua state in Garry's Mod. Currently, accessing the Lua state from a

William 5 Feb 7, 2022
A project for generating C bindings from Rust code

cbindgen   Read the full user docs here! cbindgen creates C/C++11 headers for Rust libraries which expose a public C API. While you could do this by h

Ryan Hunt 1.7k Jan 3, 2023
Rust-JDBC bindings

jdbc A Rust library that allows you to use JDBC and JDBC drivers. Usage First, add the following to your Cargo.toml: [dependencies] jdbc = "0.1" Next,

Aurora 18 Feb 9, 2022
Lua 5.3 bindings for Rust

rust-lua53 Aims to be complete Rust bindings for Lua 5.3 and beyond. Currently, master is tracking Lua 5.3.3. Requires a Unix-like environment. On Win

J.C. Moyer 150 Dec 14, 2022
Safe Rust bindings to Lua 5.1

rust-lua Copyright 2014 Lily Ballard Description This is a set of Rust bindings to Lua 5.1. The goal is to provide a (relatively) safe interface to Lu

Lily Ballard 124 Jan 5, 2023
mruby safe bindings for Rust

mrusty. mruby safe bindings for Rust mrusty lets you: run Ruby 1.9 files with a very restricted API (without having to install Ruby) reflect Rust stru

Anima 200 Oct 12, 2022
Rust bindings for writing safe and fast native Node.js modules.

Rust bindings for writing safe and fast native Node.js modules. Getting started Once you have the platform dependencies installed, getting started is

The Neon Project 7k Jan 4, 2023
Objective-C Runtime bindings and wrapper for Rust.

Objective-C Runtime bindings and wrapper for Rust. Documentation: http://ssheldon.github.io/rust-objc/objc/ Crate: https://crates.io/crates/objc Messa

Steven Sheldon 336 Jan 2, 2023
High-level Rust bindings to Perl XS API

Perl XS for Rust High-level Rust bindings to Perl XS API. Example xs! { package Array::Sum; sub sum_array(ctx, array: AV) { array.iter().map(|

Vickenty Fesunov 59 Oct 6, 2022
Rust <-> Python bindings

rust-cpython Rust bindings for the python interpreter. Documentation Cargo package: cpython Copyright (c) 2015-2020 Daniel Grunwald. Rust-cpython is l

Daniel Grunwald 1.7k Dec 29, 2022
Rust bindings for the Python interpreter

PyO3 Rust bindings for Python. This includes running and interacting with Python code from a Rust binary, as well as writing native Python modules. Us

PyO3 7.2k Jan 4, 2023
Safe Rust <---> GraalVM Polyglot bindings using procedural macros

The class macro is the primary way to generate bindings to Java types; it will generate a struct (with generics if specified) that implements Pass and Receive and has all the methods you give stubs for. The methods generated can be used like normal rust methods, however mutability is not enforced. The fully-qualified type name should precede a block containing method and constructor stubs. Java primitives like char, int, and byte are aliased to corresponding Rust types.

Alec Petridis 33 Dec 28, 2022