#![cfg(feature = "blackbox")]
use crate::tasks::blackbox_task::BLACKBOX_WRITE_QUEUE;
#[cfg(feature = "rp2350")]
use crate::tasks::init_rp::BlackboxSpiDevice;
#[cfg(feature = "std")]
use crate::drivers::sd_card::{MockSdCard, SdStorage};
#[cfg(not(feature = "std"))]
use embedded_sdmmc::{Directory, Mode, SdCard, VolumeIdx, VolumeManager};
#[cfg(not(feature = "std"))]
pub struct VehicleTimeSource;
#[cfg(not(feature = "std"))]
impl embedded_sdmmc::TimeSource for VehicleTimeSource {
fn get_timestamp(&self) -> embedded_sdmmc::Timestamp {
embedded_sdmmc::Timestamp::from_fat(0, 0)
}
}
#[cfg(not(feature = "std"))]
pub struct BlackboxWriterContext {
pub spi_device: BlackboxSpiDevice,
pub sector_buffer: [u8; Self::BUFFER_SIZE],
pub buffer_idx: usize,
}
#[cfg(not(feature = "std"))]
impl BlackboxWriterContext {
const BUFFER_SIZE: usize = 512;
pub fn new(spi_device: BlackboxSpiDevice) -> Self {
Self { spi_device, sector_buffer: [0u8; Self::BUFFER_SIZE], buffer_idx: 0 }
}
}
#[cfg(feature = "std")]
pub struct BlackboxWriterContext {
pub sd_card: MockSdCard,
}
#[cfg(feature = "std")]
impl BlackboxWriterContext {
pub fn new() -> Self {
Self { sd_card: MockSdCard::new("blackbox_log.bbl") }
}
}
#[cfg(feature = "std")]
#[embassy_executor::task]
pub async fn blackbox_writer_task(ctx: &'static mut BlackboxWriterContext) {
log::info!("BLACKBOX SD WRITER: task started");
loop {
let block = BLACKBOX_WRITE_QUEUE.receive().await;
let chunk = &block.data[..block.len];
_ = ctx.sd_card.write_all(chunk).await;
}
}
#[cfg(not(feature = "std"))]
#[embassy_executor::task]
pub async fn blackbox_writer_task(ctx: &'static mut BlackboxWriterContext) {
log::info!("BLACKBOX SD WRITER: task started");
{
let sd_card = SdCard::new(&mut ctx.spi_device, embassy_time::Delay);
let volume_mgr = VolumeManager::new(sd_card, VehicleTimeSource);
let _volume = volume_mgr.open_volume(VolumeIdx(0)).unwrap();
}
log::info!("SD CARD: Handshake verified. Shifting master clock registers to 20 MHz...");
ctx.spi_device.bus_mut().set_frequency(20_000_000);
let sd_card = SdCard::new(&mut ctx.spi_device, embassy_time::Delay);
let volume_mgr = VolumeManager::new(sd_card, VehicleTimeSource);
let volume = volume_mgr.open_volume(VolumeIdx(0)).unwrap();
let mut root_dir = volume.open_root_dir().unwrap();
let next_index = find_next_log_index(&mut root_dir);
let mut filename_buf = [0u8; 12];
let filename_str = format_log_filename(next_index, &mut filename_buf);
let log_file = root_dir.open_file_in_dir(filename_str, Mode::ReadWriteCreateOrAppend).unwrap();
loop {
let block = BLACKBOX_WRITE_QUEUE.receive().await;
let chunk = &block.data[..block.len];
if ctx.buffer_idx + chunk.len() > BlackboxWriterContext::BUFFER_SIZE {
embassy_time::Timer::after_micros(0).await;
_ = log_file.write(&ctx.sector_buffer[..ctx.buffer_idx]).unwrap();
ctx.buffer_idx = 0;
}
ctx.sector_buffer[ctx.buffer_idx..ctx.buffer_idx + chunk.len()].copy_from_slice(chunk);
ctx.buffer_idx += chunk.len();
}
}
#[cfg(not(feature = "std"))]
pub fn find_next_log_index<D, T, const DIR: usize, const FILE: usize, const VOL: usize>(
root_dir: &mut Directory<'_, D, T, DIR, FILE, VOL>,
) -> u16
where
D: embedded_sdmmc::BlockDevice,
T: embedded_sdmmc::TimeSource,
{
let mut highest_idx = 0;
_ = root_dir.iterate_dir(|entry| {
let base = entry.name.base_name(); let ext = entry.name.extension();
if ext == b"BIN" {
if &base[0..4] == b"LOG_" {
if let Ok(num_str) = core::str::from_utf8(&base[4..7]) {
if let Ok(idx) = u16::from_str_radix(num_str, 10) {
if idx > highest_idx {
highest_idx = idx;
}
}
}
}
}
});
if highest_idx >= 999 { 0 } else { highest_idx + 1 }
}
#[cfg(not(feature = "std"))]
fn format_log_filename(index: u16, buf: &mut [u8; 12]) -> &str {
buf[0..4].copy_from_slice(b"LOG_");
buf[7..12].copy_from_slice(b".BIN");
buf[4] = ((index / 100) % 10) as u8 + b'0';
buf[5] = ((index / 10) % 10) as u8 + b'0';
buf[6] = (index % 10) as u8 + b'0';
core::str::from_utf8(buf).unwrap_or("LOG_000.BIN")
}