Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for SLCAN devices #32

Merged
merged 2 commits into from
Sep 27, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ description = "A rust crate for ECU diagnostic servers and communication APIs"
license = "MIT"
repository = "https://github.com/rnd-ash/ecu_diagnostics"
readme = "README.md"
keywords = ["socketcan", "kwp2000", "uds", "j2534", "dpdu"]
keywords = ["socketcan", "kwp2000", "uds", "j2534", "dpdu", "slcan"]
exclude = [
"examples/*",
"build.rs",
Expand All @@ -22,9 +22,10 @@ all-features = true
targets = ["x86_64-unknown-linux-gnu", "i686-pc-windows-msvc", "x86_64-apple-darwin"]

[features]
default = ["passthru", "socketcan"]
default = ["passthru", "socketcan", "slcan"]
socketcan = ["dep:socketcan-isotp", "dep:socketcan"]
passthru = ["dep:libloading", "dep:shellexpand", "dep:winreg", "dep:serde_json", "dep:j2534_rust"]
slcan = ["dep:serial-rs"]

[dependencies]
#automotive_diag = { version = "0.1", path = "../automotive_diag" }
Expand All @@ -36,6 +37,7 @@ log="0.4.16"
strum = "0.26.3"
strum_macros = "0.26.4"
thiserror="1.0.44"
serial-rs = { version = "0.2.1", optional = true }

[dev-dependencies]
env_logger = "0.11.3"
Expand Down
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,10 @@ for creating Channels for diagnostic servers using the hardware
* ISO-TP
* CAN

### SLCAN
* ISO-TP
* CAN

### D-PDU (ISO 22900-2)
TBA

Expand Down
135 changes: 135 additions & 0 deletions examples/kwp_slcan.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
use std::time::Duration;

use automotive_diag::kwp2000::{KwpSessionType, KwpSessionTypeByte};
use serial_rs::{FlowControl, SerialPortSettings};

use ecu_diagnostics::{
channel::IsoTPSettings,
dynamic_diag::{
DiagProtocol, DiagServerAdvancedOptions, DiagServerBasicOptions, DiagServerEmptyLogger, DiagSessionMode, DynamicDiagSession, TimeoutConfig
},
hardware::Hardware,
kwp2000::Kwp2000Protocol,
};

extern crate ecu_diagnostics;
extern crate serial_rs;

fn ecu_waiting_hook() {
println!("Called hook! ECU is processing our request");
}

fn tx_ok_hook(data: &[u8]) {
println!(
"This {} long array was sent to the ECU OK!: {:02X?}",
data.len(),
data
);
}

fn print_diag_mode(server: &DynamicDiagSession) {
if let Some(mode) = server.get_current_diag_mode() {
println!(
"ECU is currently in '{}' diagnostic mode (0x{:02X?}). Tester present being sent?: {}",
mode.name, mode.id, mode.tp_require
);
}
}


fn main() {
env_logger::builder()
.format_timestamp(Some(env_logger::TimestampPrecision::Millis))
.init();

let port = serial_rs::new_from_path(
"/dev/cu.usbmodem90379201".into(),
Some(
SerialPortSettings::default()
.baud(2000000)
.read_timeout(Some(5))
.write_timeout(Some(100))
.set_flow_control(FlowControl::None)
.set_blocking(true),
),
).unwrap();

let mut d = ecu_diagnostics::hardware::slcan::device::SlCanDevice::new(port, 1000);

let isotp = d.create_iso_tp_channel().unwrap();

let mut protocol = Kwp2000Protocol::default();
println!("Diagnostic server is {}!", protocol.get_protocol_name());
// Register a custom diagnostic session with the protocol (Usually OEM specific)
protocol.register_session_type(DiagSessionMode {
id: 0x93,
tp_require: true,
name: "SuperSecretDiagMode".into(),
});

let mut diag_server = ecu_diagnostics::dynamic_diag::DynamicDiagSession::new_over_iso_tp(
protocol,
isotp,
IsoTPSettings {
// ISO-TP layer settings
block_size: 8,
st_min: 20,
extended_addresses: None,
pad_frame: true,
can_speed: 500_000,
can_use_ext_addr: false,
},
DiagServerBasicOptions {
// Basic server options
send_id: 0x07E1,
recv_id: 0x07E9,
timeout_cfg: TimeoutConfig {
read_timeout_ms: 2500,
write_timeout_ms: 2500,
},
},
Some(DiagServerAdvancedOptions {
// Advanced server options
global_tp_id: 0,
tester_present_interval_ms: 2000,
tester_present_require_response: true,
global_session_control: false,
tp_ext_id: None,
command_cooldown_ms: 100,
}),
DiagServerEmptyLogger{}
)
.unwrap();

// This call would work for KWP or UDS, not OBD2 as OBD2 has no form of 'session control'
if let Some(mode) = diag_server.get_current_diag_mode() {
println!(
"ECU is currently in '{}' diagnostic mode (0x{:02X?}). Tester present being sent?: {}",
mode.name, mode.id, mode.tp_require
);
}

// Register hook for when ECU responsds with RequestCorrectlyReceivedResponsePending
diag_server.register_waiting_hook(|| ecu_waiting_hook());
// Register hook for when our requests are sent to the ECU, but we have not got a response. Usually
// this can be used to just let the program know Tx was OK!
diag_server.register_send_complete_hook(|bytes| tx_ok_hook(bytes));
// Set diag session mode
let res = diag_server.kwp_set_session(KwpSessionType::ExtendedDiagnostics.into());
println!("Into extended diag mode result: {:?}", res);
// Now check diag session mode, should be extended
print_diag_mode(&diag_server);
let res = diag_server.kwp_set_session(KwpSessionTypeByte::from(0x93)); // Same ID as what we registered at the start
println!("Into special diag mode result: {:?}", res);
print_diag_mode(&diag_server);
println!("Reset result: {:?}", diag_server.kwp_reset_ecu(automotive_diag::kwp2000::ResetType::PowerOnReset));
print_diag_mode(&diag_server); // ECU should be in standard mode now as the ECU was rebooted
std::thread::sleep(Duration::from_millis(500));
println!("Read op: {:?}", diag_server.kwp_enable_normal_message_transmission());
print_diag_mode(&diag_server); // ECU will automatically be put into 0x93 mode
// (Last requested mode as enable_normal_message_transmission cannot be ran in standard mode)
loop {
// TP will be sent in this mode forever
std::thread::sleep(Duration::from_millis(1000));
}
}
45 changes: 45 additions & 0 deletions examples/slcan_can.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
use serial_rs::{FlowControl, SerialPortSettings};
use ecu_diagnostics::{channel::CanFrame, hardware::Hardware};

extern crate ecu_diagnostics;
extern crate serial_rs;

fn main() {
env_logger::builder()
.format_timestamp(Some(env_logger::TimestampPrecision::Millis))
.init();

let port = serial_rs::new_from_path(
"/dev/cu.usbmodem90379201".into(),
Some(
SerialPortSettings::default()
.baud(2000000)
.read_timeout(Some(1))
.write_timeout(Some(100))
.set_flow_control(FlowControl::None)
.set_blocking(true),
),
).unwrap();

let mut d = ecu_diagnostics::hardware::slcan::device::SlCanDevice::new(port, 1000);

let mut can = d.create_can_channel().unwrap();

can.set_can_cfg(83_333, false).unwrap();

can.open().unwrap();

let packets = can.read_packets(100, 500).unwrap();

for p in packets {
println!("{:02X?}", p);
}

can.write_packets(vec![CanFrame::new(0x5B4, vec![2, 0x10, 0x92, 0, 0,0,0].as_ref(), false)], 100).unwrap();

let packets = can.read_packets(100, 500).unwrap();

for p in packets {
println!("{:02X?}", p);
}
}
7 changes: 4 additions & 3 deletions src/hardware/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,14 @@ mod dpdu;
#[cfg(feature = "passthru")]
pub mod passthru; // Not finished at all yet, hide from the crate

#[cfg(feature = "passthru")]
use std::sync::Arc;
use std::{any::{Any, TypeId}, fmt::Debug, sync::{Mutex, PoisonError, RwLock}};
use std::{any::{Any, TypeId}, fmt::Debug, sync::{Arc, PoisonError, RwLock}};

#[cfg(all(feature="socketcan", target_os="linux"))]
pub mod socketcan;

#[cfg(feature = "slcan")]
pub mod slcan;

use crate::channel::{CanChannel, IsoTPChannel};

/// Hardware API result
Expand Down
Loading
Loading