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: split up some large files

+759 -724
+154
eepy/src/gpio_irq.rs
··· 1 + use core::cell::RefCell; 2 + use core::sync::atomic::Ordering; 3 + use critical_section::Mutex; 4 + use defmt::{debug, trace, warn}; 5 + use embedded_hal::digital::OutputPin; 6 + use embedded_hal::i2c::I2c; 7 + use mcp9808::MCP9808; 8 + use mcp9808::reg_conf::ShutdownMode; 9 + use mcp9808::reg_conf::Configuration; 10 + use eepy_sys::input_common::{Event, TouchEvent, TouchEventType}; 11 + use fw16_epd_bsp::{pac, EpdPowerSwitch, EpdTouchInt, EpdTouchReset, I2CScl, I2CSda, LaptopSleep}; 12 + use fw16_epd_bsp::hal::gpio::Interrupt::{EdgeHigh, EdgeLow}; 13 + use fw16_epd_bsp::hal::{Sio, I2C}; 14 + use fw16_epd_bsp::pac::{interrupt, I2C0}; 15 + use crate::{reset_touch, EVENT_QUEUE, TOUCH_ENABLED}; 16 + use crate::core1::{ToCore1Message, IDLE}; 17 + 18 + pub(super) static GLOBAL_TOUCH_INT_PIN: Mutex<RefCell<Option<EpdTouchInt>>> = Mutex::new(RefCell::new(None)); 19 + pub(super) static GLOBAL_I2C: Mutex<RefCell<Option<I2C<I2C0, (I2CSda, I2CScl)>>>> = Mutex::new(RefCell::new(None)); 20 + pub(super) static GLOBAL_SLEEP_PIN: Mutex<RefCell<Option<LaptopSleep>>> = Mutex::new(RefCell::new(None)); 21 + pub(super) static GLOBAL_EPD_POWER_PIN: Mutex<RefCell<Option<EpdPowerSwitch>>> = Mutex::new(RefCell::new(None)); 22 + pub(super) static GLOBAL_TOUCH_RESET_PIN: Mutex<RefCell<Option<EpdTouchReset>>> = Mutex::new(RefCell::new(None)); 23 + 24 + #[interrupt] 25 + fn IO_IRQ_BANK0() { 26 + static mut TOUCH_INT_PIN: Option<EpdTouchInt> = None; 27 + static mut SLEEP_PIN: Option<LaptopSleep> = None; 28 + static mut EPD_POWER_PIN: Option<EpdPowerSwitch> = None; 29 + static mut TOUCH_RESET_PIN: Option<EpdTouchReset> = None; 30 + 31 + trace!("IO_IRQ_BANK0"); 32 + 33 + if TOUCH_INT_PIN.is_none() { 34 + critical_section::with(|cs| *TOUCH_INT_PIN = GLOBAL_TOUCH_INT_PIN.borrow(cs).take()); 35 + } 36 + 37 + if SLEEP_PIN.is_none() { 38 + critical_section::with(|cs| *SLEEP_PIN = GLOBAL_SLEEP_PIN.borrow(cs).take()); 39 + } 40 + 41 + if EPD_POWER_PIN.is_none() { 42 + critical_section::with(|cs| *EPD_POWER_PIN = GLOBAL_EPD_POWER_PIN.borrow(cs).take()); 43 + } 44 + 45 + if TOUCH_RESET_PIN.is_none() { 46 + critical_section::with(|cs| *TOUCH_RESET_PIN = GLOBAL_TOUCH_RESET_PIN.borrow(cs).take()); 47 + } 48 + 49 + let mut i2c = critical_section::with(|cs| GLOBAL_I2C.borrow(cs).take()); 50 + 51 + if let Some(pin) = TOUCH_INT_PIN { 52 + if pin.interrupt_status(EdgeLow) { 53 + 54 + if TOUCH_ENABLED.load(Ordering::Relaxed) { 55 + if let Some(i2c) = &mut i2c { 56 + let mut buf = [0u8; 9]; 57 + i2c.write_read(0x38u8, &[0x00], &mut buf).unwrap(); 58 + let x = (((buf[3] & 0x0f) as u16) << 8) | buf[4] as u16; 59 + let y = (((buf[5] & 0x0f) as u16) << 8) | buf[6] as u16; 60 + 61 + let state = match buf[3] >> 6 { 62 + 0 => TouchEventType::Down, 63 + 1 => TouchEventType::Up, 64 + 2 => TouchEventType::Move, 65 + _ => panic!("received invalid touch event type {}", buf[3] >> 6), 66 + }; 67 + 68 + let event = TouchEvent { 69 + ev_type: state, 70 + x, 71 + y, 72 + }; 73 + 74 + debug!("touch event: {}", event); 75 + 76 + if !critical_section::with(|cs| EVENT_QUEUE.borrow_ref_mut(cs).push(Event::Touch(event))) { 77 + warn!("touch event buffer full"); 78 + } 79 + } 80 + } 81 + 82 + } 83 + pin.clear_interrupt(EdgeLow); 84 + } 85 + 86 + if let Some(pin) = SLEEP_PIN { 87 + if pin.interrupt_status(EdgeLow) { 88 + debug!("sleeping"); 89 + pin.clear_interrupt(EdgeLow); 90 + 91 + if let Some(touch_int) = TOUCH_INT_PIN { 92 + touch_int.set_interrupt_enabled(EdgeLow, false); 93 + } 94 + 95 + // Wait until refresh has finished 96 + while !IDLE.load(Ordering::Relaxed) {} 97 + 98 + // Power down temp sensor 99 + if let Some(i2c) = &mut i2c { 100 + let mut mcp9808 = MCP9808::new(i2c); 101 + let mut config = mcp9808.read_configuration().unwrap(); 102 + config.set_shutdown_mode(ShutdownMode::Shutdown); 103 + mcp9808.write_register(config).unwrap(); 104 + } 105 + 106 + // Power down display 107 + // (pin is connected to P-ch MOSFET so high = off) 108 + if let Some(power_pin) = EPD_POWER_PIN { 109 + power_pin.set_high().unwrap(); 110 + } 111 + 112 + pac::NVIC::pend(interrupt::SW0_IRQ); 113 + } 114 + 115 + if pin.interrupt_status(EdgeHigh) { 116 + pin.clear_interrupt(EdgeHigh); 117 + 118 + // Power up temp sensor 119 + if let Some(i2c) = &mut i2c { 120 + let mut mcp9808 = MCP9808::new(i2c); 121 + let mut config = mcp9808.read_configuration().unwrap(); 122 + config.set_shutdown_mode(ShutdownMode::Continuous); 123 + mcp9808.write_register(config).unwrap(); 124 + } 125 + 126 + // Power up EPD 127 + if let Some(power_pin) = EPD_POWER_PIN { 128 + power_pin.set_low().unwrap(); 129 + } 130 + 131 + let mut fifo = Sio::new(unsafe { pac::Peripherals::steal() }.SIO).fifo; 132 + fifo.write_blocking(ToCore1Message::HardResetEpd as u32); 133 + 134 + if let Some(reset) = TOUCH_RESET_PIN { 135 + reset_touch(reset); 136 + } 137 + 138 + if let Some(touch_int) = TOUCH_INT_PIN { 139 + touch_int.clear_interrupt(EdgeLow); 140 + touch_int.set_interrupt_enabled(EdgeLow, true); 141 + } 142 + 143 + debug!("woken up"); 144 + } 145 + } 146 + 147 + critical_section::with(|cs| GLOBAL_I2C.borrow(cs).replace(i2c)); 148 + } 149 + 150 + #[interrupt] 151 + fn SW0_IRQ() { 152 + trace!("SW0_IRQ"); 153 + cortex_m::asm::wfi(); 154 + }
+144 -303
eepy/src/main.rs
··· 1 1 #![no_main] 2 2 #![no_std] 3 3 4 - //mod serial; 5 4 mod ringbuffer; 6 5 mod syscall; 7 6 mod launcher; ··· 10 9 mod tickv; 11 10 mod flash; 12 11 mod core1; 12 + mod temp; 13 + mod gpio_irq; 13 14 14 15 extern crate panic_probe; 15 16 extern crate defmt_rtt; ··· 17 18 use core::arch::asm; 18 19 use core::cell::RefCell; 19 20 use core::hint::unreachable_unchecked; 21 + use cortex_m::peripheral::NVIC; 20 22 use critical_section::Mutex; 21 - use defmt::{debug, info, trace, warn}; 23 + use defmt::info; 22 24 use embedded_hal::delay::DelayNs; 23 25 use embedded_hal::digital::OutputPin; 24 26 use embedded_hal::i2c::I2c; 25 27 use mcp9808::MCP9808; 26 - use mcp9808::reg_conf::{Configuration, ShutdownMode}; 27 28 use mcp9808::reg_res::{Resolution, ResolutionVal}; 28 - use mcp9808::reg_temp_generic::ReadableTempRegister; 29 29 use once_cell::sync::OnceCell; 30 30 use portable_atomic::{AtomicBool, AtomicU8}; 31 - use portable_atomic::Ordering; 32 - use fw16_epd_bsp::{entry, hal, pac, EpdBusy, EpdCs, EpdDc, EpdPowerSwitch, EpdReset, EpdSck, EpdSdaWrite, EpdTouchInt, EpdTouchReset, I2CScl, I2CSda, LaptopSleep, Pins}; 33 - use fw16_epd_bsp::hal::{Sio, Timer, I2C}; 31 + use fw16_epd_bsp::{entry, hal, pac, EpdBusy, EpdCs, EpdDc, EpdPowerSwitch, EpdReset, EpdSck, EpdSdaWrite, EpdTouchInt, EpdTouchReset, I2CScl, I2CSda, Pins}; 32 + use fw16_epd_bsp::hal::{Sio, Timer}; 34 33 use fw16_epd_bsp::hal::clocks::ClockSource; 35 - use fw16_epd_bsp::hal::fugit::{RateExtU32, ExtU32}; 34 + use fw16_epd_bsp::hal::fugit::RateExtU32; 36 35 use fw16_epd_bsp::hal::gpio::Interrupt::{EdgeHigh, EdgeLow}; 37 36 use fw16_epd_bsp::hal::multicore::{Multicore, Stack}; 38 37 use fw16_epd_bsp::hal::timer::{Alarm, Alarm0}; 39 - use fw16_epd_bsp::pac::I2C0; 38 + use fw16_epd_bsp::pac::{PPB, PSM}; 40 39 use fw16_epd_bsp::pac::interrupt; 41 - use eepy_sys::input_common::{Event, TouchEvent, TouchEventType}; 40 + use eepy_sys::input_common::Event; 42 41 use eepy_sys::kv_store; 43 42 use eepy_sys::syscall::SyscallNumber; 43 + use fw16_epd_bsp::hal::sio::SioFifo; 44 44 use tp370pgh01::rp2040::{Rp2040PervasiveSpiDelays, IoPin}; 45 45 use tp370pgh01::{Tp370pgh01, IMAGE_BYTES}; 46 - use crate::core1::{core1_main, ToCore1Message, GLOBAL_EPD, IDLE}; 46 + use crate::core1::{core1_main, ToCore1Message, GLOBAL_EPD}; 47 + use crate::gpio_irq::{GLOBAL_EPD_POWER_PIN, GLOBAL_I2C, GLOBAL_SLEEP_PIN, GLOBAL_TOUCH_INT_PIN, GLOBAL_TOUCH_RESET_PIN}; 47 48 use crate::ringbuffer::RingBuffer; 48 49 49 50 const SRAM_END: *mut u8 = 0x20042000 as *mut u8; 50 51 51 52 static CORE1_STACK: Stack<8192> = Stack::new(); 52 53 53 - static GLOBAL_TOUCH_INT_PIN: Mutex<RefCell<Option<EpdTouchInt>>> = Mutex::new(RefCell::new(None)); 54 - static GLOBAL_I2C: Mutex<RefCell<Option<I2C<I2C0, (I2CSda, I2CScl)>>>> = Mutex::new(RefCell::new(None)); 55 - static GLOBAL_SLEEP_PIN: Mutex<RefCell<Option<LaptopSleep>>> = Mutex::new(RefCell::new(None)); 56 - static GLOBAL_EPD_POWER_PIN: Mutex<RefCell<Option<EpdPowerSwitch>>> = Mutex::new(RefCell::new(None)); 57 - static GLOBAL_TOUCH_RESET_PIN: Mutex<RefCell<Option<EpdTouchReset>>> = Mutex::new(RefCell::new(None)); 58 - 59 54 static GLOBAL_ALARM0: Mutex<RefCell<Option<Alarm0>>> = Mutex::new(RefCell::new(None)); 60 55 61 56 static IMAGE_BUFFER: Mutex<RefCell<[u8; IMAGE_BYTES]>> = Mutex::new(RefCell::new([0; IMAGE_BYTES])); ··· 83 78 84 79 core.SCB.set_sleepdeep(); 85 80 86 - // Set MPU regions for non-privileged code 87 - unsafe { 88 - // Region 0: Unprivileged RAM region (first 128K) - start 0x20020000, length 128K 89 - core.MPU.rnr.write(0); 90 - core.MPU.rbar.write(0x20020000); 91 - core.MPU.rasr.write( 92 - (0b1 << 28) // XN 93 - | (0b011 << 24) // AP: full access 94 - | (0b000 << 19) // TEX 95 - | (0b011 << 16) // S, C, B: non-shareable, writeback 96 - | (0b00000000 << 8) // all subregions enabled 97 - | (16 << 1) // size: 2^(16 + 1) = 128K 98 - | (0b1 << 0) // enable 99 - ); 100 - 101 - // Region 1: Unprivileged RAM region (final 8K) - start 0x20040000, length 8K 102 - core.MPU.rnr.write(1); 103 - core.MPU.rbar.write(0x20040000); 104 - core.MPU.rasr.write( 105 - (0b1 << 28) // XN 106 - | (0b011 << 24) // AP: full access 107 - | (0b000 << 19) // TEX 108 - | (0b011 << 16) // S, C, B: non-shareable, writeback 109 - | (0b00000000 << 8) // all subregions enabled 110 - | (12 << 1) // size: 2^(12 + 1) = 8K 111 - | (0b1 << 0) // enable 112 - ); 113 - 114 - // Region 3: Flash - start: 0x10000000, length 16M 115 - core.MPU.rnr.write(3); 116 - core.MPU.rbar.write(0x10000000); 117 - // NOTE: we of course can't actually write to the flash via the XIP memory map, but 118 - // performing writes to the flash memory region flushes the XIP cache for that area of 119 - // flash, so the kernel still needs write access 120 - core.MPU.rasr.write( 121 - (0b0 << 28) // disable XN 122 - | (0b010 << 24) // AP: privileged RW, unprivileged RO 123 - | (0b000 << 19) // TEX 124 - | (0b110 << 16) // S, C, B: shared, write-through 125 - | (0b00000000 << 8) // all subregions enabled 126 - | (23 << 1) // size: 2^(23 + 1) = 16M 127 - | (0b1 << 0) // enable 128 - ); 129 - 130 - // Enable MPU 131 - core.MPU.ctrl.write( 132 - (0b1 << 2) // PRIVDEFENA: enable default memory map for privileged access 133 - | (0b0 << 1) // HFNMIENA: disable MPU for HardFault and NMI 134 - | (0b1 << 0) // ENABLE: enable MPU 135 - ); 136 - } 81 + init_mpu(&mut core); 137 82 138 - // Read flash unique ID 139 - cortex_m::interrupt::disable(); 140 - let mut id = [0u8; 8]; 141 - unsafe { rp2040_flash::flash::flash_unique_id(&mut id, true) }; 142 - let mut id = u64::from_be_bytes(id); 143 - let mut serial = [0u8; 16]; 144 - for c in serial.iter_mut().rev() { 145 - let nibble = (id & 0x0f) as u8; 146 - *c = match nibble { 147 - 0x0..=0x9 => b'0' + nibble, 148 - 0xa..=0xf => b'A' + nibble - 0xa, 149 - _ => unreachable!(), 150 - }; 151 - id >>= 4; 83 + unsafe { 84 + read_serial(); 152 85 } 153 - SERIAL_NUMBER.set(serial).unwrap(); 154 - unsafe { cortex_m::interrupt::enable() }; 155 86 156 87 info!("eepyOS version {} (c) arthomnix 2025", env!("CARGO_PKG_VERSION")); 157 88 info!("Serial number: {}", unsafe { core::str::from_utf8_unchecked(SERIAL_NUMBER.get().unwrap()) }); ··· 164 95 &mut pac.RESETS, 165 96 ); 166 97 98 + let cs: EpdCs = pins.spi3_epd_cs.reconfigure(); 99 + let dc: EpdDc = pins.epd_dc.reconfigure(); 100 + let busy: EpdBusy = pins.epd_busy.reconfigure(); 101 + let rst: EpdReset = pins.epd_rst.reconfigure(); 102 + let sda: EpdSdaWrite = pins.spi3_epd_sda.reconfigure(); 103 + let sck: EpdSck = pins.spi3_epd_sck.reconfigure(); 104 + let i2c_sda: I2CSda = pins.i2c_sda.reconfigure(); 105 + let i2c_scl: I2CScl = pins.i2c_scl.reconfigure(); 106 + let int: EpdTouchInt = pins.epd_touch_int.reconfigure(); 107 + 108 + int.set_interrupt_enabled(EdgeLow, true); 109 + 110 + let mut i2c = hal::i2c::I2C::i2c0(pac.I2C0, i2c_sda, i2c_scl, 400.kHz(), &mut pac.RESETS, clocks.system_clock.get_freq()); 111 + init_temp_sensor(&mut i2c); 167 112 168 113 let mut epd_power: EpdPowerSwitch = pins.epd_pwr_sw.reconfigure(); 169 114 epd_power.set_low().unwrap(); ··· 177 122 critical_section::with(|cs| GLOBAL_SLEEP_PIN.borrow_ref_mut(cs).replace(sleep)); 178 123 179 124 let mut touch_reset: EpdTouchReset = pins.epd_touch_rst.reconfigure(); 180 - touch_reset.set_high().unwrap(); 181 - cortex_m::asm::delay(1000000); 182 - touch_reset.set_low().unwrap(); 183 - cortex_m::asm::delay(1000000); 184 - touch_reset.set_high().unwrap(); 185 - cortex_m::asm::delay(10000000); 125 + reset_touch(&mut touch_reset); 186 126 critical_section::with(|cs| GLOBAL_TOUCH_RESET_PIN.borrow_ref_mut(cs).replace(touch_reset)); 187 127 188 - let cs: EpdCs = pins.spi3_epd_cs.reconfigure(); 189 - let dc: EpdDc = pins.epd_dc.reconfigure(); 190 - let busy: EpdBusy = pins.epd_busy.reconfigure(); 191 - let rst: EpdReset = pins.epd_rst.reconfigure(); 192 - let sda: EpdSdaWrite = pins.spi3_epd_sda.reconfigure(); 193 - let sck: EpdSck = pins.spi3_epd_sck.reconfigure(); 194 - 195 - let i2c_sda: I2CSda = pins.i2c_sda.reconfigure(); 196 - let i2c_scl: I2CScl = pins.i2c_scl.reconfigure(); 197 - let int: EpdTouchInt = pins.epd_touch_int.reconfigure(); 198 - int.set_interrupt_enabled(EdgeLow, true); 199 - 200 - let mut i2c = hal::i2c::I2C::i2c0(pac.I2C0, i2c_sda, i2c_scl, 400.kHz(), &mut pac.RESETS, clocks.system_clock.get_freq()); 201 - 202 - { 203 - let mut mcp9808 = MCP9808::new(&mut i2c); 204 - let mut res = mcp9808::reg_res::new(); 205 - res.set_resolution(ResolutionVal::Deg_0_5C); 206 - mcp9808.write_register(res).unwrap(); 207 - } 208 - 209 128 critical_section::with(|cs| { 210 129 GLOBAL_TOUCH_INT_PIN.borrow_ref_mut(cs).replace(int); 211 130 GLOBAL_I2C.borrow_ref_mut(cs).replace(i2c); ··· 217 136 let mut alarm = timer.alarm_0().unwrap(); 218 137 alarm.enable_interrupt(); 219 138 critical_section::with(|cs| GLOBAL_ALARM0.borrow_ref_mut(cs).replace(alarm)); 220 - unsafe { 221 - core.NVIC.set_priority(interrupt::TIMER_IRQ_0, 0b10000000); 222 - pac::NVIC::unmask(interrupt::TIMER_IRQ_0); 223 - } 224 - pac::NVIC::pend(interrupt::TIMER_IRQ_0); 225 139 226 140 usb::init_usb(pac.USBCTRL_REGS, pac.USBCTRL_DPRAM, clocks.usb_clock); 227 141 228 - unsafe { 229 - core.NVIC.set_priority(interrupt::USBCTRL_IRQ, 0b11000000); 230 - } 231 - 232 142 let epd = Tp370pgh01::new(cs, IoPin::new(sda), sck, dc, busy, rst, timer, Rp2040PervasiveSpiDelays); 233 143 critical_section::with(|cs| GLOBAL_EPD.borrow_ref_mut(cs).replace(epd)); 234 - let mut mc = Multicore::new(&mut pac.PSM, &mut pac.PPB, &mut sio.fifo); 235 - let core1 = &mut mc.cores()[1]; 236 - core1.spawn(CORE1_STACK.take().unwrap(), core1_main).unwrap(); 237 - sio.fifo.write_blocking(ToCore1Message::HardResetEpd as u32); 238 144 239 - unsafe { 240 - core.NVIC.set_priority(interrupt::IO_IRQ_BANK0, 0); 241 - core.NVIC.set_priority(interrupt::SW0_IRQ, 0b01000000); 242 - pac::NVIC::unmask(interrupt::IO_IRQ_BANK0); 243 - pac::NVIC::unmask(interrupt::SW0_IRQ); 244 - }; 145 + init_core1(&mut pac.PSM, &mut pac.PPB, &mut sio.fifo); 146 + 147 + configure_interrupts(&mut core.NVIC); 245 148 246 149 let mut buf = [0u8; 1]; 247 150 // NOTE: since the kernel sits within the first 512K of flash, it counts as the same program ··· 255 158 enter_userspace(slot); 256 159 } 257 160 258 - fn enter_userspace(slot: u8) -> ! { 161 + fn init_mpu(core: &mut pac::CorePeripherals) { 162 + // Set MPU regions for non-privileged code 259 163 unsafe { 260 - asm!( 261 - "msr psp, {sram_end}", 262 - "msr control, {control_0b10}", 263 - "isb", 264 - "svc #{exec}", 265 - sram_end = in(reg) SRAM_END, 266 - control_0b10 = in(reg) 0b10, 267 - in("r0") slot, 268 - exec = const SyscallNumber::Exec as u8, 164 + // Region 0: Unprivileged RAM region (first 128K) - start 0x20020000, length 128K 165 + core.MPU.rnr.write(0); 166 + core.MPU.rbar.write(0x20020000); 167 + core.MPU.rasr.write( 168 + (0b1 << 28) // XN 169 + | (0b011 << 24) // AP: full access 170 + | (0b000 << 19) // TEX 171 + | (0b011 << 16) // S, C, B: non-shareable, writeback 172 + | (0b00000000 << 8) // all subregions enabled 173 + | (16 << 1) // size: 2^(16 + 1) = 128K 174 + | (0b1 << 0) // enable 269 175 ); 270 176 271 - // SAFETY: the exec syscall never returns 272 - unreachable_unchecked(); 273 - } 274 - } 177 + // Region 1: Unprivileged RAM region (final 8K) - start 0x20040000, length 8K 178 + core.MPU.rnr.write(1); 179 + core.MPU.rbar.write(0x20040000); 180 + core.MPU.rasr.write( 181 + (0b1 << 28) // XN 182 + | (0b011 << 24) // AP: full access 183 + | (0b000 << 19) // TEX 184 + | (0b011 << 16) // S, C, B: non-shareable, writeback 185 + | (0b00000000 << 8) // all subregions enabled 186 + | (12 << 1) // size: 2^(12 + 1) = 8K 187 + | (0b1 << 0) // enable 188 + ); 275 189 276 - #[interrupt] 277 - fn TIMER_IRQ_0() { 278 - static mut ALARM0: Option<Alarm0> = None; 190 + // Region 3: Flash - start: 0x10000000, length 16M 191 + core.MPU.rnr.write(3); 192 + core.MPU.rbar.write(0x10000000); 193 + // NOTE: we of course can't actually write to the flash via the XIP memory map, but 194 + // performing writes to the flash memory region flushes the XIP cache for that area of 195 + // flash, so the kernel still needs write access 196 + core.MPU.rasr.write( 197 + (0b0 << 28) // disable XN 198 + | (0b010 << 24) // AP: privileged RW, unprivileged RO 199 + | (0b000 << 19) // TEX 200 + | (0b110 << 16) // S, C, B: shared, write-through 201 + | (0b00000000 << 8) // all subregions enabled 202 + | (23 << 1) // size: 2^(23 + 1) = 16M 203 + | (0b1 << 0) // enable 204 + ); 279 205 280 - trace!("TIMER_IRQ_0"); 281 - 282 - 283 - if ALARM0.is_none() { 284 - critical_section::with(|cs| *ALARM0 = GLOBAL_ALARM0.borrow(cs).take()); 206 + // Enable MPU 207 + core.MPU.ctrl.write( 208 + (0b1 << 2) // PRIVDEFENA: enable default memory map for privileged access 209 + | (0b0 << 1) // HFNMIENA: disable MPU for HardFault and NMI 210 + | (0b1 << 0) // ENABLE: enable MPU 211 + ); 285 212 } 286 - 287 - let mut i2c = critical_section::with(|cs| GLOBAL_I2C.borrow(cs).take()); 288 - 289 - if let Some(alarm) = ALARM0 { 290 - if let Some(i2c) = &mut i2c { 291 - let mut mcp9808 = MCP9808::new(i2c); 213 + } 292 214 293 - let temp = ((mcp9808.read_temperature().unwrap().get_raw_value() & 0x1ff0) >> 4) as i16; 294 - let clamped = match temp { 295 - ..=0 => 0u8, 296 - 60.. => 60u8, 297 - t => t as u8, 215 + /// SAFETY: must be run when core1 is in a safe state (not started yet or running code from RAM 216 + /// with interrupts disabled) 217 + unsafe fn read_serial() { 218 + // Read flash unique ID 219 + cortex_m::interrupt::free(|_cs| { 220 + let mut id = [0u8; 8]; 221 + // SAFETY: interrupts are disabled, so this is safe as long as core1 is in a safe state 222 + unsafe { rp2040_flash::flash::flash_unique_id(&mut id, true) }; 223 + let mut id = u64::from_be_bytes(id); 224 + let mut serial = [0u8; 16]; 225 + for c in serial.iter_mut().rev() { 226 + let nibble = (id & 0x0f) as u8; 227 + *c = match nibble { 228 + 0x0..=0x9 => b'0' + nibble, 229 + 0xa..=0xf => b'A' + nibble - 0xa, 230 + _ => unreachable!(), 298 231 }; 299 - 300 - debug!("read temperature {}C (using {}C)", temp, clamped); 301 - 302 - TEMP.store(clamped, Ordering::Relaxed); 303 - 304 - alarm.clear_interrupt(); 305 - alarm.schedule(1.minutes()).unwrap(); 306 - } else { 307 - // I2C bus was in use, so try again in a short time 308 - alarm.clear_interrupt(); 309 - alarm.schedule(10.millis()).unwrap(); 232 + id >>= 4; 310 233 } 311 - } 234 + SERIAL_NUMBER.set(serial).unwrap(); 235 + }); 236 + } 312 237 313 - critical_section::with(|cs| GLOBAL_I2C.borrow(cs).replace(i2c)); 238 + fn init_temp_sensor(i2c: &mut impl I2c) { 239 + let mut mcp9808 = MCP9808::new(i2c); 240 + let mut res = mcp9808::reg_res::new(); 241 + res.set_resolution(ResolutionVal::Deg_0_5C); 242 + mcp9808.write_register(res).unwrap(); 314 243 } 315 244 316 - #[interrupt] 317 - fn IO_IRQ_BANK0() { 318 - static mut TOUCH_INT_PIN: Option<EpdTouchInt> = None; 319 - static mut SLEEP_PIN: Option<LaptopSleep> = None; 320 - static mut EPD_POWER_PIN: Option<EpdPowerSwitch> = None; 321 - static mut TOUCH_RESET_PIN: Option<EpdTouchReset> = None; 245 + fn init_core1(psm: &mut PSM, ppb: &mut PPB, fifo: &mut SioFifo) { 246 + let mut mc = Multicore::new(psm, ppb, fifo); 247 + let core1 = &mut mc.cores()[1]; 248 + core1.spawn(CORE1_STACK.take().unwrap(), core1_main).unwrap(); 249 + fifo.write_blocking(ToCore1Message::HardResetEpd as u32); 250 + } 322 251 323 - trace!("IO_IRQ_BANK0"); 252 + fn configure_interrupts(nvic: &mut NVIC) { 253 + unsafe { 254 + nvic.set_priority(interrupt::TIMER_IRQ_0, 0b10000000); 255 + nvic.set_priority(interrupt::USBCTRL_IRQ, 0b11000000); 256 + nvic.set_priority(interrupt::IO_IRQ_BANK0, 0); 257 + nvic.set_priority(interrupt::SW0_IRQ, 0b01000000); 324 258 325 - if TOUCH_INT_PIN.is_none() { 326 - critical_section::with(|cs| *TOUCH_INT_PIN = GLOBAL_TOUCH_INT_PIN.borrow(cs).take()); 259 + NVIC::unmask(interrupt::TIMER_IRQ_0); 260 + NVIC::unmask(interrupt::IO_IRQ_BANK0); 261 + NVIC::unmask(interrupt::SW0_IRQ); 327 262 } 328 263 329 - if SLEEP_PIN.is_none() { 330 - critical_section::with(|cs| *SLEEP_PIN = GLOBAL_SLEEP_PIN.borrow(cs).take()); 331 - } 264 + NVIC::pend(interrupt::TIMER_IRQ_0); 265 + } 332 266 333 - if EPD_POWER_PIN.is_none() { 334 - critical_section::with(|cs| *EPD_POWER_PIN = GLOBAL_EPD_POWER_PIN.borrow(cs).take()); 335 - } 267 + /// Switch to the PSP and start the specified program. 268 + fn enter_userspace(slot: u8) -> ! { 269 + unsafe { 270 + asm!( 271 + "msr psp, {sram_end}", 272 + "msr control, {control_0b10}", 273 + "isb", 274 + "svc #{exec}", 275 + sram_end = in(reg) SRAM_END, 276 + control_0b10 = in(reg) 0b10, 277 + in("r0") slot, 278 + exec = const SyscallNumber::Exec as u8, 279 + ); 336 280 337 - if TOUCH_RESET_PIN.is_none() { 338 - critical_section::with(|cs| *TOUCH_RESET_PIN = GLOBAL_TOUCH_RESET_PIN.borrow(cs).take()); 281 + // SAFETY: the exec syscall never returns 282 + unreachable_unchecked(); 339 283 } 340 - 341 - let mut i2c = critical_section::with(|cs| GLOBAL_I2C.borrow(cs).take()); 342 - 343 - if let Some(pin) = TOUCH_INT_PIN { 344 - if pin.interrupt_status(EdgeLow) { 345 - 346 - if TOUCH_ENABLED.load(Ordering::Relaxed) { 347 - if let Some(i2c) = &mut i2c { 348 - let mut buf = [0u8; 9]; 349 - i2c.write_read(0x38u8, &[0x00], &mut buf).unwrap(); 350 - let x = (((buf[3] & 0x0f) as u16) << 8) | buf[4] as u16; 351 - let y = (((buf[5] & 0x0f) as u16) << 8) | buf[6] as u16; 352 - 353 - let state = match buf[3] >> 6 { 354 - 0 => TouchEventType::Down, 355 - 1 => TouchEventType::Up, 356 - 2 => TouchEventType::Move, 357 - _ => panic!("received invalid touch event type {}", buf[3] >> 6), 358 - }; 359 - 360 - let event = TouchEvent { 361 - ev_type: state, 362 - x, 363 - y, 364 - }; 365 - 366 - debug!("touch event: {}", event); 367 - 368 - if !critical_section::with(|cs| EVENT_QUEUE.borrow_ref_mut(cs).push(Event::Touch(event))) { 369 - warn!("touch event buffer full"); 370 - } 371 - } 372 - } 373 - 374 - } 375 - pin.clear_interrupt(EdgeLow); 376 - } 377 - 378 - if let Some(pin) = SLEEP_PIN { 379 - if pin.interrupt_status(EdgeLow) { 380 - debug!("sleeping"); 381 - pin.clear_interrupt(EdgeLow); 382 - 383 - if let Some(touch_int) = TOUCH_INT_PIN { 384 - touch_int.set_interrupt_enabled(EdgeLow, false); 385 - } 386 - 387 - // Wait until refresh has finished 388 - while !IDLE.load(Ordering::Relaxed) {} 389 - 390 - // Power down temp sensor 391 - if let Some(i2c) = &mut i2c { 392 - let mut mcp9808 = MCP9808::new(i2c); 393 - let mut config = mcp9808.read_configuration().unwrap(); 394 - config.set_shutdown_mode(ShutdownMode::Shutdown); 395 - mcp9808.write_register(config).unwrap(); 396 - } 397 - 398 - // Power down display 399 - // (pin is connected to P-ch MOSFET so high = off) 400 - if let Some(power_pin) = EPD_POWER_PIN { 401 - power_pin.set_high().unwrap(); 402 - } 403 - 404 - pac::NVIC::pend(interrupt::SW0_IRQ); 405 - } 406 - 407 - if pin.interrupt_status(EdgeHigh) { 408 - pin.clear_interrupt(EdgeHigh); 409 - 410 - // Power up temp sensor 411 - if let Some(i2c) = &mut i2c { 412 - let mut mcp9808 = MCP9808::new(i2c); 413 - let mut config = mcp9808.read_configuration().unwrap(); 414 - config.set_shutdown_mode(ShutdownMode::Continuous); 415 - mcp9808.write_register(config).unwrap(); 416 - } 417 - 418 - // Power up EPD 419 - if let Some(power_pin) = EPD_POWER_PIN { 420 - power_pin.set_low().unwrap(); 421 - } 422 - 423 - let mut fifo = Sio::new(unsafe { pac::Peripherals::steal() }.SIO).fifo; 424 - fifo.write_blocking(ToCore1Message::HardResetEpd as u32); 425 - 426 - if let Some(reset) = TOUCH_RESET_PIN { 427 - cortex_m::asm::delay(1000000); 428 - reset.set_high().unwrap(); 429 - cortex_m::asm::delay(1000000); 430 - reset.set_low().unwrap(); 431 - cortex_m::asm::delay(1000000); 432 - reset.set_high().unwrap(); 433 - cortex_m::asm::delay(10000000); 434 - } 435 - 436 - if let Some(touch_int) = TOUCH_INT_PIN { 437 - touch_int.clear_interrupt(EdgeLow); 438 - touch_int.set_interrupt_enabled(EdgeLow, true); 439 - } 440 - 441 - debug!("woken up"); 442 - } 443 - } 444 - 445 - critical_section::with(|cs| GLOBAL_I2C.borrow(cs).replace(i2c)); 446 284 } 447 285 448 - #[interrupt] 449 - fn SW0_IRQ() { 450 - trace!("SW0_IRQ"); 451 - cortex_m::asm::wfi(); 286 + fn reset_touch(pin: &mut EpdTouchReset) { 287 + pin.set_high().unwrap(); 288 + cortex_m::asm::delay(1000000); 289 + pin.set_low().unwrap(); 290 + cortex_m::asm::delay(1000000); 291 + pin.set_high().unwrap(); 292 + cortex_m::asm::delay(10000000); 452 293 }
+10 -421
eepy/src/syscall.rs
··· 1 - use core::arch::{asm, global_asm}; 1 + mod kv_store; 2 + mod flash; 3 + mod cs; 4 + mod input; 5 + mod image; 6 + mod misc; 7 + mod exec; 8 + 9 + use core::arch::global_asm; 2 10 use defmt::trace; 3 - use eepy_sys::exec::exec; 4 - use eepy_sys::header::slot; 5 11 use eepy_sys::syscall::SyscallNumber; 6 12 use crate::exception::StackFrame; 7 - use crate::SRAM_END; 8 13 9 14 global_asm!(include_str!("syscall.s")); 10 15 ··· 31 36 Some(SyscallNumber::Image) => image::handle_image(stack_values), 32 37 Some(SyscallNumber::Input) => input::handle_input(stack_values), 33 38 Some(SyscallNumber::Usb) => crate::usb::handle_usb(stack_values), 34 - Some(SyscallNumber::Exec) => handle_exec(stack_values, using_psp), 39 + Some(SyscallNumber::Exec) => exec::handle_exec(stack_values, using_psp), 35 40 Some(SyscallNumber::CriticalSection) => cs::handle_cs(stack_values), 36 41 Some(SyscallNumber::Flash) => flash::handle_flash(stack_values), 37 42 Some(SyscallNumber::KvStore) => kv_store::handle_kv_store(stack_values), 38 43 None => panic!("illegal syscall"), 39 - } 40 - } 41 - 42 - fn handle_exec(stack_values: &mut StackFrame, using_psp: bool) { 43 - // cleanup previous program's USB 44 - crate::usb::handle_uninit(); 45 - crate::usb::handle_clear_handler(); 46 - 47 - // disable privileged mode 48 - unsafe { 49 - asm!( 50 - "msr control, {control_0b11}", 51 - "isb", 52 - control_0b11 = in(reg) 0b11, 53 - ); 54 - } 55 - 56 - let slot_n = stack_values.r0 as u8; 57 - unsafe { 58 - let program = slot(slot_n); 59 - if !(*program).is_valid() { 60 - panic!("tried to exec invalid program"); 61 - } 62 - 63 - stack_values.pc = core::mem::transmute((*program).entry); 64 - stack_values.lr = program_return_handler as *const u8; 65 - 66 - // Move the saved registers to the top of program memory 67 - // This makes sure all programs start with an empty program stack 68 - if using_psp { 69 - let ptr: *mut StackFrame = SRAM_END.sub(size_of::<StackFrame>()).cast(); 70 - ptr.write(*stack_values); 71 - asm!( 72 - "msr psp, {ptr}", 73 - ptr = in(reg) ptr, 74 - ); 75 - } else { 76 - // If the saved registers are on the main stack, just set the PSP to 77 - // the top of program memory 78 - asm!( 79 - "msr psp, {ptr}", 80 - ptr = in(reg) SRAM_END, 81 - ) 82 - } 83 - 84 - (*program).load(); 85 - } 86 - } 87 - 88 - // NOTE: this function runs in unprivileged thread mode 89 - extern "C" fn program_return_handler() -> ! { 90 - exec(0); 91 - } 92 - 93 - mod misc { 94 - use defmt::{debug, error, info, trace, warn}; 95 - use eepy_sys::header::{SLOT_SIZE, XIP_BASE}; 96 - use eepy_sys::misc::{LogLevel, MiscSyscall}; 97 - use fw16_epd_bsp::pac::Peripherals; 98 - use crate::{SERIAL_NUMBER}; 99 - use super::StackFrame; 100 - 101 - pub(super) fn handle_misc(stack_values: &mut StackFrame) { 102 - match MiscSyscall::from_repr(stack_values.r0) { 103 - Some(MiscSyscall::GetSerial) => handle_get_serial(stack_values), 104 - Some(MiscSyscall::LogMessage) => handle_log_message(stack_values), 105 - Some(MiscSyscall::GetTimeMicros) => handle_get_time_micros(stack_values), 106 - None => panic!("illegal syscall"), 107 - } 108 - } 109 - 110 - fn handle_get_serial(stack_values: &mut StackFrame) { 111 - let buf = stack_values.r1 as *mut [u8; 16]; 112 - unsafe { 113 - (*buf).copy_from_slice(SERIAL_NUMBER.get().unwrap()); 114 - } 115 - } 116 - 117 - fn handle_log_message(stack_values: &mut StackFrame) { 118 - let log_level = LogLevel::from_repr(stack_values.r1).expect("invalid log level"); 119 - let len = stack_values.r2; 120 - let ptr = stack_values.r3 as *const u8; 121 - let s = unsafe { core::str::from_utf8_unchecked(core::slice::from_raw_parts(ptr, len)) }; 122 - let slot_n = (stack_values.pc as usize - XIP_BASE as usize) / SLOT_SIZE; 123 - 124 - match log_level { 125 - LogLevel::Trace => trace!("[PROGRAM:{}] {}", slot_n, s), 126 - LogLevel::Debug => debug!("[PROGRAM:{}] {}", slot_n, s), 127 - LogLevel::Info => info!("[PROGRAM:{}] {}", slot_n, s), 128 - LogLevel::Warn => warn!("[PROGRAM:{}] {}", slot_n, s), 129 - LogLevel::Error => error!("[PROGRAM:{}] {}", slot_n, s), 130 - } 131 - } 132 - 133 - fn handle_get_time_micros(stack_values: &mut StackFrame) { 134 - let timer = unsafe { Peripherals::steal() }.TIMER; 135 - stack_values.r1 = timer.timelr().read().bits() as usize; 136 - stack_values.r0 = timer.timehr().read().bits() as usize; 137 - } 138 - } 139 - 140 - mod image { 141 - use eepy_sys::image::ImageSyscall; 142 - use fw16_epd_bsp::hal::Sio; 143 - use fw16_epd_bsp::pac; 144 - use tp370pgh01::IMAGE_BYTES; 145 - use crate::IMAGE_BUFFER; 146 - use crate::core1::{ToCore0Message, ToCore1Message}; 147 - use super::StackFrame; 148 - 149 - pub(super) fn handle_image(stack_values: &mut StackFrame) { 150 - match ImageSyscall::from_repr(stack_values.r0) { 151 - Some(ImageSyscall::Refresh) => handle_refresh(stack_values), 152 - Some(ImageSyscall::MaybeRefresh) => handle_maybe_refresh(stack_values), 153 - None => panic!("illegal syscall"), 154 - } 155 - } 156 - 157 - fn handle_refresh(stack_values: &mut StackFrame) { 158 - let fast_refresh = stack_values.r1 != 0; 159 - let image: &[u8; IMAGE_BYTES] = unsafe { &*(stack_values.r2 as *const [u8; IMAGE_BYTES]) }; 160 - critical_section::with(|cs| IMAGE_BUFFER.borrow_ref_mut(cs).copy_from_slice(image)); 161 - 162 - let mut fifo = Sio::new(unsafe { pac::Peripherals::steal() }.SIO).fifo; 163 - let message = if fast_refresh { ToCore1Message::RefreshFast } else { ToCore1Message::RefreshNormal }; 164 - fifo.write_blocking(message as u32); 165 - 166 - if fifo.read_blocking() != ToCore0Message::RefreshAck as u32 { 167 - panic!("received incorrect message"); 168 - } 169 - } 170 - 171 - fn handle_maybe_refresh(stack_values: &mut StackFrame) { 172 - let fast_refresh = stack_values.r1 != 0; 173 - let image: &[u8; IMAGE_BYTES] = unsafe { &*(stack_values.r2 as *const [u8; IMAGE_BYTES]) }; 174 - critical_section::with(|cs| IMAGE_BUFFER.borrow_ref_mut(cs).copy_from_slice(image)); 175 - 176 - let mut fifo = Sio::new(unsafe { pac::Peripherals::steal() }.SIO).fifo; 177 - let message = if fast_refresh { ToCore1Message::MaybeRefreshFast } else { ToCore1Message::MaybeRefreshNormal }; 178 - if fifo.is_write_ready() { 179 - fifo.write(message as u32); 180 - } 181 - } 182 - } 183 - 184 - mod input { 185 - use core::sync::atomic::Ordering; 186 - use eepy_sys::input::InputSyscall; 187 - use eepy_sys::input_common::Event; 188 - use eepy_sys::SafeOption; 189 - use crate::{EVENT_QUEUE, TOUCH_ENABLED}; 190 - use super::StackFrame; 191 - 192 - pub(super) fn handle_input(stack_values: &mut StackFrame) { 193 - match InputSyscall::from_repr(stack_values.r0) { 194 - Some(InputSyscall::NextEvent) => handle_next_event(stack_values), 195 - Some(InputSyscall::SetTouchEnabled) => handle_set_touch_enabled(stack_values), 196 - Some(InputSyscall::HasEvent) => handle_has_event(stack_values), 197 - None => panic!("illegal syscall"), 198 - } 199 - } 200 - 201 - fn handle_next_event(stack_values: &mut StackFrame) { 202 - let next_event = critical_section::with(|cs| EVENT_QUEUE.borrow_ref_mut(cs).pop()); 203 - let ptr = stack_values.r1 as *mut SafeOption<Event>; 204 - unsafe { ptr.write(next_event.into()) }; 205 - } 206 - 207 - fn handle_set_touch_enabled(stack_values: &mut StackFrame) { 208 - let enable = stack_values.r1 != 0; 209 - TOUCH_ENABLED.store(enable, Ordering::Relaxed); 210 - if !enable { 211 - critical_section::with(|cs| EVENT_QUEUE.borrow_ref_mut(cs).clear()); 212 - } 213 - } 214 - 215 - fn handle_has_event(stack_values: &mut StackFrame) { 216 - let empty = critical_section::with(|cs| EVENT_QUEUE.borrow_ref(cs).is_empty()); 217 - stack_values.r0 = (!empty) as usize; 218 - } 219 - } 220 - 221 - mod cs { 222 - use core::sync::atomic::Ordering; 223 - use eepy_sys::critical_section::CsSyscall; 224 - use fw16_epd_bsp::pac; 225 - use fw16_epd_bsp::pac::interrupt; 226 - use crate::exception::StackFrame; 227 - 228 - pub(super) fn handle_cs(stack_values: &mut StackFrame) { 229 - match CsSyscall::from_repr(stack_values.r0) { 230 - Some(CsSyscall::Acquire) => handle_acquire(stack_values), 231 - Some(CsSyscall::Release) => handle_release(stack_values), 232 - None => panic!("illegal syscall"), 233 - } 234 - } 235 - 236 - // USBCTRL_IRQ is the only interrupt that might cause anything to happen 237 - // with program memory 238 - 239 - fn handle_acquire(stack_values: &mut StackFrame) { 240 - core::sync::atomic::compiler_fence(Ordering::SeqCst); 241 - stack_values.r0 = pac::NVIC::is_enabled(interrupt::USBCTRL_IRQ) as usize; 242 - pac::NVIC::mask(interrupt::USBCTRL_IRQ); 243 - core::sync::atomic::compiler_fence(Ordering::SeqCst); 244 - } 245 - 246 - fn handle_release(stack_values: &mut StackFrame) { 247 - core::sync::atomic::compiler_fence(Ordering::SeqCst); 248 - if stack_values.r1 != 0 { 249 - unsafe { 250 - pac::NVIC::unmask(interrupt::USBCTRL_IRQ); 251 - } 252 - } 253 - core::sync::atomic::compiler_fence(Ordering::SeqCst); 254 - } 255 - } 256 - 257 - mod flash { 258 - use eepy_sys::flash::FlashSyscall; 259 - use eepy_sys::header::{SLOT_SIZE, XIP_BASE}; 260 - use crate::exception::StackFrame; 261 - use crate::flash::{erase, erase_and_program, program}; 262 - 263 - pub(super) fn handle_flash(stack_values: &mut StackFrame) { 264 - match FlashSyscall::from_repr(stack_values.r0) { 265 - Some(FlashSyscall::Erase) => handle_erase(stack_values), 266 - Some(FlashSyscall::Program) => handle_program(stack_values), 267 - Some(FlashSyscall::EraseAndProgram) => handle_erase_and_program(stack_values), 268 - None => panic!("illegal syscall"), 269 - } 270 - } 271 - 272 - fn assert_permissions(stack_values: &mut StackFrame, start: u32, len: u32) { 273 - let slot_n = (stack_values.pc as usize - XIP_BASE as usize) / SLOT_SIZE; 274 - let start_addr_xip = start as usize + XIP_BASE as usize; 275 - let end_addr_xip = start_addr_xip + len as usize; 276 - 277 - if slot_n == 0 { 278 - // Slot 0 (launcher) can write any flash except kernel 279 - if start_addr_xip < (XIP_BASE as usize + 128 * 1024) { 280 - panic!("illegal flash write"); 281 - } 282 - return; 283 - } 284 - 285 - let slot_start = XIP_BASE as usize + (slot_n * SLOT_SIZE); 286 - let slot_end = slot_start + SLOT_SIZE; 287 - if start_addr_xip < slot_start || end_addr_xip > slot_end { 288 - panic!("illegal flash write"); 289 - } 290 - } 291 - 292 - fn handle_erase(stack_values: &mut StackFrame) { 293 - let start_addr = stack_values.r1 as u32; 294 - let len = stack_values.r2 as u32; 295 - assert_permissions(stack_values, start_addr, len); 296 - if start_addr % 4096 != 0 || len % 4096 != 0 { 297 - panic!("unaligned flash erase"); 298 - } 299 - 300 - unsafe { 301 - erase(start_addr, len); 302 - } 303 - } 304 - 305 - fn handle_program(stack_values: &mut StackFrame) { 306 - let start_addr = stack_values.r1 as u32; 307 - let data = unsafe { core::slice::from_raw_parts(stack_values.r3 as *const u8, stack_values.r2) }; 308 - assert_permissions(stack_values, start_addr, data.len() as u32); 309 - if start_addr % 256 != 0 || data.len() % 256 != 0 { 310 - panic!("unaligned flash program"); 311 - } 312 - 313 - unsafe { 314 - program(start_addr, data); 315 - } 316 - } 317 - 318 - fn handle_erase_and_program(stack_values: &mut StackFrame) { 319 - let start_addr = stack_values.r1 as u32; 320 - let data = unsafe { core::slice::from_raw_parts(stack_values.r3 as *const u8, stack_values.r2) }; 321 - assert_permissions(stack_values, start_addr, data.len() as u32); 322 - if start_addr % 4096 != 0 || data.len() % 4096 != 0 { 323 - panic!("unaligned flash erase"); 324 - } 325 - 326 - unsafe { 327 - erase_and_program(start_addr, data); 328 - } 329 - } 330 - } 331 - 332 - mod kv_store { 333 - use core::hash::Hasher; 334 - use siphasher::sip::SipHasher; 335 - use tickv::{ErrorCode, TicKV}; 336 - use eepy_sys::header::{slot, SLOT_SIZE, XIP_BASE}; 337 - use eepy_sys::kv_store::{AppendKeyError, DeleteKeyError, KvStoreSyscall, PutKeyError, ReadKeyArgs, ReadKeyError, WriteKeyArgs}; 338 - use eepy_sys::SafeResult; 339 - use crate::exception::StackFrame; 340 - use crate::tickv::{with_tickv, EepyFlashController}; 341 - 342 - pub(super) fn handle_kv_store(stack_values: &mut StackFrame) { 343 - match KvStoreSyscall::from_repr(stack_values.r0) { 344 - Some(KvStoreSyscall::ReadKey) => handle_kv_get(stack_values), 345 - Some(KvStoreSyscall::AppendKey) => handle_kv_append(stack_values), 346 - Some(KvStoreSyscall::PutKey) => handle_kv_put(stack_values), 347 - Some(KvStoreSyscall::InvalidateKey) => handle_kv_invalidate(stack_values), 348 - Some(KvStoreSyscall::ZeroiseKey) => handle_kv_zeroise(stack_values), 349 - None => panic!("illegal syscall"), 350 - } 351 - } 352 - 353 - fn hash(stack_values: &mut StackFrame, key: &[u8]) -> u64 { 354 - let slot_number = (stack_values.pc as usize - XIP_BASE as usize) / SLOT_SIZE; 355 - let slot_header = unsafe { slot(slot_number as u8) }; 356 - let program_name = unsafe { core::slice::from_raw_parts((*slot_header).name_ptr, (*slot_header).name_len) }; 357 - 358 - let mut hasher = SipHasher::new(); 359 - hasher.write(program_name); 360 - hasher.write(key); 361 - hasher.finish() 362 - } 363 - 364 - fn append_key_gc(tickv: &TicKV<EepyFlashController, 4096>, key: u64, value: &[u8]) -> Result<(), ErrorCode> { 365 - let mut res = tickv.append_key(key, value).map(|_| ()); 366 - if let Err(ErrorCode::RegionFull | ErrorCode::FlashFull) = res { 367 - res = tickv.garbage_collect().map(|_| ()); 368 - if res.is_ok() { 369 - res = tickv.append_key(key, value).map(|_| ()); 370 - } 371 - } 372 - res 373 - } 374 - 375 - fn handle_kv_get(stack_values: &mut StackFrame) { 376 - let args = stack_values.r1 as *const ReadKeyArgs; 377 - let key = unsafe { core::slice::from_raw_parts((*args).key_ptr, (*args).key_len) }; 378 - let buf = unsafe { core::slice::from_raw_parts_mut((*args).buf_ptr, (*args).buf_len) }; 379 - 380 - let hashed_key = hash(stack_values, key); 381 - let res = unsafe { with_tickv(|tickv| tickv.get_key(hashed_key, buf)) }; 382 - 383 - let res_ptr = stack_values.r2 as *mut SafeResult<usize, ReadKeyError>; 384 - let res: SafeResult<usize, ReadKeyError> = res 385 - .map(|(_, read)| read) 386 - .map_err(|e| e.try_into().unwrap()) 387 - .into(); 388 - unsafe { res_ptr.write(res) }; 389 - } 390 - 391 - fn handle_kv_append(stack_values: &mut StackFrame) { 392 - let args = stack_values.r1 as *const WriteKeyArgs; 393 - let key = unsafe { core::slice::from_raw_parts((*args).key_ptr, (*args).key_len) }; 394 - let value = unsafe { core::slice::from_raw_parts((*args).value_ptr, (*args).value_len) }; 395 - 396 - let hashed_key = hash(stack_values, key); 397 - let res = unsafe { with_tickv(|tickv| append_key_gc(tickv, hashed_key, value)) }; 398 - 399 - let res_ptr = stack_values.r2 as *mut SafeResult<(), AppendKeyError>; 400 - let res: SafeResult<(), AppendKeyError> = res 401 - .map(|_| ()) 402 - .map_err(|e| e.try_into().unwrap()) 403 - .into(); 404 - unsafe { res_ptr.write(res) }; 405 - } 406 - 407 - fn handle_kv_put(stack_values: &mut StackFrame) { 408 - let args = stack_values.r1 as *const WriteKeyArgs; 409 - let key = unsafe { core::slice::from_raw_parts((*args).key_ptr, (*args).key_len) }; 410 - let value = unsafe { core::slice::from_raw_parts((*args).value_ptr, (*args).value_len) }; 411 - 412 - let hashed_key = hash(stack_values, key); 413 - let mut res = unsafe { with_tickv(|tickv| append_key_gc(tickv, hashed_key, value)) }; 414 - 415 - // if there is already a value for this key, invalidate it and write the new value 416 - if let Err(ErrorCode::KeyAlreadyExists) = res { 417 - res = unsafe { with_tickv(|tickv| tickv.invalidate_key(hashed_key).map(|_| ())) }; 418 - if res.is_ok() { 419 - res = unsafe { with_tickv(|tickv| append_key_gc(tickv, hashed_key, value)) }; 420 - } 421 - } 422 - 423 - let res_ptr = stack_values.r2 as *mut SafeResult<(), PutKeyError>; 424 - let res: SafeResult<(), PutKeyError> = res 425 - .map(|_| ()) 426 - .map_err(|e| e.try_into().unwrap()) 427 - .into(); 428 - unsafe { res_ptr.write(res) }; 429 - } 430 - 431 - fn handle_kv_invalidate(stack_values: &mut StackFrame) { 432 - let key = unsafe { core::slice::from_raw_parts(stack_values.r1 as *const u8, stack_values.r2) }; 433 - let hashed_key = hash(stack_values, key); 434 - let res = unsafe { with_tickv(|tickv| tickv.invalidate_key(hashed_key)) }; 435 - 436 - let res_ptr = stack_values.r3 as *mut SafeResult<(), DeleteKeyError>; 437 - let res: SafeResult<(), DeleteKeyError> = res 438 - .map(|_| ()) 439 - .map_err(|e| e.try_into().unwrap()) 440 - .into(); 441 - unsafe { res_ptr.write(res) }; 442 - } 443 - 444 - fn handle_kv_zeroise(stack_values: &mut StackFrame) { 445 - let key = unsafe { core::slice::from_raw_parts(stack_values.r1 as *const u8, stack_values.r2) }; 446 - let hashed_key = hash(stack_values, key); 447 - let res = unsafe { with_tickv(|tickv| tickv.zeroise_key(hashed_key)) }; 448 - 449 - let res_ptr = stack_values.r3 as *mut SafeResult<(), DeleteKeyError>; 450 - let res: SafeResult<(), DeleteKeyError> = res 451 - .map(|_| ()) 452 - .map_err(|e| e.try_into().unwrap()) 453 - .into(); 454 - unsafe { res_ptr.write(res) }; 455 44 } 456 45 }
+33
eepy/src/syscall/cs.rs
··· 1 + use core::sync::atomic::Ordering; 2 + use eepy_sys::critical_section::CsSyscall; 3 + use fw16_epd_bsp::pac; 4 + use fw16_epd_bsp::pac::interrupt; 5 + use crate::exception::StackFrame; 6 + 7 + pub(super) fn handle_cs(stack_values: &mut StackFrame) { 8 + match CsSyscall::from_repr(stack_values.r0) { 9 + Some(CsSyscall::Acquire) => handle_acquire(stack_values), 10 + Some(CsSyscall::Release) => handle_release(stack_values), 11 + None => panic!("illegal syscall"), 12 + } 13 + } 14 + 15 + // USBCTRL_IRQ is the only interrupt that might cause anything to happen 16 + // with program memory 17 + 18 + fn handle_acquire(stack_values: &mut StackFrame) { 19 + core::sync::atomic::compiler_fence(Ordering::SeqCst); 20 + stack_values.r0 = pac::NVIC::is_enabled(interrupt::USBCTRL_IRQ) as usize; 21 + pac::NVIC::mask(interrupt::USBCTRL_IRQ); 22 + core::sync::atomic::compiler_fence(Ordering::SeqCst); 23 + } 24 + 25 + fn handle_release(stack_values: &mut StackFrame) { 26 + core::sync::atomic::compiler_fence(Ordering::SeqCst); 27 + if stack_values.r1 != 0 { 28 + unsafe { 29 + pac::NVIC::unmask(interrupt::USBCTRL_IRQ); 30 + } 31 + } 32 + core::sync::atomic::compiler_fence(Ordering::SeqCst); 33 + }
+56
eepy/src/syscall/exec.rs
··· 1 + use core::arch::asm; 2 + use eepy_sys::exec::exec; 3 + use eepy_sys::header::slot; 4 + use crate::exception::StackFrame; 5 + use crate::SRAM_END; 6 + 7 + pub(super) fn handle_exec(stack_values: &mut StackFrame, using_psp: bool) { 8 + // cleanup previous program's USB 9 + crate::usb::handle_uninit(); 10 + crate::usb::handle_clear_handler(); 11 + 12 + // disable privileged mode 13 + unsafe { 14 + asm!( 15 + "msr control, {control_0b11}", 16 + "isb", 17 + control_0b11 = in(reg) 0b11, 18 + ); 19 + } 20 + 21 + let slot_n = stack_values.r0 as u8; 22 + unsafe { 23 + let program = slot(slot_n); 24 + if !(*program).is_valid() { 25 + panic!("tried to exec invalid program"); 26 + } 27 + 28 + stack_values.pc = core::mem::transmute((*program).entry); 29 + stack_values.lr = program_return_handler as *const u8; 30 + 31 + // Move the saved registers to the top of program memory 32 + // This makes sure all programs start with an empty program stack 33 + if using_psp { 34 + let ptr: *mut StackFrame = SRAM_END.sub(size_of::<StackFrame>()).cast(); 35 + ptr.write(*stack_values); 36 + asm!( 37 + "msr psp, {ptr}", 38 + ptr = in(reg) ptr, 39 + ); 40 + } else { 41 + // If the saved registers are on the main stack, just set the PSP to 42 + // the top of program memory 43 + asm!( 44 + "msr psp, {ptr}", 45 + ptr = in(reg) SRAM_END, 46 + ) 47 + } 48 + 49 + (*program).load(); 50 + } 51 + } 52 + 53 + // NOTE: this function runs in unprivileged thread mode 54 + extern "C" fn program_return_handler() -> ! { 55 + exec(0); 56 + }
+72
eepy/src/syscall/flash.rs
··· 1 + use eepy_sys::flash::FlashSyscall; 2 + use eepy_sys::header::{SLOT_SIZE, XIP_BASE}; 3 + use crate::exception::StackFrame; 4 + use crate::flash::{erase, erase_and_program, program}; 5 + 6 + pub(super) fn handle_flash(stack_values: &mut StackFrame) { 7 + match FlashSyscall::from_repr(stack_values.r0) { 8 + Some(FlashSyscall::Erase) => handle_erase(stack_values), 9 + Some(FlashSyscall::Program) => handle_program(stack_values), 10 + Some(FlashSyscall::EraseAndProgram) => handle_erase_and_program(stack_values), 11 + None => panic!("illegal syscall"), 12 + } 13 + } 14 + 15 + fn assert_permissions(stack_values: &mut StackFrame, start: u32, len: u32) { 16 + let slot_n = (stack_values.pc as usize - XIP_BASE as usize) / SLOT_SIZE; 17 + let start_addr_xip = start as usize + XIP_BASE as usize; 18 + let end_addr_xip = start_addr_xip + len as usize; 19 + 20 + if slot_n == 0 { 21 + // Slot 0 (launcher) can write any flash except kernel 22 + if start_addr_xip < (XIP_BASE as usize + 128 * 1024) { 23 + panic!("illegal flash write"); 24 + } 25 + return; 26 + } 27 + 28 + let slot_start = XIP_BASE as usize + (slot_n * SLOT_SIZE); 29 + let slot_end = slot_start + SLOT_SIZE; 30 + if start_addr_xip < slot_start || end_addr_xip > slot_end { 31 + panic!("illegal flash write"); 32 + } 33 + } 34 + 35 + fn handle_erase(stack_values: &mut StackFrame) { 36 + let start_addr = stack_values.r1 as u32; 37 + let len = stack_values.r2 as u32; 38 + assert_permissions(stack_values, start_addr, len); 39 + if start_addr % 4096 != 0 || len % 4096 != 0 { 40 + panic!("unaligned flash erase"); 41 + } 42 + 43 + unsafe { 44 + erase(start_addr, len); 45 + } 46 + } 47 + 48 + fn handle_program(stack_values: &mut StackFrame) { 49 + let start_addr = stack_values.r1 as u32; 50 + let data = unsafe { core::slice::from_raw_parts(stack_values.r3 as *const u8, stack_values.r2) }; 51 + assert_permissions(stack_values, start_addr, data.len() as u32); 52 + if start_addr % 256 != 0 || data.len() % 256 != 0 { 53 + panic!("unaligned flash program"); 54 + } 55 + 56 + unsafe { 57 + program(start_addr, data); 58 + } 59 + } 60 + 61 + fn handle_erase_and_program(stack_values: &mut StackFrame) { 62 + let start_addr = stack_values.r1 as u32; 63 + let data = unsafe { core::slice::from_raw_parts(stack_values.r3 as *const u8, stack_values.r2) }; 64 + assert_permissions(stack_values, start_addr, data.len() as u32); 65 + if start_addr % 4096 != 0 || data.len() % 4096 != 0 { 66 + panic!("unaligned flash erase"); 67 + } 68 + 69 + unsafe { 70 + erase_and_program(start_addr, data); 71 + } 72 + }
+41
eepy/src/syscall/image.rs
··· 1 + use eepy_sys::image::ImageSyscall; 2 + use fw16_epd_bsp::hal::Sio; 3 + use fw16_epd_bsp::pac; 4 + use tp370pgh01::IMAGE_BYTES; 5 + use crate::IMAGE_BUFFER; 6 + use crate::core1::{ToCore0Message, ToCore1Message}; 7 + use super::StackFrame; 8 + 9 + pub(super) fn handle_image(stack_values: &mut StackFrame) { 10 + match ImageSyscall::from_repr(stack_values.r0) { 11 + Some(ImageSyscall::Refresh) => handle_refresh(stack_values), 12 + Some(ImageSyscall::MaybeRefresh) => handle_maybe_refresh(stack_values), 13 + None => panic!("illegal syscall"), 14 + } 15 + } 16 + 17 + fn handle_refresh(stack_values: &mut StackFrame) { 18 + let fast_refresh = stack_values.r1 != 0; 19 + let image: &[u8; IMAGE_BYTES] = unsafe { &*(stack_values.r2 as *const [u8; IMAGE_BYTES]) }; 20 + critical_section::with(|cs| IMAGE_BUFFER.borrow_ref_mut(cs).copy_from_slice(image)); 21 + 22 + let mut fifo = Sio::new(unsafe { pac::Peripherals::steal() }.SIO).fifo; 23 + let message = if fast_refresh { ToCore1Message::RefreshFast } else { ToCore1Message::RefreshNormal }; 24 + fifo.write_blocking(message as u32); 25 + 26 + if fifo.read_blocking() != ToCore0Message::RefreshAck as u32 { 27 + panic!("received incorrect message"); 28 + } 29 + } 30 + 31 + fn handle_maybe_refresh(stack_values: &mut StackFrame) { 32 + let fast_refresh = stack_values.r1 != 0; 33 + let image: &[u8; IMAGE_BYTES] = unsafe { &*(stack_values.r2 as *const [u8; IMAGE_BYTES]) }; 34 + critical_section::with(|cs| IMAGE_BUFFER.borrow_ref_mut(cs).copy_from_slice(image)); 35 + 36 + let mut fifo = Sio::new(unsafe { pac::Peripherals::steal() }.SIO).fifo; 37 + let message = if fast_refresh { ToCore1Message::MaybeRefreshFast } else { ToCore1Message::MaybeRefreshNormal }; 38 + if fifo.is_write_ready() { 39 + fifo.write(message as u32); 40 + } 41 + }
+34
eepy/src/syscall/input.rs
··· 1 + use core::sync::atomic::Ordering; 2 + use eepy_sys::input::InputSyscall; 3 + use eepy_sys::input_common::Event; 4 + use eepy_sys::SafeOption; 5 + use crate::{EVENT_QUEUE, TOUCH_ENABLED}; 6 + use super::StackFrame; 7 + 8 + pub(super) fn handle_input(stack_values: &mut StackFrame) { 9 + match InputSyscall::from_repr(stack_values.r0) { 10 + Some(InputSyscall::NextEvent) => handle_next_event(stack_values), 11 + Some(InputSyscall::SetTouchEnabled) => handle_set_touch_enabled(stack_values), 12 + Some(InputSyscall::HasEvent) => handle_has_event(stack_values), 13 + None => panic!("illegal syscall"), 14 + } 15 + } 16 + 17 + fn handle_next_event(stack_values: &mut StackFrame) { 18 + let next_event = critical_section::with(|cs| EVENT_QUEUE.borrow_ref_mut(cs).pop()); 19 + let ptr = stack_values.r1 as *mut SafeOption<Event>; 20 + unsafe { ptr.write(next_event.into()) }; 21 + } 22 + 23 + fn handle_set_touch_enabled(stack_values: &mut StackFrame) { 24 + let enable = stack_values.r1 != 0; 25 + TOUCH_ENABLED.store(enable, Ordering::Relaxed); 26 + if !enable { 27 + critical_section::with(|cs| EVENT_QUEUE.borrow_ref_mut(cs).clear()); 28 + } 29 + } 30 + 31 + fn handle_has_event(stack_values: &mut StackFrame) { 32 + let empty = critical_section::with(|cs| EVENT_QUEUE.borrow_ref(cs).is_empty()); 33 + stack_values.r0 = (!empty) as usize; 34 + }
+123
eepy/src/syscall/kv_store.rs
··· 1 + use core::hash::Hasher; 2 + use siphasher::sip::SipHasher; 3 + use tickv::{ErrorCode, TicKV}; 4 + use eepy_sys::header::{slot, SLOT_SIZE, XIP_BASE}; 5 + use eepy_sys::kv_store::{AppendKeyError, DeleteKeyError, KvStoreSyscall, PutKeyError, ReadKeyArgs, ReadKeyError, WriteKeyArgs}; 6 + use eepy_sys::SafeResult; 7 + use crate::exception::StackFrame; 8 + use crate::tickv::{with_tickv, EepyFlashController}; 9 + 10 + pub(super) fn handle_kv_store(stack_values: &mut StackFrame) { 11 + match KvStoreSyscall::from_repr(stack_values.r0) { 12 + Some(KvStoreSyscall::ReadKey) => handle_kv_get(stack_values), 13 + Some(KvStoreSyscall::AppendKey) => handle_kv_append(stack_values), 14 + Some(KvStoreSyscall::PutKey) => handle_kv_put(stack_values), 15 + Some(KvStoreSyscall::InvalidateKey) => handle_kv_invalidate(stack_values), 16 + Some(KvStoreSyscall::ZeroiseKey) => handle_kv_zeroise(stack_values), 17 + None => panic!("illegal syscall"), 18 + } 19 + } 20 + 21 + fn hash(stack_values: &mut StackFrame, key: &[u8]) -> u64 { 22 + let slot_number = (stack_values.pc as usize - XIP_BASE as usize) / SLOT_SIZE; 23 + let slot_header = unsafe { slot(slot_number as u8) }; 24 + let program_name = unsafe { core::slice::from_raw_parts((*slot_header).name_ptr, (*slot_header).name_len) }; 25 + 26 + let mut hasher = SipHasher::new(); 27 + hasher.write(program_name); 28 + hasher.write(key); 29 + hasher.finish() 30 + } 31 + 32 + fn append_key_gc(tickv: &TicKV<EepyFlashController, 4096>, key: u64, value: &[u8]) -> Result<(), ErrorCode> { 33 + let mut res = tickv.append_key(key, value).map(|_| ()); 34 + if let Err(ErrorCode::RegionFull | ErrorCode::FlashFull) = res { 35 + res = tickv.garbage_collect().map(|_| ()); 36 + if res.is_ok() { 37 + res = tickv.append_key(key, value).map(|_| ()); 38 + } 39 + } 40 + res 41 + } 42 + 43 + fn handle_kv_get(stack_values: &mut StackFrame) { 44 + let args = stack_values.r1 as *const ReadKeyArgs; 45 + let key = unsafe { core::slice::from_raw_parts((*args).key_ptr, (*args).key_len) }; 46 + let buf = unsafe { core::slice::from_raw_parts_mut((*args).buf_ptr, (*args).buf_len) }; 47 + 48 + let hashed_key = hash(stack_values, key); 49 + let res = unsafe { with_tickv(|tickv| tickv.get_key(hashed_key, buf)) }; 50 + 51 + let res_ptr = stack_values.r2 as *mut SafeResult<usize, ReadKeyError>; 52 + let res: SafeResult<usize, ReadKeyError> = res 53 + .map(|(_, read)| read) 54 + .map_err(|e| e.try_into().unwrap()) 55 + .into(); 56 + unsafe { res_ptr.write(res) }; 57 + } 58 + 59 + fn handle_kv_append(stack_values: &mut StackFrame) { 60 + let args = stack_values.r1 as *const WriteKeyArgs; 61 + let key = unsafe { core::slice::from_raw_parts((*args).key_ptr, (*args).key_len) }; 62 + let value = unsafe { core::slice::from_raw_parts((*args).value_ptr, (*args).value_len) }; 63 + 64 + let hashed_key = hash(stack_values, key); 65 + let res = unsafe { with_tickv(|tickv| append_key_gc(tickv, hashed_key, value)) }; 66 + 67 + let res_ptr = stack_values.r2 as *mut SafeResult<(), AppendKeyError>; 68 + let res: SafeResult<(), AppendKeyError> = res 69 + .map(|_| ()) 70 + .map_err(|e| e.try_into().unwrap()) 71 + .into(); 72 + unsafe { res_ptr.write(res) }; 73 + } 74 + 75 + fn handle_kv_put(stack_values: &mut StackFrame) { 76 + let args = stack_values.r1 as *const WriteKeyArgs; 77 + let key = unsafe { core::slice::from_raw_parts((*args).key_ptr, (*args).key_len) }; 78 + let value = unsafe { core::slice::from_raw_parts((*args).value_ptr, (*args).value_len) }; 79 + 80 + let hashed_key = hash(stack_values, key); 81 + let mut res = unsafe { with_tickv(|tickv| append_key_gc(tickv, hashed_key, value)) }; 82 + 83 + // if there is already a value for this key, invalidate it and write the new value 84 + if let Err(ErrorCode::KeyAlreadyExists) = res { 85 + res = unsafe { with_tickv(|tickv| tickv.invalidate_key(hashed_key).map(|_| ())) }; 86 + if res.is_ok() { 87 + res = unsafe { with_tickv(|tickv| append_key_gc(tickv, hashed_key, value)) }; 88 + } 89 + } 90 + 91 + let res_ptr = stack_values.r2 as *mut SafeResult<(), PutKeyError>; 92 + let res: SafeResult<(), PutKeyError> = res 93 + .map(|_| ()) 94 + .map_err(|e| e.try_into().unwrap()) 95 + .into(); 96 + unsafe { res_ptr.write(res) }; 97 + } 98 + 99 + fn handle_kv_invalidate(stack_values: &mut StackFrame) { 100 + let key = unsafe { core::slice::from_raw_parts(stack_values.r1 as *const u8, stack_values.r2) }; 101 + let hashed_key = hash(stack_values, key); 102 + let res = unsafe { with_tickv(|tickv| tickv.invalidate_key(hashed_key)) }; 103 + 104 + let res_ptr = stack_values.r3 as *mut SafeResult<(), DeleteKeyError>; 105 + let res: SafeResult<(), DeleteKeyError> = res 106 + .map(|_| ()) 107 + .map_err(|e| e.try_into().unwrap()) 108 + .into(); 109 + unsafe { res_ptr.write(res) }; 110 + } 111 + 112 + fn handle_kv_zeroise(stack_values: &mut StackFrame) { 113 + let key = unsafe { core::slice::from_raw_parts(stack_values.r1 as *const u8, stack_values.r2) }; 114 + let hashed_key = hash(stack_values, key); 115 + let res = unsafe { with_tickv(|tickv| tickv.zeroise_key(hashed_key)) }; 116 + 117 + let res_ptr = stack_values.r3 as *mut SafeResult<(), DeleteKeyError>; 118 + let res: SafeResult<(), DeleteKeyError> = res 119 + .map(|_| ()) 120 + .map_err(|e| e.try_into().unwrap()) 121 + .into(); 122 + unsafe { res_ptr.write(res) }; 123 + }
+44
eepy/src/syscall/misc.rs
··· 1 + use defmt::{debug, error, info, trace, warn}; 2 + use eepy_sys::header::{SLOT_SIZE, XIP_BASE}; 3 + use eepy_sys::misc::{LogLevel, MiscSyscall}; 4 + use fw16_epd_bsp::pac::Peripherals; 5 + use crate::{SERIAL_NUMBER}; 6 + use super::StackFrame; 7 + 8 + pub(super) fn handle_misc(stack_values: &mut StackFrame) { 9 + match MiscSyscall::from_repr(stack_values.r0) { 10 + Some(MiscSyscall::GetSerial) => handle_get_serial(stack_values), 11 + Some(MiscSyscall::LogMessage) => handle_log_message(stack_values), 12 + Some(MiscSyscall::GetTimeMicros) => handle_get_time_micros(stack_values), 13 + None => panic!("illegal syscall"), 14 + } 15 + } 16 + 17 + fn handle_get_serial(stack_values: &mut StackFrame) { 18 + let buf = stack_values.r1 as *mut [u8; 16]; 19 + unsafe { 20 + (*buf).copy_from_slice(SERIAL_NUMBER.get().unwrap()); 21 + } 22 + } 23 + 24 + fn handle_log_message(stack_values: &mut StackFrame) { 25 + let log_level = LogLevel::from_repr(stack_values.r1).expect("invalid log level"); 26 + let len = stack_values.r2; 27 + let ptr = stack_values.r3 as *const u8; 28 + let s = unsafe { core::str::from_utf8_unchecked(core::slice::from_raw_parts(ptr, len)) }; 29 + let slot_n = (stack_values.pc as usize - XIP_BASE as usize) / SLOT_SIZE; 30 + 31 + match log_level { 32 + LogLevel::Trace => trace!("[PROGRAM:{}] {}", slot_n, s), 33 + LogLevel::Debug => debug!("[PROGRAM:{}] {}", slot_n, s), 34 + LogLevel::Info => info!("[PROGRAM:{}] {}", slot_n, s), 35 + LogLevel::Warn => warn!("[PROGRAM:{}] {}", slot_n, s), 36 + LogLevel::Error => error!("[PROGRAM:{}] {}", slot_n, s), 37 + } 38 + } 39 + 40 + fn handle_get_time_micros(stack_values: &mut StackFrame) { 41 + let timer = unsafe { Peripherals::steal() }.TIMER; 42 + stack_values.r1 = timer.timelr().read().bits() as usize; 43 + stack_values.r0 = timer.timehr().read().bits() as usize; 44 + }
+48
eepy/src/temp.rs
··· 1 + use core::sync::atomic::Ordering; 2 + use defmt::{debug, trace}; 3 + use mcp9808::MCP9808; 4 + use mcp9808::reg_temp_generic::ReadableTempRegister; 5 + use fw16_epd_bsp::hal::fugit::ExtU32; 6 + use fw16_epd_bsp::hal::timer::{Alarm, Alarm0}; 7 + use fw16_epd_bsp::pac::interrupt; 8 + use crate::{GLOBAL_ALARM0, GLOBAL_I2C, TEMP}; 9 + 10 + #[interrupt] 11 + fn TIMER_IRQ_0() { 12 + static mut ALARM0: Option<Alarm0> = None; 13 + 14 + trace!("TIMER_IRQ_0"); 15 + 16 + 17 + if ALARM0.is_none() { 18 + critical_section::with(|cs| *ALARM0 = GLOBAL_ALARM0.borrow(cs).take()); 19 + } 20 + 21 + let mut i2c = critical_section::with(|cs| GLOBAL_I2C.borrow(cs).take()); 22 + 23 + if let Some(alarm) = ALARM0 { 24 + if let Some(i2c) = &mut i2c { 25 + let mut mcp9808 = MCP9808::new(i2c); 26 + 27 + let temp = ((mcp9808.read_temperature().unwrap().get_raw_value() & 0x1ff0) >> 4) as i16; 28 + let clamped = match temp { 29 + ..=0 => 0u8, 30 + 60.. => 60u8, 31 + t => t as u8, 32 + }; 33 + 34 + debug!("read temperature {}C (using {}C)", temp, clamped); 35 + 36 + TEMP.store(clamped, Ordering::Relaxed); 37 + 38 + alarm.clear_interrupt(); 39 + alarm.schedule(1.minutes()).unwrap(); 40 + } else { 41 + // I2C bus was in use, so try again in a short time 42 + alarm.clear_interrupt(); 43 + alarm.schedule(10.millis()).unwrap(); 44 + } 45 + } 46 + 47 + critical_section::with(|cs| GLOBAL_I2C.borrow(cs).replace(i2c)); 48 + }