1#![doc = include_str!("../README.md")]
5#![cfg_attr(not(test), no_std)]
6#![deny(missing_docs)]
7
8pub use bitvec;
9use bitvec::prelude::*;
10use embedded_hal::digital::v2::OutputPin;
11
12pub mod packets;
13
14const BUFFER_SIZE: usize = 24 * 8;
15type BufferType = BitArr!(for 24*8, in u8, Msb0);
16const ZERO_MICROS: u32 = 100;
17const ONE_MICROS: u32 = 58;
18
19#[derive(Copy, Clone, Debug, Eq, PartialEq)]
21pub enum Error {
22 TooLong,
24 InvalidAddress,
26 InvalidSpeed,
28 InvalidOffset,
30 MissingField,
32}
33
34#[derive(Debug)]
35enum TxState {
36 Idle {
37 second_half_of_bit: bool,
38 },
39 Transmitting {
40 offset: usize,
41 second_half_of_bit: bool,
42 },
43}
44
45pub struct DccInterruptHandler<P: OutputPin> {
49 write_buffer: BufferType,
50 write_buffer_len: usize,
51 buffer: BufferType,
52 buffer_num_bits: usize,
53 state: TxState,
54 output_pin: P,
55}
56
57impl<P: OutputPin> DccInterruptHandler<P> {
58 pub fn new(output_pin: P) -> Self {
62 Self {
63 write_buffer: BitArray::default(),
64 write_buffer_len: 0,
65 buffer: BitArray::default(),
66 buffer_num_bits: 0,
67 state: TxState::Idle {
68 second_half_of_bit: false,
69 },
70 output_pin,
71 }
72 }
73
74 #[inline(always)]
76 pub fn tick(&mut self) -> Result<u32, P::Error> {
77 #[cfg(test)]
78 {
79 eprintln!("[tick] DCC state:");
80 eprintln!(
81 " write_buffer: (len {}) {:?}",
82 self.write_buffer_len,
83 &self.write_buffer[..self.write_buffer_len]
84 );
85 eprintln!(" state {:?}", self.state,);
86 }
87
88 let new_clock;
89 self.state = match self.state {
90 TxState::Idle { second_half_of_bit } => {
91 if second_half_of_bit {
93 self.output_pin.set_high()?;
94 } else {
95 self.output_pin.set_low()?;
96 }
97 new_clock = ZERO_MICROS;
98
99 if second_half_of_bit && self.write_buffer_len != 0 {
100 self.buffer.copy_from_bitslice(&self.write_buffer);
102 self.buffer_num_bits = self.write_buffer_len;
103 self.write_buffer_len = 0;
104 #[cfg(test)]
105 eprintln!("Loaded new data into tx buffer");
106
107 TxState::Transmitting {
108 offset: 0,
109 second_half_of_bit: false,
110 }
111 } else {
112 TxState::Idle {
113 second_half_of_bit: !second_half_of_bit,
114 }
115 }
116 }
117 TxState::Transmitting {
118 mut offset,
119 second_half_of_bit,
120 } => {
121 let current_bit = *self.buffer.get(offset).unwrap();
123
124 new_clock = if current_bit { ONE_MICROS } else { ZERO_MICROS };
125
126 if second_half_of_bit {
127 self.output_pin.set_high()?;
128 offset += 1;
130 } else {
131 self.output_pin.set_low()?;
132 }
133
134 if offset < self.buffer_num_bits {
137 TxState::Transmitting {
138 offset,
139 second_half_of_bit: !second_half_of_bit,
140 }
141 } else {
142 TxState::Idle {
143 second_half_of_bit: false,
144 }
145 }
146 }
147 };
148
149 Ok(new_clock)
150 }
151
152 pub fn write(&mut self, buf: &BitSlice<u8, Msb0>) -> Result<(), Error> {
154 if buf.len() > BUFFER_SIZE {
155 Err(Error::TooLong)
156 } else {
157 self.write_buffer[0..buf.len()].copy_from_bitslice(buf);
158 self.write_buffer_len = buf.len();
159 #[cfg(test)]
160 eprintln!("Written {} bits to write buffer", buf.len());
161 Ok(())
162 }
163 }
164}
165
166#[cfg(test)]
167mod test {
168 use super::*;
169 use embedded_hal::digital::v2::*;
170 use std::convert::Infallible;
171
172 #[derive(Default)]
173 struct MockPin {
174 state: bool,
175 }
176
177 impl OutputPin for MockPin {
178 type Error = Infallible;
179
180 #[inline(always)]
181 fn set_high(&mut self) -> Result<(), Self::Error> {
182 self.state = true;
183 Ok(())
184 }
185
186 #[inline(always)]
187 fn set_low(&mut self) -> Result<(), Self::Error> {
188 self.state = false;
189 Ok(())
190 }
191 }
192
193 impl StatefulOutputPin for MockPin {
194 #[inline(always)]
195 fn is_set_high(&self) -> Result<bool, Self::Error> {
196 Ok(self.state)
197 }
198
199 #[inline(always)]
200 fn is_set_low(&self) -> Result<bool, Self::Error> {
201 Ok(!self.state)
202 }
203 }
204
205 #[test]
206 fn mock_pin_works() {
207 let mut pin = MockPin::default();
208 assert!(pin.is_set_low().unwrap());
209 pin.set_high().unwrap();
210 assert!(pin.is_set_high().unwrap());
211 pin.set_low().unwrap();
212 assert!(pin.is_set_low().unwrap());
213 }
214
215 #[test]
216 fn send_a_packet() {
217 const ZERO: u32 = 100;
218 const ONE: u32 = 58;
219 let pin = MockPin::default();
220 let mut dcc = DccInterruptHandler::new(pin);
221 let buffer = [0x00, 0xff].view_bits();
222 dcc.write(buffer).unwrap();
223
224 for _ in 0..2 {
226 let new_delay = dcc.tick().unwrap();
227 eprintln!("new delay: {new_delay}");
228 assert_eq!(new_delay, ZERO);
229 }
230
231 for _ in 0..16 {
235 let new_delay = dcc.tick().unwrap();
236 eprintln!("new delay: {new_delay}");
237 assert_eq!(new_delay, ZERO);
238 }
239
240 for _ in 0..16 {
242 let new_delay = dcc.tick().unwrap();
243 eprintln!("new delay: {new_delay}");
244 assert_eq!(new_delay, ONE);
245 }
246
247 for _ in 0..8 {
249 let new_delay = dcc.tick().unwrap();
250 eprintln!("new delay: {new_delay}");
251 assert_eq!(new_delay, ZERO);
252 }
253 }
254}