firmware for my Touchscreen E-Paper Input Module for Framework Laptop 16
1#![no_std]
2#![no_main]
3
4mod serial;
5mod ui;
6
7extern crate panic_halt;
8
9use core::mem::offset_of;
10use core::sync::atomic::Ordering;
11use usb_device::bus::UsbBusAllocator;
12use eepy_gui::draw_target::EpdDrawTarget;
13use eepy_gui::element::Gui;
14use eepy_sys::input::{eep, next_event, set_touch_enabled};
15use eepy_sys::misc::get_serial;
16use eepy_sys::usb::{self, UsbBus};
17use usb_device::prelude::*;
18use usbd_serial::SerialPort;
19use eepy_sys::{eepy_app, flash, kv_store};
20use eepy_sys::header::{slot_ptr, ProgramSlotHeader};
21use crate::serial::{HOST_APP, NEEDS_REFRESH, NEEDS_REFRESH_PROGRAMS};
22use crate::ui::MainGui;
23
24static mut USB: Option<UsbBusAllocator<UsbBus>> = None;
25static mut USB_DEVICE: Option<UsbDevice<UsbBus>> = None;
26static mut USB_SERIAL: Option<SerialPort<UsbBus>> = None;
27
28pub(crate) unsafe fn delete_program(slot: u8) {
29 if get_autostart() == Some(slot) {
30 set_autostart(None);
31 }
32
33 let ptr = unsafe { slot_ptr(slot) };
34 let mut buf = [0u8; 256];
35 unsafe { buf.copy_from_slice(core::slice::from_raw_parts(ptr, 256)) };
36 let offset = offset_of!(ProgramSlotHeader, len);
37 buf[offset..offset + 4].copy_from_slice(&0usize.to_ne_bytes());
38
39 unsafe { flash::program(slot as u32 * 512 * 1024, &buf) };
40}
41
42pub(crate) fn get_autostart() -> Option<u8> {
43 let mut buf = [0u8; 1];
44 kv_store::get(b"autostart", &mut buf).ok()?;
45
46 if buf[0] == 0 {
47 None
48 } else {
49 Some(buf[0])
50 }
51}
52
53pub(crate) fn set_autostart(slot: Option<u8>) {
54 let _ignored = kv_store::put(b"autostart", &[slot.unwrap_or(0)]);
55}
56
57#[eepy_app(name = "Launcher")]
58fn main() {
59 #[allow(static_mut_refs)]
60 unsafe {
61 let bus = UsbBusAllocator::new(UsbBus::init());
62 USB = Some(bus);
63 let bus_ref = USB.as_ref().unwrap();
64
65 let serial = SerialPort::new(bus_ref);
66 USB_SERIAL = Some(serial);
67
68 let usb_dev = UsbDeviceBuilder::new(bus_ref, UsbVidPid(0x2e8a, 0x000a))
69 .strings(&[StringDescriptors::default()
70 .manufacturer("arthomnix")
71 .product("Touchscreen EPD for FW16 [eepyOS Launcher]")
72 .serial_number(get_serial())
73 ])
74 .unwrap()
75 .device_class(usbd_serial::USB_CLASS_CDC)
76 .build();
77 USB_DEVICE = Some(usb_dev);
78 }
79
80 usb::set_handler(serial::usb_handler);
81
82 let mut draw_target = EpdDrawTarget::default();
83 set_touch_enabled(true);
84 let mut gui = MainGui::new();
85 gui.draw_init(&mut draw_target);
86 draw_target.refresh(false);
87
88 loop {
89 if !HOST_APP.load(Ordering::Relaxed) {
90 while let Some(ev) = next_event() {
91 gui.tick(&mut draw_target, ev);
92 }
93
94 if NEEDS_REFRESH_PROGRAMS.swap(false, Ordering::Relaxed) {
95 if let MainGui::MainPage(page) = &mut gui {
96 page.refresh_buttons();
97 page.draw_init(&mut draw_target);
98 }
99 draw_target.refresh(false);
100 } else if NEEDS_REFRESH.swap(false, Ordering::Relaxed) {
101 gui.draw_init(&mut draw_target);
102 draw_target.refresh(false);
103 } else {
104 eep();
105 }
106 }
107 }
108}