use crate::obd2::{decode_pid_response, OBD2Cmd, OBD2Command, OBD2DiagnosticServer};
use crate::{DiagError, DiagServerResult};
#[derive(Debug)]
pub struct Service09<'a> {
server: &'a mut OBD2DiagnosticServer,
support_list: Vec<bool>,
}
#[derive(Debug, Copy, Clone, Ord, PartialOrd, Eq, PartialEq)]
pub enum Service09Pid {
VinMsgCount,
Vin,
CalibrationIDMsgCount,
CalibrationID,
CvnMsgCount,
Cvn,
InUsePerfTracking,
EcuNameMsgCount,
EcuName,
Unknown(u8),
}
impl OBD2DiagnosticServer {
pub fn init_service_09(&mut self) -> DiagServerResult<Service09> {
let pid_support_list = self.exec_command(OBD2Cmd::new(OBD2Command::Service09, &[0x00]))?;
Ok(Service09 {
server: self,
support_list: decode_pid_response(&pid_support_list[2..]),
})
}
}
impl<'a> Service09<'a> {
pub fn get_supported_sids(&self) -> Vec<Service09Pid> {
let mut r = Vec::new();
for (pid, supported) in self.support_list.iter().enumerate() {
if *supported {
r.push(match pid + 1 {
0x01 => Service09Pid::VinMsgCount,
0x02 => Service09Pid::Vin,
0x03 => Service09Pid::CalibrationIDMsgCount,
0x04 => Service09Pid::CalibrationID,
0x05 => Service09Pid::CvnMsgCount,
0x06 => Service09Pid::Cvn,
0x08 => Service09Pid::InUsePerfTracking,
0x09 => Service09Pid::EcuNameMsgCount,
0x0A => Service09Pid::EcuName,
x => Service09Pid::Unknown(x as u8),
})
}
}
r
}
pub fn read_vin(&mut self) -> DiagServerResult<String> {
if !self.support_list[0x01] {
return Err(DiagError::NotSupported); }
let resp = self
.server
.exec_command(OBD2Cmd::new(OBD2Command::Service09, &[0x02]))?;
Ok(unsafe { String::from_utf8_unchecked(resp[3..].to_vec()) })
}
pub fn read_calibration_id(&mut self) -> DiagServerResult<Vec<String>> {
if !self.support_list[0x03] {
return Err(DiagError::NotSupported); }
let mut resp = self
.server
.exec_command(OBD2Cmd::new(OBD2Command::Service09, &[0x04]))?;
resp.drain(0..3);
return Ok(resp
.chunks(16)
.map(|c| String::from_utf8_lossy(c).to_string())
.collect());
}
pub fn read_cvn(&mut self) -> DiagServerResult<Vec<String>> {
if !self.support_list[0x05] {
return Err(DiagError::NotSupported); }
let mut resp = self
.server
.exec_command(OBD2Cmd::new(OBD2Command::Service09, &[0x06]))?;
resp.drain(0..3);
return Ok(resp
.chunks(4)
.map(|c| format!("{:02X}{:02X}{:02X}{:02X}", c[0], c[1], c[2], c[3]))
.collect());
}
}
#[cfg(test)]
pub mod service_09_test {
use crate::channel::IsoTPSettings;
use crate::hardware::socketcan::SocketCanScanner;
use crate::hardware::Hardware;
use crate::hardware::HardwareScanner;
use crate::obd2::{OBD2DiagnosticServer, Obd2ServerOptions};
#[test]
#[ignore] pub fn test_init() {
let scan = SocketCanScanner::new().open_device_by_name("can0").unwrap();
let socket = Hardware::create_iso_tp_channel(scan).unwrap();
let mut obd = OBD2DiagnosticServer::new_over_iso_tp(
Obd2ServerOptions {
send_id: 0x07E0,
recv_id: 0x07E8,
read_timeout_ms: 500,
write_timeout_ms: 500,
},
socket,
IsoTPSettings {
block_size: 8,
st_min: 20,
extended_addressing: false,
pad_frame: true,
can_speed: 500_000,
can_use_ext_addr: false,
},
)
.unwrap();
let mut s_09 = obd.init_service_09().unwrap();
println!("Supported Service_09 Pids: {:?}", s_09.get_supported_sids());
println!("VIN: {}", s_09.read_vin().unwrap());
println!("CID(s): {:?}", s_09.read_calibration_id().unwrap());
println!("CVN(s): {:?}", s_09.read_cvn().unwrap());
}
}