#![cfg(windows)]
#[macro_use]
extern crate bitflags;
use std::ffi;
use std::ffi::OsStr;
use std::fmt;
use std::fmt::Debug;
use std::io;
use std::path::Path;
use std::str::Utf8Error;
use bitflags::_core::fmt::Formatter;
use libloading::{Library, Symbol};
use winreg::enums::*;
use winreg::RegKey;
pub type Result<T> = std::result::Result<T, Error>;
#[derive(thiserror::Error, Debug)]
pub enum Error {
#[error(transparent)]
Utf8Error(#[from] Utf8Error),
#[error(transparent)]
Io(#[from] io::Error),
#[error("success")]
NoError,
#[error("option not supported')")]
NotSupported,
#[error("invalid channel id")]
InvalidChannelId,
#[error("invalid protocol id")]
InvalidProtocolId,
#[error("NULL was incorrectly passed as a parameter")]
NullParameter,
#[error("invalid ioctl parameter")]
InvalidIoctlValue,
#[error("invalid flags")]
InvalidFlags,
#[error("unspecified error")]
Failed,
#[error("a PassThru device is not connected")]
DeviceNotConnected,
#[error("timed out")]
Timeout,
#[error("invalid message")]
InvalidMessage,
#[error("invalid time interval")]
InvalidTimeInterval,
#[error("exceeded message limit")]
ExceededLimit,
#[error("invalid message id")]
InvalidMessageId,
#[error("device in use")]
DeviceInUse,
#[error("invalid ioctl id")]
InvalidIoctlId,
#[error("could not read messages")]
BufferEmpty,
#[error("transmit queue full")]
BufferFull,
#[error("receive buffer overflowed")]
BufferOverflow,
#[error("unknown pin number or resource in use")]
PinInvalid,
#[error("channel already in use")]
ChannelInUse,
#[error("message protocol does not match channel protocol")]
MessageProtocolId,
#[error("invalid filter id")]
InvalidFilterId,
#[error("no flow control filter matches outgoing message")]
NoFlowControl,
#[error("filter already exists")]
NotUnique,
#[error("unsupported baudrate")]
InvalidBaudrate,
#[error("invalid device id")]
InvalidDeviceId,
#[error("unknown j2534 error code {0}")]
Unknown(i32),
}
impl Error {
pub fn from_code(code: i32) -> Error {
match code {
0x00 => Error::NoError,
0x01 => Error::NotSupported,
0x02 => Error::InvalidChannelId,
0x03 => Error::InvalidProtocolId,
0x04 => Error::NullParameter,
0x05 => Error::InvalidIoctlValue,
0x06 => Error::InvalidFlags,
0x07 => Error::Failed,
0x08 => Error::DeviceNotConnected,
0x09 => Error::Timeout,
0x0A => Error::InvalidMessage,
0x0B => Error::InvalidTimeInterval,
0x0C => Error::ExceededLimit,
0x0D => Error::InvalidMessageId,
0x0E => Error::DeviceInUse,
0x0F => Error::InvalidIoctlId,
0x10 => Error::BufferEmpty,
0x11 => Error::BufferFull,
0x12 => Error::BufferOverflow,
0x13 => Error::PinInvalid,
0x14 => Error::ChannelInUse,
0x15 => Error::MessageProtocolId,
0x16 => Error::InvalidFilterId,
0x17 => Error::NoFlowControl,
0x18 => Error::NotUnique,
0x19 => Error::InvalidBaudrate,
0x1A => Error::InvalidDeviceId,
other => Error::Unknown(other),
}
}
}
type PassThruOpenFn = unsafe extern "system" fn(
name: *const libc::c_void,
device_id: *mut libc::uint32_t,
) -> libc::int32_t;
type PassThruCloseFn = unsafe extern "system" fn(device_id: libc::uint32_t) -> libc::int32_t;
type PassThruConnectFn = unsafe extern "system" fn(
device_id: libc::uint32_t,
protocol_id: libc::uint32_t,
flags: libc::uint32_t,
baudrate: libc::uint32_t,
channel_id: *mut libc::uint32_t,
) -> libc::int32_t;
type PassThruDisconnectFn = unsafe extern "system" fn(channel_id: libc::uint32_t) -> libc::int32_t;
type PassThruReadMsgsFn = unsafe extern "system" fn(
channel_id: libc::uint32_t,
msgs: *mut PassThruMsg,
num_msgs: *mut libc::uint32_t,
timeout: libc::uint32_t,
) -> libc::int32_t;
type PassThruWriteMsgsFn = unsafe extern "system" fn(
channel_id: libc::uint32_t,
msgs: *mut PassThruMsg,
num_msgs: *mut libc::uint32_t,
timeout: libc::uint32_t,
) -> libc::int32_t;
type PassThruStartPeriodicMsgFn = unsafe extern "system" fn(
channel_id: libc::uint32_t,
msg: *const PassThruMsg,
msg_id: *mut libc::uint32_t,
time_interval: libc::uint32_t,
) -> libc::int32_t;
type PassThruStopPeriodicMsgFn =
unsafe extern "system" fn(channel_id: libc::uint32_t, msg_id: libc::uint32_t) -> libc::int32_t;
type PassThruStartMsgFilterFn = unsafe extern "system" fn(
channel_id: libc::uint32_t,
filter_type: libc::uint32_t,
msg_mask: *const PassThruMsg,
pattern_msg: *const PassThruMsg,
flow_control_msg: *const PassThruMsg,
filter_id: *mut libc::uint32_t,
) -> libc::int32_t;
type PassThruStopMsgFilterFn = unsafe extern "system" fn(
channel_id: libc::uint32_t,
filter_id: libc::uint32_t,
) -> libc::int32_t;
type PassThruSetProgrammingVoltageFn = unsafe extern "system" fn(
device_id: libc::uint32_t,
pin_number: libc::uint32_t,
voltage: libc::uint32_t,
) -> libc::int32_t;
type PassThruReadVersionFn = unsafe extern "system" fn(
device_id: libc::uint32_t,
firmware_version: *mut libc::c_char,
dll_version: *mut libc::c_char,
api_version: *mut libc::c_char,
) -> libc::int32_t;
type PassThruGetLastErrorFn =
unsafe extern "system" fn(error_description: *mut libc::c_char) -> libc::int32_t;
type PassThruIoctlFn = unsafe extern "system" fn(
handle_id: libc::uint32_t,
ioctl_id: libc::uint32_t,
input: *mut libc::c_void,
output: *mut libc::c_void,
) -> libc::int32_t;
#[derive(Copy, Clone)]
#[repr(C, packed(1))]
pub struct PassThruMsg {
pub protocol_id: u32,
pub rx_status: u32,
pub tx_flags: u32,
pub timestamp: u32,
pub data_size: u32,
pub extra_data_index: u32,
pub data: [u8; 4128],
}
#[repr(C, packed(1))]
pub struct SConfig {
parameter: ConfigId,
value: u32,
}
#[repr(C, packed(1))]
pub struct SConfigList {
size: u32,
config_ptr: *const SConfig,
}
#[repr(C, packed(1))]
pub struct SByteArray {
size: u32,
byte_ptr: *const u8,
}
impl PassThruMsg {
pub fn new_raw(
protocol: Protocol,
rx_status: RxStatus,
tx_flags: TxFlags,
timestamp: u32,
data_size: u32,
extra_data_index: u32,
data: [u8; 4128],
) -> PassThruMsg {
PassThruMsg {
protocol_id: protocol as u32,
rx_status: rx_status.bits,
tx_flags: tx_flags.bits,
timestamp,
data_size,
extra_data_index,
data,
}
}
pub fn new(
protocol: Protocol,
rx_status: RxStatus,
tx_flags: TxFlags,
timestamp: u32,
extra_data_index: u32,
data: &[u8],
) -> PassThruMsg {
PassThruMsg::new_raw(
protocol,
rx_status,
tx_flags,
timestamp,
data.len() as u32,
extra_data_index,
{
let mut d: [u8; 4128] = [0; 4128];
d[..data.len()].copy_from_slice(&data);
d
},
)
}
}
impl Default for PassThruMsg {
fn default() -> PassThruMsg {
PassThruMsg {
protocol_id: 0,
rx_status: 0,
tx_flags: 0,
timestamp: 0,
data_size: 0,
extra_data_index: 0,
data: [0; 4128],
}
}
}
impl Debug for PassThruMsg {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
unsafe {
f.debug_struct("PassThruMsg")
.field("protocol_id", &self.protocol_id)
.field("rx_status", &self.rx_status)
.field("tx_flags", &self.tx_flags)
.field("timestamp", &self.timestamp)
.field("extra_data_index", &self.extra_data_index)
.field("data", &&self.data[..self.data_size as usize])
.finish()
}
}
}
#[derive(Copy, Clone, Debug)]
pub struct ChannelId(u32);
#[derive(Copy, Clone, Debug)]
pub struct MessageId(u32);
#[derive(Copy, Clone, Debug)]
pub struct FilterId(u32);
pub struct Interface {
library: Library,
c_pass_thru_open: PassThruOpenFn,
c_pass_thru_close: PassThruCloseFn,
c_pass_thru_connect: PassThruConnectFn,
c_pass_thru_disconnect: PassThruDisconnectFn,
c_pass_thru_read_version: PassThruReadVersionFn,
c_pass_thru_get_last_error: PassThruGetLastErrorFn,
c_pass_thru_read_msgs: PassThruReadMsgsFn,
c_pass_thru_start_msg_filter: PassThruStartMsgFilterFn,
c_pass_thru_stop_msg_filter: PassThruStopMsgFilterFn,
c_pass_thru_write_msgs: PassThruWriteMsgsFn,
c_pass_thru_start_periodic_msg: PassThruStartPeriodicMsgFn,
c_pass_thru_stop_periodic_msg: PassThruStopPeriodicMsgFn,
c_pass_thru_set_programming_voltage: PassThruSetProgrammingVoltageFn,
c_pass_thru_ioctl: PassThruIoctlFn,
}
pub struct Device<'a> {
interface: &'a Interface,
id: u32,
}
pub struct Channel<'a> {
device: &'a Device<'a>,
id: u32,
protocol_id: u32,
}
impl Interface {
pub fn new<S: AsRef<OsStr>>(path: S) -> libloading::Result<Interface> {
let library = Library::new(path)?;
let interface = unsafe {
let c_pass_thru_open: Symbol<PassThruOpenFn> = library.get(b"PassThruOpen\0")?;
let c_pass_thru_close: Symbol<PassThruCloseFn> = library.get(b"PassThruClose\0")?;
let c_pass_thru_connect: Symbol<PassThruConnectFn> =
library.get(b"PassThruConnect\0")?;
let c_pass_thru_disconnect: Symbol<PassThruDisconnectFn> =
library.get(b"PassThruDisconnect\0")?;
let c_pass_thru_read_version: Symbol<PassThruReadVersionFn> =
library.get(b"PassThruReadVersion\0")?;
let c_pass_thru_get_last_error: Symbol<PassThruGetLastErrorFn> =
library.get(b"PassThruGetLastError\0")?;
let c_pass_thru_read_msgs: Symbol<PassThruReadMsgsFn> =
library.get(b"PassThruReadMsgs\0")?;
let c_pass_thru_start_msg_filter: Symbol<PassThruStartMsgFilterFn> =
library.get(b"PassThruStartMsgFilter\0")?;
let c_pass_thru_stop_msg_filter: Symbol<PassThruStopMsgFilterFn> =
library.get(b"PassThruStopMsgFilter\0")?;
let c_pass_thru_write_msgs: Symbol<PassThruWriteMsgsFn> =
library.get(b"PassThruWriteMsgs\0")?;
let c_pass_thru_start_periodic_msg: Symbol<PassThruStartPeriodicMsgFn> =
library.get(b"PassThruStartPeriodicMsg\0")?;
let c_pass_thru_stop_periodic_msg: Symbol<PassThruStopPeriodicMsgFn> =
library.get(b"PassThruStopPeriodicMsg\0")?;
let c_pass_thru_set_programming_voltage: Symbol<PassThruSetProgrammingVoltageFn> =
library.get(b"PassThruSetProgrammingVoltage\0")?;
let c_pass_thru_ioctl: Symbol<PassThruIoctlFn> = library.get(b"PassThruIoctl\0")?;
Interface {
c_pass_thru_open: *c_pass_thru_open.into_raw(),
c_pass_thru_close: *c_pass_thru_close.into_raw(),
c_pass_thru_connect: *c_pass_thru_connect.into_raw(),
c_pass_thru_disconnect: *c_pass_thru_disconnect.into_raw(),
c_pass_thru_read_version: *c_pass_thru_read_version.into_raw(),
c_pass_thru_get_last_error: *c_pass_thru_get_last_error.into_raw(),
c_pass_thru_read_msgs: *c_pass_thru_read_msgs.into_raw(),
c_pass_thru_start_msg_filter: *c_pass_thru_start_msg_filter.into_raw(),
c_pass_thru_stop_msg_filter: *c_pass_thru_stop_msg_filter.into_raw(),
c_pass_thru_write_msgs: *c_pass_thru_write_msgs.into_raw(),
c_pass_thru_start_periodic_msg: *c_pass_thru_start_periodic_msg.into_raw(),
c_pass_thru_stop_periodic_msg: *c_pass_thru_stop_periodic_msg.into_raw(),
c_pass_thru_set_programming_voltage: *c_pass_thru_set_programming_voltage
.into_raw(),
c_pass_thru_ioctl: *c_pass_thru_ioctl.into_raw(),
library,
}
};
Ok(interface)
}
pub fn get_last_error(&self) -> Result<String> {
let mut error: [u8; 80] = [0; 80];
let res =
unsafe { (&self.c_pass_thru_get_last_error)(error.as_mut_ptr() as *mut libc::c_char) };
if res != 0 {
return Err(Error::from_code(res));
}
unsafe {
Ok(String::from(
ffi::CStr::from_ptr(error.as_mut_ptr() as *mut libc::c_char).to_str()?,
))
}
}
pub fn open<S: Into<Vec<u8>>>(&self, port: S) -> Result<Device> {
let s = ffi::CString::new(port).unwrap();
let raw = s.as_ptr() as *const libc::c_void;
let mut id = 0;
let res = unsafe { (&self.c_pass_thru_open)(raw, &mut id as *mut libc::uint32_t) };
if res != 0 {
return Err(Error::from_code(res));
}
Ok(Device {
interface: self,
id,
})
}
pub fn open_any(&self) -> Result<Device> {
let raw = std::ptr::null() as *const libc::c_void;
let mut id = 0;
let res = unsafe { (&self.c_pass_thru_open)(raw, &mut id as *mut libc::uint32_t) };
if res != 0 {
return Err(Error::from_code(res));
}
Ok(Device {
interface: self,
id,
})
}
pub unsafe fn ioctl(
&self,
handle: u32,
id: IoctlId,
input: *mut libc::c_void,
output: *mut libc::c_void,
) -> Result<i32> {
let res = (&self.c_pass_thru_ioctl)(handle, id as u32, input, output);
if res != 0 {
return Err(Error::from_code(res));
}
Ok(res)
}
}
#[derive(Copy, Clone)]
pub enum Protocol {
J1850VPW = 1,
J1850PWM = 2,
ISO9141 = 3,
ISO14230 = 4,
CAN = 5,
ISO15765 = 6,
SCI_A_ENGINE = 7,
SCI_A_TRANS = 8,
SCI_B_ENGINE = 9,
SCI_B_TRANS = 10,
}
bitflags! {
pub struct ConnectFlags: u32 {
const NONE = 0;
const CAN_29_BIT_ID = 0x100;
const ISO9141_NO_CHECKSUM = 0x200;
const CAN_ID_BOTH = 0x800;
const ISO9141_K_LINE_ONLY = 0x1000;
}
}
bitflags! {
pub struct TxFlags: u32 {
const NONE = 0;
const ISO15765_FRAME_PAD = 0x00000040;
const ISO15765_ADDR_TYPE = 0x00000080;
const CAN_29BIT_ID = 0x00000100;
const WAIT_P3_MIN_ONLY = 0x00000200;
const SW_CAN_HV_TX = 0x00000400;
const SCI_MODE = 0x00400000;
const SCI_TX_VOLTAGE = 0x00800000;
const DT_PERIODIC_UPDATE = 0x10000000;
}
}
bitflags! {
pub struct RxStatus: u32 {
const NONE = 0;
const TX_MSG_TYPE = 0x00000001;
const START_OF_MESSAGE = 0x00000002;
const ISO15765_FIRST_FRAME = 0x00000002 ;
const ISO15765_EXT_ADDR = 0x00000080;
const RX_BREAK = 0x00000004;
const TX_INDICATION = 0x00000008;
const TX_DONE = 0x00000008;
const ISO15765_PADDING_ERROR = 0x00000010;
const ISO15765_ADDR_TYPE = 0x00000080;
const CAN_29BIT_ID = 0x00000100;
const SW_CAN_NS_RX = 0x00040000;
const SW_CAN_HS_RX = 0x00020000;
const SW_CAN_HV_RX = 0x00010000;
}
}
#[derive(Copy, Clone)]
pub enum IoctlId {
GET_CONFIG = 0x01,
SET_CONFIG = 0x02,
READ_VBATT = 0x03,
FIVE_BAUD_INIT = 0x04,
FAST_INIT = 0x05,
CLEAR_TX_BUFFER = 0x07,
CLEAR_RX_BUFFER = 0x08,
CLEAR_PERIODIC_MSGS = 0x09,
CLEAR_MSG_FILTERS = 0x0A,
CLEAR_FUNCT_MSG_LOOKUP_TABLE = 0x0B,
ADD_TO_FUNCT_MSG_LOOKUP_TABLE = 0x0C,
DELETE_FROM_FUNCT_MSG_LOOKUP_TABLE = 0x0D,
READ_PROG_VOLTAGE = 0x0E,
SW_CAN_HS = 0x8000,
SW_CAN_NS = 0x8001,
SET_POLL_RESPONSE = 0x8002,
BECOME_MASTER = 0x8003,
}
#[derive(Copy, Clone)]
pub enum ConfigId {
DATA_RATE = 0x01,
LOOPBACK = 0x03,
NODE_ADDRESS = 0x04,
NETWORK_LINE = 0x05,
P1_MIN = 0x06,
P1_MAX = 0x07,
P2_MIN = 0x08,
P2_MAX = 0x09,
P3_MIN = 0x0A,
P3_MAX = 0x0B,
P4_MIN = 0x0C,
P4_MAX = 0x0D,
W1 = 0x0E,
W2 = 0x0F,
W3 = 0x10,
W4 = 0x11,
W5 = 0x12,
TIDLE = 0x13,
TINIL = 0x14,
TWUP = 0x15,
PARITY = 0x16,
BIT_SAMPLE_POINT = 0x17,
SYNC_JUMP_WIDTH = 0x18,
W0 = 0x19,
T1_MAX = 0x1A,
T2_MAX = 0x1B,
T4_MAX = 0x1C,
T5_MAX = 0x1D,
ISO15765_BS = 0x1E,
ISO15765_STMIN = 0x1F,
DATA_BITS = 0x20,
FIVE_BAUD_MOD = 0x21,
BS_TX = 0x22,
STMIN_TX = 0x23,
T3_MAX = 0x24,
ISO15765_WFT_MAX = 0x25,
CAN_MIXED_FORMAT = 0x8000,
J1962_PINS = 0x8001,
SW_CAN_HS_DATA_RATE = 0x8010,
SW_CAN_SPEEDCHANGE_ENABLE = 0x8011,
SW_CAN_RES_SWITCH = 0x8012,
ACTIVE_CHANNELS = 0x8020,
SAMPLE_RATE = 0x8021,
SAMPLES_PER_READING = 0x8022,
READINGS_PER_MSG = 0x8023,
AVERAGING_METHOD = 0x8024,
SAMPLE_RESOLUTION = 0x8025,
INPUT_RANGE_LOW = 0x8026,
INPUT_RANGE_HIGH = 0x8027,
}
#[derive(Copy, Clone)]
pub enum FilterType {
Pass = 1,
Block = 2,
FlowControl = 3,
}
#[derive(Debug)]
pub struct VersionInfo {
pub firmware_version: String,
pub dll_version: String,
pub api_version: String,
}
pub const SHORT_TO_GROUND: u32 = 0xFFFFFFFE;
pub const VOLTAGE_OFF: u32 = 0xFFFFFFFF;
impl<'a> Device<'a> {
pub fn read_version(&self) -> Result<VersionInfo> {
let mut firmware_version: [u8; 80] = [0; 80];
let mut dll_version: [u8; 80] = [0; 80];
let mut api_version: [u8; 80] = [0; 80];
let res = unsafe {
(&self.interface.c_pass_thru_read_version)(
self.id,
firmware_version.as_mut_ptr() as *mut libc::c_char,
dll_version.as_mut_ptr() as *mut libc::c_char,
api_version.as_mut_ptr() as *mut libc::c_char,
)
};
if res != 0 {
return Err(Error::from_code(res));
}
unsafe {
Ok(VersionInfo {
firmware_version: String::from(
ffi::CStr::from_ptr(firmware_version.as_mut_ptr() as *mut libc::c_char)
.to_str()?,
),
api_version: String::from(
ffi::CStr::from_ptr(api_version.as_mut_ptr() as *mut libc::c_char).to_str()?,
),
dll_version: String::from(
ffi::CStr::from_ptr(dll_version.as_mut_ptr() as *mut libc::c_char).to_str()?,
),
})
}
}
pub fn set_programming_voltage(&self, pin_number: u32, voltage: u32) -> Result<()> {
let res = unsafe {
(&self.interface.c_pass_thru_set_programming_voltage)(self.id, pin_number, voltage)
};
if res != 0 {
return Err(Error::from_code(res));
}
Ok(())
}
pub fn connect_raw(&self, protocol: u32, flags: u32, baudrate: u32) -> Result<Channel> {
let mut id: u32 = 0;
let res = unsafe {
(&self.interface.c_pass_thru_connect)(
self.id,
protocol,
flags,
baudrate,
&mut id as *mut libc::uint32_t,
)
};
if res != 0 {
return Err(Error::from_code(res));
}
Ok(Channel {
device: self,
id,
protocol_id: protocol,
})
}
pub fn connect(
&self,
protocol: Protocol,
flags: ConnectFlags,
baudrate: u32,
) -> Result<Channel> {
self.connect_raw(protocol as u32, flags.bits(), baudrate)
}
pub fn read_battery_voltage(&self) -> Result<u32> {
let mut voltage: u32 = 0;
unsafe {
self.interface.ioctl(
self.id,
IoctlId::READ_VBATT,
std::ptr::null_mut::<libc::c_void>(),
(&mut voltage) as *mut _ as *mut libc::c_void,
)
}?;
Ok(voltage)
}
pub fn read_programming_voltage(&self) -> Result<u32> {
let mut voltage: u32 = 0;
unsafe {
self.interface.ioctl(
self.id,
IoctlId::READ_PROG_VOLTAGE,
std::ptr::null_mut::<libc::c_void>(),
(&mut voltage) as *mut _ as *mut libc::c_void,
)
}?;
Ok(voltage)
}
}
impl<'a> Drop for Device<'a> {
fn drop(&mut self) {
unsafe { (&self.interface.c_pass_thru_close)(self.id) };
}
}
impl<'a> Channel<'a> {
pub fn read_msgs<'b>(
&self,
msgs: &'b mut [PassThruMsg],
timeout: u32,
) -> Result<&'b [PassThruMsg]> {
for msg in msgs.iter_mut() {
msg.protocol_id = self.protocol_id;
}
let mut num_msgs: u32 = msgs.len() as u32;
let res = unsafe {
(&self.device.interface.c_pass_thru_read_msgs)(
self.id,
msgs.as_mut_ptr(),
&mut num_msgs as *mut libc::uint32_t,
timeout,
)
};
if res != 0 {
return Err(Error::from_code(res));
}
Ok(&msgs[..(num_msgs as usize)])
}
pub fn read_msg(&self, timeout: u32) -> Result<PassThruMsg> {
let mut msg = PassThruMsg {
protocol_id: self.protocol_id,
..Default::default()
};
let mut num_msgs = 1 as u32;
let res = unsafe {
(&self.device.interface.c_pass_thru_read_msgs)(
self.id,
&mut msg as *mut PassThruMsg,
&mut num_msgs as *mut libc::uint32_t,
timeout,
)
};
if res != 0 {
return Err(Error::from_code(res));
}
Ok(msg)
}
pub fn write_msgs(&self, msgs: &mut [PassThruMsg], timeout: u32) -> Result<usize> {
for msg in msgs.iter_mut() {
msg.protocol_id = self.protocol_id;
}
let mut num_msgs: u32 = msgs.len() as u32;
let res = unsafe {
(&self.device.interface.c_pass_thru_write_msgs)(
self.id,
msgs.as_mut_ptr(),
&mut num_msgs as *mut libc::uint32_t,
timeout,
)
};
if res != 0 {
return Err(Error::from_code(res));
}
Ok(num_msgs as usize)
}
pub fn start_msg_filter(
&self,
filter_type: FilterType,
mask_msg: Option<&PassThruMsg>,
pattern_msg: Option<&PassThruMsg>,
flow_control_msg: Option<&PassThruMsg>,
) -> Result<FilterId> {
let mut msg_id: u32 = 0;
let mask_ptr = match mask_msg {
Some(msg) => msg as *const PassThruMsg,
None => std::ptr::null() as *const PassThruMsg,
};
let pattern_ptr = match pattern_msg {
Some(msg) => msg as *const PassThruMsg,
None => std::ptr::null() as *const PassThruMsg,
};
let flow_control_ptr = match flow_control_msg {
Some(msg) => msg as *const PassThruMsg,
None => std::ptr::null() as *const PassThruMsg,
};
let res = unsafe {
(&self.device.interface.c_pass_thru_start_msg_filter)(
self.id,
filter_type as u32,
mask_ptr,
pattern_ptr,
flow_control_ptr,
&mut msg_id as *mut libc::uint32_t,
)
};
if res != 0 {
return Err(Error::from_code(res));
}
Ok(FilterId(msg_id))
}
pub fn stop_msg_filter(&self, filter_id: FilterId) -> Result<()> {
let res =
unsafe { (&self.device.interface.c_pass_thru_stop_msg_filter)(self.id, filter_id.0) };
if res != 0 {
return Err(Error::from_code(res));
}
Ok(())
}
pub fn start_periodic_msg(&self, msg: &PassThruMsg, time_interval: u32) -> Result<MessageId> {
let mut msg_id = 0;
let res = unsafe {
(&self.device.interface.c_pass_thru_start_periodic_msg)(
self.id,
msg as *const PassThruMsg,
&mut msg_id as *mut libc::uint32_t,
time_interval,
)
};
if res != 0 {
return Err(Error::from_code(res));
}
Ok(MessageId(msg_id))
}
pub fn stop_periodic_msg(&self, msg_id: MessageId) -> Result<()> {
let res =
unsafe { (&self.device.interface.c_pass_thru_stop_periodic_msg)(self.id, msg_id.0) };
if res != 0 {
return Err(Error::from_code(res));
}
Ok(())
}
pub fn clear_transmit_buffer(&self) -> Result<()> {
unsafe {
self.device.interface.ioctl(
self.id,
IoctlId::CLEAR_TX_BUFFER,
std::ptr::null_mut::<libc::c_void>(),
std::ptr::null_mut::<libc::c_void>(),
)
}?;
Ok(())
}
pub fn clear_periodic_messages(&self) -> Result<()> {
unsafe {
self.device.interface.ioctl(
self.id,
IoctlId::CLEAR_PERIODIC_MSGS,
std::ptr::null_mut::<libc::c_void>(),
std::ptr::null_mut::<libc::c_void>(),
)
}?;
Ok(())
}
pub fn clear_receive_buffer(&self) -> Result<()> {
unsafe {
self.device.interface.ioctl(
self.id,
IoctlId::CLEAR_RX_BUFFER,
std::ptr::null_mut::<libc::c_void>(),
std::ptr::null_mut::<libc::c_void>(),
)
}?;
Ok(())
}
pub fn clear_message_filters(&self) -> Result<()> {
unsafe {
self.device.interface.ioctl(
self.id,
IoctlId::CLEAR_MSG_FILTERS,
std::ptr::null_mut::<libc::c_void>(),
std::ptr::null_mut::<libc::c_void>(),
)
}?;
Ok(())
}
pub fn get_config(&self, id: ConfigId) -> Result<u32> {
let mut input = SConfig {
parameter: id,
value: 0,
};
unsafe {
self.device.interface.ioctl(
self.id,
IoctlId::GET_CONFIG,
&mut input as *mut _ as *mut libc::c_void,
std::ptr::null_mut::<libc::c_void>(),
)
}?;
Ok(input.value)
}
pub fn set_config(&self, id: ConfigId, value: u32) -> Result<()> {
let mut input = SConfig {
parameter: id,
value,
};
unsafe {
self.device.interface.ioctl(
self.id,
IoctlId::SET_CONFIG,
&mut input as *mut _ as *mut libc::c_void,
std::ptr::null_mut::<libc::c_void>(),
)
}?;
Ok(())
}
}
impl<'a> Drop for Channel<'a> {
fn drop(&mut self) {
unsafe { (&self.device.interface.c_pass_thru_disconnect)(self.id) };
}
}
#[derive(Debug)]
pub struct Listing {
pub name: String,
pub vendor: String,
pub path: String,
}
pub fn drivers() -> io::Result<Vec<Listing>> {
let hklm = RegKey::predef(HKEY_LOCAL_MACHINE);
let passthru = match hklm.open_subkey(Path::new("SOFTWARE").join("PassThruSupport.04.04")) {
Err(err) if err.kind() == io::ErrorKind::NotFound => {
return Ok(Vec::new());
}
other => other,
}?;
let mut listings = Vec::new();
for name in passthru.enum_keys() {
let name = name?;
let key = passthru.open_subkey(name)?;
let device_name: String = key.get_value("Name")?;
let vendor: String = key.get_value("Vendor")?;
let path: String = key.get_value("FunctionLibrary")?;
listings.push(Listing {
name: device_name,
vendor,
path,
});
}
Ok(listings)
}