diff --git a/boards/communication/src/health.rs b/boards/communication/src/health.rs index 1f5cbd97..d357d11a 100644 --- a/boards/communication/src/health.rs +++ b/boards/communication/src/health.rs @@ -4,7 +4,7 @@ use atsamd_hal::gpio::{Alternate, Pin, B, PB00, PB01, PB02, PB03, PB05, PB06, PB07, PB08, PB09}; use atsamd_hal::{adc::Adc, ehal::adc::OneShot, pac::ADC0, pac::ADC1}; -use common_arm::HealthMonitorChannels; +use common_arm::{HealthMonitorChannels, SdManager}; // make sure to define the ADC types in types.rs @@ -13,6 +13,7 @@ use common_arm::HealthMonitorChannels; pub struct HealthMonitorChannelsCommunication { reader: Adc, reader1: Adc, + sd_manager: SdManager, pin_3v3: Pin>, pin_5v: Pin>, pin_pyro: Pin>, @@ -52,12 +53,16 @@ impl HealthMonitorChannels for HealthMonitorChannelsCommunication { fn get_failover(&mut self) -> Option { self.reader1.read(&mut self.pin_failover).ok() } + fn get_sd_card_status(&mut self) -> Option { + self.sd_manager.is_mounted() + } } impl HealthMonitorChannelsCommunication { pub fn new( reader: Adc, reader1: Adc, + sd_manager: SdManager, pin_3v3: Pin>, pin_5v: Pin>, pin_pyro: Pin>, @@ -71,6 +76,7 @@ impl HealthMonitorChannelsCommunication { HealthMonitorChannelsCommunication { reader, reader1, + sd_manager, pin_3v3, pin_5v, pin_pyro, diff --git a/boards/communication/src/main.rs b/boards/communication/src/main.rs index dcd1ea95..f1163529 100644 --- a/boards/communication/src/main.rs +++ b/boards/communication/src/main.rs @@ -155,6 +155,7 @@ mod app { let health_monitor_channels = HealthMonitorChannelsCommunication::new( adc0, adc1, + sd_manager, pins.pb01.into(), pins.pb02.into(), pins.pb03.into(), diff --git a/libraries/common-arm/src/health/health_monitor.rs b/libraries/common-arm/src/health/health_monitor.rs index 29d61afe..62be04a2 100644 --- a/libraries/common-arm/src/health/health_monitor.rs +++ b/libraries/common-arm/src/health/health_monitor.rs @@ -17,6 +17,7 @@ pub trait HealthMonitorChannels { fn get_ext_5v(&mut self) -> Option; fn get_ext_3v3(&mut self) -> Option; fn get_failover(&mut self) -> Option; + fn get_sd_card_status(&mut self) -> Option; } pub struct HealthMonitor { @@ -74,6 +75,7 @@ where ext_v5: None, ext_3v3: None, failover_sense: None, + sd_card: None }, range_5v, range_3v3, @@ -102,6 +104,7 @@ where self.data.ext_v5 = self.channels.get_ext_5v(); self.data.ext_3v3 = self.channels.get_ext_3v3(); self.data.failover_sense = self.channels.get_failover(); + self.data.sd_card = self.channels.get_sd_card_status(); } } diff --git a/libraries/common-arm/src/sd_manager.rs b/libraries/common-arm/src/sd_manager.rs index d4abe100..e7a6bb61 100644 --- a/libraries/common-arm/src/sd_manager.rs +++ b/libraries/common-arm/src/sd_manager.rs @@ -1,9 +1,12 @@ use core::{fmt::Debug, marker::PhantomData}; -use defmt::info; +use defmt::{info, error}; use embedded_hal as hal; use embedded_sdmmc as sd; use hal::spi::FullDuplex; +use messages::ErrorContext; +use crate::herror; + /// Time source for `[SdInterface]`. It doesn't return any useful information for now, and will /// always return an arbitrary time. pub struct TimeSink { @@ -39,8 +42,8 @@ where CS: hal::digital::v2::OutputPin, { pub sd_controller: sd::Controller, TimeSink>, - pub volume: sd::Volume, - pub root_directory: sd::Directory, + pub volume: Option, + pub root_directory: Option, pub file: Option, } @@ -52,85 +55,134 @@ where { pub fn new(spi: SPI, cs: CS) -> Self { let time_sink: TimeSink = TimeSink::new(); // Need to give this a DateTime object for actual timing. - let mut sd_cont = sd::Controller::new(sd::SdMmcSpi::new(spi, cs), time_sink); - match sd_cont.device().init() { - Ok(_) => match sd_cont.device().card_size_bytes() { + let mut sd_controller = sd::Controller::new(sd::SdMmcSpi::new(spi, cs), time_sink); + match sd_controller.device().init() { + Ok(_) => match sd_controller.device().card_size_bytes() { Ok(size) => info!("Card is {} bytes", size), - Err(_) => panic!("Cannot get card size"), + Err(_) => error!("Cannot get card size"), }, Err(_) => { - panic!("Cannot get SD card."); + herror!(Error, ErrorContext::SDCardNotConnected); } - } + }; - let mut volume = match sd_cont.get_volume(sd::VolumeIdx(0)) { - Ok(volume) => volume, + let mut volume = match sd_controller.get_volume(sd::VolumeIdx(0)) { + Ok(volume) => Some(volume), Err(_) => { - panic!("Cannot get volume 0"); + error!("Cannot get volume 0"); + None } }; - let root_directory = match sd_cont.open_root_dir(&volume) { - Ok(root_directory) => root_directory, - Err(_) => { - panic!("Cannot get root"); + let root_directory = match &volume { + Some(volume) => match sd_controller.open_root_dir(volume) { + Ok(root_directory) => Some(root_directory), + Err(_) => { + error!("Cannot get root"); + None + } } + _ => None, }; - let file = sd_cont.open_file_in_dir( - &mut volume, - &root_directory, - "log.txt", - sd::Mode::ReadWriteCreateOrTruncate, - ); - let file = match file { - Ok(file) => file, - Err(_) => { - panic!("Cannot create file."); - } + + let file = match (&mut volume, &root_directory) { + (Some(volume), Some(root_directory)) => { + let _file = sd_controller.open_file_in_dir( + volume, + &root_directory, + "log.txt", + sd::Mode::ReadWriteCreateOrTruncate, + ); + let _file = match _file { + Ok(__file) => Some(__file), + Err(_) => { + error!("Cannot create file."); + None + } + }; + _file + }, + _ => None }; SdManager { - sd_controller: sd_cont, + sd_controller, volume, root_directory, - file: Some(file), + file, } } + pub fn write( &mut self, file: &mut sd::File, buffer: &[u8], ) -> Result> { - self.sd_controller.write(&mut self.volume, file, buffer) + if !self.is_mounted() { + return Err(sd::Error::DeviceError(sd::SdMmcError::CardNotFound)); + } + self.sd_controller.write(self.volume.as_mut().unwrap(), file, buffer) } + pub fn write_str( &mut self, file: &mut sd::File, msg: &str, ) -> Result> { + if !self.is_mounted() { + return Err(sd::Error::DeviceError(sd::SdMmcError::CardNotFound)); + } let buffer: &[u8] = msg.as_bytes(); - self.sd_controller.write(&mut self.volume, file, buffer) + self.sd_controller.write(self.volume.as_mut().unwrap(), file, buffer) } + pub fn open_file(&mut self, file_name: &str) -> Result> { + if !self.is_mounted() { + return Err(sd::Error::DeviceError(sd::SdMmcError::CardNotFound)); + } self.sd_controller.open_file_in_dir( - &mut self.volume, - &self.root_directory, + self.volume.as_mut().unwrap(), + self.root_directory.as_ref().unwrap(), file_name, sd::Mode::ReadWriteCreateOrTruncate, ) } + pub fn close_current_file(&mut self) -> Result<(), sd::Error> { + if !self.is_mounted() { + return Err(sd::Error::DeviceError(sd::SdMmcError::CardNotFound)); + } if let Some(file) = self.file.take() { return self.close_file(file); } Ok(()) } + pub fn close_file(&mut self, file: sd::File) -> Result<(), sd::Error> { - self.sd_controller.close_file(&self.volume, file) + if !self.is_mounted() { + return Err(sd::Error::DeviceError(sd::SdMmcError::CardNotFound)); + } + self.sd_controller.close_file(self.volume.as_ref().unwrap(), file) } - pub fn close(mut self) { - self.sd_controller - .close_dir(&self.volume, self.root_directory); + + pub fn close(&mut self) -> Result<(), sd::Error> { + if !self.is_mounted() { + return Err(sd::Error::DeviceError(sd::SdMmcError::CardNotFound)); + } + self.sd_controller.close_dir( + self.volume.as_ref().unwrap(), + self.root_directory.unwrap() + ); + Ok(()) + } + + pub fn is_mounted(&mut self) -> bool { + // Sd crate doesn't have a check method for SD card being still mounted + // Use `card_size_bytes()` as indicator if device is still connected or not + match self.sd_controller.device().card_size_bytes() { + Ok(size) => true, + Err(_) => false, + } } } diff --git a/libraries/messages/src/health.rs b/libraries/messages/src/health.rs index 0c852eca..9d4722fa 100644 --- a/libraries/messages/src/health.rs +++ b/libraries/messages/src/health.rs @@ -56,6 +56,7 @@ pub struct HealthStatus { pub ext_v5: Option, pub ext_3v3: Option, pub failover_sense: Option, + pub sd_card: Option, } impl Health { diff --git a/libraries/messages/src/logging/mod.rs b/libraries/messages/src/logging/mod.rs index d05cee3b..762e636f 100644 --- a/libraries/messages/src/logging/mod.rs +++ b/libraries/messages/src/logging/mod.rs @@ -43,6 +43,7 @@ pub enum ErrorContext { UnknownRadioMessage, UnkownPostcardMessage, NoRadioTransfer, + SDCardNotConnected, } display_context!( @@ -50,5 +51,6 @@ display_context!( [UnkownCanMessage, "Unknown CAN message received"], [UnknownRadioMessage, "Unknown radio message received"], [NoRadioTransfer, "No radio transfer available"], - [UnkownPostcardMessage, "Unknown postcard message received"] + [UnkownPostcardMessage, "Unknown postcard message received"], + [SDCardNotConnected, "SD Card is not connected"] );