firmware for my Touchscreen E-Paper Input Module for Framework Laptop 16
1use core::marker::PhantomData;
2use core::str::Utf8Error;
3use defmt::debug;
4use fw16_epd_program_interface::ProgramFunctionTable;
5
6#[link_section = ".prog1"]
7#[used]
8static PROG1: [u32; 11] = [
9 0, // block_erase_cycles
10 1419452448, // crc
11 44, // len
12 4, // name_len
13 32, // name_offset
14 5, // version_len
15 36, // version_offset
16 0, // entry_offset
17 0x74736554,
18 0x2E302E30,
19 0x00000032,
20];
21
22const XIP_BASE: *const u8 = 0x10000000 as *const u8;
23
24const SLOT_SIZE: usize = 0x80000;
25
26pub(crate) const unsafe fn slot<'a>(id: u8) -> &'a ProgramSlotHeader {
27 if id < 1 || id > 31 {
28 panic!("slot ID must be between 1 and 31");
29 }
30
31 &*XIP_BASE.add(SLOT_SIZE * id as usize).cast::<ProgramSlotHeader>()
32}
33
34#[repr(C)]
35pub(crate) struct ProgramSlotHeader {
36 pub(crate) block_erase_cycles: usize,
37 pub(crate) crc: u32,
38 pub(crate) len: usize,
39 pub(crate) name_len: usize,
40 pub(crate) name_offset: usize,
41 pub(crate) version_len: usize,
42 pub(crate) version_offset: usize,
43 pub(crate) entry_offset: usize,
44}
45
46impl ProgramSlotHeader {
47 fn ptr(&self) -> *const u8 {
48 (&raw const *self).cast()
49 }
50
51 pub(crate) fn is_valid_program(&self) -> bool {
52 self.len != 0
53 && self.check_crc()
54 && self.name_offset.saturating_add(self.name_len) <= self.len
55 && self.version_offset.saturating_add(self.version_len) <= self.len
56 && self.entry_offset < self.len
57 && self.name().is_ok()
58 && self.version_string().is_ok()
59 }
60
61 pub(crate) fn check_crc(&self) -> bool {
62 if self.len >= SLOT_SIZE || self.len < size_of::<ProgramSlotHeader>() {
63 return false;
64 }
65
66 let ptr = unsafe { self.ptr().add(8) };
67 let slice = unsafe { core::slice::from_raw_parts(ptr, self.len - 8) };
68 let crc = crc32fast::hash(slice);
69 crc == self.crc
70 }
71
72 pub(crate) fn name(&self) -> Result<&str, Utf8Error> {
73 let ptr = unsafe { self.ptr().add(self.name_offset) };
74 let slice = unsafe { core::slice::from_raw_parts(ptr, self.name_len) };
75 core::str::from_utf8(slice)
76 }
77
78 pub(crate) fn version_string(&self) -> Result<&str, Utf8Error> {
79 let ptr = unsafe { self.ptr().add(self.version_offset) };
80 let slice = unsafe { core::slice::from_raw_parts(ptr, self.version_len) };
81 core::str::from_utf8(slice)
82 }
83
84 pub(crate) unsafe fn entry(&self) -> unsafe extern "C" fn(&ProgramFunctionTable) -> () {
85 let ptr = self.ptr().add(self.entry_offset);
86 core::mem::transmute(ptr)
87 }
88}
89
90pub(crate) struct Programs<'a> {
91 id: u8,
92 _phantom: PhantomData<&'a ProgramSlotHeader>,
93}
94
95impl<'a> Programs<'a> {
96 pub(crate) fn new() -> Self {
97 Self { id: 0, _phantom: PhantomData }
98 }
99}
100
101impl<'a> Iterator for Programs<'a> {
102 type Item = &'a ProgramSlotHeader;
103
104 fn next(&mut self) -> Option<Self::Item> {
105 loop {
106 self.id += 1;
107
108 if self.id == 32 {
109 return None;
110 }
111
112 let s = unsafe { slot(self.id) };
113
114 if s.is_valid_program() {
115 debug!("Found program {} version {} in slot {}", s.name().unwrap(), s.version_string().unwrap(), self.id);
116 return Some(s);
117 } else {
118 debug!("No program found in slot {}", self.id);
119 }
120
121 }
122 }
123
124 fn size_hint(&self) -> (usize, Option<usize>) {
125 (0, Some(32 - self.id as usize))
126 }
127}