capsules_core/virtualizers/
virtual_pwm.rs1use kernel::collections::list::{List, ListLink, ListNode};
28use kernel::hil;
29use kernel::utilities::cells::OptionalCell;
30use kernel::ErrorCode;
31
32pub struct MuxPwm<'a, P: hil::pwm::Pwm> {
33 pwm: &'a P,
34 devices: List<'a, PwmPinUser<'a, P>>,
35 inflight: OptionalCell<&'a PwmPinUser<'a, P>>,
36}
37
38impl<'a, P: hil::pwm::Pwm> MuxPwm<'a, P> {
39 pub const fn new(pwm: &'a P) -> MuxPwm<'a, P> {
40 MuxPwm {
41 pwm,
42 devices: List::new(),
43 inflight: OptionalCell::empty(),
44 }
45 }
46
47 fn do_next_op(&self) {
50 if self.inflight.is_none() {
51 let mnode = self.devices.iter().find(|node| node.operation.is_some());
52 mnode.map(|node| {
53 let started = node.operation.take().is_some_and(|operation| {
54 match operation {
55 Operation::Simple {
56 frequency_hz,
57 duty_cycle,
58 } => {
59 let _ = self.pwm.start(&node.pin, frequency_hz, duty_cycle);
60 true
61 }
62 Operation::Stop => {
63 false
65 }
66 }
67 });
68 if started {
69 self.inflight.set(node);
70 } else {
71 self.do_next_op();
73 }
74 });
75 } else {
76 self.inflight.map(|node| {
79 node.operation.take().map(|operation| {
80 match operation {
81 Operation::Simple {
82 frequency_hz,
83 duty_cycle,
84 } => {
85 let _ = self.pwm.start(&node.pin, frequency_hz, duty_cycle);
87 }
88 Operation::Stop => {
89 let _ = self.pwm.stop(&node.pin);
91 self.inflight.clear();
92 }
93 }
94 self.do_next_op();
96 });
97 });
98 }
99 }
100}
101
102#[derive(Copy, Clone, PartialEq)]
103enum Operation {
104 Simple {
105 frequency_hz: usize,
106 duty_cycle: usize,
107 },
108 Stop,
109}
110
111pub struct PwmPinUser<'a, P: hil::pwm::Pwm> {
112 mux: &'a MuxPwm<'a, P>,
113 pin: P::Pin,
114 operation: OptionalCell<Operation>,
115 next: ListLink<'a, PwmPinUser<'a, P>>,
116}
117
118impl<'a, P: hil::pwm::Pwm> PwmPinUser<'a, P> {
119 pub const fn new(mux: &'a MuxPwm<'a, P>, pin: P::Pin) -> PwmPinUser<'a, P> {
120 PwmPinUser {
121 mux,
122 pin,
123 operation: OptionalCell::empty(),
124 next: ListLink::empty(),
125 }
126 }
127
128 pub fn add_to_mux(&'a self) {
129 self.mux.devices.push_head(self);
130 }
131}
132
133impl<'a, P: hil::pwm::Pwm> ListNode<'a, PwmPinUser<'a, P>> for PwmPinUser<'a, P> {
134 fn next(&'a self) -> &'a ListLink<'a, PwmPinUser<'a, P>> {
135 &self.next
136 }
137}
138
139impl<P: hil::pwm::Pwm> hil::pwm::PwmPin for PwmPinUser<'_, P> {
140 fn start(&self, frequency_hz: usize, duty_cycle: usize) -> Result<(), ErrorCode> {
141 self.operation.set(Operation::Simple {
142 frequency_hz,
143 duty_cycle,
144 });
145 self.mux.do_next_op();
146 Ok(())
147 }
148
149 fn stop(&self) -> Result<(), ErrorCode> {
150 self.operation.set(Operation::Stop);
151 self.mux.do_next_op();
152 Ok(())
153 }
154
155 fn get_maximum_frequency_hz(&self) -> usize {
156 self.mux.pwm.get_maximum_frequency_hz()
157 }
158
159 fn get_maximum_duty_cycle(&self) -> usize {
160 self.mux.pwm.get_maximum_duty_cycle()
161 }
162}