Skip to content

Commit 90c8459

Browse files
committed
feat: add SerialHandler-based sync messages
1 parent 36cfc28 commit 90c8459

File tree

5 files changed

+180
-67
lines changed

5 files changed

+180
-67
lines changed

src/countdown.rs

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use core::cell::RefCell;
22

3-
use arduino_hal::{delay_ms, Delay};
3+
use arduino_hal::{delay_ms, hal::Atmega, usart::UsartOps, Delay};
44
use embedded_hal::digital::v2::{InputPin, OutputPin};
55
use hd44780_driver::{bus::DataBus, HD44780};
66
use ufmt::uwrite;
@@ -9,6 +9,7 @@ use crate::{
99
error::RuntimeError,
1010
lcd_writer::LcdWriter,
1111
millis::millis,
12+
serial::{SerialHandler, SerialMsg},
1213
time_set::{render_time, TimeSetting},
1314
LCD_LINE_LENGTH,
1415
};
@@ -28,11 +29,21 @@ pub enum Turn {
2829
P2,
2930
}
3031

31-
pub fn countdown<DP: InputPin, UP: InputPin, SP: InputPin, BP: OutputPin, B: DataBus>(
32+
pub fn countdown<
33+
DP: InputPin,
34+
UP: InputPin,
35+
SP: InputPin,
36+
BP: OutputPin,
37+
B: DataBus,
38+
USART: UsartOps<Atmega, RX, TX>,
39+
RX,
40+
TX,
41+
>(
3242
down_pin: &mut DP,
3343
up_pin: &mut UP,
3444
start_pin: &mut SP,
3545
buzzer_pin: &mut BP,
46+
serial_handler: &mut SerialHandler<USART, RX, TX>,
3647
delay: &mut Delay,
3748
lcd: &RefCell<HD44780<B>>,
3849
writer: &mut LcdWriter<'_, B>,
@@ -110,6 +121,8 @@ pub fn countdown<DP: InputPin, UP: InputPin, SP: InputPin, BP: OutputPin, B: Dat
110121
delay_ms(LOOP_DELAY);
111122
}
112123

124+
let _msg = serial_handler.read().ok();
125+
113126
if start.update(start_pin.is_low().map_err(|_| RuntimeError::PinReadError)?)
114127
== Some(debouncr::Edge::Falling)
115128
{
@@ -132,6 +145,9 @@ pub fn countdown<DP: InputPin, UP: InputPin, SP: InputPin, BP: OutputPin, B: Dat
132145
// Down/P1 press (switch to P2)
133146
// Unsafe subtraction since it's already been checked in the rendering code
134147
p1_ms_at_change = p1_ms_at_change - time_since_change;
148+
let _ = serial_handler.write(SerialMsg::StartP2 {
149+
p1_time: p1_ms_at_change, // TODO: fix this
150+
});
135151
last_change_time = millis();
136152
*turn = Turn::P2
137153
}
@@ -142,6 +158,9 @@ pub fn countdown<DP: InputPin, UP: InputPin, SP: InputPin, BP: OutputPin, B: Dat
142158
// Up/P2 press (switch to P1)
143159
// Unsafe subtraction since it's already been checked in the rendering code
144160
p2_ms_at_change = p2_ms_at_change - time_since_change;
161+
let _ = serial_handler.write(SerialMsg::StartP1 {
162+
p2_time: p2_ms_at_change, // TODO: fix this
163+
});
145164
last_change_time = millis();
146165
*turn = Turn::P1;
147166
}

src/finish.rs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,18 @@
11
use core::cell::RefCell;
22

3-
use arduino_hal::{delay_ms, Delay};
3+
use arduino_hal::{delay_ms, hal::Atmega, usart::UsartOps, Delay};
44
use embedded_hal::digital::v2::{InputPin, OutputPin};
55
use hd44780_driver::{bus::DataBus, HD44780};
66
use ufmt::uwrite;
77

8-
use crate::{countdown::Turn, error::RuntimeError, lcd_writer::LcdWriter};
8+
use crate::{countdown::Turn, error::RuntimeError, lcd_writer::LcdWriter, serial::SerialHandler};
99

1010
const LOOP_DELAY: u16 = 5;
1111
const BUZZER_LENGTH: u16 = 120;
1212

