diff --git a/Cargo.toml b/Cargo.toml index c248a56..1c46b7c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -30,6 +30,6 @@ usbd-serial = "0.2" crc32fast = { version = "1.4", default-features = false } embedded-graphics = "0.8.1" heapless = "0.8" -once_cell = { version = "1.20", default-features = false, features = ["critical-section", "portable-atomic"] } +once_cell = { version = "1.20", default-features = false, features = ["critical-section"] } postcard = "1.1" serde = { version = "1.0", default-features = false, features = ["derive"] } diff --git a/eepy-launcher/.cargo/config.toml b/eepy-launcher/.cargo/config.toml index f1fa78a..6bf0e29 100644 --- a/eepy-launcher/.cargo/config.toml +++ b/eepy-launcher/.cargo/config.toml @@ -5,4 +5,7 @@ target = "thumbv6m-none-eabi" rustflags = [ "-C", "link-arg=--nmagic", "-C", "link-arg=-Tlauncher.x", -] \ No newline at end of file +] + +[profile.release] +debug = 2 \ No newline at end of file diff --git a/eepy-launcher/Cargo.toml b/eepy-launcher/Cargo.toml index 4e031e8..72262fc 100644 --- a/eepy-launcher/Cargo.toml +++ b/eepy-launcher/Cargo.toml @@ -4,7 +4,7 @@ version = "0.1.0" edition = "2021" [dependencies] -eepy-sys = { path = "../eepy-sys" } +eepy-sys = { path = "../eepy-sys", features = ["critical-section-impl"] } eepy-gui = { path = "../eepy-gui" } embedded-graphics.workspace = true usb-device.workspace = true diff --git a/eepy-launcher/src/main.rs b/eepy-launcher/src/main.rs index 14ee029..4c95854 100644 --- a/eepy-launcher/src/main.rs +++ b/eepy-launcher/src/main.rs @@ -17,7 +17,7 @@ use eepy_sys::exec::exec; use eepy_sys::image::RefreshBlockMode; use eepy_sys::input::{has_event, next_event, set_touch_enabled, Event, TouchEventType}; use eepy_sys::header::{ProgramSlotHeader, Programs}; -use eepy_sys::misc::{get_serial, info}; +use eepy_sys::misc::{get_serial, info, trace}; use eepy_sys::usb; use eepy_sys::usb::UsbBus; use usb_device::prelude::*; @@ -295,7 +295,7 @@ pub extern "C" fn testing_usb_handler() { let dev: &mut UsbDevice = unsafe { USB_DEVICE.as_mut().unwrap() }; let serial: &mut SerialPort = unsafe { USB_SERIAL.as_mut().unwrap() }; - info("hello from USB handler"); + trace("Launcher USB handler"); if dev.poll(&mut [serial]) { let mut buf = [0u8; 64]; @@ -332,13 +332,10 @@ pub extern "C" fn entry() { let serial = SerialPort::new(bus_ref); USB_SERIAL = Some(serial); - let usb_dev = UsbDeviceBuilder::new( - bus_ref, - UsbVidPid(0x2e8a, 0x000a), - ) + let usb_dev = UsbDeviceBuilder::new(bus_ref, UsbVidPid(0x2e8a, 0x000a)) .strings(&[StringDescriptors::default() .manufacturer("arthomnix") - .product("Touchscreen E-Paper Input Module for Framework 16 [eepyOS Launcher]") + .product("Touchscreen EPD for FW16 [eepyOS Launcher]") .serial_number(get_serial()) ]) .unwrap() diff --git a/eepy-sys/Cargo.toml b/eepy-sys/Cargo.toml index b8b33ae..c014a2d 100644 --- a/eepy-sys/Cargo.toml +++ b/eepy-sys/Cargo.toml @@ -10,6 +10,9 @@ embedded-graphics = { workspace = true, optional = true } serde.workspace = true crc32fast.workspace = true usb-device.workspace = true +critical-section = { workspace = true, optional = true } +once_cell = { workspace = true, optional = true } [features] -defmt = ["dep:defmt", "usb-device/defmt"] \ No newline at end of file +defmt = ["dep:defmt", "usb-device/defmt"] +critical-section-impl = ["critical-section", "critical-section/restore-state-bool", "once_cell"] \ No newline at end of file diff --git a/eepy-sys/src/critical_section.rs b/eepy-sys/src/critical_section.rs new file mode 100644 index 0000000..58bb887 --- /dev/null +++ b/eepy-sys/src/critical_section.rs @@ -0,0 +1,19 @@ +#[repr(usize)] +#[derive(Copy, Clone, Debug, Eq, PartialEq)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub enum CsSyscall { + Acquire = 0, + Release = 1, +} + +impl TryFrom for CsSyscall { + type Error = (); + + fn try_from(value: usize) -> Result { + match value { + x if x == CsSyscall::Acquire as usize => Ok(CsSyscall::Acquire), + x if x == CsSyscall::Release as usize => Ok(CsSyscall::Release), + _ => Err(()), + } + } +} \ No newline at end of file diff --git a/eepy-sys/src/critical_section_impl.rs b/eepy-sys/src/critical_section_impl.rs new file mode 100644 index 0000000..939b230 --- /dev/null +++ b/eepy-sys/src/critical_section_impl.rs @@ -0,0 +1,25 @@ +use crate::critical_section::CsSyscall; +use crate::syscall; +use crate::syscall::SyscallNumber; + +struct EepyCs; +critical_section::set_impl!(EepyCs); + +unsafe impl critical_section::Impl for EepyCs { + unsafe fn acquire() -> bool { + let mut state: bool; + syscall!( + SyscallNumber::CriticalSection, + out state in CsSyscall::Acquire, + ); + state + } + + unsafe fn release(state: bool) { + syscall!( + SyscallNumber::CriticalSection, + in CsSyscall::Release, + in state, + ); + } +} \ No newline at end of file diff --git a/eepy-sys/src/lib.rs b/eepy-sys/src/lib.rs index 741f8ce..a4221c0 100644 --- a/eepy-sys/src/lib.rs +++ b/eepy-sys/src/lib.rs @@ -7,6 +7,10 @@ pub mod image; pub mod input; pub mod usb; pub mod exec; +pub mod critical_section; + +#[cfg(feature = "critical-section-impl")] +mod critical_section_impl; pub use tp370pgh01::IMAGE_BYTES; diff --git a/eepy-sys/src/misc.rs b/eepy-sys/src/misc.rs index dced6ca..1c74fca 100644 --- a/eepy-sys/src/misc.rs +++ b/eepy-sys/src/misc.rs @@ -1,6 +1,10 @@ +use core::mem::MaybeUninit; use crate::syscall; use crate::syscall::SyscallNumber; +#[cfg(feature = "critical-section-impl")] +use once_cell::sync::OnceCell; + #[repr(usize)] #[derive(Copy, Clone, Debug, Eq, PartialEq)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] @@ -47,17 +51,36 @@ impl TryFrom for LogLevel { } } -pub fn get_serial() -> &'static str { - let mut ptr: *const [u8; 16]; +pub fn get_serial_raw() -> [u8; 16] { + let mut buf: MaybeUninit<[u8; 16]> = MaybeUninit::uninit(); + let ptr = buf.as_mut_ptr(); + unsafe { syscall!( SyscallNumber::Misc, - out ptr in MiscSyscall::GetSerial, + in MiscSyscall::GetSerial, + in ptr, ); - core::str::from_utf8_unchecked(&*ptr) + + buf.assume_init() + } +} + +#[cfg(feature = "critical-section-impl")] +static SERIAL: OnceCell<[u8; 16]> = OnceCell::new(); + +#[cfg(feature = "critical-section-impl")] +pub fn get_serial() -> &'static str { + if SERIAL.get().is_none() { + SERIAL.set(get_serial_raw()).unwrap(); + } + + unsafe { + core::str::from_utf8_unchecked(SERIAL.get().unwrap()) } } + pub fn log(message: &str, level: LogLevel) { let len = message.len(); let ptr = message.as_ptr(); diff --git a/eepy-sys/src/syscall.rs b/eepy-sys/src/syscall.rs index 3594ac1..bfc421d 100644 --- a/eepy-sys/src/syscall.rs +++ b/eepy-sys/src/syscall.rs @@ -7,6 +7,7 @@ pub enum SyscallNumber { Input = 2, Usb = 3, Exec = 4, + CriticalSection = 5, } impl TryFrom for SyscallNumber { @@ -19,6 +20,7 @@ impl TryFrom for SyscallNumber { x if x == SyscallNumber::Input as u8 => Ok(SyscallNumber::Input), x if x == SyscallNumber::Usb as u8 => Ok(SyscallNumber::Usb), x if x == SyscallNumber::Exec as u8 => Ok(SyscallNumber::Exec), + x if x == SyscallNumber::CriticalSection as u8 => Ok(SyscallNumber::CriticalSection), _ => Err(()), } } diff --git a/eepy/Cargo.toml b/eepy/Cargo.toml index ebd2ee3..3a66e96 100644 --- a/eepy/Cargo.toml +++ b/eepy/Cargo.toml @@ -4,9 +4,8 @@ version = "0.1.0-alpha" edition = "2021" [dependencies] -fw16-epd-bsp = { path = "../fw16-epd-bsp" } +fw16-epd-bsp = { path = "../fw16-epd-bsp", features = ["defmt"] } eepy-sys = { path = "../eepy-sys", features = ["defmt"] } -eepy-serial = { path = "../eepy-serial" } tp370pgh01 = { path = "../tp370pgh01", features = ["rp2040", "defmt"] } cortex-m.workspace = true cortex-m-rt.workspace = true @@ -17,6 +16,6 @@ defmt-rtt.workspace = true panic-probe.workspace = true critical-section.workspace = true portable-atomic.workspace = true -usb-device.workspace = true +usb-device = { workspace = true, features = ["defmt"] } once_cell.workspace = true mcp9808.workspace = true \ No newline at end of file diff --git a/eepy/src/main.rs b/eepy/src/main.rs index 6415f56..fcf50fe 100644 --- a/eepy/src/main.rs +++ b/eepy/src/main.rs @@ -169,7 +169,7 @@ fn main() -> ! { unsafe { cortex_m::interrupt::enable() }; info!("eepyOS version {} (c) arthomnix 2025", env!("CARGO_PKG_VERSION")); - info!("Serial number: {}", eepy_sys::misc::get_serial()); + info!("Serial number: {}", unsafe { core::str::from_utf8_unchecked(SERIAL_NUMBER.get().unwrap()) }); let mut sio = Sio::new(pac.SIO); let pins = Pins::new( @@ -285,7 +285,7 @@ fn main() -> ! { */ unsafe { - core.NVIC.set_priority(interrupt::SW5_IRQ, 0b11000000); + core.NVIC.set_priority(interrupt::USBCTRL_IRQ, 0b11000000); } let mut mc = Multicore::new(&mut pac.PSM, &mut pac.PPB, &mut sio.fifo); diff --git a/eepy/src/syscall.rs b/eepy/src/syscall.rs index c0ef486..51c2533 100644 --- a/eepy/src/syscall.rs +++ b/eepy/src/syscall.rs @@ -32,6 +32,7 @@ extern "C" fn handle_syscall(sp: *mut StackFrame, using_psp: bool) { Ok(SyscallNumber::Input) => input::handle_input(stack_values), Ok(SyscallNumber::Usb) => crate::usb::handle_usb(stack_values), Ok(SyscallNumber::Exec) => handle_exec(stack_values, using_psp), + Ok(SyscallNumber::CriticalSection) => cs::handle_cs(stack_values), Err(_) => panic!("illegal syscall"), } } @@ -103,7 +104,10 @@ mod misc { } fn handle_get_serial(stack_values: &mut StackFrame) { - stack_values.r0 = (&raw const *SERIAL_NUMBER.get().unwrap()) as usize; + let buf = stack_values.r1 as *mut [u8; 16]; + unsafe { + (*buf).copy_from_slice(SERIAL_NUMBER.get().unwrap()); + } } fn handle_log_message(stack_values: &mut StackFrame) { @@ -195,4 +199,40 @@ mod input { let empty = critical_section::with(|cs| EVENT_QUEUE.borrow_ref(cs).is_empty()); stack_values.r0 = (!empty) as usize; } +} + +mod cs { + use core::sync::atomic::Ordering; + use eepy_sys::critical_section::CsSyscall; + use fw16_epd_bsp::pac; + use fw16_epd_bsp::pac::interrupt; + use crate::exception::StackFrame; + + pub(super) fn handle_cs(stack_values: &mut StackFrame) { + match CsSyscall::try_from(stack_values.r0) { + Ok(CsSyscall::Acquire) => handle_acquire(stack_values), + Ok(CsSyscall::Release) => handle_release(stack_values), + Err(_) => panic!("illegal syscall"), + } + } + + // USBCTRL_IRQ is the only interrupt that might cause anything to happen + // with program memory + + fn handle_acquire(stack_values: &mut StackFrame) { + core::sync::atomic::compiler_fence(Ordering::SeqCst); + stack_values.r0 = pac::NVIC::is_enabled(interrupt::USBCTRL_IRQ) as usize; + pac::NVIC::mask(interrupt::USBCTRL_IRQ); + core::sync::atomic::compiler_fence(Ordering::SeqCst); + } + + fn handle_release(stack_values: &mut StackFrame) { + core::sync::atomic::compiler_fence(Ordering::SeqCst); + if stack_values.r1 != 0 { + unsafe { + pac::NVIC::unmask(interrupt::USBCTRL_IRQ); + } + } + core::sync::atomic::compiler_fence(Ordering::SeqCst); + } } \ No newline at end of file diff --git a/eepy/src/usb.rs b/eepy/src/usb.rs index e6e7b36..8960bfc 100644 --- a/eepy/src/usb.rs +++ b/eepy/src/usb.rs @@ -28,7 +28,7 @@ impl Usb { regs, dpram, clock, - false, + true, &mut unsafe { pac::RESETS::steal() }, )); } @@ -225,6 +225,8 @@ fn handle_alloc_ep(stack_values: &mut StackFrame) { ) }); + trace!("{}", res); + let res: Result = res.map(|v| v.into()).map_err(|e| e.into()); unsafe { res_ptr.write(res.into()); diff --git a/fw16-epd-bsp/Cargo.toml b/fw16-epd-bsp/Cargo.toml index c65a530..8c0f36a 100644 --- a/fw16-epd-bsp/Cargo.toml +++ b/fw16-epd-bsp/Cargo.toml @@ -19,4 +19,5 @@ rt = ["cortex-m-rt", "rp2040-hal/rt"] rp2040-e5 = ["rp2040-hal/rp2040-e5"] rom-func-cache = ["rp2040-hal/rom-func-cache"] disable-intrinsics = ["rp2040-hal/disable-intrinsics"] -rom-v2-intrinsics = ["rp2040-hal/rom-v2-intrinsics"] \ No newline at end of file +rom-v2-intrinsics = ["rp2040-hal/rom-v2-intrinsics"] +defmt = ["rp2040-hal/defmt"] \ No newline at end of file