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-launcher/eepy: add autostart feature

+74 -6
+20 -1
eepy-launcher/src/main.rs
··· 17 17 use eepy_sys::usb::{self, UsbBus}; 18 18 use usb_device::prelude::*; 19 19 use usbd_serial::SerialPort; 20 - use eepy_sys::{eepy_app, flash}; 20 + use eepy_sys::{eepy_app, flash, kv_store}; 21 21 use eepy_sys::header::{slot_ptr, ProgramSlotHeader}; 22 22 use crate::serial::{HOST_APP, NEEDS_REFRESH, NEEDS_REFRESH_PROGRAMS}; 23 23 use crate::ui::MainGui; ··· 27 27 static mut USB_SERIAL: Option<SerialPort<UsbBus>> = None; 28 28 29 29 pub(crate) unsafe fn delete_program(slot: u8) { 30 + if get_autostart() == Some(slot) { 31 + set_autostart(None); 32 + } 33 + 30 34 let ptr = unsafe { slot_ptr(slot) }; 31 35 let mut buf = [0u8; 256]; 32 36 unsafe { buf.copy_from_slice(core::slice::from_raw_parts(ptr, 256)) }; ··· 34 38 buf[offset..offset + 4].copy_from_slice(&0usize.to_ne_bytes()); 35 39 36 40 unsafe { flash::program(slot as u32 * 512 * 1024, &buf) }; 41 + } 42 + 43 + pub(crate) fn get_autostart() -> Option<u8> { 44 + let mut buf = [0u8; 1]; 45 + kv_store::get(b"autostart", &mut buf).ok()?; 46 + 47 + if buf[0] == 0 { 48 + None 49 + } else { 50 + Some(buf[0]) 51 + } 52 + } 53 + 54 + pub(crate) fn set_autostart(slot: Option<u8>) { 55 + let _ignored = kv_store::put(b"autostart", &[slot.unwrap_or(0)]); 37 56 } 38 57 39 58 #[eepy_app(name = "Launcher")]
+31 -1
eepy-launcher/src/ui/page/app_info.rs
··· 1 1 use eepy_gui::element::button::Button; 2 2 use embedded_graphics::prelude::*; 3 + use embedded_graphics::primitives::Rectangle; 3 4 use embedded_graphics::text::Text; 4 5 use eepy_gui::draw_target::EpdDrawTarget; 5 6 use eepy_gui::element::{Gui, DEFAULT_TEXT_STYLE}; 6 7 use eepy_sys::header::slot; 7 8 use eepy_sys::input_common::Event; 8 - use crate::delete_program; 9 + use crate::{delete_program, get_autostart, set_autostart}; 9 10 use crate::ui::MainGui; 10 11 use crate::ui::page::main::MainPage; 11 12 ··· 13 14 slot: u8, 14 15 back_button: Button<'static>, 15 16 delete_button: Button<'static>, 17 + autostart_button: Button<'static>, 16 18 } 17 19 18 20 impl AppInfoPage { 21 + fn autostart_label(slot: u8) -> &'static str { 22 + if get_autostart() == Some(slot) { 23 + "Disable autostart" 24 + } else { 25 + "Enable autostart" 26 + } 27 + } 28 + 19 29 pub(crate) fn new(slot: u8) -> Self { 20 30 Self { 21 31 slot, 22 32 back_button: Button::with_default_style_auto_sized(Point::new(10, 386), "Back", true), 23 33 delete_button: Button::with_default_style_auto_sized(Point::new(10, 60), "Delete program", true), 34 + autostart_button: Button::with_default_style( 35 + Rectangle::new(Point::new(10, 90), Size::new((10 * "Disable autostart".len() + 5) as u32, 20)), 36 + Self::autostart_label(slot), 37 + true 38 + ), 24 39 } 25 40 } 26 41 } ··· 62 77 63 78 self.back_button.draw_init(target); 64 79 self.delete_button.draw_init(target); 80 + self.autostart_button.draw_init(target); 65 81 } 66 82 67 83 fn tick(&mut self, target: &mut EpdDrawTarget, ev: Event) -> Self::Output { ··· 79 95 return Some(MainGui::MainPage(MainPage::new())); 80 96 } 81 97 refresh |= d.needs_refresh; 98 + 99 + let a = self.autostart_button.tick(target, ev); 100 + if a.clicked { 101 + if get_autostart() == Some(self.slot) { 102 + set_autostart(None); 103 + } else { 104 + set_autostart(Some(self.slot)); 105 + } 106 + 107 + self.autostart_button.label = Self::autostart_label(self.slot); 108 + self.autostart_button.draw_init(target); 109 + refresh = true; 110 + } 111 + refresh |= a.needs_refresh; 82 112 83 113 if refresh { 84 114 target.refresh(true);
+21 -2
eepy/src/main.rs
··· 16 16 17 17 use core::arch::asm; 18 18 use core::cell::RefCell; 19 + use core::hint::unreachable_unchecked; 19 20 use critical_section::Mutex; 20 21 use defmt::{debug, info, trace, warn}; 21 22 use embedded_hal::delay::DelayNs; ··· 28 29 use once_cell::sync::OnceCell; 29 30 use portable_atomic::{AtomicBool, AtomicU8}; 30 31 use portable_atomic::Ordering; 31 - use eepy_sys::exec::exec; 32 32 use fw16_epd_bsp::{entry, hal, pac, EpdBusy, EpdCs, EpdDc, EpdPowerSwitch, EpdReset, EpdSck, EpdSdaWrite, EpdTouchInt, EpdTouchReset, I2CScl, I2CSda, LaptopSleep, Pins}; 33 33 use fw16_epd_bsp::hal::{Sio, Timer, I2C}; 34 34 use fw16_epd_bsp::hal::clocks::ClockSource; ··· 39 39 use fw16_epd_bsp::pac::I2C0; 40 40 use fw16_epd_bsp::pac::interrupt; 41 41 use eepy_sys::input_common::{Event, TouchEvent, TouchEventType}; 42 + use eepy_sys::kv_store; 43 + use eepy_sys::syscall::SyscallNumber; 42 44 use tp370pgh01::rp2040::{Rp2040PervasiveSpiDelays, IoPin}; 43 45 use tp370pgh01::{Tp370pgh01, IMAGE_BYTES}; 44 46 use crate::core1::{core1_main, ToCore1Message, GLOBAL_EPD, IDLE}; ··· 241 243 pac::NVIC::unmask(interrupt::SW0_IRQ); 242 244 }; 243 245 246 + let mut buf = [0u8; 1]; 247 + // NOTE: since the kernel sits within the first 512K of flash, it counts as the same program 248 + // as the launcher for KV purposes, so we can read the autostart value set by the launcher 249 + let slot = if kv_store::get(b"autostart", &mut buf).is_ok() { 250 + buf[0] 251 + } else { 252 + 0 253 + }; 254 + 255 + enter_userspace(slot); 256 + } 257 + 258 + fn enter_userspace(slot: u8) -> ! { 244 259 unsafe { 245 260 asm!( 246 261 "msr psp, {sram_end}", 247 262 "msr control, {control_0b10}", 248 263 "isb", 264 + "svc #{exec}", 249 265 sram_end = in(reg) SRAM_END, 250 266 control_0b10 = in(reg) 0b10, 267 + in("r0") slot, 268 + exec = const SyscallNumber::Exec as u8, 251 269 ); 252 270 253 - exec(0); 271 + // SAFETY: the exec syscall never returns 272 + unreachable_unchecked(); 254 273 } 255 274 } 256 275
+2 -2
eepy/src/syscall.rs
··· 333 333 use core::hash::Hasher; 334 334 use siphasher::sip::SipHasher; 335 335 use tickv::{ErrorCode, TicKV}; 336 - use eepy_sys::header::{slot, SLOT_SIZE}; 336 + use eepy_sys::header::{slot, SLOT_SIZE, XIP_BASE}; 337 337 use eepy_sys::kv_store::{AppendKeyError, DeleteKeyError, KvStoreSyscall, PutKeyError, ReadKeyArgs, ReadKeyError, WriteKeyArgs}; 338 338 use eepy_sys::SafeResult; 339 339 use crate::exception::StackFrame; ··· 351 351 } 352 352 353 353 fn hash(stack_values: &mut StackFrame, key: &[u8]) -> u64 { 354 - let slot_number = (stack_values.pc as usize) / SLOT_SIZE; 354 + let slot_number = (stack_values.pc as usize - XIP_BASE as usize) / SLOT_SIZE; 355 355 let slot_header = unsafe { slot(slot_number as u8) }; 356 356 let program_name = unsafe { core::slice::from_raw_parts((*slot_header).name_ptr, (*slot_header).name_len) }; 357 357