13-
pub fn finish<SP: InputPin, BP: OutputPin, B: DataBus>(
13+
pub fn finish<SP: InputPin, BP: OutputPin, B: DataBus, USART: UsartOps<Atmega, RX, TX>, RX, TX>(
1414
loser: &Turn,
15+
_serial_handler: &mut SerialHandler<USART, RX, TX>,
1516
delay: &mut Delay,
1617
lcd: &RefCell<HD44780<B>>,
1718
writer: &mut LcdWriter<'_, B>,

src/main.rs

Lines changed: 30 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ use error::RuntimeError;
1212
use hd44780_driver::{bus::DataBus, DisplayMode, HD44780};
1313
use lcd_writer::LcdWriter;
1414
use panic_halt as _;
15-
use serial::SerialHandler;
15+
use serial::{SerialHandler, SerialMsg};
1616
use ufmt::uwrite;
1717
use void::ResultVoidExt;
1818

@@ -169,6 +169,7 @@ fn runtime<
169169
&mut down_btn,
170170
&mut up_btn,
171171
&mut start_btn,
172+
&mut serial_handler,
172173
lcd_delay,
173174
&lcd,
174175
writer,
@@ -189,11 +190,20 @@ fn runtime<
189190
pause::PauseResult::Stopped => continue 'main,
190191
};
191192
let loser = loop {
193+
serial_handler.write(match turn {
194+
Turn::P1 => SerialMsg::StartP1 {
195+
p2_time: times.1.into_millis(),
196+
},
197+
Turn::P2 => SerialMsg::StartP2 {
198+
p1_time: times.0.into_millis(),
199+
},
200+
});
192201
match countdown::countdown(
193202
&mut down_btn,
194203
&mut up_btn,
195204
&mut start_btn,
196205
&mut buzzer,
206+
&mut serial_handler,
197207
lcd_delay,
198208
&lcd,
199209
writer,
@@ -205,6 +215,12 @@ fn runtime<
205215
countdown::CountdownResult::FinishedP2 => break Turn::P2,
206216
countdown::CountdownResult::Paused => (),
207217
}
218+
serial_handler.write(SerialMsg::Pause {
219+
time: match turn {
220+
Turn::P1 => times.0.into_millis(),
221+
Turn::P2 => times.1.into_millis(),
222+
},
223+
});
208224
match pause::pause(
209225
&mut down_btn,
210226
&mut up_btn,
@@ -221,6 +237,18 @@ fn runtime<
221237
pause::PauseResult::Stopped => continue 'main,
222238
}
223239
};
224-
finish::finish(&loser, lcd_delay, &lcd, writer, &mut start_btn, &mut buzzer)?;
240+
serial_handler.write(match loser {
241+
Turn::P1 => SerialMsg::P1Finish,
242+
Turn::P2 => SerialMsg::P2Finish,
243+
});
244+
finish::finish(
245+
&loser,
246+
&mut serial_handler,
247+
lcd_delay,
248+
&lcd,
249+
writer,
250+
&mut start_btn,
251+
&mut buzzer,
252+
)?;
225253
}
226254
}

src/serial.rs

Lines changed: 102 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -1,51 +1,75 @@
11
use arduino_hal::{hal::Atmega, usart::UsartOps, Usart};
22
use embedded_hal::serial::{Read, Write};
3+
use void::ResultVoidExt;
34

45
use crate::millis::millis;
56

6-
/// Note: all arguments are big-endian
7+
/// The types of sendable messages.
8+
/// Keep up to date with /src/serial.rs
9+
///
10+
/// Note: all messages are big-endian
711
pub enum SerialMsg {
812
/// Just send HandshakeResponse back if you get this.
913
///
10-
/// 0x00
11-
Handshake,
14+
/// Parameter: mode
15+
/// 0x0000 - let the other party decide
16+
/// 0x0001 - sync
17+
/// 0x0002 - other party is slave
18+
/// 0x0003 - other party is master
19+
///
20+
/// 0xc0
21+
Handshake { mode: u32 },
1222
/// Yay, Handshake was successful!
1323
///
14-
/// 0x01
15-
HandshakeResponse,
16-
/// P1 is now counting down, and P2 has the specified # of ms. This will
17-
/// wrap after about an hour.
24+
/// Parameter: selected_mode
25+
/// 0x0000 - mode not supported
26+
/// 0x0001 - sync
27+
/// 0x0002 - we're slave
28+
/// 0x0003 - we're master
29+
///
30+
/// 0xc1
31+
HandshakeResponse { selected_mode: u32 },
32+
/// P1 is now counting down, and P2 has the specified # of ms.
1833
///
19-
/// 0x02
20-
StartP1 { p2_time: u16 },
21-
/// P2 is now counting down, and P1 has the specified # of ms. This will
22-
/// wrap after about an hour.
34+
/// 0xc2
35+
StartP1 { p2_time: u32 },
36+
/// P2 is now counting down, and P1 has the specified # of ms.
2337
///
24-
/// 0x03
25-
StartP2 { p1_time: u16 },
38+
/// 0xc3
39+
StartP2 { p1_time: u32 },
2640
/// Syncing time. P1 first, then P2, in ms.
2741
///
28-
/// 0x04
29-
Sync { p1_time: u16, p2_time: u16 },
42+
/// 0xc4
43+
Sync { p1_time: u32, p2_time: u32 },
3044
/// Pause both times. The currently running clock finished at the specified
3145
/// ms.
3246
///
33-
/// 0x05
34-
Pause { time: u16 },
47+
/// 0xc5
48+
Pause { time: u32 },
49+
/// P1 won by time.
50+
///
51+
/// 0xc6
52+
P1Finish,
53+
/// P2 won by time.
54+
///
55+
/// 0xc7
56+
P2Finish,
3557
}
3658

