Skip to content

Commit f9be42c

Browse files
committed
feat(test_runner): retry if the RP2040 bootrom device wasn't found
1 parent bb05d73 commit f9be42c

File tree

2 files changed

+38
-4
lines changed

2 files changed

+38
-4
lines changed

src/r3_test_runner/src/targets/rp_pico.rs

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ use std::future::Future;
44
use tokio::task::spawn_blocking;
55

66
use super::{jlink::read_elf, Arch, DebugProbe, Target};
7+
use crate::utils::retry_on_fail_with_delay;
78

89
pub struct RaspberryPiPico;
910

@@ -67,9 +68,10 @@ impl DebugProbe for RaspberryPiPicoUsbDebugProbe {
6768

6869
/// Program and execute the specified ELF file by PICOBOOT protocol.
6970
async fn program_and_run_by_picoboot(exe: &std::path::Path) -> Result<()> {
70-
let (picoboot_interface, loadable_code) =
71-
tokio::join!(spawn_blocking(open_picoboot), read_elf(exe));
72-
let picoboot_interface = picoboot_interface.unwrap(); // ignore `JoinError`
71+
let picoboot_interface_async = retry_on_fail_with_delay(|| async {
72+
spawn_blocking(open_picoboot).await.unwrap() // ignore `JoinError`
73+
});
74+
let (picoboot_interface, loadable_code) = tokio::join!(picoboot_interface_async, read_elf(exe));
7375
let PicobootInterface {
7476
mut device_handle,
7577
out_endpoint_i,

src/r3_test_runner/src/utils.rs

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
use std::{fmt, future::Future};
1+
use std::{fmt, future::Future, time::Duration};
2+
use tokio::time::delay_for;
23

34
pub struct CommaSeparatedNoSpace<T>(pub T);
45
impl<T> fmt::Display for CommaSeparatedNoSpace<T>
@@ -82,3 +83,34 @@ where
8283
}
8384
}
8485
}
86+
87+
pub async fn retry_on_fail_with_delay<R, T, E: std::fmt::Debug>(
88+
mut f: impl FnMut() -> R,
89+
) -> Result<T, E>
90+
where
91+
R: Future<Output = Result<T, E>>,
92+
{
93+
let mut count = 8u32;
94+
loop {
95+
match f().await {
96+
Ok(x) => return Ok(x),
97+
Err(e) => {
98+
log::warn!("Attempt failed: {:?}", e);
99+
count -= 1;
100+
if count == 0 {
101+
log::warn!("Retry limit reached");
102+
return Err(e);
103+
} else {
104+
let delay = (16 >> count).max(1);
105+
log::warn!(
106+
"Retrying in {} seconds... (remaining count = {:?})",
107+
delay,
108+
count
109+
);
110+
111+
delay_for(Duration::from_secs(delay)).await;
112+
}
113+
}
114+
}
115+
}
116+
}

0 commit comments

Comments
 (0)