use crate::hardware::Bank;
use crate::log;
use crc::{Crc, CRC_32_CKSUM};
#[cfg(feature = "defmt")]
use defmt::Format;
#[cfg(feature = "ram-state")]
use desse::{Desse, DesseSized};
#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};
#[cfg_attr(feature = "use-defmt", derive(Format))]
#[cfg_attr(feature = "derive", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "ram-state", derive(Desse, DesseSized))]
#[derive(Debug, PartialEq, Eq)]
pub enum Update {
None,
Request(Bank),
Revert(Bank),
Exchanging(ExchangeProgress),
Error(UpdateError),
}
#[cfg_attr(feature = "use-defmt", derive(Format))]
#[cfg_attr(feature = "derive", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "ram-state", derive(Desse, DesseSized))]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum UpdateError {
InvalidImageIndex,
ImageExchangeFailed,
InvalidState,
InvalidSignature,
}
#[cfg_attr(feature = "use-defmt", derive(Format))]
#[cfg_attr(feature = "derive", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "ram-state", derive(Desse, DesseSized))]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct ExchangeProgress {
pub(crate) a: Bank,
pub(crate) b: Bank,
pub(crate) page_index: u32,
pub(crate) recovering: bool,
}
#[cfg_attr(feature = "use-defmt", derive(Format))]
#[cfg_attr(feature = "derive", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "ram-state", derive(Desse, DesseSized))]
#[derive(Debug)]
pub struct MoonbootState {
pub update: Update,
}
pub trait State {
fn read(&mut self) -> MoonbootState;
fn write(&mut self, data: MoonbootState) -> Result<(), ()>;
}
pub const STATE_SERIALIZED_MAX_SIZE: usize = MoonbootState::SIZE;
pub type StateCrcType = u32;
const CRC: Crc<StateCrcType> = Crc::<StateCrcType>::new(&CRC_32_CKSUM);
fn checksum(bytes: &[u8]) -> StateCrcType {
CRC.checksum(bytes)
}
#[cfg(feature = "ram-state")]
pub mod ram {
use super::*;
pub struct RamState;
extern "C" {
static mut _moonboot_state_crc_start: StateCrcType;
static mut _moonboot_state_data_start: [u8; STATE_SERIALIZED_MAX_SIZE];
}
impl State for RamState {
fn read(&mut self) -> MoonbootState {
let crc = unsafe { _moonboot_state_crc_start };
log::info!(
"Reading data with len: {}, CRC: {}",
STATE_SERIALIZED_MAX_SIZE,
crc
);
let checksum = checksum(unsafe { &_moonboot_state_data_start });
if crc == checksum {
let data =
MoonbootState::deserialize_from(unsafe { &_moonboot_state_data_start });
log::trace!("CRC Match! {}: {:?}", crc, data);
return data;
} else {
log::trace!("CRC Mismatch! {} vs {}", crc, checksum);
}
MoonbootState {
update: Update::None,
}
}
fn write(&mut self, data: MoonbootState) -> Result<(), ()> {
log::trace!("Writing data {:?}", data);
unsafe { _moonboot_state_data_start = data.serialize() };
log::trace!("Written data: {:?}", unsafe {
&_moonboot_state_data_start
});
unsafe {
_moonboot_state_crc_start = checksum(&_moonboot_state_data_start);
}
log::info!(
"Written len: {}, checksum: {}",
STATE_SERIALIZED_MAX_SIZE,
unsafe { _moonboot_state_crc_start }
);
Ok(())
}
}
}