Skip to content
File

Blob: archive/fft-benchmark/firmware/crates/esp32-radio/src/app.rs

rust60 lines
1//! Task ownership and terminal recovery. All ordinary state is explicitly owned.
2use crate::{
3 console,
4 error::{Error, Result},
5 platform::{self, Board},
6 radio, signaling,
7};
8use std::{
9 sync::{
10 atomic::{AtomicBool, Ordering},
11 mpsc::sync_channel,
12 },
13 thread,
14 time::Duration,
15};
16 
17pub(crate) fn run() -> Result<()> {
18 platform::log("Pocket Radio: Rust application starting");
19 let board = Board::init()?;
20 let (requests, radio_requests) = sync_channel(4);
21 let (radio_events, events) = sync_channel(8);
22 thread::Builder::new()
23 .name("radio".into())
24 .stack_size(16_384)
25 .spawn(move || {
26 if let Err(error) = radio::run(board, radio_requests, radio_events) {
27 recover(error);
28 }
29 })
30 .map_err(|_| Error::new("cannot start radio task"))?;
31 thread::Builder::new()
32 .name("signaling".into())
33 .stack_size(16_384)
34 .spawn(move || {
35 if let Err(error) = signaling::run(requests, events) {
36 recover(error);
37 }
38 })
39 .map_err(|_| Error::new("cannot start signaling task"))?;
40 console::run()
41}
42 
43static RECOVERING: AtomicBool = AtomicBool::new(false);
44 
45/// Fatal runtime failures restart the complete native transport. One caller owns
46/// the recovery counter; concurrent failures park until reset, avoiding races.
47pub(crate) fn recover(error: Error) -> ! {
48 if RECOVERING.swap(true, Ordering::AcqRel) {
49 loop {
50 thread::sleep(Duration::from_secs(1));
51 }
52 }
53 let seconds = 5u64 << platform::recovery_attempt(false).min(3);
54 platform::log(&format!("{error}; restarting in {seconds} seconds"));
55 thread::sleep(Duration::from_millis(
56 seconds * 1000 + u64::from(platform::random() % 1000),
57 ));
58 platform::restart()
59}