Skip to content

Commit 5442d69

Browse files
committed
Switch config sharing from handoff to watch.
Not only is it better specified, it's significantly smaller in flash!
1 parent f6280e7 commit 5442d69

File tree

5 files changed

+59
-59
lines changed

5 files changed

+59
-59
lines changed

Cargo.lock

Lines changed: 8 additions & 9 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,15 +17,13 @@ futures = { version = "0.3.28", default-features = false, features = ["async-awa
1717
panic-halt = {optional = true, version = "0.2.0"}
1818
panic-semihosting = {optional = true, version = "0.6.0"}
1919
scopeguard = { version = "1.1.0", default-features = false }
20+
lilos-watch = "0.1"
2021

2122
[dependencies.lilos]
22-
version = "1.0.0"
23+
version = "1.2"
2324
default-features = false
2425
features = ["spsc", "systick"]
2526

26-
[dependencies.lilos-handoff]
27-
version = "1.0.0"
28-
2927
[dependencies.stm32-metapac]
3028
default-features = false
3129
features = ["rt", "pac"]

src/main.rs

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -277,10 +277,10 @@ fn main() -> ! {
277277
let mut scan_event_q = pin!(Queue::new(SCAN_EVENT_Q.take()));
278278
let (scan_event_from_scanner, scan_event_to_serial) = scan_event_q.split();
279279

280-
// Allocate the serial-to-scanner synchronous config handoff (no storage
281-
// required)
282-
let mut config_handoff = lilos_handoff::Handoff::new();
283-
let (config_to_scanner, config_from_serial) = config_handoff.split();
280+
// Allocate the serial-to-scanner synchronous config watcher.
281+
let config_watch = lilos_watch::Watch::new(cfg.scanner);
282+
let config_to_scanner = config_watch.sender();
283+
let config_from_serial = config_watch.subscribe();
284284

285285
// Create the serial-to-I2C byte queue using static storage.
286286
let mut i2c_byte_q = pin!(Queue::new(I2C_Q.take()));
@@ -298,7 +298,6 @@ fn main() -> ! {
298298
));
299299

300300
let scanner_task = pin!(scanner::task(
301-
cfg.scanner,
302301
config_from_serial,
303302
gpioa,
304303
scan_event_from_scanner,

src/scanner.rs

Lines changed: 39 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -151,59 +151,63 @@ pub enum KeyState { #[default] Up, Down }
151151

152152
/// Keypad scanner loop.
153153
///
154-
/// Pass this its initial `config` plus a handoff channel through which it can
154+
/// Pass this its initial `config` plus a watch channel through which it can
155155
/// receive updated configs. It'll scan the provided GPIO port (pins 0-7) and
156156
/// emit events through `out_queue`.
157157
pub async fn task(
158-
mut config: Config,
159-
mut config_update: lilos_handoff::Popper<'_, Config>,
158+
mut config_update: lilos_watch::Receiver<'_, Config>,
160159
gpio: device::gpio::Gpio,
161160
mut out_queue: spsc::Pusher<'_, KeyEvent>,
162161
) -> Infallible {
163162
configure_pins(gpio);
164163

164+
// Make a copy of the config so we can be specific about changes.
165+
let mut config = config_update.copy_current();
166+
165167
let debouncers = DEBOUNCERS.take();
166168
let mut scan_gate = PeriodicGate::from(SCAN_INTERVAL);
167169
loop {
168170
scan_gate.next_time().await;
169171

170172
// Process any config update before starting the scan.
171-
if let Some(new_config) = config_update.try_pop() {
172-
// Handle any "killed" drive lines. This occurs when the
173-
// `driven_lines` bit was 1 in the old config, and is becoming 0.
174-
// When a drive line is killed we need to reset the state of its
175-
// debouncers so they don't do anything.
176-
for (line, debounce_row) in debouncers.iter_mut().enumerate() {
177-
let line_mask = 1 << line;
178-
let in_use_before = config.driven_lines & line_mask != 0;
179-
let still_in_use = new_config.driven_lines & line_mask != 0;
180-
if in_use_before && !still_in_use {
181-
for debouncer in debounce_row {
182-
*debouncer = Default::default();
173+
if config_update.is_changed() {
174+
config_update.glimpse_and_update(|new_config| {
175+
// Handle any "killed" drive lines. This occurs when the
176+
// `driven_lines` bit was 1 in the old config, and is becoming 0.
177+
// When a drive line is killed we need to reset the state of its
178+
// debouncers so they don't do anything.
179+
for (line, debounce_row) in debouncers.iter_mut().enumerate() {
180+
let line_mask = 1 << line;
181+
let in_use_before = config.driven_lines & line_mask != 0;
182+
let still_in_use = new_config.driven_lines & line_mask != 0;
183+
if in_use_before && !still_in_use {
184+
for debouncer in debounce_row {
185+
*debouncer = Default::default();
186+
}
183187
}
184188
}
185-
}
186-
// Handle any "killed" keys. This occurs when the key's bit in the
187-
// `ghost_mask` was not set before, but has become set. As in the
188-
// killed line case, we need to reset its debouncer state.
189-
//
190-
// This is written using a range and indexing because, believe it or
191-
// not, enumerate generates much larger code -- at least as of
192-
// 1.75.0. This is because we're at opt-level="z", which makes dumb
193-
// decisions like "not inlining the enumerate iterator for slices."
194-
#[allow(clippy::needless_range_loop)]
195-
for line in 0..8 {
196-
for col in 0..8 {
197-
let col_mask = 1 << col;
198-
let real_before = config.ghost_mask[line] & col_mask == 0;
199-
let still_real = new_config.ghost_mask[line] & col_mask != 0;
200-
if real_before && !still_real {
201-
debouncers[line][col] = Default::default();
189+
// Handle any "killed" keys. This occurs when the key's bit in the
190+
// `ghost_mask` was not set before, but has become set. As in the
191+
// killed line case, we need to reset its debouncer state.
192+
//
193+
// This is written using a range and indexing because, believe it or
194+
// not, enumerate generates much larger code -- at least as of
195+
// 1.75.0. This is because we're at opt-level="z", which makes dumb
196+
// decisions like "not inlining the enumerate iterator for slices."
197+
#[allow(clippy::needless_range_loop)]
198+
for line in 0..8 {
199+
for col in 0..8 {
200+
let col_mask = 1 << col;
201+
let real_before = config.ghost_mask[line] & col_mask == 0;
202+
let still_real = new_config.ghost_mask[line] & col_mask != 0;
203+
if real_before && !still_real {
204+
debouncers[line][col] = Default::default();
205+
}
202206
}
203207
}
204-
}
205-
// Apply the config.
206-
config = new_config;
208+
// Apply the config.
209+
config = *new_config;
210+
});
207211
}
208212
// Config doesn't get modified anywhere else in this loop -- see:
209213
let config = &config;

src/serial.rs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ pub async fn task(
8484
keymap: &[[u8; 8]; 8],
8585
setup_mode: bool,
8686
mut from_scanner: spsc::Popper<'_, scanner::KeyEvent>,
87-
config_to_scanner: lilos_handoff::Pusher<'_, scanner::Config>,
87+
config_to_scanner: lilos_watch::Sender<'_, scanner::Config>,
8888
mut bytes_to_i2c: spsc::Pusher<'_, u8>,
8989
storage: Storage,
9090
) -> Infallible {
@@ -348,7 +348,7 @@ const SETTLE: Millis = Millis(100);
348348
/// so, during setup the I2C port will be dead.
349349
async fn setup(
350350
uart: Uart,
351-
mut config_to_scanner: lilos_handoff::Pusher<'_, scanner::Config>,
351+
config_to_scanner: lilos_watch::Sender<'_, scanner::Config>,
352352
mut from_scanner: lilos::spsc::Popper<'_, scanner::KeyEvent>,
353353
mut storage: Storage,
354354
) -> Infallible {
@@ -360,14 +360,14 @@ async fn setup(
360360
// configuration has been applied (which will use this epoch).
361361
const SETUP_EPOCH: u8 = 0x55;
362362

363-
config_to_scanner.push(scanner::Config {
363+
config_to_scanner.send(scanner::Config {
364364
// Recognizable epoch in case we raced the scan
365365
epoch: SETUP_EPOCH,
366366
// All lines should be driven during setup.
367367
driven_lines: 0xFF,
368368
// No ghost keys should be ignored, we want to know about everything.
369369
ghost_mask: [0; 8],
370-
}).await;
370+
});
371371

372372
transmit(uart, concat!(
373373
"\r\n\
@@ -580,11 +580,11 @@ async fn setup(
580580

581581
// Push the configuration over whether or not we saved it, so we can run the
582582
// demo loop.
583-
config_to_scanner.push(scanner::Config {
583+
config_to_scanner.send(scanner::Config {
584584
epoch: DEMO_EPOCH,
585585
driven_lines,
586586
ghost_mask,
587-
}).await;
587+
});
588588

589589
transmit(uart, b"Running demo until reset:\r\n").await;
590590

0 commit comments

Comments
 (0)