use core::cmp;
type BaudRatePrescalaInnerType = u32;
type BitSamplePointInnerType = u16;
type SegmentLengthInnerType = u8;
pub struct BitsPerSecond(u32);
pub struct MegaHertz(u32);
pub struct SegmentLength(SegmentLengthInnerType);
pub struct CanTimingLimits {
pub max_baud_rate_prescaler: u32,
pub max_segment_1_length: SegmentLength,
pub max_segment_2_length: SegmentLength,
pub max_jump_width: SegmentLength,
}
pub struct CanBitTimingParameters {
pub baud_rate_prescaler: BaudRatePrescalaInnerType,
pub seg1: SegmentLength,
pub seg2: SegmentLength,
pub jump_width: SegmentLength,
}
pub struct BitSamplePoint {
tenths_of_a_percent: BitSamplePointInnerType,
}
impl BitSamplePoint {
pub const MINIMUM_SAMPLE_POINT: BitSamplePoint = BitSamplePoint { tenths_of_a_percent: 500 };
pub const MAXIMUM_SAMPLE_POINT: BitSamplePoint = BitSamplePoint { tenths_of_a_percent: 990 };
pub fn new(tenths_of_a_percent: BitSamplePointInnerType) -> BitSamplePoint {
BitSamplePoint { tenths_of_a_percent }
}
}
pub struct CanBitTimingParameterIter<'a> {
bit_width: u32,
jump_width: SegmentLengthInnerType,
target_sample_point: BitSamplePointInnerType,
last_attempted_prescaler: BaudRatePrescalaInnerType,
interface_limits: &'a CanTimingLimits,
}
impl<'a> Iterator for CanBitTimingParameterIter<'a> {
type Item = CanBitTimingParameters;
fn next(&mut self) -> Option<CanBitTimingParameters> {
let mut result: Option<CanBitTimingParameters> = None;
while result.is_none() &&
self.last_attempted_prescaler < self.interface_limits.max_baud_rate_prescaler {
self.last_attempted_prescaler += 1;
if self.bit_width % self.last_attempted_prescaler != 0 {
continue;
}
let tq = self.bit_width / self.last_attempted_prescaler;
if tq < 8 { continue;
}
let sample = tq * 1000 / (self.target_sample_point as u32);
let seg2 = cmp::max(1, tq - sample) as SegmentLengthInnerType; let seg1 = tq as SegmentLengthInnerType - seg2 - 1;
if seg1 > self.interface_limits.max_segment_1_length.0 ||
seg2 > self.interface_limits.max_segment_2_length.0 {
continue;
}
result = Some(CanBitTimingParameters {
baud_rate_prescaler: self.last_attempted_prescaler,
seg1: SegmentLength(seg1),
seg2: SegmentLength(seg2),
jump_width: SegmentLength(self.jump_width),
});
}
result
}
}
pub fn compute_timing_parameters<'a>(clock_speed: MegaHertz,
nominal_bitrate: BitsPerSecond,
target_sample_point: BitSamplePoint,
jump_width: SegmentLength,
limits: &'a CanTimingLimits) -> CanBitTimingParameterIter {
CanBitTimingParameterIter {
bit_width: 1_000_000 * clock_speed.0 / nominal_bitrate.0,
jump_width: jump_width.0,
target_sample_point: target_sample_point.tenths_of_a_percent,
last_attempted_prescaler: 1,
interface_limits: limits,
}
}
pub mod recommended_sample_points {
use super::BitSamplePoint;
pub const ARINC825: BitSamplePoint = BitSamplePoint { tenths_of_a_percent: 750 };
pub const CANOPEN: BitSamplePoint = BitSamplePoint { tenths_of_a_percent: 875 };
pub const DEVICENET: BitSamplePoint = BitSamplePoint { tenths_of_a_percent: 875 };
pub const J1939: BitSamplePoint = BitSamplePoint { tenths_of_a_percent: 900 };
pub const J2284: BitSamplePoint = BitSamplePoint { tenths_of_a_percent: 900 };
}