Skip to content

Commit

Permalink
UX improvements for loader update interface
Browse files Browse the repository at this point in the history
  • Loading branch information
bunnie committed Nov 20, 2024
1 parent 9c11860 commit ed085f2
Showing 1 changed file with 69 additions and 122 deletions.
191 changes: 69 additions & 122 deletions loader/src/platform/cramium/update.rs
Original file line number Diff line number Diff line change
@@ -1,15 +1,22 @@
use core::fmt::Display;

use cramium_hal::iox::{IoGpio, IoSetup, Iox, IoxPort, IoxValue};
use cramium_hal::minigfx::{FrameBuffer, Point};
use cramium_hal::sh1107::Mono;
use cramium_hal::udma;
use simple_fatfs::io::{IOBase, Read, Seek, SeekFrom, Write};
use simple_fatfs::{IOError, IOErrorKind, PathBuf};
use cramium_hal::usb::driver::UsbDeviceState;
use simple_fatfs::PathBuf;
use utralib::generated::*;

use crate::platform::cramium::gfx;
use crate::platform::cramium::usb;
use crate::platform::cramium::usb::SliceCursor;

// TODO:
// - Port unicode font drawing into loader
// - Support localization

// Empirically measured PORTSC when the port is unplugged. This might be a brittle way
// to detect if the device is unplugged.
const DISCONNECT_STATE: u32 = 0x40b;

