tangled
alpha
login
or
join now
arthomnix.dev
/
eepy
3
fork
atom
firmware for my Touchscreen E-Paper Input Module for Framework Laptop 16
3
fork
atom
overview
issues
pulls
pipelines
eepy-launcher: improve main page, implement app updates
arthomnix.dev
1 year ago
a3ff1f4e
58afaf4b
+69
-27
5 changed files
expand all
collapse all
unified
split
eepy-launcher
src
main.rs
serial.rs
ui
page
app_info.rs
main.rs
eepy-sys
src
header.rs
+13
-1
eepy-launcher/src/main.rs
reviewed
···
7
7
extern crate panic_halt;
8
8
9
9
use core::arch::asm;
10
10
+
use core::mem::offset_of;
10
11
use core::sync::atomic::Ordering;
11
12
use usb_device::bus::UsbBusAllocator;
12
13
use eepy_gui::draw_target::EpdDrawTarget;
···
16
17
use eepy_sys::usb::{self, UsbBus};
17
18
use usb_device::prelude::*;
18
19
use usbd_serial::SerialPort;
19
19
-
use eepy_sys::eepy_app;
20
20
+
use eepy_sys::{eepy_app, flash};
21
21
+
use eepy_sys::header::{slot_ptr, ProgramSlotHeader};
20
22
use crate::serial::{HOST_APP, NEEDS_REFRESH, NEEDS_REFRESH_PROGRAMS};
21
23
use crate::ui::MainGui;
22
24
23
25
static mut USB: Option<UsbBusAllocator<UsbBus>> = None;
24
26
static mut USB_DEVICE: Option<UsbDevice<UsbBus>> = None;
25
27
static mut USB_SERIAL: Option<SerialPort<UsbBus>> = None;
28
28
+
29
29
+
pub(crate) unsafe fn delete_program(slot: u8) {
30
30
+
let ptr = unsafe { slot_ptr(slot) };
31
31
+
let mut buf = [0u8; 256];
32
32
+
unsafe { buf.copy_from_slice(core::slice::from_raw_parts(ptr, 256)) };
33
33
+
let offset = offset_of!(ProgramSlotHeader, len);
34
34
+
buf[offset..offset + 4].copy_from_slice(&0usize.to_ne_bytes());
35
35
+
36
36
+
unsafe { flash::program(slot as u32 * 512 * 1024, &buf) };
37
37
+
}
26
38
27
39
#[eepy_app(name = "Launcher")]
28
40
fn main() {
+19
-3
eepy-launcher/src/serial.rs
reviewed
···
5
5
use usbd_serial::SerialPort;
6
6
use eepy_serial::{Response, SerialCommand};
7
7
use eepy_sys::flash::erase_and_program;
8
8
-
use eepy_sys::header::{slot, slot_ptr};
8
8
+
use eepy_sys::header::{slot, slot_ptr, Programs};
9
9
use eepy_sys::image::refresh;
10
10
-
use eepy_sys::IMAGE_BYTES;
10
10
+
use eepy_sys::{header, IMAGE_BYTES};
11
11
use eepy_sys::input::{next_event, set_touch_enabled};
12
12
use eepy_sys::misc::{debug, info, trace};
13
13
use eepy_sys::usb::UsbBus;
14
14
-
use crate::{USB_DEVICE, USB_SERIAL};
14
14
+
use crate::{delete_program, USB_DEVICE, USB_SERIAL};
15
15
use crate::ui::flashing::draw_flashing_ui;
16
16
17
17
#[derive(Copy, Clone, Debug)]
···
225
225
buf[0..4].copy_from_slice(&(erase_cycles + 1).to_ne_bytes());
226
226
227
227
unsafe { write_flash(&buf[0..4096], slot, 0) };
228
228
+
229
229
+
let this_header = unsafe { header::slot(slot) };
230
230
+
let this_name = unsafe { core::slice::from_raw_parts((*this_header).name_ptr, (*this_header).name_len) };
231
231
+
232
232
+
// If there is an old program with the same name, delete it
233
233
+
Programs::new()
234
234
+
.filter_map(|prog| unsafe {
235
235
+
let name = core::slice::from_raw_parts((*prog).name_ptr, (*prog).name_len);
236
236
+
if (*prog).slot() != slot && name == this_name {
237
237
+
Some((*prog).slot())
238
238
+
} else {
239
239
+
None
240
240
+
}
241
241
+
})
242
242
+
.for_each(|slot| unsafe { delete_program(slot) });
243
243
+
228
244
PROG_SLOT.store(0, Ordering::Relaxed);
229
245
230
246
NEEDS_REFRESH_PROGRAMS.store(true, Ordering::Relaxed);
+11
-10
eepy-launcher/src/ui/page/app_info.rs
reviewed
···
1
1
-
use core::mem::offset_of;
2
1
use eepy_gui::element::button::Button;
3
2
use embedded_graphics::prelude::*;
4
3
use embedded_graphics::text::Text;
5
4
use eepy_gui::draw_target::EpdDrawTarget;
6
5
use eepy_gui::element::{Gui, DEFAULT_TEXT_STYLE};
7
7
-
use eepy_sys::flash;
8
8
-
use eepy_sys::header::{slot, slot_ptr, ProgramSlotHeader};
6
6
+
use eepy_sys::header::slot;
9
7
use eepy_sys::input_common::Event;
8
8
+
use crate::delete_program;
10
9
use crate::ui::MainGui;
11
10
use crate::ui::page::main::MainPage;
12
11
···
66
65
}
67
66
68
67
fn tick(&mut self, target: &mut EpdDrawTarget, ev: Event) -> Self::Output {
68
68
+
let mut refresh = false;
69
69
+
69
70
let b = self.back_button.tick(target, ev);
70
71
if b.clicked {
71
72
return Some(MainGui::MainPage(MainPage::new()));
72
73
}
74
74
+
refresh |= b.needs_refresh;
73
75
74
76
let d = self.delete_button.tick(target, ev);
75
77
if d.clicked {
76
76
-
let ptr = unsafe { slot_ptr(self.slot) };
77
77
-
let mut buf = [0u8; 256];
78
78
-
unsafe { buf.copy_from_slice(core::slice::from_raw_parts(ptr, 256)) };
79
79
-
let offset = offset_of!(ProgramSlotHeader, len);
80
80
-
buf[offset..offset + 4].copy_from_slice(&[0; 4]);
81
81
-
82
82
-
unsafe { flash::program(self.slot as u32 * 512 * 1024, &buf) };
78
78
+
unsafe { delete_program(self.slot) };
83
79
return Some(MainGui::MainPage(MainPage::new()));
80
80
+
}
81
81
+
refresh |= d.needs_refresh;
82
82
+
83
83
+
if refresh {
84
84
+
target.refresh(true);
84
85
}
85
86
86
87
None
+22
-9
eepy-launcher/src/ui/page/main.rs
reviewed
···
16
16
}
17
17
18
18
impl MainPage {
19
19
+
fn app_button(x: usize, y: usize, label: &'static str) -> Button<'static> {
20
20
+
let x_coord = 10 + 115 * x as i32;
21
21
+
let y_coord = 8 + 25 * y as i32;
22
22
+
Button::with_default_style(
23
23
+
Rectangle::new(Point::new(x_coord, y_coord), Size::new(105, 20)),
24
24
+
label,
25
25
+
false,
26
26
+
)
27
27
+
}
28
28
+
19
29
pub(crate) fn refresh_buttons(&mut self) {
20
30
let mut programs = Programs::new();
21
31
22
32
for y in 0..16 {
23
33
for x in 0..2 {
34
34
+
// Reserve the first space for the scratchpad
35
35
+
if x == 0 && y == 0 {
36
36
+
continue;
37
37
+
}
38
38
+
24
39
if let Some(prog) = programs.next() {
25
40
let bi = y * 2 + x;
26
26
-
let x_coord = if x == 0 { 10 } else { 125 };
27
27
-
let y_coord = 35 + 23 * y as i32;
28
28
-
let button = Button::with_default_style(
29
29
-
Rectangle::new(Point::new(x_coord, y_coord), Size::new(105, 20)),
30
30
-
unsafe { (*prog).name().unwrap() },
31
31
-
false,
32
32
-
);
41
41
+
let button = Self::app_button(x, y, unsafe { (*prog).name().unwrap_or("<invalid>") });
33
42
let slot_num = unsafe { (&*prog).slot() };
34
43
self.app_buttons[bi] = Some((button, slot_num))
35
44
}
···
39
48
40
49
pub(crate) fn new() -> Self {
41
50
let mut res = Self {
42
42
-
scratchpad_button: Button::with_default_style_auto_sized(Point::new(10, 10), "Scratchpad", true),
51
51
+
scratchpad_button: Button::with_default_style(
52
52
+
Rectangle::new(Point::new(10, 8), Size::new(105, 20)),
53
53
+
"Scratchpad",
54
54
+
true
55
55
+
),
43
56
app_buttons: [const { None }; 32],
44
57
};
45
58
res.refresh_buttons();
···
69
82
draw_target.refresh(true);
70
83
}
71
84
72
72
-
for b in &mut self.app_buttons {
85
85
+
for b in &mut self.app_buttons[1..] {
73
86
if let Some((button, s)) = b {
74
87
let response = button.tick(draw_target, ev);
75
88
+4
-4
eepy-sys/src/header.rs
reviewed
···
128
128
return false;
129
129
}
130
130
131
131
-
if self.name().is_err() {
131
131
+
if unsafe { self.name() }.is_err() {
132
132
#[cfg(feature = "defmt")]
133
133
warn!("Program name is not valid UTF-8");
134
134
return false;
135
135
}
136
136
137
137
-
if self.version().is_err() {
137
137
+
if unsafe { self.version() }.is_err() {
138
138
#[cfg(feature = "defmt")]
139
139
warn!("Program version string is not valid UTF-8");
140
140
return false;
···
187
187
crc == self.crc
188
188
}
189
189
190
190
-
pub fn name(&self) -> Result<&str, Utf8Error> {
190
190
+
pub unsafe fn name(&self) -> Result<&str, Utf8Error> {
191
191
unsafe {
192
192
core::str::from_utf8(core::slice::from_raw_parts(self.name_ptr, self.name_len))
193
193
}
194
194
}
195
195
196
196
-
pub fn version(&self) -> Result<&str, Utf8Error> {
196
196
+
pub unsafe fn version(&self) -> Result<&str, Utf8Error> {
197
197
unsafe {
198
198
core::str::from_utf8(core::slice::from_raw_parts(self.version_ptr, self.version_len))
199
199
}