firmware for my Touchscreen E-Paper Input Module for Framework Laptop 16
0

Configure Feed

Select the types of activity you want to include in your feed.

1use core::str::Utf8Error; 2 3#[cfg(feature = "defmt")] 4use defmt::{warn, debug}; 5 6pub const XIP_BASE: *const u8 = 0x10000000 as *const u8; 7pub const PROGRAM_RAM_AREA_BASE: *mut u8 = 0x20020000 as *mut u8; 8 9pub const SLOT_SIZE: usize = 0x80000; 10 11pub const unsafe fn slot(id: u8) -> *const ProgramSlotHeader { 12 if id > 31 { 13 panic!("slot ID must be between 0 and 31"); 14 } 15 16 if id == 0 { 17 // "Slot 0" is used for the launcher, which is stored 128K into the flash 18 XIP_BASE.add(128 * 1024).cast() 19 } else { 20 XIP_BASE.add(SLOT_SIZE * id as usize).cast() 21 } 22} 23 24 25pub struct Programs { 26 id: u8, 27} 28 29impl Programs { 30 pub fn new() -> Self { 31 Self { id: 0 } 32 } 33} 34 35impl Iterator for Programs { 36 type Item = *const ProgramSlotHeader; 37 38 fn next(&mut self) -> Option<Self::Item> { 39 loop { 40 self.id += 1; 41 42 if self.id > 31 { 43 return None; 44 } 45 46 let s = unsafe { slot(self.id) }; 47 48 unsafe { 49 if (*s).is_valid() { 50 #[cfg(feature = "defmt")] 51 debug!("Found program {} version {} in slot {}", (*s).name().unwrap(), (*s).version().unwrap(), self.id); 52 return Some(s); 53 } else { 54 #[cfg(feature = "defmt")] 55 debug!("No program found in slot {}", self.id); 56 } 57 } 58 } 59 } 60 61 fn size_hint(&self) -> (usize, Option<usize>) { 62 (0, Some(32 - self.id as usize)) 63 } 64} 65 66#[repr(C)] 67pub struct ProgramSlotHeader { 68 pub block_erase_cycles: usize, 69 pub crc: u32, 70 pub len: usize, 71 72 pub data_len: usize, 73 pub data_lma: *const u8, 74 pub data_vma: *mut u8, 75 76 pub bss_len: usize, 77 pub bss_vma: *mut u8, 78 79 pub name_len: usize, 80 pub name_ptr: *const u8, 81 82 pub version_len: usize, 83 pub version_ptr: *const u8, 84 85 pub entry: unsafe extern "C" fn(), 86} 87 88unsafe impl Sync for ProgramSlotHeader {} 89 90impl ProgramSlotHeader { 91 pub const fn partial(name: &'static str, version: &'static str, entry: unsafe extern "C" fn()) -> Self { 92 Self { 93 block_erase_cycles: 0, 94 crc: 0, 95 len: 0, 96 data_len: 0, 97 data_lma: core::ptr::null(), 98 data_vma: core::ptr::null_mut(), 99 bss_len: 0, 100 bss_vma: core::ptr::null_mut(), 101 name_len: name.len(), 102 name_ptr: name.as_ptr(), 103 version_len: version.len(), 104 version_ptr: version.as_ptr(), 105 entry, 106 } 107 } 108 109 pub fn is_valid(&self) -> bool { 110 // Erased flash contains all 1s 111 if self.len == 0 || self.len == usize::MAX { 112 return false; 113 } 114 115 if self.len > SLOT_SIZE { 116 #[cfg(feature = "defmt")] 117 warn!("Program header has invalid size"); 118 return false; 119 } 120 121 if !self.check_crc() { 122 #[cfg(feature = "defmt")] 123 warn!("Program has invalid CRC"); 124 return false; 125 } 126 127 if self.name().is_err() { 128 #[cfg(feature = "defmt")] 129 warn!("Program name is not valid UTF-8"); 130 return false; 131 } 132 133 if self.version().is_err() { 134 #[cfg(feature = "defmt")] 135 warn!("Program version string is not valid UTF-8"); 136 return false; 137 } 138 139 let slot_min = (&raw const *self) as usize; 140 let slot_max = slot_min + SLOT_SIZE; 141 let slot_range = slot_min..slot_max; 142 let ram_min = PROGRAM_RAM_AREA_BASE as usize; 143 let ram_max = ram_min + 136 * 1024; 144 let ram_range = ram_min..ram_max; 145 146 if self.data_len > 0 { 147 if !slot_range.contains(&(self.data_lma as usize)) || !slot_range.contains(&(self.data_lma as usize + self.data_len - 1)) { 148 #[cfg(feature = "defmt")] 149 warn!("Program has invalid data section addresses"); 150 return false; 151 } 152 153 if !ram_range.contains(&(self.data_vma as usize)) || !ram_range.contains(&(self.data_vma as usize + self.data_len - 1)) { 154 #[cfg(feature = "defmt")] 155 warn!("Program has invalid data section load addresses"); 156 return false; 157 } 158 } 159 160 if self.bss_len > 0 { 161 if !ram_range.contains(&(self.bss_vma as usize)) || !ram_range.contains(&(self.data_vma as usize + self.data_len - 1)) { 162 #[cfg(feature = "defmt")] 163 warn!("Program has invalid bss section addresses"); 164 return false; 165 } 166 } 167 168 true 169 } 170 171 pub fn slot(&self) -> u8 { 172 (((&raw const *self as usize) - XIP_BASE as usize) / SLOT_SIZE) as u8 173 } 174 175 pub fn check_crc(&self) -> bool { 176 if self.len >= SLOT_SIZE || self.len < size_of::<ProgramSlotHeader>() { 177 return false; 178 } 179 180 let ptr = unsafe { (&raw const *self).cast::<u8>().add(8) }; 181 let slice = unsafe { core::slice::from_raw_parts(ptr, self.len - 8) }; 182 let crc = crc32fast::hash(slice); 183 crc == self.crc 184 } 185 186 pub fn name(&self) -> Result<&str, Utf8Error> { 187 unsafe { 188 core::str::from_utf8(core::slice::from_raw_parts(self.name_ptr, self.name_len)) 189 } 190 } 191 192 pub fn version(&self) -> Result<&str, Utf8Error> { 193 unsafe { 194 core::str::from_utf8(core::slice::from_raw_parts(self.version_ptr, self.version_len)) 195 } 196 } 197 198 pub unsafe fn load(&self) { 199 if self.data_len > 0 { 200 core::ptr::copy_nonoverlapping(self.data_lma, self.data_vma, self.data_len); 201 } 202 203 if self.bss_len > 0 { 204 self.bss_vma.write_bytes(0, self.bss_len); 205 } 206 } 207}