use std::time::Duration;
use rusb::{DeviceHandle, GlobalContext};
use crate::constants::*;
use crate::error::{GsUsbError, Result};
use crate::frame::GsUsbFrame;
use crate::structures::{DeviceBitTiming, DeviceCapability, DeviceInfo, DeviceMode, DeviceState};
pub struct GsUsb {
handle: DeviceHandle<GlobalContext>,
capability: Option<DeviceCapability>,
device_flags: u32,
fd_mode: bool,
started: bool,
bus: u8,
address: u8,
serial_number: Option<String>,
last_timing: Option<DeviceBitTiming>,
last_data_timing: Option<DeviceBitTiming>,
}
impl GsUsb {
fn new(handle: DeviceHandle<GlobalContext>, bus: u8, address: u8) -> Self {
Self {
handle,
capability: None,
device_flags: 0,
fd_mode: false,
started: false,
bus,
address,
serial_number: None,
last_timing: None,
last_data_timing: None,
}
}
pub fn start(&mut self, flags: u32) -> Result<()> {
self.handle.reset()?;
#[cfg(any(target_os = "linux", target_os = "macos"))]
{
if self.handle.kernel_driver_active(0).unwrap_or(false) {
self.handle
.detach_kernel_driver(0)
.map_err(GsUsbError::DetachKernelDriver)?;
}
}
self.handle
.claim_interface(0)
.map_err(GsUsbError::ClaimInterface)?;
let capability = self.device_capability()?;
let mut flags = flags & capability.feature;
flags &= GS_CAN_MODE_LISTEN_ONLY
| GS_CAN_MODE_LOOP_BACK
| GS_CAN_MODE_ONE_SHOT
| GS_CAN_MODE_HW_TIMESTAMP
| GS_CAN_MODE_FD;
self.device_flags = flags;
self.fd_mode = (flags & GS_CAN_MODE_FD) == GS_CAN_MODE_FD;
let mode = DeviceMode::new(GS_CAN_MODE_START, flags);
self.control_out(GS_USB_BREQ_MODE, 0, &mode.pack())?;
self.started = true;
Ok(())
}
pub fn stop(&mut self) -> Result<()> {
let mode = DeviceMode::new(GS_CAN_MODE_RESET, 0);
let _ = self.control_out(GS_USB_BREQ_MODE, 0, &mode.pack());
self.started = false;
Ok(())
}
pub fn set_bitrate(&mut self, bitrate: u32) -> Result<()> {
let capability = self.device_capability()?;
let clock = capability.fclk_can;
let timing = match clock {
80_000_000 => match bitrate {
10_000 => Some((87, 87, 25, 12, 40)), 20_000 => Some((87, 87, 25, 12, 20)), 50_000 => Some((87, 87, 25, 12, 8)), 100_000 => Some((87, 87, 25, 12, 4)), 125_000 => Some((69, 70, 20, 10, 4)), 250_000 => Some((69, 70, 20, 10, 2)), 500_000 => Some((69, 70, 20, 10, 1)), 1_000_000 => Some((29, 30, 20, 10, 1)), _ => None,
},
40_000_000 => match bitrate {
10_000 => Some((87, 87, 25, 12, 20)), 20_000 => Some((87, 87, 25, 12, 10)), 50_000 => Some((87, 87, 25, 12, 4)), 100_000 => Some((87, 87, 25, 12, 2)), 125_000 => Some((69, 70, 20, 10, 2)), 250_000 => Some((69, 70, 20, 10, 1)), 500_000 => Some((34, 35, 10, 5, 1)), 1_000_000 => Some((14, 15, 10, 5, 1)), _ => None,
},
_ => None,
};
match timing {
Some((prop_seg, phase_seg1, phase_seg2, sjw, brp)) => {
self.set_timing(prop_seg, phase_seg1, phase_seg2, sjw, brp)
}
None => Err(GsUsbError::UnsupportedBitrate {
bitrate,
clock_hz: clock,
}),
}
}
pub fn set_timing(
&mut self,
prop_seg: u32,
phase_seg1: u32,
phase_seg2: u32,
sjw: u32,
brp: u32,
) -> Result<()> {
let timing = DeviceBitTiming::new(prop_seg, phase_seg1, phase_seg2, sjw, brp);
self.control_out(GS_USB_BREQ_BITTIMING, 0, &timing.pack())?;
self.last_timing = Some(timing);
Ok(())
}
pub fn set_data_timing(
&mut self,
prop_seg: u32,
phase_seg1: u32,
phase_seg2: u32,
sjw: u32,
brp: u32,
) -> Result<()> {
let timing = DeviceBitTiming::new(prop_seg, phase_seg1, phase_seg2, sjw, brp);
self.control_out(GS_USB_BREQ_DATA_BITTIMING, 0, &timing.pack())?;
self.last_data_timing = Some(timing);
Ok(())
}
pub fn last_timing(&self) -> Option<DeviceBitTiming> {
self.last_timing
}
pub fn last_data_timing(&self) -> Option<DeviceBitTiming> {
self.last_data_timing
}
pub fn set_data_bitrate(&mut self, bitrate: u32) -> Result<()> {
let capability = self.device_capability()?;
if (capability.feature & GS_CAN_FEATURE_FD) == 0 {
return Err(GsUsbError::FdNotSupported);
}
let clock = capability.fclk_can;
let timing = match clock {
80_000_000 => match bitrate {
1_000_000 => Some((14, 15, 10, 5, 2)), 2_000_000 => Some((14, 15, 10, 5, 1)), 5_000_000 => Some((5, 6, 4, 2, 1)), 8_000_000 => Some((3, 3, 3, 1, 1)), 10_000_000 => Some((2, 3, 2, 1, 1)), _ => None,
},
40_000_000 => match bitrate {
1_000_000 => Some((14, 15, 10, 5, 1)), 2_000_000 => Some((7, 7, 5, 2, 1)), 5_000_000 => Some((2, 3, 2, 1, 1)), 8_000_000 => Some((1, 1, 2, 1, 1)), 10_000_000 => Some((1, 1, 1, 1, 1)), _ => None,
},
_ => None,
};
match timing {
Some((prop_seg, phase_seg1, phase_seg2, sjw, brp)) => {
self.set_data_timing(prop_seg, phase_seg1, phase_seg2, sjw, brp)
}
None => Err(GsUsbError::UnsupportedDataBitrate {
bitrate,
clock_hz: clock,
}),
}
}
pub fn send(&mut self, frame: &GsUsbFrame) -> Result<()> {
let hw_timestamps = (self.device_flags & GS_CAN_MODE_HW_TIMESTAMP) != 0;
let data = frame.pack(hw_timestamps, self.fd_mode);
self.handle
.write_bulk(GS_USB_ENDPOINT_OUT, &data, Duration::from_millis(1000))
.map_err(GsUsbError::BulkTransfer)?;
Ok(())
}
pub fn read(&mut self, timeout: Duration) -> Result<GsUsbFrame> {
let hw_timestamps = (self.device_flags & GS_CAN_MODE_HW_TIMESTAMP) != 0;
let max_size = GsUsbFrame::frame_size(hw_timestamps, self.fd_mode);
let mut buf = vec![0u8; max_size];
let len = match self.handle.read_bulk(GS_USB_ENDPOINT_IN, &mut buf, timeout) {
Ok(len) => len,
Err(rusb::Error::Timeout) => return Err(GsUsbError::ReadTimeout),
Err(e) => return Err(GsUsbError::BulkTransfer(e)),
};
let is_fd_frame = if len >= 11 {
(buf[10] & GS_CAN_FLAG_FD) != 0
} else {
false
};
Ok(GsUsbFrame::from_bytes(
&buf[..len],
hw_timestamps,
is_fd_frame,
))
}
pub fn bus(&self) -> u8 {
self.bus
}
pub fn address(&self) -> u8 {
self.address
}
pub fn serial_number(&mut self) -> Result<String> {
if let Some(ref sn) = self.serial_number {
return Ok(sn.clone());
}
let device = self.handle.device();
let desc = device.device_descriptor()?;
if desc.serial_number_string_index().is_some() {
let sn = self
.handle
.read_string_descriptor_ascii(desc.serial_number_string_index().unwrap())?;
self.serial_number = Some(sn.clone());
Ok(sn)
} else {
Ok(String::new())
}
}
pub fn device_info(&mut self) -> Result<DeviceInfo> {
let data = self.control_in(GS_USB_BREQ_DEVICE_CONFIG, 0, 12)?;
Ok(DeviceInfo::unpack(&data))
}
pub fn device_capability(&mut self) -> Result<DeviceCapability> {
if let Some(ref cap) = self.capability {
return Ok(*cap);
}
let data = self.control_in(GS_USB_BREQ_BT_CONST, 0, 40)?;
let cap = DeviceCapability::unpack(&data);
self.capability = Some(cap);
Ok(cap)
}
pub fn device_capability_extended(&mut self) -> Result<Option<DeviceCapability>> {
let cap = self.device_capability()?;
if (cap.feature & GS_CAN_FEATURE_BT_CONST_EXT) == 0 {
return Ok(None);
}
if let Some(ref cap) = self.capability {
if cap.has_fd_timing() {
return Ok(Some(*cap));
}
}
let data = self.control_in(GS_USB_BREQ_BT_CONST_EXT, 0, 72)?;
let cap = DeviceCapability::unpack_extended(&data);
self.capability = Some(cap);
Ok(Some(cap))
}
pub fn supports_fd(&mut self) -> Result<bool> {
let cap = self.device_capability()?;
Ok((cap.feature & GS_CAN_FEATURE_FD) != 0)
}
pub fn supports_get_state(&mut self) -> Result<bool> {
let cap = self.device_capability()?;
Ok((cap.feature & GS_CAN_FEATURE_GET_STATE) != 0)
}
pub fn get_state(&mut self, channel: u16) -> Result<DeviceState> {
if !self.supports_get_state()? {
return Err(GsUsbError::GetStateNotSupported);
}
let data = self.control_in(GS_USB_BREQ_GET_STATE, channel, 12)?;
Ok(DeviceState::unpack(&data))
}
pub fn send_host_format(&mut self) -> Result<()> {
let host_format: [u8; 4] = 0x0000_BEEFu32.to_le_bytes();
let _ = self.control_out(GS_USB_BREQ_HOST_FORMAT, 0, &host_format);
Ok(())
}
fn control_out(&self, request: u8, value: u16, data: &[u8]) -> Result<()> {
self.handle
.write_control(
0x41, request,
value,
0, data,
Duration::from_millis(1000),
)
.map_err(GsUsbError::ControlTransfer)?;
Ok(())
}
fn control_in(&self, request: u8, value: u16, length: usize) -> Result<Vec<u8>> {
let mut buf = vec![0u8; length];
let len = self
.handle
.read_control(
0xC1, request,
value,
0, &mut buf,
Duration::from_millis(1000),
)
.map_err(GsUsbError::ControlTransfer)?;
if len < length {
return Err(GsUsbError::InvalidResponse {
expected: length,
actual: len,
});
}
Ok(buf)
}
fn is_gs_usb_device(vendor_id: u16, product_id: u16) -> bool {
matches!(
(vendor_id, product_id),
(GS_USB_ID_VENDOR, GS_USB_ID_PRODUCT)
| (GS_USB_CANDLELIGHT_VENDOR_ID, GS_USB_CANDLELIGHT_PRODUCT_ID)
| (
GS_USB_CES_CANEXT_FD_VENDOR_ID,
GS_USB_CES_CANEXT_FD_PRODUCT_ID
)
| (
GS_USB_ABE_CANDEBUGGER_FD_VENDOR_ID,
GS_USB_ABE_CANDEBUGGER_FD_PRODUCT_ID
)
)
}
pub fn scan() -> Result<Vec<GsUsb>> {
let mut devices = Vec::new();
for device in rusb::devices()?.iter() {
let desc = match device.device_descriptor() {
Ok(desc) => desc,
Err(_) => continue,
};
if Self::is_gs_usb_device(desc.vendor_id(), desc.product_id()) {
let handle = match device.open() {
Ok(handle) => handle,
Err(_) => continue,
};
devices.push(GsUsb::new(handle, device.bus_number(), device.address()));
}
}
Ok(devices)
}
pub fn find(bus: u8, address: u8) -> Result<Option<GsUsb>> {
for device in rusb::devices()?.iter() {
if device.bus_number() != bus || device.address() != address {
continue;
}
let desc = match device.device_descriptor() {
Ok(desc) => desc,
Err(_) => continue,
};
if Self::is_gs_usb_device(desc.vendor_id(), desc.product_id()) {
let handle = device.open()?;
return Ok(Some(GsUsb::new(handle, bus, address)));
}
}
Ok(None)
}
}
impl std::fmt::Display for GsUsb {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let device = self.handle.device();
if let Ok(desc) = device.device_descriptor() {
write!(
f,
"GS-USB {:04x}:{:04x} (bus {}, addr {})",
desc.vendor_id(),
desc.product_id(),
self.bus,
self.address
)
} else {
write!(f, "GS-USB (bus {}, addr {})", self.bus, self.address)
}
}
}
impl std::fmt::Debug for GsUsb {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("GsUsb")
.field("bus", &self.bus)
.field("address", &self.address)
.field("started", &self.started)
.field("fd_mode", &self.fd_mode)
.field("device_flags", &format_args!("0x{:08x}", self.device_flags))
.finish()
}
}
impl Drop for GsUsb {
fn drop(&mut self) {
let _ = self.stop();
}
}