summaryrefslogtreecommitdiffstats
path: root/src/main.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/main.rs')
-rw-r--r--src/main.rs214
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);
}
}