use arrayvec::ArrayVec;
use core::any::{Any, TypeId};
use core::cell::RefCell;
use core::marker::PhantomData;
use cortex_m::singleton;
use critical_section::Mutex;
use defmt::Format;
use fugit::HertzU32;
use pio::Program;
use pio_proc::pio_file;
use rp2040_hal::clocks::SystemClock;
use rp2040_hal::dma::double_buffer::{
Config as DoubleBufferingConfig, ReadNext, Transfer as DoubleBuffering,
};
use rp2040_hal::dma::{Channel, ChannelIndex, ReadTarget, SingleChannel};
use rp2040_hal::gpio::{DynPinId, Function, Pin, PullNone};
use rp2040_hal::pio::{
PIOExt, PinDir, Running, StateMachine, StateMachineIndex, Tx, UninitStateMachine, PIO,
};
use rp2040_hal::{self, Clock};
use crate::initialize_array;
pub type DynPin<F> = Pin<DynPinId, F, PullNone>;
type PinData = &'static mut Sequence;
type TxTransfer<C1, C2, P, SM> =
DoubleBuffering<Channel<C1>, Channel<C2>, PinData, Tx<(P, SM)>, ReadNext<PinData>>;
type WaitingTxTransfer<C1, C2, P, SM> =
DoubleBuffering<Channel<C1>, Channel<C2>, PinData, Tx<(P, SM)>, ()>;
const NUM_BUFFERS: usize = 3;
const BUFFER_SIZE: usize = 64;
const LOADING_ZONE_SIZE: u32 = 3;
const LOADING_ZONE_POSITION: u32 = 55;
const MAX_PWM_CLUSTER_WRAP: u64 = u16::MAX as u64;
const PWM_CLUSTER_CYCLES: u64 = 5;
pub struct GlobalState<C1, C2, P, SM>
where
C1: ChannelIndex,
C2: ChannelIndex,
P: PIOExt,
SM: StateMachineIndex,
{
handler: Option<InterruptHandler<C1, C2, P, SM>>,
indices: Mutex<RefCell<Indices>>,
sequences: Mutex<RefCell<SequenceList>>,
sequence1: Sequence,
sequence2: Sequence,
sequence3: Sequence,
loop_sequences: Mutex<RefCell<SequenceList>>,
loop_sequence1: Sequence,
loop_sequence2: Sequence,
loop_sequence3: Sequence,
}
pub trait Handler: Any {
fn try_next_dma_sequence(&mut self);
}
impl dyn Handler {
#[inline]
pub(crate) fn downcast_mut<T: Any>(&mut self) -> Option<&mut T> {
if self.is::<T>() {
unsafe { Some(self.downcast_mut_unchecked()) }
} else {
None
}
}
#[inline]
pub(crate) unsafe fn downcast_mut_unchecked<T: Any>(&mut self) -> &mut T {
debug_assert!(self.is::<T>());
unsafe { &mut *(self as *mut dyn Handler as *mut T) }
}
#[inline]
pub(crate) fn is<T: Any>(&self) -> bool {
let t = TypeId::of::<T>();
let concrete = self.type_id();
t == concrete
}
}
impl<C1, C2, P, SM> Handler for GlobalState<C1, C2, P, SM>
where
C1: ChannelIndex + 'static,
C2: ChannelIndex + 'static,
P: PIOExt + 'static,
SM: StateMachineIndex + 'static,
{
fn try_next_dma_sequence(&mut self) {
if let Some(ref mut handler) = self.handler {
handler.try_next_dma_sequence();
}
}
}
pub struct GlobalStates<const NUM_CHANNELS: usize> {
pub states: [Option<&'static mut dyn Handler>; NUM_CHANNELS],
}
impl<const NUM_CHANNELS: usize> GlobalStates<NUM_CHANNELS> {
pub(crate) fn get_mut<C1, C2, P, SM, F>(
&mut self,
_channels: &mut (Channel<C1>, Channel<C2>),
ctor: F,
) -> Option<*mut GlobalState<C1, C2, P, SM>>
where
C1: ChannelIndex + 'static,
C2: ChannelIndex + 'static,
P: PIOExt + 'static,
SM: StateMachineIndex + 'static,
F: FnOnce() -> &'static mut GlobalState<C1, C2, P, SM>,
{
let entry = &mut self.states[<C1 as ChannelIndex>::id() as usize];
if entry.is_none() {
*entry = Some(ctor())
}
let state: *mut &'static mut dyn Handler = entry.as_mut().unwrap() as *mut _;
let state: &'static mut dyn Handler = unsafe { *state };
<dyn Handler>::downcast_mut::<GlobalState<C1, C2, P, SM>>(state).map(|d| d as *mut _)
}
}
struct Indices {
last_written_index: usize,
read_index: usize,
}
impl Indices {
fn new() -> Self {
Self {
last_written_index: 0,
read_index: 0,
}
}
}
struct SequenceListBuilder;
type SequenceList = [Option<*mut Sequence>; NUM_BUFFERS];
impl SequenceListBuilder {
fn build() -> SequenceList {
initialize_array::<Option<*mut Sequence>, NUM_BUFFERS>(|| None)
}
}
pub struct InterruptHandler<C1, C2, P, SM>
where
C1: ChannelIndex,
C2: ChannelIndex,
P: PIOExt,
SM: StateMachineIndex,
{
sequences: &'static Mutex<RefCell<SequenceList>>,
loop_sequences: &'static Mutex<RefCell<SequenceList>>,
indices: &'static Mutex<RefCell<Indices>>,
tx_transfer: Option<TxTransfer<C1, C2, P, SM>>,
last_was_loop: Option<bool>,
}
#[inline]
pub fn dma_interrupt<const NUM_PINS: usize>(global_state: &'static mut GlobalStates<NUM_PINS>) {
for state in global_state.states.iter_mut().flatten() {
state.try_next_dma_sequence();
}
}
impl<C1, C2, P, SM> InterruptHandler<C1, C2, P, SM>
where
C1: ChannelIndex,
C2: ChannelIndex,
P: PIOExt,
SM: StateMachineIndex,
{
fn try_next_dma_sequence(&mut self) {
let (tx_buf, tx) = {
if let Some(mut tx_transfer) = self.tx_transfer.take() {
if tx_transfer.check_irq0() && tx_transfer.is_done() {
tx_transfer.wait()
} else {
self.tx_transfer = Some(tx_transfer);
return;
}
} else {
return;
}
};
self.next_dma_sequence(tx_buf, tx);
}
fn next_dma_sequence(
&mut self,
tx_buf: &'static mut Sequence,
tx: WaitingTxTransfer<C1, C2, P, SM>,
) {
critical_section::with(|cs| {
let mut indices = self.indices.borrow(cs).borrow_mut();
let next_buf = if indices.last_written_index != indices.read_index {
if let Some(last_was_loop) = self.last_was_loop {
if last_was_loop {
self.loop_sequences.borrow(cs).borrow_mut()[indices.read_index] =
Some(tx_buf);
} else {
self.sequences.borrow(cs).borrow_mut()[indices.read_index] = Some(tx_buf);
}
}
indices.read_index = indices.last_written_index;
self.last_was_loop = Some(false);
self.sequences.borrow(cs).borrow_mut()[indices.read_index]
.take()
.unwrap()
} else {
if let Some(false) = self.last_was_loop {
self.sequences.borrow(cs).borrow_mut()[indices.read_index] = Some(tx_buf);
}
if let Some(sequence) =
self.loop_sequences.borrow(cs).borrow_mut()[indices.read_index].take()
{
self.last_was_loop = Some(true);
sequence
} else {
tx_buf as *mut _
}
};
self.tx_transfer = Some(tx.read_next(unsafe { &mut *next_buf }));
});
}
}
pub struct PwmCluster<const NUM_PINS: usize, P, SM>
where
P: PIOExt,
SM: StateMachineIndex,
{
sm: Option<StateMachine<(P, SM), Running>>,
channel_to_pin_map: [u8; NUM_PINS],
channels: [ChannelState; NUM_PINS],
sequences: &'static Mutex<RefCell<SequenceList>>,
loop_sequences: &'static Mutex<RefCell<SequenceList>>,
indices: &'static Mutex<RefCell<Indices>>,
transitions: [TransitionData; BUFFER_SIZE],
looping_transitions: [TransitionData; BUFFER_SIZE],
loading_zone: bool,
top: u32,
}
pub struct PwmClusterBuilder<const NUM_PINS: usize, P> {
pin_mask: u32,
#[cfg(feature = "debug_pio")]
side_set_pin: u8,
channel_to_pin_map: [u8; NUM_PINS],
_phantom: PhantomData<P>,
}
impl<const NUM_PINS: usize, P> PwmClusterBuilder<NUM_PINS, P> {
pub fn new() -> Self {
Self {
pin_mask: 0,
#[cfg(feature = "debug_pio")]
side_set_pin: 0,
channel_to_pin_map: [0; NUM_PINS],
_phantom: PhantomData,
}
}
pub fn pin_base<F>(mut self, base_pin: DynPin<F>) -> Self
where
P: PIOExt<PinFunction = F>,
F: Function,
{
let base_pin = base_pin.id().num;
for (i, pin_map) in self.channel_to_pin_map.iter_mut().enumerate() {
let pin_id = base_pin + i as u8;
self.pin_mask |= 1 << pin_id;
*pin_map = pin_id;
}
self
}
pub fn pins<F>(mut self, pins: &[DynPin<F>; NUM_PINS]) -> Self
where
P: PIOExt<PinFunction = F>,
F: Function,
{
for (pin, pin_map) in pins.iter().zip(self.channel_to_pin_map.iter_mut()) {
let pin_id = pin.id().num;
self.pin_mask |= 1 << pin_id;
*pin_map = pin_id;
}
self
}
#[cfg(feature = "debug_pio")]
pub fn side_pin<F>(mut self, side_set_pin: &DynPin<F>) -> Self
where
P: PIOExt<PinFunction = F>,
F: Function,
{
self.side_set_pin = side_set_pin.id().num;
self
}
pub(crate) fn prep_global_state<C1, C2, SM>(
global_state: &'static mut Option<GlobalState<C1, C2, P, SM>>,
) -> &'static mut GlobalState<C1, C2, P, SM>
where
C1: ChannelIndex,
C2: ChannelIndex,
P: PIOExt,
SM: StateMachineIndex,
{
if global_state.is_none() {
*global_state = Some(GlobalState {
handler: None,
indices: Mutex::new(RefCell::new(Indices::new())),
sequences: Mutex::new(RefCell::new(SequenceListBuilder::build())),
sequence1: Sequence::new_for_list(),
sequence2: Sequence::new_for_list(),
sequence3: Sequence::new_for_list(),
loop_sequences: Mutex::new(RefCell::new(SequenceListBuilder::build())),
loop_sequence1: Sequence::new_for_list(),
loop_sequence2: Sequence::new_for_list(),
loop_sequence3: Sequence::new_for_list(),
});
{
let state = (*global_state).as_mut().unwrap();
critical_section::with(|cs| {
let mut sequences = state.sequences.borrow(cs).borrow_mut();
sequences[0] = Some(&mut state.sequence1 as *mut _);
sequences[1] = Some(&mut state.sequence2 as *mut _);
sequences[2] = Some(&mut state.sequence3 as *mut _);
let mut loop_sequences = state.loop_sequences.borrow(cs).borrow_mut();
loop_sequences[0] = Some(&mut state.loop_sequence1 as *mut _);
loop_sequences[1] = Some(&mut state.loop_sequence2 as *mut _);
loop_sequences[2] = Some(&mut state.loop_sequence3 as *mut _);
});
}
}
global_state.as_mut().unwrap()
}
#[allow(clippy::too_many_arguments)]
pub unsafe fn build<C1, C2, SM, F>(
self,
servo_pins: [DynPin<F>; NUM_PINS],
pio: &mut PIO<P>,
sm: UninitStateMachine<(P, SM)>,
mut dma_channels: (Channel<C1>, Channel<C2>),
sys_clock: &SystemClock,
global_state: *mut GlobalState<C1, C2, P, SM>,
) -> PwmCluster<NUM_PINS, P, SM>
where
C1: ChannelIndex,
C2: ChannelIndex,
P: PIOExt<PinFunction = F>,
F: Function,
SM: StateMachineIndex,
{
let program = Self::pio_program();
let installed = pio.install(&program).unwrap();
const DESIRED_CLOCK_HZ: u32 = 500_000;
let sys_hz = sys_clock.freq().to_Hz();
let (int, frac) = (
(sys_hz / DESIRED_CLOCK_HZ) as u16,
(sys_hz as u64 * 256 / DESIRED_CLOCK_HZ as u64) as u8,
);
let (mut sm, _, tx) = {
let mut builder = rp2040_hal::pio::PIOBuilder::from_program(installed);
#[cfg(not(feature = "debug_pio"))]
{
builder = builder.out_pins(0, 32)
}
#[cfg(feature = "debug_pio")]
{
builder = builder
.out_pins(0, self.side_set_pin)
.side_set_pin_base(self.side_set_pin)
}
builder.clock_divisor_fixed_point(int, frac).build(sm)
};
{
let iter_a = servo_pins.into_iter().map(|pin| pin.id().num);
let iter;
#[cfg(not(feature = "debug_pio"))]
{
iter = iter_a;
}
#[cfg(feature = "debug_pio")]
{
iter = iter_a.chain(Some(self.side_set_pin));
}
sm.set_pindirs(iter.map(|id| (id, PinDir::Output)));
}
let sequence = Sequence::new_for_list();
let mut interrupt_handler = unsafe {
InterruptHandler {
sequences: &(*global_state).sequences,
loop_sequences: &(*global_state).loop_sequences,
indices: &(*global_state).indices,
tx_transfer: None,
last_was_loop: None,
}
};
let tx_buf = singleton!(: Sequence = sequence.clone()).unwrap();
dma_channels.0.enable_irq0();
dma_channels.1.enable_irq0();
let tx = DoubleBufferingConfig::new(dma_channels, tx_buf, tx).start();
let tx_buf = singleton!(: Sequence = sequence).unwrap();
interrupt_handler.next_dma_sequence(tx_buf, tx);
unsafe { (*global_state).handler = Some(interrupt_handler) };
let sm = sm.start();
unsafe {
PwmCluster::new(
sm,
self.channel_to_pin_map,
&(*global_state).indices,
&(*global_state).sequences,
&(*global_state).loop_sequences,
)
}
}
#[cfg(feature = "debug_pio")]
fn pio_program() -> Program<32> {
#[allow(non_snake_case)]
let pwm_program = pio_file!("./src/pwm.pio", select_program("debug_pwm_cluster"));
pwm_program.program
}
#[cfg(not(feature = "debug_pio"))]
fn pio_program() -> Program<32> {
#[allow(non_snake_case)]
let pwm_program = pio_file!("./src/pwm.pio", select_program("pwm_cluster"));
pwm_program.program
}
}
impl<const NUM_PINS: usize, P> Default for PwmClusterBuilder<NUM_PINS, P> {
fn default() -> Self {
Self::new()
}
}
impl<const NUM_PINS: usize, P, SM> PwmCluster<NUM_PINS, P, SM>
where
P: PIOExt,
SM: StateMachineIndex,
{
pub const CHANNEL_COUNT: usize = NUM_PINS;
pub const CHANNEL_PAIR_COUNT: usize = NUM_PINS / 2;
pub fn builder() -> PwmClusterBuilder<NUM_PINS, P> {
PwmClusterBuilder::new()
}
fn new(
sm: StateMachine<(P, SM), Running>,
channel_to_pin_map: [u8; NUM_PINS],
indices: &'static Mutex<RefCell<Indices>>,
sequences: &'static Mutex<RefCell<SequenceList>>,
loop_sequences: &'static Mutex<RefCell<SequenceList>>,
) -> Self {
let channels = [ChannelState::new(); NUM_PINS];
let transitions = [TransitionData::default(); BUFFER_SIZE];
let looping_transitions = [TransitionData::default(); BUFFER_SIZE];
Self {
sm: Some(sm),
channel_to_pin_map,
channels,
sequences,
loop_sequences,
loading_zone: false,
top: 0,
indices,
transitions,
looping_transitions,
}
}
pub fn calculate_pwm_factors(system_clock_hz: HertzU32, freq: f32) -> Option<(u32, u32)> {
let source_hz = system_clock_hz.to_Hz() as u64 / PWM_CLUSTER_CYCLES;
if (freq >= 0.01) && (freq <= (source_hz >> 1) as f32) {
let mut div256_top = ((source_hz << 8) as f32 / freq) as u64;
let mut top: u64 = 1;
loop {
if (div256_top >= (11 << 8))
&& (div256_top % 11 == 0)
&& (top * 11 <= MAX_PWM_CLUSTER_WRAP)
{
div256_top /= 11;
top *= 11;
} else if (div256_top >= (7 << 8))
&& (div256_top % 7 == 0)
&& (top * 7 <= MAX_PWM_CLUSTER_WRAP)
{
div256_top /= 7;
top *= 7;
} else if (div256_top >= (5 << 8))
&& (div256_top % 5 == 0)
&& (top * 5 <= MAX_PWM_CLUSTER_WRAP)
{
div256_top /= 5;
top *= 5;
} else if (div256_top >= (3 << 8))
&& (div256_top % 3 == 0)
&& (top * 3 <= MAX_PWM_CLUSTER_WRAP)
{
div256_top /= 3;
top *= 3;
} else if (div256_top >= (2 << 8)) && (top * 2 <= MAX_PWM_CLUSTER_WRAP) {
div256_top /= 2;
top *= 2;
} else {
break;
}
}
if div256_top >= 256 && div256_top <= ((u8::MAX as u64) << 8) {
Some((top as u32, div256_top as u32))
} else {
None
}
} else {
None
}
}
pub fn clock_divisor_fixed_point(&mut self, div: u16, frac: u8) {
if let Some(sm) = self.sm.take() {
let mut sm = sm.stop();
sm.clock_divisor_fixed_point(div, frac);
self.sm = Some(sm.start());
}
}
pub fn channel_level(&self, channel: u8) -> Result<u32, PwmError> {
self.channels
.get(channel as usize)
.map(|c| c.level)
.ok_or(PwmError::MissingChannel)
}
pub fn set_channel_level(
&mut self,
channel: u8,
level: u32,
load: bool,
) -> Result<(), PwmError> {
let res = self
.channels
.get_mut(channel as usize)
.map(|c| c.level = level)
.ok_or(PwmError::MissingChannel);
if load {
self.load_pwm();
}
res
}
pub fn channel_offset(&self, channel: u8) -> Result<u32, PwmError> {
self.channels
.get(channel as usize)
.map(|c| c.offset)
.ok_or(PwmError::MissingChannel)
}
pub fn set_channel_offset(
&mut self,
channel: u8,
offset: u32,
load: bool,
) -> Result<(), PwmError> {
self.channels
.get_mut(channel as usize)
.map(|c| c.offset = offset)
.ok_or(PwmError::MissingChannel)?;
if load {
self.load_pwm();
}
Ok(())
}
pub fn channel_polarity(&self, channel: u8) -> Result<bool, PwmError> {
self.channels
.get(channel as usize)
.map(|c| c.polarity)
.ok_or(PwmError::MissingChannel)
}
pub fn set_channel_polarity(
&mut self,
channel: u8,
polarity: bool,
load: bool,
) -> Result<(), PwmError> {
self.channels
.get_mut(channel as usize)
.map(|c| c.polarity = polarity)
.ok_or(PwmError::MissingChannel)?;
if load {
self.load_pwm()
}
Ok(())
}
pub fn top(&self) -> u32 {
self.top
}
pub fn set_top(&mut self, top: u32, load_pwm: bool) {
self.top = top.max(1); if load_pwm {
self.load_pwm();
}
}
pub fn load_pwm(&mut self) {
let mut data_size = 0;
let mut looping_data_size = 0;
let mut pin_states = 0;
let read_since_last_write = critical_section::with(|cs| {
let indices = self.indices.borrow(cs).borrow();
indices.read_index == indices.last_written_index
});
for (channel_idx, state) in self.channels.iter_mut().enumerate() {
if state.polarity {
pin_states |= 1 << self.channel_to_pin_map[channel_idx];
}
let channel_start = state.offset;
let channel_end = state.offset + state.level;
let channel_wrap_end = channel_end % self.top;
if read_since_last_write {
state.overrun = state.next_overrun;
}
state.next_overrun = 0;
if state.overrun > 0 {
pin_states ^= 1 << self.channel_to_pin_map[channel_idx];
if channel_wrap_end < channel_start {
Self::sorted_insert(
&mut self.transitions,
&mut data_size,
TransitionData::new(channel_idx as u8, channel_wrap_end, state.polarity),
)
} else if state.overrun < channel_start {
Self::sorted_insert(
&mut self.transitions,
&mut data_size,
TransitionData::new(channel_idx as u8, state.overrun, state.polarity),
)
}
}
if state.level > 0 && channel_start < self.top {
Self::sorted_insert(
&mut self.transitions,
&mut data_size,
TransitionData {
channel: channel_idx as u8,
level: channel_start,
state: !state.polarity,
dummy: false,
},
);
Self::sorted_insert(
&mut self.looping_transitions,
&mut looping_data_size,
TransitionData {
channel: channel_idx as u8,
level: channel_start,
state: !state.polarity,
dummy: false,
},
);
if channel_wrap_end < channel_start {
state.next_overrun = channel_wrap_end;
}
}
if state.level < self.top {
if channel_end < self.top {
Self::sorted_insert(
&mut self.transitions,
&mut data_size,
TransitionData::new(channel_idx as u8, channel_end, state.polarity),
);
}
Self::sorted_insert(
&mut self.looping_transitions,
&mut looping_data_size,
TransitionData::new(channel_idx as u8, channel_wrap_end, state.polarity),
);
}
}
if self.loading_zone {
let zone_inserts = LOADING_ZONE_SIZE.min(self.top - LOADING_ZONE_POSITION);
for i in (zone_inserts + LOADING_ZONE_POSITION)..LOADING_ZONE_POSITION {
Self::sorted_insert(
&mut self.transitions,
&mut data_size,
TransitionData::with_level(self.top - i),
);
Self::sorted_insert(
&mut self.looping_transitions,
&mut looping_data_size,
TransitionData::with_level(self.top - i),
);
}
}
let write_index = critical_section::with(|cs| {
let indices = self.indices.borrow(cs).borrow();
let write_index = (indices.read_index + 1) % NUM_BUFFERS;
if write_index == indices.last_written_index {
(write_index + 1) % NUM_BUFFERS
} else {
write_index
}
});
self.populate_sequence(
TransitionType::Normal,
data_size,
write_index,
&mut pin_states,
);
self.populate_sequence(
TransitionType::Loop,
looping_data_size,
write_index,
&mut pin_states,
);
critical_section::with(|cs| {
let mut indices = self.indices.borrow(cs).borrow_mut();
indices.last_written_index = write_index;
});
}
fn sorted_insert(transitions: &mut [TransitionData], size: &mut usize, data: TransitionData) {
let mut i = *size;
while i > 0 && transitions[i - 1].level > data.level {
transitions[i] = transitions[i - 1];
i -= 1;
}
transitions[i] = data;
*size += 1;
}
fn populate_sequence(
&mut self,
transition_type: TransitionType,
transition_size: usize,
sequence_id: usize,
pin_states: &mut u32,
) {
critical_section::with(|cs| {
let mut sequences;
let mut loop_sequences;
let (transitions, sequence) = match transition_type {
TransitionType::Normal => {
sequences = self.sequences.borrow(cs).borrow_mut();
(
&self.transitions[..transition_size],
sequences[sequence_id].as_mut().unwrap(),
)
}
TransitionType::Loop => {
loop_sequences = self.loop_sequences.borrow(cs).borrow_mut();
(
&self.looping_transitions[..transition_size],
loop_sequences[sequence_id].as_mut().unwrap(),
)
}
};
(unsafe { &mut **sequence }).data.clear();
let mut data_index = 0;
let mut current_level = 0;
while data_index < transition_size {
let mut next_level = self.top;
loop {
let transition = &transitions[data_index];
if transition.level <= current_level {
if !transition.dummy {
if transition.state {
*pin_states |=
1 << self.channel_to_pin_map[transition.channel as usize];
} else {
*pin_states &=
!(1 << self.channel_to_pin_map[transition.channel as usize]);
}
}
data_index += 1;
} else {
next_level = transition.level;
break;
}
if data_index >= transition_size {
break;
}
}
let transition = Transition {
mask: *pin_states,
delay: (next_level - current_level) - 1,
};
(unsafe { &mut **sequence }).data.push(transition);
current_level = next_level;
}
});
}
}
pub enum PwmError {
MissingChannel,
}
#[derive(Copy, Clone, Format)]
enum TransitionType {
Normal,
Loop,
}
#[derive(Copy, Clone, Format)]
struct ChannelState {
level: u32,
offset: u32,
polarity: bool,
overrun: u32,
next_overrun: u32,
}
impl ChannelState {
fn new() -> Self {
Self {
level: 0,
offset: 0,
polarity: false,
overrun: 0,
next_overrun: 0,
}
}
}
#[derive(Clone)]
pub struct Sequence {
data: ArrayVec<Transition, BUFFER_SIZE>,
}
impl Sequence {
pub fn new() -> Self {
let mut data = ArrayVec::default();
data.push(Transition::new());
Self { data }
}
fn new_for_list() -> Self {
let mut this = Self::new();
this.data[0].delay = 10;
this
}
}
impl Default for Sequence {
fn default() -> Self {
Self::new()
}
}
unsafe impl ReadTarget for &mut Sequence {
type ReceivedWord = u32;
fn rx_treq() -> Option<u8> {
None
}
fn rx_address_count(&self) -> (u32, u32) {
(self.data.as_ptr() as u32, self.data.len() as u32 * 2)
}
fn rx_increment(&self) -> bool {
true
}
}
#[derive(Copy, Clone)]
#[repr(C)]
pub struct Transition {
mask: u32,
delay: u32,
}
impl Format for Transition {
fn format(&self, f: defmt::Formatter) {
defmt::write!(
f,
"Transition {{ mask: {:#032b}, delay: {} }}",
self.mask,
self.delay
)
}
}
impl Transition {
fn new() -> Self {
Self { mask: 0, delay: 0 }
}
}
#[derive(Copy, Clone, Default, Format)]
struct TransitionData {
channel: u8,
level: u32,
state: bool,
dummy: bool,
}
impl TransitionData {
fn new(channel: u8, level: u32, state: bool) -> Self {
Self {
channel,
level,
state,
dummy: false,
}
}
fn with_level(level: u32) -> Self {
Self {
channel: 0,
level,
state: false,
dummy: true,
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn transition_must_be_exact() {
assert_eq!(core::mem::size_of::<Transition>(), 2);
assert_eq!(core::mem::size_of::<MaybeUninit<Transition>>(), 2);
}
}