From e8c998e5c260f8327af57a5d6c7aa58cd435bc9f Mon Sep 17 00:00:00 2001 From: Cyril Fougeray Date: Fri, 25 Oct 2024 09:20:53 +0200 Subject: [PATCH] orb-mcu-util: add --can-fd option (#277) for all commands usage: orb-mcu-util --can-fd args --- mcu-util/src/main.rs | 9 +-- mcu-util/src/orb/main_board.rs | 98 +++++++++++------------- mcu-util/src/orb/mod.rs | 9 ++- mcu-util/src/orb/security_board.rs | 116 ++++++++++++----------------- 4 files changed, 98 insertions(+), 134 deletions(-) diff --git a/mcu-util/src/main.rs b/mcu-util/src/main.rs index 9b61b1f0..9856d048 100644 --- a/mcu-util/src/main.rs +++ b/mcu-util/src/main.rs @@ -34,6 +34,8 @@ static BUILD_INFO: BuildInfo = make_build_info!(); struct Args { #[clap(subcommand)] subcmd: SubCommand, + #[clap(short, long, default_value = "false")] + can_fd: bool, } #[derive(Parser, Debug)] @@ -97,9 +99,6 @@ pub struct McuUpdate { /// Path to binary file #[clap(short, long)] path: String, - /// Use CAN-FD to send the image - #[clap(short, long, default_value = "false")] - can_fd: bool, } /// Stress tests options @@ -133,7 +132,7 @@ enum SecureElement { } async fn execute(args: Args) -> Result<()> { - let (mut orb, orb_tasks) = Orb::new().await?; + let (mut orb, orb_tasks) = Orb::new(args.can_fd).await?; match args.subcmd { SubCommand::Info => { @@ -161,7 +160,7 @@ async fn execute(args: Args) -> Result<()> { } SubCommand::Image(Image::Update(opts)) => { orb.borrow_mut_mcu(opts.mcu) - .update_firmware(&opts.path, opts.can_fd) + .update_firmware(&opts.path) .await? } SubCommand::HardwareRevision { filename } => { diff --git a/mcu-util/src/orb/main_board.rs b/mcu-util/src/orb/main_board.rs index 67d0f63e..4cb224e2 100644 --- a/mcu-util/src/orb/main_board.rs +++ b/mcu-util/src/orb/main_board.rs @@ -23,6 +23,7 @@ pub struct MainBoard { canfd_iface: CanRawMessaging, isotp_iface: CanIsoTpMessaging, message_queue_rx: mpsc::UnboundedReceiver, + canfd: bool, } pub struct MainBoardBuilder { @@ -41,8 +42,8 @@ impl MainBoardBuilder { } } - pub async fn build(self) -> Result<(MainBoard, BoardTaskHandles)> { - let (mut canfd_iface, raw_can_task_handle) = CanRawMessaging::new( + pub async fn build(self, canfd: bool) -> Result<(MainBoard, BoardTaskHandles)> { + let (canfd_iface, raw_can_task_handle) = CanRawMessaging::new( String::from("can0"), Device::Main, self.message_queue_tx.clone(), @@ -57,34 +58,12 @@ impl MainBoardBuilder { ) .wrap_err("Failed to create CanIsoTpMessaging for MainBoard")?; - // Send a heartbeat to the main mcu to ensure it is alive - // & "subscribe" to the main mcu messages: messages to the Jetson - // are going to be sent after the heartbeat - let ack_result = canfd_iface - .send(McuPayload::ToMain( - main_messaging::jetson_to_mcu::Payload::Heartbeat( - main_messaging::Heartbeat { - timeout_seconds: 0_u32, - }, - ), - )) - .await - .map(|c| { - if let CommonAckError::Success = c { - Ok(()) - } else { - Err(eyre!("ack error: {c}")) - } - }); - if let Err(e) = ack_result { - error!("Failed to send heartbeat to main mcu: {:#?}", e); - } - Ok(( MainBoard { canfd_iface, isotp_iface, message_queue_rx: self.message_queue_rx, + canfd, }, BoardTaskHandles { raw: raw_can_task_handle, @@ -98,19 +77,38 @@ impl MainBoard { pub fn builder() -> MainBoardBuilder { MainBoardBuilder::new() } + + /// Send a message to the security board with preferred interface + pub async fn send(&mut self, payload: McuPayload) -> Result { + if matches!(payload, McuPayload::ToMain(_)) { + tracing::trace!( + "sending to main mcu over {}: {:?}", + if self.canfd { "can-fd" } else { "iso-tp" }, + payload + ); + if self.canfd { + self.canfd_iface.send(payload).await + } else { + self.isotp_iface.send(payload).await + } + } else { + Err(eyre!( + "Message not targeted to security board: {:?}", + payload + )) + } + } } #[async_trait] impl Board for MainBoard { async fn reboot(&mut self, delay: Option) -> Result<()> { let delay = delay.unwrap_or(REBOOT_DELAY); - self.isotp_iface - .send(McuPayload::ToMain( - main_messaging::jetson_to_mcu::Payload::Reboot( - main_messaging::RebootWithDelay { delay }, - ), - )) - .await?; + let reboot_msg = + McuPayload::ToMain(main_messaging::jetson_to_mcu::Payload::Reboot( + main_messaging::RebootWithDelay { delay }, + )); + self.send(reboot_msg).await?; info!("🚦 Rebooting main microcontroller in {} seconds", delay); Ok(()) } @@ -161,7 +159,7 @@ impl Board for MainBoard { Ok(()) } - async fn update_firmware(&mut self, path: &str, canfd: bool) -> Result<()> { + async fn update_firmware(&mut self, path: &str) -> Result<()> { let buffer = dfu::load_binary_file(path)?; debug!("Sending file {} ({} bytes)", path, buffer.len()); let mut block_iter = @@ -170,24 +168,12 @@ impl Board for MainBoard { ); while let Some(payload) = block_iter.next() { - if canfd { - while self - .canfd_iface - .send(McuPayload::ToMain(payload.clone())) - .await - .is_err() - { - tokio::time::sleep(Duration::from_millis(100)).await; - } - } else { - while self - .isotp_iface - .send(McuPayload::ToMain(payload.clone())) - .await - .is_err() - { - tokio::time::sleep(Duration::from_millis(100)).await; - } + while self + .send(McuPayload::ToMain(payload.clone())) + .await + .is_err() + { + tokio::time::sleep(Duration::from_millis(100)).await; } dfu::print_progress(block_iter.progress_percentage()); } @@ -200,7 +186,8 @@ impl Board for MainBoard { McuPayload::ToMain(main_messaging::jetson_to_mcu::Payload::FwImageCheck( main_messaging::FirmwareImageCheck { crc32: crc }, )); - if let Ok(ack) = self.isotp_iface.send(payload).await { + + if let Ok(ack) = self.send(payload).await { if !matches!(ack, CommonAckError::Success) { return Err(eyre!( "Unable to check image integrity: ack error: {}", @@ -240,7 +227,7 @@ impl Board for MainBoard { }, ), ); - if let Ok(ack) = self.isotp_iface.send(payload).await { + if let Ok(ack) = self.send(payload).await { if !matches!(ack, CommonAckError::Success) { return Err(eyre!( "Unable to activate image: ack error: {}", @@ -349,8 +336,8 @@ impl MainBoardInfo { /// on timeout, returns the info that was fetched so far async fn build(mut self, main_board: &mut MainBoard) -> Result { let mut is_err = false; + if let Err(e) = main_board - .isotp_iface .send(McuPayload::ToMain( main_messaging::jetson_to_mcu::Payload::ValueGet( main_messaging::ValueGet { @@ -366,7 +353,6 @@ impl MainBoardInfo { } if let Err(e) = main_board - .isotp_iface .send(McuPayload::ToMain( main_messaging::jetson_to_mcu::Payload::ValueGet( main_messaging::ValueGet { @@ -382,7 +368,6 @@ impl MainBoardInfo { } if let Err(e) = main_board - .isotp_iface .send(McuPayload::ToMain( main_messaging::jetson_to_mcu::Payload::ValueGet( main_messaging::ValueGet { @@ -437,6 +422,7 @@ impl MainBoardInfo { unreachable!("should always be a message from the main board") }; + tracing::trace!("rx message from main-mcu: {:?}", main_mcu_payload); match main_mcu_payload { main_messaging::mcu_to_jetson::Payload::Versions(v) => { self.fw_versions = Some(v); diff --git a/mcu-util/src/orb/mod.rs b/mcu-util/src/orb/mod.rs index 3c4414c0..6dc51c91 100644 --- a/mcu-util/src/orb/mod.rs +++ b/mcu-util/src/orb/mod.rs @@ -37,7 +37,7 @@ pub trait Board { /// This operation will also switch the board, and in case /// of the security microcontroller, it will reboot the board /// to perform the update. - async fn update_firmware(&mut self, path: &str, canfd: bool) -> Result<()>; + async fn update_firmware(&mut self, path: &str) -> Result<()>; /// Switch the firmware images on the board, from secondary to primary /// Images are checked for validity before the switch: if the images are @@ -59,9 +59,10 @@ pub struct Orb { } impl Orb { - pub async fn new() -> Result<(Self, OrbTaskHandles)> { - let (main_board, main_task_handle) = MainBoard::builder().build().await?; - let (sec_board, sec_task_handle) = SecurityBoard::builder().build().await?; + pub async fn new(can_fd: bool) -> Result<(Self, OrbTaskHandles)> { + let (main_board, main_task_handle) = MainBoard::builder().build(can_fd).await?; + let (sec_board, sec_task_handle) = + SecurityBoard::builder().build(can_fd).await?; let info = OrbInfo::default(); Ok(( diff --git a/mcu-util/src/orb/security_board.rs b/mcu-util/src/orb/security_board.rs index 149addaa..389022b6 100644 --- a/mcu-util/src/orb/security_board.rs +++ b/mcu-util/src/orb/security_board.rs @@ -24,6 +24,7 @@ pub struct SecurityBoard { canfd_iface: CanRawMessaging, isotp_iface: CanIsoTpMessaging, message_queue_rx: mpsc::UnboundedReceiver, + canfd: bool, } pub struct SecurityBoardBuilder { @@ -42,8 +43,8 @@ impl SecurityBoardBuilder { } } - pub async fn build(self) -> Result<(SecurityBoard, BoardTaskHandles)> { - let (mut canfd_iface, raw_can_task) = CanRawMessaging::new( + pub async fn build(self, canfd: bool) -> Result<(SecurityBoard, BoardTaskHandles)> { + let (canfd_iface, raw_can_task) = CanRawMessaging::new( String::from("can0"), Device::Security, self.message_queue_tx.clone(), @@ -58,34 +59,12 @@ impl SecurityBoardBuilder { ) .wrap_err("Failed to create CanIsoTpMessaging for SecurityBoard")?; - // Send a heartbeat to the mcu to ensure it is alive - // & "subscribe" to the mcu messages: messages to the Jetson - // are going to be sent after the heartbeat - let ack_result = canfd_iface - .send(McuPayload::ToSec( - security_messaging::jetson_to_sec::Payload::Heartbeat( - security_messaging::Heartbeat { - timeout_seconds: 0_u32, - }, - ), - )) - .await - .map(|c| { - if let CommonAckError::Success = c { - Ok(()) - } else { - Err(eyre!("ack error: {c}")) - } - }); - if let Err(e) = ack_result { - error!("Failed to send heartbeat to security mcu: {:#?}", e); - } - Ok(( SecurityBoard { canfd_iface, isotp_iface, message_queue_rx: self.message_queue_rx, + canfd, }, BoardTaskHandles { raw: raw_can_task, @@ -100,20 +79,39 @@ impl SecurityBoard { SecurityBoardBuilder::new() } - pub async fn power_cycle_secure_element(&mut self) -> Result<()> { - self.isotp_iface - .send(McuPayload::ToSec( - security_messaging::jetson_to_sec::Payload::SeRequest( - security_messaging::SeRequest { - id: security_messaging::se_request::RequestType::PowerOff - as u32, - data: vec![], - rx_length: 0, - request_type: 0, - }, - ), + /// Send a message to the security board with preferred interface + pub async fn send(&mut self, payload: McuPayload) -> Result { + if matches!(payload, McuPayload::ToSec(_)) { + tracing::trace!( + "sending message to security mcu over {}: {:?}", + if self.canfd { "can-fd" } else { "iso-tp" }, + payload + ); + if self.canfd { + self.canfd_iface.send(payload).await + } else { + self.isotp_iface.send(payload).await + } + } else { + Err(eyre!( + "Message not targeted to security board: {:?}", + payload )) - .await?; + } + } + + pub async fn power_cycle_secure_element(&mut self) -> Result<()> { + self.send(McuPayload::ToSec( + security_messaging::jetson_to_sec::Payload::SeRequest( + security_messaging::SeRequest { + id: security_messaging::se_request::RequestType::PowerOff as u32, + data: vec![], + rx_length: 0, + request_type: 0, + }, + ), + )) + .await?; info!("🔌 Power cycling secure element"); Ok(()) } @@ -123,13 +121,11 @@ impl SecurityBoard { impl Board for SecurityBoard { async fn reboot(&mut self, delay: Option) -> Result<()> { let delay = delay.unwrap_or(REBOOT_DELAY); - self.isotp_iface - .send(McuPayload::ToSec( - orb_messages::mcu_sec::jetson_to_sec::Payload::Reboot( - security_messaging::RebootWithDelay { delay }, - ), - )) - .await?; + let reboot_msg = + McuPayload::ToSec(orb_messages::mcu_sec::jetson_to_sec::Payload::Reboot( + security_messaging::RebootWithDelay { delay }, + )); + self.send(reboot_msg).await?; info!("🚦 Rebooting security microcontroller in {} seconds", delay); Ok(()) } @@ -179,7 +175,7 @@ impl Board for SecurityBoard { Ok(()) } - async fn update_firmware(&mut self, path: &str, canfd: bool) -> Result<()> { + async fn update_firmware(&mut self, path: &str) -> Result<()> { let buffer = dfu::load_binary_file(path)?; debug!("Sending file {} ({} bytes)", path, buffer.len()); let mut block_iter = @@ -188,24 +184,8 @@ impl Board for SecurityBoard { ); while let Some(payload) = block_iter.next() { - if canfd { - while self - .canfd_iface - .send(McuPayload::ToSec(payload.clone())) - .await - .is_err() - { - tokio::time::sleep(Duration::from_millis(100)).await; - } - } else { - while self - .isotp_iface - .send(McuPayload::ToSec(payload.clone())) - .await - .is_err() - { - tokio::time::sleep(Duration::from_millis(100)).await; - } + while self.send(McuPayload::ToSec(payload.clone())).await.is_err() { + tokio::time::sleep(Duration::from_millis(100)).await; } dfu::print_progress(block_iter.progress_percentage()); } @@ -219,7 +199,7 @@ impl Board for SecurityBoard { security_messaging::FirmwareImageCheck { crc32: crc }, ), ); - if let Ok(ack) = self.isotp_iface.send(payload).await { + if let Ok(ack) = self.send(payload).await { if !matches!(ack, CommonAckError::Success) { return Err(eyre!( "Unable to check image integrity: ack error: {}", @@ -261,7 +241,7 @@ impl Board for SecurityBoard { }, ), ); - if let Ok(ack) = self.isotp_iface.send(payload).await { + if let Ok(ack) = self.send(payload).await { if !matches!(ack, CommonAckError::Success) { return Err(eyre!( "Unable to activate image: ack error: {}", @@ -369,7 +349,6 @@ impl SecurityBoardInfo { async fn build(mut self, sec_board: &mut SecurityBoard) -> Result { let mut is_err = false; if let Err(e) = sec_board - .isotp_iface .send(McuPayload::ToSec( security_messaging::jetson_to_sec::Payload::ValueGet( security_messaging::ValueGet { @@ -385,7 +364,6 @@ impl SecurityBoardInfo { } if let Err(e) = sec_board - .isotp_iface .send(McuPayload::ToSec( security_messaging::jetson_to_sec::Payload::ValueGet( security_messaging::ValueGet { @@ -401,7 +379,6 @@ impl SecurityBoardInfo { } if let Err(e) = sec_board - .isotp_iface .send(McuPayload::ToSec( security_messaging::jetson_to_sec::Payload::ValueGet( security_messaging::ValueGet { @@ -456,6 +433,7 @@ impl SecurityBoardInfo { unreachable!("should always be a message from the security board") }; + tracing::trace!("rx message from sec-mcu: {:?}", sec_mcu_payload); match sec_mcu_payload { security_messaging::sec_to_jetson::Payload::Versions(v) => { self.fw_versions = Some(v);