diff --git a/loader/src/platform/cramium/update.rs b/loader/src/platform/cramium/update.rs index ddad83f16..33b96c123 100644 --- a/loader/src/platform/cramium/update.rs +++ b/loader/src/platform/cramium/update.rs @@ -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 { @@ -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()); @@ -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); @@ -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 { @@ -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(); @@ -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(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 { - 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 { - 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 { - 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(); }