#[derive(Debug, PartialEq, Eq, Clone)]
#[non_exhaustive]
pub struct Parameters {
pub address: u8,
pub baudrate: crate::Baudrate,
pub slot_bits: u16,
pub token_rotation_bits: u32,
pub gap_wait_rotations: u8,
pub highest_station_address: u8,
pub max_retry_limit: u8,
pub min_tsdr_bits: u8,
pub watchdog_factors: Option<(u8, u8)>,
}
impl Default for Parameters {
fn default() -> Self {
Parameters {
address: 1,
baudrate: crate::Baudrate::B19200,
slot_bits: 100,
token_rotation_bits: 32436,
gap_wait_rotations: 10,
highest_station_address: 126,
min_tsdr_bits: 11,
max_retry_limit: 1,
watchdog_factors: None,
}
}
}
impl Parameters {
#[inline(always)]
pub fn debug_assert_consistency(&self) {
crate::debug_assert_address(self.address);
debug_assert!(self.highest_station_address <= 126);
}
}
#[inline]
fn min_slot_bits(baudrate: crate::Baudrate) -> u16 {
match baudrate {
crate::Baudrate::B9600
| crate::Baudrate::B19200
| crate::Baudrate::B31250
| crate::Baudrate::B45450
| crate::Baudrate::B93750
| crate::Baudrate::B187500 => 100,
crate::Baudrate::B500000 => 200,
crate::Baudrate::B1500000 => 300,
crate::Baudrate::B3000000 => 400,
crate::Baudrate::B6000000 => 600,
crate::Baudrate::B12000000 => 1000,
}
}
#[inline]
fn watchdog_factors(dur: crate::time::Duration) -> Option<Result<(u8, u8), ()>> {
Some(dur)
.filter(|dur| *dur != crate::time::Duration::ZERO)
.map(|dur| {
let timeout_10ms: u32 = (dur.total_millis() / 10).try_into().or(Err(()))?;
for f1 in 1..256 {
let f2 = (timeout_10ms + f1 - 1) / f1;
if f2 < 256 {
return Ok((u8::try_from(f1).unwrap(), u8::try_from(f2).unwrap()));
}
}
Err(())
})
}
pub struct ParametersBuilder(Parameters);
impl ParametersBuilder {
#[inline]
pub fn new(address: u8, baudrate: crate::Baudrate) -> Self {
assert!(address <= 125);
Self(Parameters {
address,
baudrate,
slot_bits: min_slot_bits(baudrate),
..Default::default()
})
}
#[inline]
pub fn slot_bits(&mut self, slot_bits: u16) -> &mut Self {
self.0.slot_bits = slot_bits;
assert!(slot_bits >= min_slot_bits(self.0.baudrate));
self
}
#[inline]
pub fn highest_station_address(&mut self, hsa: u8) -> &mut Self {
assert!(hsa > self.0.address && hsa <= 126);
self.0.highest_station_address = hsa;
self.token_rotation_bits(u32::from(hsa) * 5000);
self
}
pub fn token_rotation_bits(&mut self, ttr: u32) -> &mut Self {
assert!(ttr >= 256 && ttr <= 16_777_960);
self.0.token_rotation_bits = ttr;
self
}
pub fn gap_wait_rotations(&mut self, gap_wait: u8) -> &mut Self {
assert!(gap_wait >= 1 && gap_wait <= 100);
self.0.gap_wait_rotations = gap_wait;
self
}
#[inline]
pub fn max_retry_limit(&mut self, max_retry_limit: u8) -> &mut Self {
assert!(max_retry_limit >= 1 && max_retry_limit <= 15);
self.0.max_retry_limit = max_retry_limit;
self
}
#[inline]
pub fn min_tsdr(&mut self, min_tsdr_bits: u8) -> &mut Self {
assert!(min_tsdr_bits >= 11);
self.0.min_tsdr_bits = min_tsdr_bits;
self
}
#[inline]
pub fn watchdog_timeout(&mut self, wdg: crate::time::Duration) -> &mut Self {
assert!(wdg >= crate::time::Duration::from_millis(10));
assert!(wdg <= crate::time::Duration::from_secs(650));
self.0.watchdog_factors = watchdog_factors(wdg).transpose().unwrap();
self
}
#[inline]
pub fn build(&self) -> Parameters {
self.0.clone()
}
#[inline]
pub fn build_verified(&self, dp_master: &crate::dp::DpMaster) -> Parameters {
for (_, peripheral) in dp_master.iter() {
assert!(
peripheral.options().max_tsdr + 15 <= self.0.slot_bits,
"max Tsdr of peripheral #{} too large for slot time",
peripheral.address(),
);
}
self.0.clone()
}
}
impl Parameters {
pub fn bits_to_time(&self, bits: u32) -> crate::time::Duration {
self.baudrate.bits_to_time(bits)
}
pub fn slot_time(&self) -> crate::time::Duration {
self.bits_to_time(u32::from(self.slot_bits))
}
pub fn min_tsdr_time(&self) -> crate::time::Duration {
self.bits_to_time(u32::from(self.min_tsdr_bits))
}
pub fn token_lost_timeout(&self) -> crate::time::Duration {
let timeout_bits = u32::from(self.slot_bits) * (6 + 2 * u32::from(self.address));
self.bits_to_time(timeout_bits)
}
pub fn token_rotation_time(&self) -> crate::time::Duration {
self.bits_to_time(self.token_rotation_bits)
}
pub fn watchdog_timeout(&self) -> Option<crate::time::Duration> {
self.watchdog_factors
.map(|(f1, f2)| crate::time::Duration::from_millis(u64::from(f1) * u64::from(f2) * 10))
}
}