j2534_rust/
lib.rs

1#[macro_use]
2extern crate bitflags;
3use std::{fmt::Display, convert::TryFrom};
4
5// SAE J2534 API definition,
6// Based on J2534.h
7
8#[repr(u32)]
9#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
10#[allow(non_camel_case_types, dead_code)]
11pub enum Protocol {
12    J1850VPW = 0x01,
13    J1850PWM = 0x02,
14    ISO9141 = 0x03,
15    ISO14230 = 0x04,
16    CAN = 0x05,
17    ISO15765 = 0x06,
18    SCI_A_ENGINE = 0x07,
19    SCI_A_TRANS = 0x08,
20    SCI_B_ENGINE = 0x09,
21    SCI_B_TRANS = 0x0A,
22}
23
24impl TryFrom<u32> for Protocol {
25    type Error = ();
26
27    fn try_from(value: u32) -> Result<Self, Self::Error> {
28        Ok(match value {
29            0x01 => Protocol::J1850VPW,
30            0x02 => Protocol::J1850PWM,
31            0x03 => Protocol::ISO9141,
32            0x04 => Protocol::ISO14230,
33            0x05 => Protocol::CAN,
34            0x06 => Protocol::ISO15765,
35            0x07 => Protocol::SCI_A_ENGINE,
36            0x08 => Protocol::SCI_A_TRANS,
37            0x09 => Protocol::SCI_B_ENGINE,
38            0x0A => Protocol::SCI_B_TRANS,
39            _ => return Err(())
40        })
41    }
42}
43
44impl Display for Protocol {
45    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
46        f.write_str(match &self {
47            Protocol::J1850VPW => "J1850 VPW",
48            Protocol::J1850PWM => "J1850 PWM",
49            Protocol::ISO9141 => "ISO 9141",
50            Protocol::ISO14230 => "ISO 14230",
51            Protocol::CAN => "CAN",
52            Protocol::ISO15765 => "ISO 15765",
53            Protocol::SCI_A_ENGINE => "SCI A ENGINE",
54            Protocol::SCI_A_TRANS => "SCI A TRANS",
55            Protocol::SCI_B_ENGINE => "SCI B ENGINE",
56            Protocol::SCI_B_TRANS => "SCI B TRANS",
57        })
58    }
59}
60
61#[repr(u32)]
62#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
63#[allow(non_camel_case_types, dead_code)]
64pub enum IoctlID {
65    GET_CONFIG = 0x01,
66    SET_CONFIG = 0x02,
67    READ_VBATT = 0x03,
68    FIVE_BAUD_INIT = 0x04,
69    FAST_INIT = 0x05,
70    CLEAR_TX_BUFFER = 0x07,
71    CLEAR_RX_BUFFER = 0x08,
72    CLEAR_PERIODIC_MSGS = 0x09,
73    CLEAR_MSG_FILTERS = 0x0A,
74    CLEAR_FUNCT_MSG_LOOKUP_TABLE = 0x0B,
75    ADD_TO_FUNCT_MSG_LOOKUP_TABLE = 0x0C,
76    DELETE_FROM_FUNCT_MSG_LOOKUP_TABLE = 0x0D,
77    READ_PROG_VOLTAGE = 0x0E,
78}
79
80impl TryFrom<u32> for IoctlID {
81    type Error = ();
82
83    fn try_from(value: u32) -> Result<Self, Self::Error> {
84        Ok(match value {
85            0x01 => IoctlID::GET_CONFIG,
86            0x02 => IoctlID::SET_CONFIG,
87            0x03 => IoctlID::READ_VBATT,
88            0x04 => IoctlID::FIVE_BAUD_INIT,
89            0x05 => IoctlID::FAST_INIT,
90            0x06 => IoctlID::CLEAR_TX_BUFFER,
91            0x07 => IoctlID::CLEAR_RX_BUFFER,
92            0x08 => IoctlID::CLEAR_PERIODIC_MSGS,
93            0x09 => IoctlID::CLEAR_MSG_FILTERS,
94            0x0A => IoctlID::CLEAR_FUNCT_MSG_LOOKUP_TABLE,
95            0x0B => IoctlID::ADD_TO_FUNCT_MSG_LOOKUP_TABLE,
96            0x0D => IoctlID::DELETE_FROM_FUNCT_MSG_LOOKUP_TABLE,
97            0x0E => IoctlID::READ_PROG_VOLTAGE,
98            _ => return Err(())
99        })
100    }
101}
102
103impl std::fmt::Display for IoctlID {
104    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
105        f.write_str(format!("{:?}", self).as_str())
106    }
107}
108
109#[repr(u32)]
110#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
111#[allow(non_camel_case_types, dead_code)]
112pub enum IoctlParam {
113    DATA_RATE = 0x01,
114    LOOPBACK = 0x03,
115
116    NODE_ADDRESS = 0x04,
117    NETWORK_LINE = 0x05,
118    P1_MIN = 0x06,
119    P1_MAX = 0x07,
120    P2_MIN = 0x08,
121    P2_MAX = 0x09,
122    P3_MIN = 0x0A,
123    P3_MAX = 0x0B,
124    P4_MIN = 0x0C,
125    P4_MAX = 0x0D,
126    W1 = 0x0E,
127    W2 = 0x0F,
128    W3 = 0x10,
129    W4 = 0x11,
130    W5 = 0x12,
131
132    TIDLE = 0x13,
133    TINL = 0x14,
134    TWUP = 0x15,
135    PARITY = 0x16,
136    BIT_SAMPLE_POINT = 0x17,
137    SYNCH_JUMP_WIDTH = 0x18,
138    W0 = 0x19,
139    T1_MAX = 0x1A,
140    T2_MAX = 0x1B,
141    T4_MAX = 0x1C,
142    T5_MAX = 0x1D,
143    ISO15765_BS = 0x1E,
144    ISO15765_STMIN = 0x1F,
145
146    DATA_BITS = 0x20,
147    FIVE_BAUD_MOD = 0x21,
148    BS_TX = 0x22,
149    STMIN_TX = 0x23,
150    T3_MAX = 0x24,
151    ISO15765_WFT_MAX = 0x25,
152    CAN_MIXED_FORMAT = 0x8000
153}
154
155impl TryFrom<u32> for IoctlParam {
156    type Error = ();
157
158    fn try_from(value: u32) -> Result<Self, Self::Error> {
159        Ok(match value {
160            0x01 => IoctlParam::DATA_RATE,
161            0x03 => IoctlParam::LOOPBACK,
162            0x04 => IoctlParam::NODE_ADDRESS,
163            0x05 => IoctlParam::NETWORK_LINE,
164            0x06 => IoctlParam::P1_MIN,
165            0x07 => IoctlParam::P1_MAX,
166            0x08 => IoctlParam::P2_MIN,
167            0x09 => IoctlParam::P2_MAX,
168            0x0A => IoctlParam::P3_MIN,
169            0x0B => IoctlParam::P3_MAX,
170            0x0C => IoctlParam::P4_MIN,
171            0x0D => IoctlParam::P4_MAX,
172            0x0E => IoctlParam::W1,
173            0x0F => IoctlParam::W2,
174            0x10 => IoctlParam::W3,
175            0x11 => IoctlParam::W4,
176            0x12 => IoctlParam::W5,
177            0x13 => IoctlParam::TIDLE,
178            0x14 => IoctlParam::TINL,
179            0x15 => IoctlParam::TWUP,
180            0x16 => IoctlParam::PARITY,
181            0x17 => IoctlParam::BIT_SAMPLE_POINT,
182            0x18 => IoctlParam::SYNCH_JUMP_WIDTH,
183            0x19 => IoctlParam::W0,
184            0x1A => IoctlParam::T1_MAX,
185            0x1B => IoctlParam::T2_MAX,
186            0x1C => IoctlParam::T4_MAX,
187            0x1D => IoctlParam::T5_MAX,
188            0x1E => IoctlParam::ISO15765_BS,
189            0x1F => IoctlParam::ISO15765_STMIN,
190            0x20 => IoctlParam::DATA_BITS,
191            0x21 => IoctlParam::FIVE_BAUD_MOD,
192            0x22 => IoctlParam::BS_TX,
193            0x23 => IoctlParam::STMIN_TX,
194            0x24 => IoctlParam::T3_MAX,
195            0x25 => IoctlParam::ISO15765_WFT_MAX,
196            0x8000 => IoctlParam::CAN_MIXED_FORMAT,
197            _ => return Err(())
198        })
199    }
200}
201
202impl std::fmt::Display for IoctlParam {
203    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
204        f.write_str(format!("{:?}", self).as_str())
205    }
206}
207
208#[repr(u32)]
209#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
210#[allow(non_camel_case_types, dead_code)]
211pub enum PassthruError {
212    STATUS_NOERROR = 0x00,
213    ERR_NOT_SUPPORTED = 0x01,
214    ERR_INVALID_CHANNEL_ID = 0x02,
215    ERR_INVALID_PROTOCOL_ID = 0x03,
216    ERR_NULL_PARAMETER = 0x04,
217    ERR_INVALID_IOCTL_VALUE = 0x05,
218    ERR_INVALID_FLAGS = 0x06,
219    ERR_FAILED = 0x07,
220    ERR_DEVICE_NOT_CONNECTED = 0x08,
221    ERR_TIMEOUT = 0x09,
222
223    ERR_INVALID_MSG = 0x0A,
224    ERR_INVALID_TIME_INTERVAL = 0x0B,
225    ERR_EXCEEDED_LIMIT = 0x0C,
226    ERR_INVALID_MSG_ID = 0x0D,
227    ERR_DEVICE_IN_USE = 0x0E,
228    ERR_INVALID_IOCTL_ID = 0x0F,
229    ERR_BUFFER_EMPTY = 0x10,
230    ERR_BUFFER_FULL = 0x11,
231    ERR_BUFFER_OVERFLOW = 0x12,
232    ERR_PIN_INVALID = 0x13,
233    ERR_CHANNEL_IN_USE = 0x14,
234    ERR_MSG_PROTOCOL_ID = 0x15,
235
236    ERR_INVALID_FILTER_ID = 0x16,
237    ERR_NO_FLOW_CONTROL = 0x17,
238    ERR_NOT_UNIQUE = 0x18,
239    ERR_INVALID_BAUDRATE = 0x19,
240    ERR_INVALID_DEVICE_ID = 0x1A,
241}
242
243impl TryFrom<u32> for PassthruError {
244    type Error = ();
245
246    fn try_from(value: u32) -> Result<Self, Self::Error> {
247        Ok(match value {
248            0x00 => PassthruError::STATUS_NOERROR,
249            0x01 => PassthruError::ERR_NOT_SUPPORTED,
250            0x02 => PassthruError::ERR_INVALID_CHANNEL_ID,
251            0x03 => PassthruError::ERR_INVALID_PROTOCOL_ID,
252            0x04 => PassthruError::ERR_NULL_PARAMETER,
253            0x05 => PassthruError::ERR_INVALID_IOCTL_VALUE,
254            0x06 => PassthruError::ERR_INVALID_FLAGS,
255            0x07 => PassthruError::ERR_FAILED,
256            0x08 => PassthruError::ERR_DEVICE_NOT_CONNECTED,
257            0x09 => PassthruError::ERR_TIMEOUT,
258            0x0A => PassthruError::ERR_INVALID_MSG,
259            0x0B => PassthruError::ERR_INVALID_TIME_INTERVAL,
260            0x0C => PassthruError::ERR_EXCEEDED_LIMIT,
261            0x0D => PassthruError::ERR_INVALID_MSG_ID,
262            0x0E => PassthruError::ERR_DEVICE_IN_USE,
263            0x0F => PassthruError::ERR_INVALID_IOCTL_ID,
264            0x10 => PassthruError::ERR_BUFFER_EMPTY,
265            0x11 => PassthruError::ERR_BUFFER_FULL,
266            0x12 => PassthruError::ERR_BUFFER_OVERFLOW,
267            0x13 => PassthruError::ERR_PIN_INVALID,
268            0x14 => PassthruError::ERR_CHANNEL_IN_USE,
269            0x15 => PassthruError::ERR_MSG_PROTOCOL_ID,
270            0x16 => PassthruError::ERR_INVALID_FILTER_ID,
271            0x17 => PassthruError::ERR_NO_FLOW_CONTROL,
272            0x18 => PassthruError::ERR_NOT_UNIQUE,
273            0x19 => PassthruError::ERR_INVALID_BAUDRATE,
274            0x1A => PassthruError::ERR_INVALID_DEVICE_ID,
275            _ => return Err(())
276        })
277    }
278}
279
280impl Display for PassthruError {
281    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
282        f.write_str(match &self {
283            PassthruError::STATUS_NOERROR => "No Error",
284            PassthruError::ERR_NOT_SUPPORTED => "Operation not supported",
285            PassthruError::ERR_INVALID_CHANNEL_ID => "Invalid channel ID",
286            PassthruError::ERR_INVALID_PROTOCOL_ID => "Invalid protocol ID",
287            PassthruError::ERR_NULL_PARAMETER => "Null parameter received",
288            PassthruError::ERR_INVALID_IOCTL_VALUE => "Invalid IOCTL Value",
289            PassthruError::ERR_INVALID_FLAGS => "Invalid flags",
290            PassthruError::ERR_FAILED => "Unspecified error",
291            PassthruError::ERR_DEVICE_NOT_CONNECTED => "Device not connected",
292            PassthruError::ERR_TIMEOUT => "Device timeout",
293            PassthruError::ERR_INVALID_MSG => "Invalid or malformed message",
294            PassthruError::ERR_INVALID_TIME_INTERVAL => "Time interval outside specified range",
295            PassthruError::ERR_EXCEEDED_LIMIT => "Too many filters or periodic messages",
296            PassthruError::ERR_INVALID_MSG_ID => "Message ID / Handle ID not recognized",
297            PassthruError::ERR_DEVICE_IN_USE => "Device is already in use",
298            PassthruError::ERR_INVALID_IOCTL_ID => "IOCTL ID not recognized",
299            PassthruError::ERR_BUFFER_EMPTY => "Receive buffer is empty",
300            PassthruError::ERR_BUFFER_FULL => "Transmit buffer is full",
301            PassthruError::ERR_BUFFER_OVERFLOW => "Device buffer overflow",
302            PassthruError::ERR_PIN_INVALID => "Unknown pin specified",
303            PassthruError::ERR_CHANNEL_IN_USE => "Channel is already in use",
304            PassthruError::ERR_MSG_PROTOCOL_ID => "Message protocol ID does not match that of the communication channel",
305            PassthruError::ERR_INVALID_FILTER_ID => "Filter ID not recognized",
306            PassthruError::ERR_NO_FLOW_CONTROL => "No flow control filter is set",
307            PassthruError::ERR_NOT_UNIQUE => "An existing filter already matches",
308            PassthruError::ERR_INVALID_BAUDRATE => "Unable to set requested baudrate",
309            PassthruError::ERR_INVALID_DEVICE_ID => "Device ID not recognized",
310        })
311    }
312}
313
314#[repr(u32)]
315#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
316#[allow(non_camel_case_types, dead_code)]
317pub enum FilterType {
318    PASS_FILTER = 0x01,
319    BLOCK_FILTER = 0x02,
320    FLOW_CONTROL_FILTER = 0x03,
321}
322
323impl TryFrom<u32> for FilterType {
324    type Error = ();
325
326    fn try_from(value: u32) -> Result<Self, Self::Error> {
327        Ok(match value {
328            0x01 => FilterType::PASS_FILTER,
329            0x02 => FilterType::BLOCK_FILTER,
330            0x03 => FilterType::FLOW_CONTROL_FILTER,
331            _ => return Err(())
332        })
333    }
334}
335
336impl std::fmt::Display for FilterType {
337    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
338        match &self {
339            FilterType::PASS_FILTER => f.write_str("Pass filter"),
340            FilterType::BLOCK_FILTER => f.write_str("Block filter"),
341            FilterType::FLOW_CONTROL_FILTER => f.write_str("ISO-TP flow control filter"),
342        }
343    }
344}
345
346#[repr(u32)]
347#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
348#[allow(non_camel_case_types, dead_code)]
349pub enum LoopBackSetting {
350    OFF = 0x00,
351    ON = 0x01,
352}
353
354#[repr(u32)]
355#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
356#[allow(non_camel_case_types, dead_code)]
357pub enum DataBits {
358    DATA_BITS_8 = 0x00,
359    DATA_BITS_7 = 0x01,
360}
361
362#[repr(u32)]
363#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
364#[allow(non_camel_case_types, dead_code)]
365pub enum ParitySetting {
366    NO_PARITY = 0x00,
367    ODD_PARITY = 0x01,
368    EVEN_PARITY = 0x02,
369}
370
371#[repr(u32)]
372#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
373#[allow(non_camel_case_types, dead_code)]
374pub enum J1850PWMNetworkLine {
375    BUS_NORMAL = 0x00,
376    BUS_PLUS = 0x01,
377    BUS_MINUS = 0x02,
378}
379
380bitflags! {
381    pub struct ConnectFlags: u32 {
382        const CAN_29BIT_ID = 0x00000100;
383        const ISO9141_NO_CHECKSUM = 0x00000200;
384        const CAN_ID_BOTH = 0x00000800;
385        const ISO15765_ADDR_TYPE = 0x00000080;
386        const ISO9141_K_LINE_ONLY = 0x00001000;
387    }
388}
389
390bitflags! {
391    pub struct RxFlag: u32 {
392        const CAN_29BIT_ID = 0x00000100;
393        const ISO15765_ADDR_TYPE = 0x00000080;
394        const ISO15765_PADDING_ERROR = 0x00000010;
395        const TX_DONE = 0x00000008;
396        const RX_BREAK = 0x00000004;
397        const ISO15765_FIRST_FRAME = 0x00000002;
398        const START_OF_MESSAGE = 0x00000002;
399        const TX_MSG_TYPE = 0x00000001;
400    }
401}
402
403bitflags! {
404    pub struct TxFlag: u32 {
405        const SCI_TX_VOLTAGE = 0x00800000;
406        const SCI_MODE = 0x00400000;
407        const BLOCKING = 0x00010000;
408        const WAIT_P3_MIN_ONLY = 0x00000200;
409        const CAN_29BIT_ID = 0x00000100;
410        const CAN_EXTENDED_ID = 0x00000100;
411        const ISO15765_ADDR_TYPE = 0x00000080;
412        const ISO15765_EXT_ADDR = 0x00000080;
413        const ISO15765_FRAME_PAD = 0x00000040;
414        const TX_NORMAL_TRANSMIT = 0x00000000;
415    }
416}
417
418#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
419#[repr(C)]
420pub struct PASSTHRU_MSG {
421    pub protocol_id: u32,
422    pub rx_status: u32,
423    pub tx_flags: u32,
424    pub timestamp: u32,
425    pub data_size: u32,
426    pub extra_data_size: u32,
427    pub data: [u8; 4128],
428}
429
430impl Default for PASSTHRU_MSG {
431    fn default() -> Self {
432        PASSTHRU_MSG {
433            protocol_id: 0,
434            rx_status: 0,
435            tx_flags: 0,
436            timestamp: 0,
437            data_size: 0,
438            extra_data_size: 0,
439            data: [0; 4128],
440        }
441    }
442}
443
444impl std::fmt::Display for PASSTHRU_MSG {
445    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
446        f.write_str(format!(
447            "Protocol: {}, RxStatus: {:08X}, TxFlags: {:08X}, Data: {:02X?}", 
448            Protocol::try_from(self.protocol_id).unwrap(),
449            self.rx_status,
450            self.tx_flags,
451            &self.data[0..self.data_size as usize]
452            
453        ).as_str())
454    }
455}
456
457#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
458#[repr(C)]
459pub struct SBYTE_ARRAY {
460    pub num_of_bytes: u32,
461    pub byte_ptr: *mut u8,
462}
463
464#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
465#[repr(C)]
466pub struct SConfig {
467    pub parameter: u32,
468    pub value: u32,
469}
470
471#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
472#[repr(C)]
473pub struct SConfigList {
474    pub num_of_params: u32,
475    pub config_ptr: *mut SConfig,
476}