3759
impl SerialMsg {
3860
fn to_u8(&self) -> u8 {
3961
match *self {
40-
SerialMsg::Handshake => 0x00,
41-
SerialMsg::HandshakeResponse => 0x01,
42-
SerialMsg::StartP1 { p2_time: _ } => 0x02,
43-
SerialMsg::StartP2 { p1_time: _ } => 0x03,
62+
SerialMsg::Handshake { mode: _ } => 0xc0,
63+
SerialMsg::HandshakeResponse { selected_mode: _ } => 0xc1,
64+
SerialMsg::StartP1 { p2_time: _ } => 0xc2,
65+
SerialMsg::StartP2 { p1_time: _ } => 0xc3,
4466
SerialMsg::Sync {
4567
p1_time: _,
4668
p2_time: _,
47-
} => 0x04,
48-
SerialMsg::Pause { time: _ } => 0x05,
69+
} => 0xc4,
70+
SerialMsg::Pause { time: _ } => 0xc5,
71+
SerialMsg::P1Finish => 0xc6,
72+
SerialMsg::P2Finish => 0xc7,
4973
}
5074
}
5175
}
@@ -56,59 +80,72 @@ pub struct SerialHandler<USART: UsartOps<Atmega, RX, TX>, RX, TX> {
5680
pub connected: bool,
5781
}
5882

