diff options
Diffstat (limited to 'src/main.rs')
| -rw-r--r-- | src/main.rs | 214 |
1 files changed, 131 insertions, 83 deletions
diff --git a/src/main.rs b/src/main.rs index cc1623e..06b7b24 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,23 +1,68 @@ #![no_std] #![no_main] +#![feature(abi_avr_interrupt)] use core::char; +use core::cell; -use arduino_uno::{delay_ms, hal::port::{mode::Output, portb::PB5}, prelude::*}; +use arduino_uno::{delay_ms, hal::{clock::MHz16, port::{mode::{Floating, Input, Output}, portb::PB5, portd::{PD0, PD1}}, usart::Usart}, pac::USART0, prelude::*}; use panic_halt as _; -const SHORT: u16 = 75; +const SHORT: u16 = 100; const LONG: u16 = SHORT * 3; const SPACE: u16 = SHORT * 7; -struct RingBuf<T: Copy, const N: usize> { - data: [T; N], +const PRESCALER: u32 = 1024; +const TIMER_COUNTS: u32 = 125; + +const MILLIS_INCREMENT: u32 = PRESCALER * TIMER_COUNTS / 16000; + +static MILLIS_COUNTER: avr_device::interrupt::Mutex<cell::Cell<u32>> = + avr_device::interrupt::Mutex::new(cell::Cell::new(0)); + +type Serial = Usart<USART0, PD0<Input<Floating>>, PD1<Output>, MHz16>; + +fn millis_init(tc0: arduino_uno::pac::TC0) { + // Configure the timer for the above interval (in CTC mode) + // and enable its interrupt. + tc0.tccr0a.write(|w| w.wgm0().ctc()); + tc0.ocr0a.write(|w| unsafe { w.bits(TIMER_COUNTS as u8) }); + tc0.tccr0b.write(|w| match PRESCALER { + 8 => w.cs0().prescale_8(), + 64 => w.cs0().prescale_64(), + 256 => w.cs0().prescale_256(), + 1024 => w.cs0().prescale_1024(), + _ => panic!(), + }); + tc0.timsk0.write(|w| w.ocie0a().set_bit()); + + // Reset the global millisecond counter + avr_device::interrupt::free(|cs| { + MILLIS_COUNTER.borrow(cs).set(0); + }); +} + +#[avr_device::interrupt(atmega328p)] +fn TIMER0_COMPA() { + avr_device::interrupt::free(|cs| { + let counter_cell = MILLIS_COUNTER.borrow(cs); + let counter = counter_cell.get(); + counter_cell.set(counter + MILLIS_INCREMENT); + }) +} + +fn millis() -> u32 { + avr_device::interrupt::free(|cs| MILLIS_COUNTER.borrow(cs).get()) +} + +struct RingBuf<const N: usize> { + data: [LedInstruction; N], read_idx: usize, write_idx: usize, } -impl<T: Copy, const N: usize> RingBuf<T, N> { - pub fn new(initial: T) -> Self { +impl<const N: usize> RingBuf<N> { + pub fn new(initial: LedInstruction) -> Self { Self { data: [initial; N], read_idx: 0, @@ -25,15 +70,23 @@ impl<T: Copy, const N: usize> RingBuf<T, N> { } } - pub fn peek(&self) -> Option<T> { + pub fn _peek(&self) -> Option<&LedInstruction> { + if self.write_idx != self.read_idx { + Some(&self.data[self.read_idx]) + } else { + None + } + } + + pub fn peek_mut(&mut self) -> Option<&mut LedInstruction> { if self.write_idx != self.read_idx { - Some(self.data[self.read_idx]) + Some(&mut self.data[self.read_idx]) } else { None } } - pub fn push(&mut self, value: T) { + pub fn push(&mut self, value: LedInstruction) { if self.write_idx + 1 != self.read_idx { self.data[self.write_idx] = value; self.write_idx += 1; @@ -43,7 +96,7 @@ impl<T: Copy, const N: usize> RingBuf<T, N> { } } - pub fn pop(&mut self) -> Option<T> { + pub fn pop(&mut self) -> Option<LedInstruction> { if self.write_idx != self.read_idx { let res = Some(self.data[self.read_idx]); self.read_idx += 1; @@ -55,13 +108,30 @@ impl<T: Copy, const N: usize> RingBuf<T, N> { None } } + + pub fn update(&mut self, millis: u16, led: &mut PB5<Output>, serial: &mut Serial) { + if let Some(cur) = self.peek_mut() { + if cur.state { + led.set_high().void_unwrap() + } else { + led.set_low().void_unwrap(); + } + + if cur.time > millis { + cur.time -= millis; + } else { + let time = cur.time; + self.pop().unwrap(); + self.update(millis - time, led, serial); + } + } + } } #[derive(Clone, Copy)] struct LedInstruction { state: bool, time: u16, - left: u16, } impl LedInstruction { @@ -69,25 +139,10 @@ impl LedInstruction { Self { state, time, - left: time, } } } -macro_rules! morse { - ( $led:expr, $( $delay:expr ),* ) => { - { - $( - $led.set_high().void_unwrap(); - delay_ms($delay); - $led.set_low().void_unwrap(); - delay_ms(SHORT); - )* - delay_ms(LONG - SHORT); - } - }; -} - macro_rules! push_morse { ( $buf:expr, $( $delay:expr ),* ) => { { @@ -100,65 +155,47 @@ macro_rules! push_morse { } } -fn push_morse<const N: usize>(buf: &mut RingBuf<LedInstruction, N>, c: u8) { +fn push_morse<const N: usize>(buf: &mut RingBuf<N>, c: u8) { let c = char::from_u32(c as u32); if let Some(c) = c { match c { - 'a' => { - buf.push(LedInstruction::new(true, SHORT)); - buf.push(LedInstruction::new(false, SHORT)); - buf.push(LedInstruction::new(true, LONG)); - buf.push(LedInstruction::new(false, SHORT)); - buf.push(LedInstruction::new(false, LONG - SHORT)); - }, + 'a' => push_morse!(buf, SHORT, LONG), 'b' => push_morse!(buf, LONG, SHORT, SHORT, SHORT), - - _ => {}, - } - } -} - -fn blink_morse(led: &mut PB5<Output>, c: u8) { - let c = char::from_u32(c as u32); - if let Some(c) = c { - match c { - 'a' => morse!(led, SHORT, LONG), - 'b' => morse!(led, LONG, SHORT, SHORT, SHORT), - 'c' => morse!(led, LONG, SHORT, LONG, SHORT), - 'd' => morse!(led, LONG, SHORT, SHORT), - 'e' => morse!(led, SHORT), - 'f' => morse!(led, SHORT, SHORT, LONG, SHORT), - 'g' => morse!(led, LONG, LONG, SHORT), - 'h' => morse!(led, SHORT, SHORT, SHORT, SHORT), - 'i' => morse!(led, SHORT, SHORT), - 'j' => morse!(led, SHORT, LONG, LONG, LONG), - 'k' => morse!(led, LONG, SHORT, LONG), - 'l' => morse!(led, SHORT, LONG, SHORT, SHORT), - 'm' => morse!(led, LONG, LONG), - 'n' => morse!(led, LONG, SHORT), - 'o' => morse!(led, LONG, LONG, LONG), - 'p' => morse!(led, SHORT, LONG, LONG, SHORT), - 'q' => morse!(led, LONG, LONG, SHORT, LONG), - 'r' => morse!(led, SHORT, LONG, SHORT), - 's' => morse!(led, SHORT, SHORT, SHORT), - 't' => morse!(led, LONG), - 'u' => morse!(led, SHORT, SHORT, LONG), - 'v' => morse!(led, SHORT, SHORT, SHORT, LONG), - 'w' => morse!(led, SHORT, LONG, LONG), - 'x' => morse!(led, LONG, SHORT, SHORT, LONG), - 'y' => morse!(led, LONG, SHORT, LONG, LONG), - 'z' => morse!(led, LONG, LONG, SHORT, SHORT), - '1' => morse!(led, SHORT, LONG, LONG, LONG, LONG), - '2' => morse!(led, SHORT, SHORT, LONG, LONG, LONG), - '3' => morse!(led, SHORT, SHORT, SHORT, LONG, LONG), - '4' => morse!(led, SHORT, SHORT, SHORT, SHORT, LONG), - '5' => morse!(led, SHORT, SHORT, SHORT, SHORT, SHORT), - '6' => morse!(led, LONG, SHORT, SHORT, SHORT, SHORT), - '7' => morse!(led, LONG, LONG, SHORT, SHORT, SHORT), - '8' => morse!(led, LONG, LONG, LONG, SHORT, SHORT), - '9' => morse!(led, LONG, LONG, LONG, LONG, SHORT), - '0' => morse!(led, LONG, LONG, LONG, LONG, LONG), - ' ' => delay_ms(SPACE - LONG), + 'c' => push_morse!(buf, LONG, SHORT, LONG, SHORT), + 'd' => push_morse!(buf, LONG, SHORT, SHORT), + 'e' => push_morse!(buf, SHORT), + 'f' => push_morse!(buf, SHORT, SHORT, LONG, SHORT), + 'g' => push_morse!(buf, LONG, LONG, SHORT), + 'h' => push_morse!(buf, SHORT, SHORT, SHORT, SHORT), + 'i' => push_morse!(buf, SHORT, SHORT), + 'j' => push_morse!(buf, SHORT, LONG, LONG, LONG), + 'k' => push_morse!(buf, LONG, SHORT, LONG), + 'l' => push_morse!(buf, SHORT, LONG, SHORT, SHORT), + 'm' => push_morse!(buf, LONG, LONG), + 'n' => push_morse!(buf, LONG, SHORT), + 'o' => push_morse!(buf, LONG, LONG, LONG), + 'p' => push_morse!(buf, SHORT, LONG, LONG, SHORT), + 'q' => push_morse!(buf, LONG, LONG, SHORT, LONG), + 'r' => push_morse!(buf, SHORT, LONG, SHORT), + 's' => push_morse!(buf, SHORT, SHORT, SHORT), + 't' => push_morse!(buf, LONG), + 'u' => push_morse!(buf, SHORT, SHORT, LONG), + 'v' => push_morse!(buf, SHORT, SHORT, SHORT, LONG), + 'w' => push_morse!(buf, SHORT, LONG, LONG), + 'x' => push_morse!(buf, LONG, SHORT, SHORT, LONG), + 'y' => push_morse!(buf, LONG, SHORT, LONG, LONG), + 'z' => push_morse!(buf, LONG, LONG, SHORT, SHORT), + '1' => push_morse!(buf, SHORT, LONG, LONG, LONG, LONG), + '2' => push_morse!(buf, SHORT, SHORT, LONG, LONG, LONG), + '3' => push_morse!(buf, SHORT, SHORT, SHORT, LONG, LONG), + '4' => push_morse!(buf, SHORT, SHORT, SHORT, SHORT, LONG), + '5' => push_morse!(buf, SHORT, SHORT, SHORT, SHORT, SHORT), + '6' => push_morse!(buf, LONG, SHORT, SHORT, SHORT, SHORT), + '7' => push_morse!(buf, LONG, LONG, SHORT, SHORT, SHORT), + '8' => push_morse!(buf, LONG, LONG, LONG, SHORT, SHORT), + '9' => push_morse!(buf, LONG, LONG, LONG, LONG, SHORT), + '0' => push_morse!(buf, LONG, LONG, LONG, LONG, LONG), + ' ' => buf.push(LedInstruction::new(false, SPACE)), _ => {}, } } @@ -180,7 +217,14 @@ fn main() -> ! { 57600.into_baudrate(), ); - let mut buf: RingBuf<_, 100> = RingBuf::new(LedInstruction::new(false, 0)); + let mut buf: RingBuf<100> = RingBuf::new(LedInstruction::new(false, 0)); + + millis_init(dp.TC0); + + // Enable interrupts globally + unsafe { avr_device::interrupt::enable() }; + + let mut last_millis = millis(); loop { // let b = nb::block!(serial.read()).void_unwrap(); @@ -189,6 +233,10 @@ fn main() -> ! { Err(_) => {}, } - buf.update(millis()); + let new_millis = millis(); + buf.update((new_millis - last_millis) as u16, &mut led, &mut serial); + last_millis = new_millis; + + delay_ms(100); } } |
