Skip to main content

stm_32/peripherals/
sd_card.rs

1// ******************************************************************************
2// * File     : platforms/stm_32/src/peripherals/sd_card.rs
3// * Date     : June 28, 2026
4// ******************************************************************************
5// *
6// * Copyright (c) 2023, AeroVironment, Inc.
7// * All rights reserved.
8// *
9// * Redistribution and use in source and binary forms, with or without
10// * modification, are permitted provided that the following conditions are met:
11// *
12// * 1.Redistributions of source code must retain the above copyright notice, this
13// * list of conditions and the following disclaimer.
14// *
15// * 2.Redistributions in binary form must reproduce the above copyright notice,
16// * this list of conditions and the following disclaimer in the documentation
17// * and/or other materials provided with the distribution.
18// *
19// * 3.Neither the name of the copyright holder nor the names of its
20// * contributors may be used to endorse or promote products derived from
21// * this software without specific prior written permission.
22// *
23// * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
24// * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25// * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
26// * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
27// * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28// * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
29// * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
30// * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
31// * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
32// * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33// *
34// ******************************************************************************
35
36use embassy_stm32::gpio::Input;
37use embassy_stm32::sdmmc::Error;
38use embassy_stm32::sdmmc::Sdmmc;
39use embassy_stm32::sdmmc::sd::{Addressable, CmdBlock, DataBlock, StorageDevice};
40use embassy_stm32::time::mhz;
41use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex;
42use embassy_sync::signal::Signal;
43use embassy_time::Instant;
44
45use veloxity_core::errors;
46use veloxity_core::packets;
47
48pub static SD_WRITE_SIGNAL: Signal<
49    CriticalSectionRawMutex,
50    Result<packets::ParamPacket, errors::SensorError>,
51> = Signal::<CriticalSectionRawMutex, Result<packets::ParamPacket, errors::SensorError>>::new();
52
53pub static SD_READ_SIGNAL: Signal<
54    CriticalSectionRawMutex,
55    Result<packets::ParamPacket, errors::SensorError>,
56> = Signal::<CriticalSectionRawMutex, Result<packets::ParamPacket, errors::SensorError>>::new();
57
58pub struct SdCard {
59    pub sdmmc: Sdmmc<'static>,
60    pub detect: Input<'static>,
61}
62
63impl SdCard {
64    async fn read(&mut self, p: &mut packets::ParamPacket, max_blocks: usize) -> Result<(), Error> {
65        let mut cmd_block = CmdBlock::new();
66        let mut storage =
67            StorageDevice::new_sd_card(&mut self.sdmmc, &mut cmd_block, mhz(4)).await?;
68        read(&mut storage, p, max_blocks).await
69    }
70
71    async fn write(&mut self, p: &packets::ParamPacket, max_blocks: usize) -> Result<(), Error> {
72        let mut cmd_block = CmdBlock::new();
73        let mut storage =
74            StorageDevice::new_sd_card(&mut self.sdmmc, &mut cmd_block, mhz(4)).await?;
75        write(&mut storage, p, max_blocks).await
76    }
77
78    async fn run(&mut self) {
79        let mut card_blocks = 0usize;
80        let mut cmd_block = CmdBlock::new();
81
82        if let Ok(storage) =
83            StorageDevice::new_sd_card(&mut self.sdmmc, &mut cmd_block, mhz(4)).await
84        {
85            let card = storage.card();
86            card_blocks = (card.size() / 512) as usize;
87        }
88
89        let header = packets::RosflightPacketHeader {
90            timestamp: Instant::now().as_micros(),
91            status: 0u16,
92        };
93        let values = [0u8; packets::PARAM_PACKET_SIZE];
94        let mut param_packet = packets::ParamPacket { header, values };
95
96        let _result = self.read(&mut param_packet, card_blocks).await;
97
98        SD_READ_SIGNAL.signal(Ok(param_packet));
99
100        loop {
101            match SD_WRITE_SIGNAL.wait().await {
102                Ok(mut packet) => {
103                    let result = self.write(&packet, card_blocks).await;
104                    match result {
105                        Ok(()) => {
106                            packet.header.status = 1;
107                        }
108                        Err(_e) => {
109                            packet.header.status = 0;
110                        }
111                    }
112                    SD_READ_SIGNAL.signal(Ok(packet));
113                }
114                Err(_e) => {}
115            }
116        }
117    }
118}
119
120async fn read(
121    storage: &mut StorageDevice<'_, '_, impl Addressable>,
122    p: &mut packets::ParamPacket,
123    max_blocks: usize,
124) -> Result<(), Error> {
125    let block_size = 512; // this is a fixed value
126    // number of blocks to write
127    let p_size = p.values.len();
128    let p_blocks = (p_size + block_size - 1) / block_size;
129
130    let mut blocks = p_blocks;
131    if blocks > max_blocks {
132        blocks = max_blocks;
133    };
134
135    for i in 0..blocks {
136        let mut block = DataBlock::new();
137        storage.read_block(i as u32, &mut block).await?;
138        p.values[i * 512..(i + 1) * 512].copy_from_slice(&block[..]);
139    }
140    Ok(())
141}
142
143async fn write(
144    storage: &mut StorageDevice<'_, '_, impl Addressable>,
145    p: &packets::ParamPacket,
146    max_blocks: usize,
147) -> Result<(), Error> {
148    let block_size = 512; // this is a fixed value
149    // number of blocks to write
150    let p_size = p.values.len();
151    let p_blocks = (p_size + block_size - 1) / block_size;
152
153    let mut blocks = p_blocks;
154    if blocks > max_blocks {
155        blocks = max_blocks;
156    };
157
158    for i in 0..blocks {
159        let mut block = DataBlock::new();
160        block.copy_from_slice(&p.values[(i * 512)..((i + 1) * 512)]);
161        storage.write_block(i as u32, &block).await?;
162    }
163    Ok(())
164}
165
166#[embassy_executor::task]
167pub async fn task(mut sd_card: SdCard) {
168    sd_card.run().await;
169}