83+
/// Handles serial communication between the firmware and website.
84+
/// Keep up to date with /www/src/serial.ts
5985
impl<USART: UsartOps<Atmega, RX, TX>, RX, TX> SerialHandler<USART, RX, TX> {
60-
fn write_u16(&mut self, v: u16) -> nb::Result<(), void::Void> {
86+
fn write_u32(&mut self, v: u32) {
6187
let bytes = v.to_be_bytes();
62-
self.serial.write(bytes[0])?;
63-
self.serial.write(bytes[1])?;
64-
Ok(())
88+
for byte in bytes {
89+
nb::block!(self.serial.write(byte)).void_unwrap();
90+
}
6591
}
6692

67-
pub fn write(&mut self, msg: SerialMsg) -> nb::Result<(), void::Void> {
68-
self.serial.write(msg.to_u8())?;
93+
pub fn write(&mut self, msg: SerialMsg) {
94+
self.serial.write_byte(msg.to_u8());
6995
match msg {
70-
SerialMsg::Handshake => {}
71-
SerialMsg::HandshakeResponse => {}
96+
SerialMsg::Handshake { mode } => {
97+
self.write_u32(mode);
98+
}
99+
SerialMsg::HandshakeResponse { selected_mode } => {
100+
self.write_u32(selected_mode);
101+
}
72102
SerialMsg::StartP1 { p2_time } => {
73-
self.write_u16(p2_time)?;
103+
self.write_u32(p2_time);
74104
}
75105
SerialMsg::StartP2 { p1_time } => {
76-
self.write_u16(p1_time)?;
106+
self.write_u32(p1_time);
77107
}
78108
SerialMsg::Sync { p1_time, p2_time } => {
79-
self.write_u16(p1_time)?;
80-
self.write_u16(p2_time)?;
109+
self.write_u32(p1_time);
110+
self.write_u32(p2_time);
81111
}
82112
SerialMsg::Pause { time } => {
83-
self.write_u16(time)?;
113+
self.write_u32(time);
84114
}
115+
SerialMsg::P1Finish => {}
116+
SerialMsg::P2Finish => {}
85117
}
86-
Ok(())
118+
}
119+
120+
fn read_u32(&mut self) -> u32 {
121+
((nb::block!(self.serial.read()).void_unwrap() as u32) << 24)
122+
| ((nb::block!(self.serial.read()).void_unwrap() as u32) << 16)
123+
| ((nb::block!(self.serial.read()).void_unwrap() as u32) << 8)
124+
| nb::block!(self.serial.read()).void_unwrap() as u32
87125
}
88126

89127
/// Reads a raw message from the wire and blocks until it's completely received.
90128
fn raw_read(&mut self) -> nb::Result<SerialMsg, void::Void> {
91129
let msg = self.serial.read()?;
92130
match msg {
93-
0x00 => Ok(SerialMsg::Handshake),
94-
0x01 => Ok(SerialMsg::HandshakeResponse),
95-
0x02 => Ok(SerialMsg::StartP1 {
96-
p2_time: ((nb::block!(self.serial.read())? as u16) << 8)
97-
| nb::block!(self.serial.read())? as u16,
131+
0xc0 => Ok(SerialMsg::Handshake {
132+
mode: self.read_u32(),
133+
}),
134+
0xc1 => Ok(SerialMsg::HandshakeResponse {
135+
selected_mode: self.read_u32(),
136+
}),
137+
0xc2 => Ok(SerialMsg::StartP1 {
138+
p2_time: self.read_u32(),
98139
}),
99-
0x03 => Ok(SerialMsg::StartP2 {
100-
p1_time: ((nb::block!(self.serial.read())? as u16) << 8)
101-
| nb::block!(self.serial.read())? as u16,
140+
0xc3 => Ok(SerialMsg::StartP2 {
141+
p1_time: self.read_u32(),
102142
}),
103-
0x04 => Ok(SerialMsg::Sync {
104-
p1_time: ((nb::block!(self.serial.read())? as u16) << 8)
105-
| nb::block!(self.serial.read())? as u16,
106-
p2_time: ((nb::block!(self.serial.read())? as u16) << 8)
107-
| nb::block!(self.serial.read())? as u16,
143+
0xc4 => Ok(SerialMsg::Sync {
144+
p1_time: self.read_u32(),
145+
p2_time: self.read_u32(),
108146
}),
109-
0x05 => Ok(SerialMsg::Pause {
110-
time: ((nb::block!(self.serial.read())? as u16) << 8)
111-
| nb::block!(self.serial.read())? as u16,
147+
0xc5 => Ok(SerialMsg::Pause {
148+
time: self.read_u32(),
112149
}),
113150
_ => {
114151
// Huh? Malformed message, this isn't good, ignore the message
@@ -120,12 +157,20 @@ impl<USART: UsartOps<Atmega, RX, TX>, RX, TX> SerialHandler<USART, RX, TX> {
120157
pub fn read(&mut self) -> nb::Result<SerialMsg, void::Void> {
121158
let msg = self.raw_read()?;
122159
match msg {
123-
SerialMsg::Handshake => {
160+
SerialMsg::Handshake { mode } => {
124161
self.connected = true;
125-
self.write(SerialMsg::HandshakeResponse)?;
162+
let selected_mode = match mode {
163+
0x0000 => 0x0002, // if we decide, make them a slave
164+
0x0001 => 0x0001, // syncing
165+
0x0002 => 0x0000, // if we're a slave, it's not supported
166+
0x0003 => 0x0003, // we're master
167+
_ => 0x0000, // unsupported value
168+
};
169+
self.write(SerialMsg::HandshakeResponse { selected_mode });
126170
Err(nb::Error::WouldBlock)
127171
}
128-
SerialMsg::HandshakeResponse => {
172+
SerialMsg::HandshakeResponse { selected_mode: _ } => {
173+
// hopefully selected_mode is ok. we don't have the resources to check
129174
self.connected = true;
130175
Err(nb::Error::WouldBlock)
131176
}
@@ -137,7 +182,7 @@ impl<USART: UsartOps<Atmega, RX, TX>, RX, TX> SerialHandler<USART, RX, TX> {
137182
if let None = self.wait_start {
138183
self.connected = false;
139184
self.wait_start = Some(millis());
140-
self.write(SerialMsg::Handshake)?;
185+
self.write(SerialMsg::Handshake { mode: 0x0002 });
141186
}
142187
let wait_start = self.wait_start.unwrap();
143188
match self.read() {

0 commit comments

Comments
 (0)