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

Configure Feed

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

eepy: complete initial userspace USB impl eepy-sys: add critical_section impl for userspace programs

+141 -23
+1 -1
Cargo.toml
··· 30 30 crc32fast = { version = "1.4", default-features = false } 31 31 embedded-graphics = "0.8.1" 32 32 heapless = "0.8" 33 - once_cell = { version = "1.20", default-features = false, features = ["critical-section", "portable-atomic"] } 33 + once_cell = { version = "1.20", default-features = false, features = ["critical-section"] } 34 34 postcard = "1.1" 35 35 serde = { version = "1.0", default-features = false, features = ["derive"] }
+4 -1
eepy-launcher/.cargo/config.toml
··· 5 5 rustflags = [ 6 6 "-C", "link-arg=--nmagic", 7 7 "-C", "link-arg=-Tlauncher.x", 8 - ] 8 + ] 9 + 10 + [profile.release] 11 + debug = 2
+1 -1
eepy-launcher/Cargo.toml
··· 4 4 edition = "2021" 5 5 6 6 [dependencies] 7 - eepy-sys = { path = "../eepy-sys" } 7 + eepy-sys = { path = "../eepy-sys", features = ["critical-section-impl"] } 8 8 eepy-gui = { path = "../eepy-gui" } 9 9 embedded-graphics.workspace = true 10 10 usb-device.workspace = true
+4 -7
eepy-launcher/src/main.rs
··· 17 17 use eepy_sys::image::RefreshBlockMode; 18 18 use eepy_sys::input::{has_event, next_event, set_touch_enabled, Event, TouchEventType}; 19 19 use eepy_sys::header::{ProgramSlotHeader, Programs}; 20 - use eepy_sys::misc::{get_serial, info}; 20 + use eepy_sys::misc::{get_serial, info, trace}; 21 21 use eepy_sys::usb; 22 22 use eepy_sys::usb::UsbBus; 23 23 use usb_device::prelude::*; ··· 295 295 let dev: &mut UsbDevice<UsbBus> = unsafe { USB_DEVICE.as_mut().unwrap() }; 296 296 let serial: &mut SerialPort<UsbBus> = unsafe { USB_SERIAL.as_mut().unwrap() }; 297 297 298 - info("hello from USB handler"); 298 + trace("Launcher USB handler"); 299 299 300 300 if dev.poll(&mut [serial]) { 301 301 let mut buf = [0u8; 64]; ··· 332 332 let serial = SerialPort::new(bus_ref); 333 333 USB_SERIAL = Some(serial); 334 334 335 - let usb_dev = UsbDeviceBuilder::new( 336 - bus_ref, 337 - UsbVidPid(0x2e8a, 0x000a), 338 - ) 335 + let usb_dev = UsbDeviceBuilder::new(bus_ref, UsbVidPid(0x2e8a, 0x000a)) 339 336 .strings(&[StringDescriptors::default() 340 337 .manufacturer("arthomnix") 341 - .product("Touchscreen E-Paper Input Module for Framework 16 [eepyOS Launcher]") 338 + .product("Touchscreen EPD for FW16 [eepyOS Launcher]") 342 339 .serial_number(get_serial()) 343 340 ]) 344 341 .unwrap()
+4 -1
eepy-sys/Cargo.toml
··· 10 10 serde.workspace = true 11 11 crc32fast.workspace = true 12 12 usb-device.workspace = true 13 + critical-section = { workspace = true, optional = true } 14 + once_cell = { workspace = true, optional = true } 13 15 14 16 [features] 15 - defmt = ["dep:defmt", "usb-device/defmt"] 17 + defmt = ["dep:defmt", "usb-device/defmt"] 18 + critical-section-impl = ["critical-section", "critical-section/restore-state-bool", "once_cell"]
+19
eepy-sys/src/critical_section.rs
··· 1 + #[repr(usize)] 2 + #[derive(Copy, Clone, Debug, Eq, PartialEq)] 3 + #[cfg_attr(feature = "defmt", derive(defmt::Format))] 4 + pub enum CsSyscall { 5 + Acquire = 0, 6 + Release = 1, 7 + } 8 + 9 + impl TryFrom<usize> for CsSyscall { 10 + type Error = (); 11 + 12 + fn try_from(value: usize) -> Result<Self, Self::Error> { 13 + match value { 14 + x if x == CsSyscall::Acquire as usize => Ok(CsSyscall::Acquire), 15 + x if x == CsSyscall::Release as usize => Ok(CsSyscall::Release), 16 + _ => Err(()), 17 + } 18 + } 19 + }
+25
eepy-sys/src/critical_section_impl.rs
··· 1 + use crate::critical_section::CsSyscall; 2 + use crate::syscall; 3 + use crate::syscall::SyscallNumber; 4 + 5 + struct EepyCs; 6 + critical_section::set_impl!(EepyCs); 7 + 8 + unsafe impl critical_section::Impl for EepyCs { 9 + unsafe fn acquire() -> bool { 10 + let mut state: bool; 11 + syscall!( 12 + SyscallNumber::CriticalSection, 13 + out state in CsSyscall::Acquire, 14 + ); 15 + state 16 + } 17 + 18 + unsafe fn release(state: bool) { 19 + syscall!( 20 + SyscallNumber::CriticalSection, 21 + in CsSyscall::Release, 22 + in state, 23 + ); 24 + } 25 + }
+4
eepy-sys/src/lib.rs
··· 7 7 pub mod input; 8 8 pub mod usb; 9 9 pub mod exec; 10 + pub mod critical_section; 11 + 12 + #[cfg(feature = "critical-section-impl")] 13 + mod critical_section_impl; 10 14 11 15 pub use tp370pgh01::IMAGE_BYTES; 12 16
+27 -4
eepy-sys/src/misc.rs
··· 1 + use core::mem::MaybeUninit; 1 2 use crate::syscall; 2 3 use crate::syscall::SyscallNumber; 4 + 5 + #[cfg(feature = "critical-section-impl")] 6 + use once_cell::sync::OnceCell; 3 7 4 8 #[repr(usize)] 5 9 #[derive(Copy, Clone, Debug, Eq, PartialEq)] ··· 47 51 } 48 52 } 49 53 50 - pub fn get_serial() -> &'static str { 51 - let mut ptr: *const [u8; 16]; 54 + pub fn get_serial_raw() -> [u8; 16] { 55 + let mut buf: MaybeUninit<[u8; 16]> = MaybeUninit::uninit(); 56 + let ptr = buf.as_mut_ptr(); 57 + 52 58 unsafe { 53 59 syscall!( 54 60 SyscallNumber::Misc, 55 - out ptr in MiscSyscall::GetSerial, 61 + in MiscSyscall::GetSerial, 62 + in ptr, 56 63 ); 57 - core::str::from_utf8_unchecked(&*ptr) 64 + 65 + buf.assume_init() 66 + } 67 + } 68 + 69 + #[cfg(feature = "critical-section-impl")] 70 + static SERIAL: OnceCell<[u8; 16]> = OnceCell::new(); 71 + 72 + #[cfg(feature = "critical-section-impl")] 73 + pub fn get_serial() -> &'static str { 74 + if SERIAL.get().is_none() { 75 + SERIAL.set(get_serial_raw()).unwrap(); 76 + } 77 + 78 + unsafe { 79 + core::str::from_utf8_unchecked(SERIAL.get().unwrap()) 58 80 } 59 81 } 82 + 60 83 61 84 pub fn log(message: &str, level: LogLevel) { 62 85 let len = message.len();
+2
eepy-sys/src/syscall.rs
··· 7 7 Input = 2, 8 8 Usb = 3, 9 9 Exec = 4, 10 + CriticalSection = 5, 10 11 } 11 12 12 13 impl TryFrom<u8> for SyscallNumber { ··· 19 20 x if x == SyscallNumber::Input as u8 => Ok(SyscallNumber::Input), 20 21 x if x == SyscallNumber::Usb as u8 => Ok(SyscallNumber::Usb), 21 22 x if x == SyscallNumber::Exec as u8 => Ok(SyscallNumber::Exec), 23 + x if x == SyscallNumber::CriticalSection as u8 => Ok(SyscallNumber::CriticalSection), 22 24 _ => Err(()), 23 25 } 24 26 }
+2 -3
eepy/Cargo.toml
··· 4 4 edition = "2021" 5 5 6 6 [dependencies] 7 - fw16-epd-bsp = { path = "../fw16-epd-bsp" } 7 + fw16-epd-bsp = { path = "../fw16-epd-bsp", features = ["defmt"] } 8 8 eepy-sys = { path = "../eepy-sys", features = ["defmt"] } 9 - eepy-serial = { path = "../eepy-serial" } 10 9 tp370pgh01 = { path = "../tp370pgh01", features = ["rp2040", "defmt"] } 11 10 cortex-m.workspace = true 12 11 cortex-m-rt.workspace = true ··· 17 16 panic-probe.workspace = true 18 17 critical-section.workspace = true 19 18 portable-atomic.workspace = true 20 - usb-device.workspace = true 19 + usb-device = { workspace = true, features = ["defmt"] } 21 20 once_cell.workspace = true 22 21 mcp9808.workspace = true
+2 -2
eepy/src/main.rs
··· 169 169 unsafe { cortex_m::interrupt::enable() }; 170 170 171 171 info!("eepyOS version {} (c) arthomnix 2025", env!("CARGO_PKG_VERSION")); 172 - info!("Serial number: {}", eepy_sys::misc::get_serial()); 172 + info!("Serial number: {}", unsafe { core::str::from_utf8_unchecked(SERIAL_NUMBER.get().unwrap()) }); 173 173 174 174 let mut sio = Sio::new(pac.SIO); 175 175 let pins = Pins::new( ··· 285 285 */ 286 286 287 287 unsafe { 288 - core.NVIC.set_priority(interrupt::SW5_IRQ, 0b11000000); 288 + core.NVIC.set_priority(interrupt::USBCTRL_IRQ, 0b11000000); 289 289 } 290 290 291 291 let mut mc = Multicore::new(&mut pac.PSM, &mut pac.PPB, &mut sio.fifo);
+41 -1
eepy/src/syscall.rs
··· 32 32 Ok(SyscallNumber::Input) => input::handle_input(stack_values), 33 33 Ok(SyscallNumber::Usb) => crate::usb::handle_usb(stack_values), 34 34 Ok(SyscallNumber::Exec) => handle_exec(stack_values, using_psp), 35 + Ok(SyscallNumber::CriticalSection) => cs::handle_cs(stack_values), 35 36 Err(_) => panic!("illegal syscall"), 36 37 } 37 38 } ··· 103 104 } 104 105 105 106 fn handle_get_serial(stack_values: &mut StackFrame) { 106 - stack_values.r0 = (&raw const *SERIAL_NUMBER.get().unwrap()) as usize; 107 + let buf = stack_values.r1 as *mut [u8; 16]; 108 + unsafe { 109 + (*buf).copy_from_slice(SERIAL_NUMBER.get().unwrap()); 110 + } 107 111 } 108 112 109 113 fn handle_log_message(stack_values: &mut StackFrame) { ··· 194 198 fn handle_has_event(stack_values: &mut StackFrame) { 195 199 let empty = critical_section::with(|cs| EVENT_QUEUE.borrow_ref(cs).is_empty()); 196 200 stack_values.r0 = (!empty) as usize; 201 + } 202 + } 203 + 204 + mod cs { 205 + use core::sync::atomic::Ordering; 206 + use eepy_sys::critical_section::CsSyscall; 207 + use fw16_epd_bsp::pac; 208 + use fw16_epd_bsp::pac::interrupt; 209 + use crate::exception::StackFrame; 210 + 211 + pub(super) fn handle_cs(stack_values: &mut StackFrame) { 212 + match CsSyscall::try_from(stack_values.r0) { 213 + Ok(CsSyscall::Acquire) => handle_acquire(stack_values), 214 + Ok(CsSyscall::Release) => handle_release(stack_values), 215 + Err(_) => panic!("illegal syscall"), 216 + } 217 + } 218 + 219 + // USBCTRL_IRQ is the only interrupt that might cause anything to happen 220 + // with program memory 221 + 222 + fn handle_acquire(stack_values: &mut StackFrame) { 223 + core::sync::atomic::compiler_fence(Ordering::SeqCst); 224 + stack_values.r0 = pac::NVIC::is_enabled(interrupt::USBCTRL_IRQ) as usize; 225 + pac::NVIC::mask(interrupt::USBCTRL_IRQ); 226 + core::sync::atomic::compiler_fence(Ordering::SeqCst); 227 + } 228 + 229 + fn handle_release(stack_values: &mut StackFrame) { 230 + core::sync::atomic::compiler_fence(Ordering::SeqCst); 231 + if stack_values.r1 != 0 { 232 + unsafe { 233 + pac::NVIC::unmask(interrupt::USBCTRL_IRQ); 234 + } 235 + } 236 + core::sync::atomic::compiler_fence(Ordering::SeqCst); 197 237 } 198 238 }
+3 -1
eepy/src/usb.rs
··· 28 28 regs, 29 29 dpram, 30 30 clock, 31 - false, 31 + true, 32 32 &mut unsafe { pac::RESETS::steal() }, 33 33 )); 34 34 } ··· 224 224 interval, 225 225 ) 226 226 }); 227 + 228 + trace!("{}", res); 227 229 228 230 let res: Result<u8, SafeUsbError> = res.map(|v| v.into()).map_err(|e| e.into()); 229 231 unsafe {
+2 -1
fw16-epd-bsp/Cargo.toml
··· 19 19 rp2040-e5 = ["rp2040-hal/rp2040-e5"] 20 20 rom-func-cache = ["rp2040-hal/rom-func-cache"] 21 21 disable-intrinsics = ["rp2040-hal/disable-intrinsics"] 22 - rom-v2-intrinsics = ["rp2040-hal/rom-v2-intrinsics"] 22 + rom-v2-intrinsics = ["rp2040-hal/rom-v2-intrinsics"] 23 + defmt = ["rp2040-hal/defmt"]