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::arch::asm;
10use core::mem::offset_of;
11use core::sync::atomic::Ordering;
12use usb_device::bus::UsbBusAllocator;
13use eepy_gui::draw_target::EpdDrawTarget;
14use eepy_gui::element::Gui;
15use eepy_sys::input::{has_event, next_event, set_touch_enabled};
16use eepy_sys::misc::get_serial;
17use eepy_sys::usb::{self, UsbBus};
18use usb_device::prelude::*;
19use usbd_serial::SerialPort;
20use eepy_sys::{eepy_app, flash};
21use eepy_sys::header::{slot_ptr, ProgramSlotHeader};
22use crate::serial::{HOST_APP, NEEDS_REFRESH, NEEDS_REFRESH_PROGRAMS};
23use crate::ui::MainGui;
24
25static mut USB: Option<UsbBusAllocator<UsbBus>> = None;
26static mut USB_DEVICE: Option<UsbDevice<UsbBus>> = None;
27static mut USB_SERIAL: Option<SerialPort<UsbBus>> = None;
28
29pub(crate) unsafe fn delete_program(slot: u8) {
30 let ptr = unsafe { slot_ptr(slot) };
31 let mut buf = [0u8; 256];
32 unsafe { buf.copy_from_slice(core::slice::from_raw_parts(ptr, 256)) };
33 let offset = offset_of!(ProgramSlotHeader, len);
34 buf[offset..offset + 4].copy_from_slice(&0usize.to_ne_bytes());
35
36 unsafe { flash::program(slot as u32 * 512 * 1024, &buf) };
37}
38
39#[eepy_app(name = "Launcher")]
40fn main() {
41 #[allow(static_mut_refs)]
42 unsafe {
43 let bus = UsbBusAllocator::new(UsbBus::init());
44 USB = Some(bus);
45 let bus_ref = USB.as_ref().unwrap();
46
47 let serial = SerialPort::new(bus_ref);
48 USB_SERIAL = Some(serial);
49
50 let usb_dev = UsbDeviceBuilder::new(bus_ref, UsbVidPid(0x2e8a, 0x000a))
51 .strings(&[StringDescriptors::default()
52 .manufacturer("arthomnix")
53 .product("Touchscreen EPD for FW16 [eepyOS Launcher]")
54 .serial_number(get_serial())
55 ])
56 .unwrap()
57 .device_class(usbd_serial::USB_CLASS_CDC)
58 .build();
59 USB_DEVICE = Some(usb_dev);
60 }
61
62 usb::set_handler(serial::usb_handler);
63
64 let mut draw_target = EpdDrawTarget::default();
65 set_touch_enabled(true);
66 let mut gui = MainGui::new();
67 gui.draw_init(&mut draw_target);
68 draw_target.refresh(false);
69
70 loop {
71 if !HOST_APP.load(Ordering::Relaxed) {
72 while let Some(ev) = next_event() {
73 gui.tick(&mut draw_target, ev);
74 }
75
76 if NEEDS_REFRESH_PROGRAMS.swap(false, Ordering::Relaxed) {
77 if let MainGui::MainPage(page) = &mut gui {
78 page.refresh_buttons();
79 page.draw_init(&mut draw_target);
80 }
81 draw_target.refresh(false);
82 } else if NEEDS_REFRESH.swap(false, Ordering::Relaxed) {
83 gui.draw_init(&mut draw_target);
84 draw_target.refresh(false);
85 } else if !has_event() {
86 // has_event() is a syscall. The SVCall exception is a WFE wakeup event, so we need two
87 // WFEs so we don't immediately wake up.
88 unsafe { asm!("wfe", "wfe") };
89 }
90 }
91 }
92}