#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum KeyPress {
Expand Down Expand Up @@ -69,6 +76,7 @@ pub fn process_update(perclk: u32) {
let mut iox = Iox::new(utra::iox::HW_IOX_BASE as *mut u32);
let mut udma_global = udma::GlobalConfig::new(utra::udma_ctrl::HW_UDMA_CTRL_BASE as *mut u32);

let iox_kbd = iox.clone();
let mut sh1107 = cramium_hal::sh1107::Oled128x128::new(perclk, &mut iox, &mut udma_global);

gfx::msg(&mut sh1107, " START to boot", Point::new(0, 16), Mono::White.into(), Mono::Black.into());
Expand All @@ -78,12 +86,12 @@ pub fn process_update(perclk: u32) {
sh1107.draw();

// setup IO pins to check for update viability
let (rows, cols) = cramium_hal::board::baosec::setup_kb_pins(&iox);
let (rows, cols) = cramium_hal::board::baosec::setup_kb_pins(&iox_kbd);

let mut key_pressed = false;
let mut do_update = false;
while !key_pressed {
let kps = scan_keyboard(&iox, &rows, &cols);
let kps = scan_keyboard(&iox_kbd, &rows, &cols);
for kp in kps {
if kp != KeyPress::None {
crate::println!("Got key: {:?}", kp);
Expand All @@ -94,7 +102,14 @@ pub fn process_update(perclk: u32) {
}
}
}

sh1107.clear();

if do_update {
gfx::msg(&mut sh1107, "Connect to USB", Point::new(16, 64), Mono::White.into(), Mono::Black.into());
sh1107.buffer_swap();
sh1107.draw();

crate::platform::cramium::usb::init_usb();
// it's all unsafe because USB is global mutable state
unsafe {
Expand All @@ -117,16 +132,57 @@ pub fn process_update(perclk: u32) {
usb.start();
usb.update_current_speed();

crate::println!("hw started...");

let mut last_usb_state = usb.get_device_state();
let mut portsc = usb.portsc_val();
crate::println!("USB state: {:?}, {:x}", last_usb_state, portsc);
loop {
let kps = scan_keyboard(&iox, &rows, &cols);
let kps = scan_keyboard(&iox_kbd, &rows, &cols);
// only consider the first key returned in case of multi-key hit, for simplicity
if kps[0] == KeyPress::Select {
break;
} else if kps[0] != KeyPress::None {
crate::println!("Got key {:?}; ignoring", kps[0]);
}
let new_usb_state = usb.get_device_state();
let new_portsc = usb.portsc_val();
// alternately, break out of the loop when USB is disconnected
if new_portsc != portsc {
crate::println!("PP: {:x}", portsc);
portsc = new_portsc;
if portsc == DISCONNECT_STATE && new_usb_state == UsbDeviceState::Configured {
break;
}
}
if new_usb_state != last_usb_state {
crate::println!("USB state: {:?}", new_usb_state);
if new_usb_state == UsbDeviceState::Configured {
sh1107.clear();
gfx::msg(
&mut sh1107,
"Copy files to device",
Point::new(6, 64),
Mono::White.into(),
Mono::Black.into(),
);
gfx::msg(
&mut sh1107,
"Press SELECT",
Point::new(22, 46),
Mono::Black.into(),
Mono::White.into(),
);
gfx::msg(
&mut sh1107,
"when finished!",
Point::new(19, 32),
Mono::Black.into(),
Mono::White.into(),
);
sh1107.buffer_swap();
sh1107.draw();
last_usb_state = new_usb_state;
}
}
}

let disk = usb::conjure_disk();
Expand All @@ -149,118 +205,9 @@ pub fn process_update(perclk: u32) {
}
}
}
}

pub struct SliceCursor<'a> {
slice: &'a mut [u8],
pos: u64,
}

impl<'a> SliceCursor<'a> {
pub fn new(slice: &'a mut [u8]) -> Self { Self { slice, pos: 0 } }
}

#[derive(Debug, PartialEq, Eq, Copy, Clone)]
pub enum IOErrorFatfs {
UnexpectedEof,
Interrupted,
InvalidData,
Description,
SeekUnderflow,
SeekOverflow,
SeekOutOfBounds,
}

impl Display for IOErrorFatfs {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
match self {
IOErrorFatfs::UnexpectedEof => write!(f, "Unexpected EOF"),
IOErrorFatfs::Interrupted => write!(f, "Interrupted"),
IOErrorFatfs::InvalidData => write!(f, "Invalid Data"),
IOErrorFatfs::Description => write!(f, "Unsupported string description"),
IOErrorFatfs::SeekOutOfBounds => write!(f, "Seek out of bounds"),
IOErrorFatfs::SeekOverflow => write!(f, "Seek overflow"),
IOErrorFatfs::SeekUnderflow => write!(f, "Seek underflow"),
}
}
}

impl From<&str> for IOErrorFatfs {
fn from(_value: &str) -> Self { IOErrorFatfs::Description }
}
impl IOErrorKind for IOErrorFatfs {
fn new_unexpected_eof() -> Self { Self::UnexpectedEof }

fn new_invalid_data() -> Self { Self::InvalidData }

fn new_interrupted() -> Self { Self::Interrupted }
}
impl IOError for IOErrorFatfs {
type Kind = IOErrorFatfs;

fn new<M>(kind: Self::Kind, _msg: M) -> Self
where
M: core::fmt::Display,
{
kind
}

fn kind(&self) -> Self::Kind { *self }
}

impl simple_fatfs::Error for IOErrorFatfs {}

impl IOBase for SliceCursor<'_> {
type Error = IOErrorFatfs;
}

impl Seek for SliceCursor<'_> {
fn seek(&mut self, seek_from: simple_fatfs::io::SeekFrom) -> Result<u64, Self::Error> {
let new_pos = match seek_from {
SeekFrom::Start(offset) => offset,
SeekFrom::End(offset) => {
let result = if offset < 0 {
self.slice.len().checked_sub((-offset) as usize).ok_or(IOErrorFatfs::SeekUnderflow)?
} else {
self.slice.len().checked_add(offset as usize).ok_or(IOErrorFatfs::SeekOverflow)?
};
result as u64
}
SeekFrom::Current(offset) => {
if offset < 0 {
self.pos.checked_sub((-offset) as u64).ok_or(IOErrorFatfs::SeekUnderflow)?
} else {
self.pos.checked_add(offset as u64).ok_or(IOErrorFatfs::SeekUnderflow)?
}
}
};

if new_pos > self.slice.len() as u64 {
Err(IOErrorFatfs::SeekOutOfBounds)
} else {
self.pos = new_pos;
Ok(self.pos)
}
}
}

impl Read for SliceCursor<'_> {
fn read(&mut self, buf: &mut [u8]) -> Result<usize, Self::Error> {
let available = &self.slice[self.pos as usize..];
let to_read = buf.len().min(available.len());
buf[..to_read].copy_from_slice(&available[..to_read]);
self.pos += to_read as u64;
Ok(to_read)
}
}
impl Write for SliceCursor<'_> {
fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Error> {
let available = &mut self.slice[self.pos as usize..];
let to_write = buf.len().min(available.len());
available[..to_write].copy_from_slice(&buf[..to_write]);
self.pos += to_write as u64;
Ok(to_write)
}

fn flush(&mut self) -> Result<(), Self::Error> { Ok(()) }
gfx::msg(&mut sh1107, " Booting Xous...", Point::new(0, 64), Mono::White.into(), Mono::Black.into());
sh1107.buffer_swap();
sh1107.draw();
sh1107.clear();
}

0 comments on commit ed085f2

Please sign in to comment.