pub const MAX_SEQUENCE: usize = 8;
const INCH_MASK: u16 = 0x001F;
const EOS: u16 = 0x0080;
const VRSEL_VREF: u16 = 0x0100;
const CH_TEMPERATURE: u8 = 30;
const CH_SUPPLY_HALF: u8 = 31;
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
pub(crate) enum SeqInternal {
None,
SupplyHalf,
Temperature,
}
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
pub struct SeqMember {
pub(crate) channel: u8,
pub(crate) vref: bool,
pub(crate) internal: SeqInternal,
}
impl SeqMember {
pub const fn channel(channel: u8) -> SeqMember {
SeqMember { channel, vref: false, internal: SeqInternal::None }
}
pub const fn channel_vref(channel: u8) -> SeqMember {
SeqMember { channel, vref: true, internal: SeqInternal::None }
}
pub const fn supply_half() -> SeqMember {
SeqMember { channel: CH_SUPPLY_HALF, vref: false, internal: SeqInternal::SupplyHalf }
}
pub const fn supply_vref() -> SeqMember {
SeqMember { channel: CH_SUPPLY_HALF, vref: true, internal: SeqInternal::SupplyHalf }
}
pub const fn temperature() -> SeqMember {
SeqMember { channel: CH_TEMPERATURE, vref: true, internal: SeqInternal::Temperature }
}
pub const fn needs_vref(&self) -> bool {
self.vref
}
}
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
pub enum SequenceError {
Empty,
TooLong,
BufferTooShort,
ChannelOutOfRange,
NeedsRef,
DmaIncomplete,
}
pub(crate) fn validate(
members: &[SeqMember],
results_len: usize,
have_ref: bool,
) -> Result<(), SequenceError> {
if members.is_empty() {
return Err(SequenceError::Empty);
}
if members.len() > MAX_SEQUENCE {
return Err(SequenceError::TooLong);
}
if results_len < members.len() {
return Err(SequenceError::BufferTooShort);
}
for m in members {
if m.channel > 31 {
return Err(SequenceError::ChannelOutOfRange);
}
if m.vref && !have_ref {
return Err(SequenceError::NeedsRef);
}
}
Ok(())
}
pub(crate) fn mctl_word(member: &SeqMember, last: bool) -> u16 {
(member.channel as u16 & INCH_MASK)
| if member.vref { VRSEL_VREF } else { 0 }
| if last { EOS } else { 0 }
}
pub(crate) fn encode_mctl(members: &[SeqMember], out: &mut [u16]) {
let last = members.len() - 1;
for (i, m) in members.iter().enumerate() {
out[i] = mctl_word(m, i == last);
}
}
pub(crate) fn map_bits(members: &[SeqMember]) -> (bool, bool) {
let mut batmap = false;
let mut tcmap = false;
for m in members {
match m.internal {
SeqInternal::None => {}
SeqInternal::SupplyHalf => batmap = true,
SeqInternal::Temperature => tcmap = true,
}
}
(batmap, tcmap)
}