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