#![warn(missing_docs)]
use std::fmt;
use std::sync::{Arc, RwLock};
use std::thread;
use crossbeam_channel::RecvError;
use serde::{Deserialize, Serialize};
mod device;
use device::gsusb::*;
use device::*;
pub mod c;
#[cfg(feature = "python")]
pub mod python;
#[derive(Debug)]
pub enum Error {
DeviceError(device::Error),
DeviceNotFound,
Timeout,
Running,
NotRunning,
InvalidChannel,
InvalidBitrate(u32),
}
impl From<device::Error> for Error {
fn from(e: device::Error) -> Error {
Error::DeviceError(e)
}
}
#[derive(Debug, Clone)]
pub struct Frame {
pub can_id: u32,
pub can_dlc: u8,
pub channel: u8,
pub data: [u8; 8],
pub ext: bool,
pub fd: bool,
pub loopback: bool,
pub rtr: bool,
}
impl Frame {
fn to_host_frame(&self) -> HostFrame {
let mut can_id = if self.ext {
self.can_id | GSUSB_EXT_FLAG
} else {
self.can_id
};
can_id = if self.rtr {
can_id | GSUSB_RTR_FLAG
} else {
can_id
};
HostFrame {
echo_id: 1,
flags: 0,
reserved: 0,
can_id,
can_dlc: self.can_dlc,
channel: self.channel,
data: self.data,
}
}
pub fn default() -> Frame {
Frame {
can_id: 0,
can_dlc: 0,
data: [0u8; 8],
channel: 0,
ext: false,
fd: false,
loopback: false,
rtr: false,
}
}
fn from_host_frame(hf: HostFrame) -> Frame {
let ext = (hf.can_id & GSUSB_EXT_FLAG) > 0;
let rtr = (hf.can_id & GSUSB_RTR_FLAG) > 0;
let can_id = hf.can_id & 0x3FFF_FFFF;
let loopback = hf.echo_id != GSUSB_RX_ECHO_ID;
Frame {
can_id,
can_dlc: hf.can_dlc,
data: hf.data,
channel: hf.channel,
ext,
loopback,
rtr,
fd: false,
}
}
}
#[derive(Debug, Serialize, Deserialize, Clone)]
pub struct Channel {
pub bitrate: u32,
pub enabled: bool,
pub loopback: bool,
pub monitor: bool,
}
pub struct Interface {
dev: Device,
running: Arc<RwLock<bool>>,
can_clock: u32,
channel_count: usize,
sw_version: u32,
hw_version: u32,
channels: Vec<Channel>,
}
impl fmt::Debug for Interface {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Interface")
.field("running", &(*self.running.read().unwrap()))
.field("can_clock", &self.can_clock)
.field("channel_count", &self.channel_count)
.field("sw_version", &self.sw_version)
.field("hw_version", &self.hw_version)
.field("channels", &self.channels)
.finish()
}
}
impl Interface {
pub fn new() -> Result<Interface, Error> {
let mut dev = match Device::new(UsbContext::new()) {
Ok(d) => d,
Err(_) => return Err(Error::DeviceNotFound),
};
let dev_config = dev.get_device_config()?;
let bt_consts = dev.get_bit_timing_consts()?;
let channel_count = dev_config.icount as usize;
let mut channels = Vec::new();
for _ in 0..(channel_count + 1) {
channels.push(Channel {
bitrate: 0,
enabled: true,
loopback: false,
monitor: false,
});
}
let i = Interface {
dev,
running: Arc::new(RwLock::from(false)),
channel_count,
can_clock: bt_consts.fclk_can,
sw_version: dev_config.sw_version,
hw_version: dev_config.hw_version,
channels,
};
Ok(i)
}
pub fn start(
&mut self,
mut rx_callback: impl FnMut(Frame) + Sync + Send + 'static,
) -> Result<(), Error> {
for (i, ch) in self.channels.iter().enumerate() {
let mut flags = 0;
if ch.monitor {
flags |= GSUSB_FEATURE_LISTEN_ONLY;
}
if ch.loopback {
flags |= GSUSB_FEATURE_LOOP_BACK;
}
let mode = Mode {
mode: CanMode::Start as u32,
flags,
};
if ch.enabled {
self.dev.set_mode(i as u16, mode).unwrap();
}
}
{
*self.running.write().unwrap() = true;
}
let can_rx = self.dev.can_rx_recv.clone();
let running = Arc::clone(&self.running);
thread::spawn(move || {
while *running.read().unwrap() {
match can_rx.recv() {
Ok(hf) => rx_callback(Frame::from_host_frame(hf)),
Err(RecvError) => {
break;
}
}
}
});
self.dev.start_transfers().unwrap();
Ok(())
}
pub fn stop(&mut self) -> Result<(), Error> {
for (i, ch) in self.channels.iter().enumerate() {
let mode = Mode {
mode: CanMode::Reset as u32,
flags: 0,
};
if ch.enabled {
self.dev.set_mode(i as u16, mode).unwrap();
}
}
self.dev.stop_transfers().unwrap();
*self.running.write().unwrap() = false;
Ok(())
}
pub fn set_bitrate(&mut self, channel: usize, bitrate: u32) -> Result<(), Error> {
if channel > self.channel_count {
return Err(Error::InvalidChannel);
}
let bt = calculate_bit_timing(self.can_clock, bitrate)?;
self.dev
.set_bit_timing(channel as u16, bt)
.expect("failed to set bit timing");
self.channels[channel].bitrate = bitrate;
Ok(())
}
pub fn set_monitor(&mut self, channel: usize, enabled: bool) -> Result<(), Error> {
if channel > self.channel_count {
return Err(Error::InvalidChannel);
}
if *self.running.read().unwrap() {
return Err(Error::Running);
}
self.channels[channel].monitor = enabled;
Ok(())
}
pub fn set_enabled(&mut self, channel: usize, enabled: bool) -> Result<(), Error> {
if channel > self.channel_count {
return Err(Error::InvalidChannel);
}
if *self.running.read().unwrap() {
return Err(Error::Running);
}
self.channels[channel].enabled = enabled;
Ok(())
}
pub fn set_loopback(&mut self, channel: usize, enabled: bool) -> Result<(), Error> {
if channel > self.channel_count {
return Err(Error::InvalidChannel);
}
if *self.running.read().unwrap() {
return Err(Error::Running);
}
self.channels[channel].loopback = enabled;
Ok(())
}
pub fn send(&mut self, f: Frame) -> Result<(), Error> {
if !*self.running.read().unwrap() {
return Err(Error::NotRunning);
}
self.dev.send(f.to_host_frame()).unwrap();
Ok(())
}
pub fn channels(&self) -> usize {
self.channel_count + 1
}
}
fn calculate_bit_timing(clk: u32, bitrate: u32) -> Result<BitTiming, Error> {
let max_brp = 32;
let min_seg1 = 3;
let max_seg1 = 18;
let min_seg2 = 2;
let max_seg2 = 8;
let tolerances = vec![0.0, 0.1 / 100.0, 0.5 / 100.0];
for tolerance in tolerances {
let tmp = clk as f32 / bitrate as f32;
for brp in 1..(max_brp + 1) {
let btq = tmp / brp as f32;
let btq_rounded = btq.round() as u32;
if btq_rounded >= 4 && btq_rounded <= 32 {
let err = ((btq / (btq_rounded as f32) - 1.0) * 10000.0).round() / 10000.0;
if err.abs() > tolerance {
continue;
}
}
for seg1 in min_seg1..max_seg1 {
let seg2 = btq_rounded - seg1 - 1;
if seg2 < min_seg2 || seg2 > max_seg2 {
continue;
}
return Ok(BitTiming {
brp,
prop_seg: 0,
phase_seg1: seg1,
phase_seg2: seg2,
sjw: 1,
});
}
}
}
Err(Error::InvalidBitrate(bitrate))
}
#[allow(dead_code)]
fn effective_bitrate(clk: u32, bt: BitTiming) -> u32 {
clk / bt.brp / (bt.prop_seg + bt.phase_seg1 + bt.phase_seg2 + 1)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_bit_timing() {
let clk = 48000000;
let bitrates = vec![1000000, 500000, 250000, 125000];
for b in bitrates {
let bt = calculate_bit_timing(clk, b).unwrap();
let err = 100.0 * (1.0 - (effective_bitrate(clk, bt) as f32 / b as f32).abs());
assert!(err < 0.5);
}
}
}