This commit is contained in:
2025-11-18 15:20:03 -07:00
parent 49c11978d5
commit cc31cb4711
20 changed files with 182 additions and 197 deletions

View File

@@ -11,7 +11,7 @@ doctest = false
bench = false
[features]
default = ["rp235x", "defmt"]
default = ["rp235x"]
pimoroni2w = ["rp235x", "psram"]
# rp2040 = ["embassy-rp/rp2040"] # unsupported, ram too small for fb
rp235x = ["embassy-rp/rp235xb"]

View File

@@ -14,7 +14,7 @@ use std::io::Write;
use std::path::PathBuf;
#[cfg(all(feature = "rp235x", not(feature = "pimoroni2w")))]
const MEMORY: &'static [u8] = include_bytes!("rp2350.x");
const MEMORY: &[u8] = include_bytes!("rp2350.x");
#[cfg(feature = "pimoroni2w")]
const MEMORY: &'static [u8] = include_bytes!("rp2350.x");

View File

@@ -120,8 +120,10 @@ impl<'d, PIO: Instance, const SM: usize> PioPwmAudio<'d, PIO, SM> {
let mut cfg = Config::default();
cfg.set_set_pins(&[&pin]);
cfg.fifo_join = FifoJoin::TxOnly;
let mut shift_cfg = ShiftConfig::default();
shift_cfg.auto_fill = true;
let shift_cfg = ShiftConfig {
auto_fill: true,
..Default::default()
};
cfg.shift_out = shift_cfg;
cfg.use_program(&prg.0, &[]);
sm.set_config(&cfg);

View File

@@ -1,5 +1,4 @@
use crate::framebuffer::{self, AtomicFrameBuffer, FB_PAUSED};
use core::alloc::{GlobalAlloc, Layout};
use core::sync::atomic::Ordering;
use embassy_futures::yield_now;
use embassy_rp::{
@@ -9,17 +8,20 @@ use embassy_rp::{
spi::{Async, Spi},
};
use embassy_time::Delay;
use embedded_graphics::{draw_target::DrawTarget, pixelcolor::Rgb565, prelude::RgbColor};
use embedded_hal_bus::spi::ExclusiveDevice;
use st7365p_lcd::ST7365P;
#[cfg(feature = "psram")]
use crate::heap::HEAP;
#[cfg(feature = "psram")]
use core::alloc::{GlobalAlloc, Layout};
#[cfg(feature = "psram")]
use embedded_graphics::{draw_target::DrawTarget, pixelcolor::Rgb565, prelude::RgbColor};
#[cfg(feature = "fps")]
pub use framebuffer::fps::{FPS_CANVAS, FPS_COUNTER};
type DISPLAY = ST7365P<
type Display = ST7365P<
ExclusiveDevice<Spi<'static, SPI1, Async>, Output<'static>, Delay>,
Output<'static>,
Output<'static>,
@@ -56,7 +58,7 @@ pub async fn init_display(
cs: Peri<'static, PIN_13>,
data: Peri<'static, PIN_14>,
reset: Peri<'static, PIN_15>,
) -> DISPLAY {
) -> Display {
init_fb();
let spi_device = ExclusiveDevice::new(spi, Output::new(cs, Level::Low), Delay).unwrap();
@@ -84,7 +86,7 @@ pub async fn init_display(
}
#[embassy_executor::task]
pub async fn display_handler(mut display: DISPLAY) {
pub async fn display_handler(mut display: Display) {
use embassy_time::{Instant, Timer};
// Target ~60 Hz refresh (≈16.67 ms per frame)
@@ -111,7 +113,7 @@ pub async fn display_handler(mut display: DISPLAY) {
}
}
let elapsed = start.elapsed().as_millis() as u64;
let elapsed = start.elapsed().as_millis();
if elapsed < FRAME_TIME_MS {
Timer::after_millis(FRAME_TIME_MS - elapsed).await;
} else {

View File

@@ -39,7 +39,7 @@ pub async unsafe fn load_binary(name: &ShortFileName) -> Option<(EntryFn, Bump)>
let mut ph_buf = vec![0_u8; elf_header.e_phentsize as usize];
let (total_size, min_vaddr, _max_vaddr) =
total_loadable_size(&mut file, &elf_header, &mut ph_buf);
total_loadable_size(&mut file, elf_header, &mut ph_buf);
let bump = Bump::with_capacity(total_size);
let base = bump.alloc_slice_fill_default::<u8>(total_size);
@@ -52,25 +52,22 @@ pub async unsafe fn load_binary(name: &ShortFileName) -> Option<(EntryFn, Bump)>
let ph = cast_phdr(&ph_buf);
let seg_offset = (ph.p_vaddr - min_vaddr) as usize;
let mut segment = &mut base[seg_offset..seg_offset + ph.p_memsz as usize];
let segment = &mut base[seg_offset..seg_offset + ph.p_memsz as usize];
if ph.p_type == PT_LOAD {
load_segment(&mut file, &ph, &mut segment).unwrap();
load_segment(&mut file, &ph, segment).unwrap();
}
}
for i in 0..elf_header.e_shnum {
let sh = read_section(&mut file, elf_header, i.into());
match sh.sh_type {
SHT_REL => {
if sh.sh_type == SHT_REL {
apply_relocations(&sh, min_vaddr, base.as_mut_ptr(), &mut file).unwrap();
}
_ => {}
}
}
patch_syscalls(&elf_header, base.as_mut_ptr(), min_vaddr, &mut file).unwrap();
patch_syscalls(elf_header, base.as_mut_ptr(), min_vaddr, &mut file).unwrap();
// entry pointer is base_ptr + (entry - min_vaddr)
let entry_ptr: EntryFn = unsafe {
@@ -157,7 +154,7 @@ fn patch_syscalls(
file: &mut File,
) -> Result<(), ()> {
for i in 1..=elf_header.e_shnum {
let sh = read_section(file, &elf_header, i.into());
let sh = read_section(file, elf_header, i.into());
// find the symbol table
if sh.sh_type == SHT_SYMTAB {
@@ -172,7 +169,7 @@ fn patch_syscalls(
&symtab_buf[i * sh.sh_entsize as usize..(i + 1) * sh.sh_entsize as usize];
let sym = cast_sym(sym_bytes);
let str_sh = read_section(file, &elf_header, sh.sh_link);
let str_sh = read_section(file, elf_header, sh.sh_link);
let mut name = Vec::new();
file.seek_from_start(str_sh.sh_offset + sym.st_name)
@@ -211,7 +208,7 @@ fn patch_syscalls(
SyscallTable::SendAudioBuffer => syscalls::send_audio_buffer as usize,
};
unsafe {
table_base.add(idx as usize).write(ptr);
table_base.add(idx).write(ptr);
}
}
return Ok(());
@@ -233,7 +230,7 @@ fn total_loadable_size(
file.seek_from_start(elf_header.e_phoff + (elf_header.e_phentsize * i) as u32)
.unwrap();
file.read(ph_buf).unwrap();
let ph = cast_phdr(&ph_buf);
let ph = cast_phdr(ph_buf);
if ph.p_type == PT_LOAD {
if ph.p_vaddr < min_vaddr {

View File

@@ -46,7 +46,7 @@ impl<'a> AtomicFrameBuffer<'a> {
}
fn mark_tiles_dirty(&mut self, rect: Rectangle) {
let tiles_x = (SCREEN_WIDTH + TILE_SIZE - 1) / TILE_SIZE;
let tiles_x = SCREEN_WIDTH.div_ceil(TILE_SIZE);
let start_tx = (rect.top_left.x as usize) / TILE_SIZE;
let end_tx = ((rect.top_left.x + rect.size.width as i32 - 1) as usize) / TILE_SIZE;
let start_ty = (rect.top_left.y as usize) / TILE_SIZE;
@@ -346,11 +346,10 @@ impl<'a> DrawTarget for AtomicFrameBuffer<'a> {
}
}
if changed {
if let Some(rect) = dirty_rect {
if changed
&& let Some(rect) = dirty_rect {
self.mark_tiles_dirty(rect);
}
}
Ok(())
}
@@ -402,7 +401,7 @@ impl<'a> DrawTarget for AtomicFrameBuffer<'a> {
fn fill_solid(&mut self, area: &Rectangle, color: Self::Color) -> Result<(), Self::Error> {
self.fill_contiguous(
area,
core::iter::repeat(color).take((self.size().width * self.size().height) as usize),
core::iter::repeat_n(color, (self.size().width * self.size().height) as usize),
)
}
@@ -412,8 +411,7 @@ impl<'a> DrawTarget for AtomicFrameBuffer<'a> {
0,
self.size().width as u16 - 1,
self.size().height as u16 - 1,
core::iter::repeat(RawU16::from(color).into_inner())
.take((self.size().width * self.size().height) as usize),
core::iter::repeat_n(RawU16::from(color).into_inner(), (self.size().width * self.size().height) as usize),
)?;
for tile in self.dirty_tiles.iter() {

View File

@@ -12,11 +12,15 @@ mod audio;
mod display;
mod elf;
mod framebuffer;
// TODO: NEED TO UPDATE MCU TO TEST BATTERY READS
#[allow(unused)]
mod peripherals;
#[allow(unused)]
mod scsi;
mod storage;
mod syscalls;
mod ui;
#[allow(unused)]
mod usb;
mod utils;
@@ -28,7 +32,7 @@ mod heap;
mod psram;
#[cfg(feature = "psram")]
use crate::{heap::HEAP, heap::init_qmi_psram_heap, psram::init_psram, psram::init_psram_qmi};
use crate::{heap::init_qmi_psram_heap, psram::init_psram_qmi};
use crate::{
audio::audio_handler,
@@ -102,7 +106,7 @@ async fn watchdog_task(mut watchdog: Watchdog) {
ResetReason::Forced => "forced",
ResetReason::TimedOut => "timed out",
};
#[cfg(feature = "debug")]
#[cfg(feature = "defmt")]
defmt::error!("Watchdog reset reason: {}", _reason);
}
@@ -321,7 +325,7 @@ async fn setup_display(display: Display, spawner: Spawner) {
async fn setup_qmi_psram() {
Timer::after_millis(250).await;
let psram_qmi_size = init_psram_qmi(&embassy_rp::pac::QMI, &embassy_rp::pac::XIP_CTRL);
#[cfg(feature = "debug")]
#[cfg(feature = "defmt")]
defmt::info!("size: {}", psram_qmi_size);
Timer::after_millis(100).await;
@@ -363,7 +367,7 @@ async fn kernel_task(
.spawn(watchdog_task(Watchdog::new(watchdog)))
.unwrap();
#[cfg(feature = "debug")]
#[cfg(feature = "defmt")]
defmt::info!("Clock: {}", embassy_rp::clocks::clk_sys_freq());
setup_mcu(mcu).await;

View File

@@ -526,7 +526,7 @@ pub fn init_psram_qmi(
let psram_size = detect_psram_qmi(qmi);
if psram_size == 0 {
#[cfg(feature = "debug")]
#[cfg(feature = "defmt")]
defmt::error!("qmi psram size 0");
return 0;
}

View File

@@ -30,7 +30,7 @@ pub struct MassStorageClass<'d, D: Driver<'d>> {
bulk_in: D::EndpointIn,
}
impl<'d, 's, D: Driver<'d>> MassStorageClass<'d, D> {
impl<'d, D: Driver<'d>> MassStorageClass<'d, D> {
pub fn new(builder: &mut Builder<'d, D>, temp_sd: Option<SdCard>) -> Self {
let mut function = builder.function(0x08, SUBCLASS_SCSI, 0x50); // Mass Storage class
let mut interface = function.interface();
@@ -72,9 +72,10 @@ impl<'d, 's, D: Driver<'d>> MassStorageClass<'d, D> {
async fn handle_cbw(&mut self) {
let mut cbw_buf = [0u8; 31];
if let Ok(n) = self.bulk_out.read(&mut cbw_buf).await {
if n == 31 {
if let Some(cbw) = CommandBlockWrapper::parse(&cbw_buf[..n]) {
if let Ok(n) = self.bulk_out.read(&mut cbw_buf).await
&& n == 31
&& let Some(cbw) = CommandBlockWrapper::parse(&cbw_buf[..n])
{
// Take sdcard to increase speed
if self.temp_sd.is_none() {
let mut guard = SDCARD.get().lock().await;
@@ -94,15 +95,13 @@ impl<'d, 's, D: Driver<'d>> MassStorageClass<'d, D> {
self.send_csw_fail(cbw.dCBWTag).await
}
if self.pending_eject {
if let ScsiCommand::Write { lba: _, len: _ } = command {
if self.pending_eject
&& let ScsiCommand::Write { lba: _, len: _ } = command
{
MSC_SHUTDOWN.signal(());
}
}
}
}
}
}
async fn handle_command(&mut self, command: ScsiCommand) -> Result<(), ()> {
let mut response: Vec<u8, BULK_ENDPOINT_PACKET_SIZE> = Vec::new();
@@ -238,7 +237,7 @@ impl<'d, 's, D: Driver<'d>> MassStorageClass<'d, D> {
let block_size = SdCard::BLOCK_SIZE as u64;
let total_blocks = self.temp_sd.as_ref().unwrap().size() / block_size;
let last_lba = total_blocks.checked_sub(1).unwrap_or(0);
let last_lba = total_blocks.saturating_sub(1);
response.extend_from_slice(&(last_lba as u32).to_be_bytes())?;
response.extend_from_slice(&(block_size as u32).to_be_bytes())?;
@@ -249,7 +248,7 @@ impl<'d, 's, D: Driver<'d>> MassStorageClass<'d, D> {
let block_size = SdCard::BLOCK_SIZE as u64;
let total_blocks = self.temp_sd.as_ref().unwrap().size() / block_size;
let last_lba = total_blocks.checked_sub(1).unwrap_or(0);
let last_lba = total_blocks.saturating_sub(1);
response.extend_from_slice(&last_lba.to_be_bytes())?; // 8 bytes last LBA
response.extend_from_slice(&(block_size as u32).to_be_bytes())?; // 4 bytes block length
@@ -269,7 +268,7 @@ impl<'d, 's, D: Driver<'d>> MassStorageClass<'d, D> {
sdcard.read_blocks(block_buf, BlockIdx(idx as u32))?;
for block in &mut *block_buf {
for chunk in block.contents.chunks(BULK_ENDPOINT_PACKET_SIZE.into()) {
for chunk in block.contents.chunks(BULK_ENDPOINT_PACKET_SIZE) {
self.bulk_in.write(chunk).await.map_err(|_| ())?;
}
}
@@ -281,7 +280,7 @@ impl<'d, 's, D: Driver<'d>> MassStorageClass<'d, D> {
.read_blocks(&mut block_buf[..blocks as usize], BlockIdx(idx as u32))?;
for block in &block_buf[..blocks as usize] {
for chunk in block.contents.chunks(BULK_ENDPOINT_PACKET_SIZE.into()) {
for chunk in block.contents.chunks(BULK_ENDPOINT_PACKET_SIZE) {
self.bulk_in.write(chunk).await.map_err(|_| ())?;
}
}
@@ -301,8 +300,7 @@ impl<'d, 's, D: Driver<'d>> MassStorageClass<'d, D> {
while blocks > 0 {
if blocks >= block_buf.len() as u64 {
for block in block_buf.as_mut() {
for chunk in block.contents.chunks_mut(BULK_ENDPOINT_PACKET_SIZE.into())
{
for chunk in block.contents.chunks_mut(BULK_ENDPOINT_PACKET_SIZE) {
self.bulk_out.read(chunk).await.map_err(|_| ())?;
}
}
@@ -313,8 +311,7 @@ impl<'d, 's, D: Driver<'d>> MassStorageClass<'d, D> {
idx += block_buf.len() as u64;
} else {
for block in block_buf[..blocks as usize].as_mut() {
for chunk in block.contents.chunks_mut(BULK_ENDPOINT_PACKET_SIZE.into())
{
for chunk in block.contents.chunks_mut(BULK_ENDPOINT_PACKET_SIZE) {
self.bulk_out.read(chunk).await.map_err(|_| ())?;
}
}

View File

@@ -1,7 +1,7 @@
use num_enum::TryFromPrimitive;
/// THE CODE BELOW ORIGINATES FROM: https://github.com/apohrebniak/usbd-storage/blob/master/usbd-storage/src/subclass/scsi.rs
///
/// SCSI device subclass code
pub const SUBCLASS_SCSI: u8 = 0x06; // SCSI Transparent command set
@@ -91,6 +91,7 @@ pub enum ScsiCommand {
},
}
#[allow(clippy::enum_variant_names)]
#[repr(u8)]
#[derive(Copy, Clone, Debug, TryFromPrimitive)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]

View File

@@ -9,8 +9,8 @@ use embassy_sync::mutex::Mutex;
use embassy_time::Delay;
use embedded_hal_bus::spi::ExclusiveDevice;
use embedded_sdmmc::{
Block, BlockCount, BlockDevice, BlockIdx, Directory, SdCard as SdmmcSdCard, TimeSource,
Timestamp, Volume, VolumeIdx, VolumeManager, sdcard::Error,
Block, BlockDevice, BlockIdx, Directory, SdCard as SdmmcSdCard, TimeSource, Timestamp,
VolumeIdx, VolumeManager, sdcard::Error,
};
use embedded_sdmmc::{File as SdFile, LfnBuffer, Mode, ShortFileName};
@@ -21,7 +21,6 @@ pub const MAX_VOLUMES: usize = 1;
type Device = ExclusiveDevice<Spi<'static, SPI0, Blocking>, Output<'static>, embassy_time::Delay>;
type SD = SdmmcSdCard<Device, Delay>;
type VolMgr = VolumeManager<SD, DummyTimeSource, MAX_DIRS, MAX_FILES, MAX_VOLUMES>;
type Vol<'a> = Volume<'a, SD, DummyTimeSource, MAX_DIRS, MAX_FILES, MAX_VOLUMES>;
pub type Dir<'a> = Directory<'a, SD, DummyTimeSource, MAX_DIRS, MAX_FILES, MAX_VOLUMES>;
pub type File<'a> = SdFile<'a, SD, DummyTimeSource, MAX_DIRS, MAX_FILES, MAX_VOLUMES>;
@@ -43,7 +42,7 @@ pub struct FileName {
impl PartialOrd for FileName {
fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
Some(self.long_name.cmp(&other.long_name))
Some(self.cmp(other))
}
}
@@ -67,10 +66,7 @@ impl SdCard {
DummyTimeSource {},
5000,
);
Self {
det: det,
volume_mgr,
}
Self { det, volume_mgr }
}
/// Returns true if an SD card is inserted.
@@ -90,17 +86,6 @@ impl SdCard {
result
}
pub fn num_blocks(&self) -> u32 {
let mut result = 0;
self.volume_mgr.device(|sd| {
result = sd.num_blocks().unwrap_or(BlockCount(0)).0;
DummyTimeSource {}
});
result
}
pub fn read_blocks(&self, blocks: &mut [Block], start_block_idx: BlockIdx) -> Result<(), ()> {
let mut res: Result<(), Error> = Ok(());
self.volume_mgr.device(|sd| {

View File

@@ -35,7 +35,7 @@ pub extern "C" fn alloc(layout: CLayout) -> *mut u8 {
#[cfg(not(feature = "psram"))]
{
return alloc::alloc::alloc(layout.into());
alloc::alloc::alloc(layout.into())
}
}
}
@@ -134,7 +134,7 @@ unsafe fn copy_entry_to_user_buf(name: &[u8], dest: *mut c_char, max_str_len: us
if !dest.is_null() {
let len = name.len().min(max_str_len - 1);
unsafe {
ptr::copy_nonoverlapping(name.as_ptr(), dest as *mut u8, len);
ptr::copy_nonoverlapping(name.as_ptr(), dest, len);
*dest.add(len) = 0; // nul terminator
}
}
@@ -191,7 +191,7 @@ pub extern "C" fn list_dir(
let mut wrote = 0;
sd.access_root_dir(|root| {
if dirs[0] == "" && dirs.len() >= 2 {
if dirs[0].is_empty() && dirs.len() >= 2 {
unsafe {
if dir == "/" {
wrote = get_dir_entries(&root, files, max_entry_str_len);
@@ -214,11 +214,11 @@ fn recurse_file<T>(
let mut buf = LfnBuffer::new(&mut b);
let mut short_name = None;
dir.iterate_dir_lfn(&mut buf, |entry, name| {
if let Some(name) = name {
if name == dirs[0] || entry.name.to_string().as_str() == dirs[0] {
if let Some(name) = name
&& (name == dirs[0] || entry.name.to_string().as_str() == dirs[0])
{
short_name = Some(entry.name.clone());
}
}
})
.expect("Failed to iterate dir");
@@ -257,7 +257,7 @@ pub extern "C" fn read_file(
}
// SAFETY: caller guarantees `ptr` is valid for `len` bytes
let mut buf = unsafe { core::slice::from_raw_parts_mut(buf, buf_len) };
let buf = unsafe { core::slice::from_raw_parts_mut(buf, buf_len) };
let mut read = 0;
@@ -267,7 +267,7 @@ pub extern "C" fn read_file(
sd.access_root_dir(|root| {
if let Ok(result) = recurse_file(&root, &components[1..count], |file| {
file.seek_from_start(start_from as u32).unwrap_or(());
file.read(&mut buf).unwrap()
file.read(buf).unwrap()
}) {
read = result
};
@@ -306,7 +306,7 @@ pub extern "C" fn write_file(
sd.access_root_dir(|root| {
recurse_file(&root, &components[1..count], |file| {
file.seek_from_start(start_from as u32).unwrap();
file.write(&buf).unwrap()
file.write(buf).unwrap()
})
.unwrap_or(())
});
@@ -343,7 +343,9 @@ pub extern "C" fn send_audio_buffer(ptr: *const u8, len: usize) {
// SAFETY: caller guarantees `ptr` is valid for `len` bytes
let buf = unsafe { core::slice::from_raw_parts(ptr, len) };
while !AUDIO_BUFFER_READY.load(Ordering::Acquire) {}
while !AUDIO_BUFFER_READY.load(Ordering::Acquire) {
core::hint::spin_loop();
}
if buf.len() == AUDIO_BUFFER_SAMPLES * 2 {
AUDIO_BUFFER_READY.store(false, Ordering::Release);

View File

@@ -2,7 +2,6 @@ use crate::{
BINARY_CH, display::FRAMEBUFFER, elf::load_binary, framebuffer::FB_PAUSED,
peripherals::keyboard, storage::FileName,
};
use userlib_sys::keyboard::{KeyCode, KeyState};
use alloc::{str::FromStr, string::String, vec::Vec};
use core::sync::atomic::Ordering;
use embassy_sync::{blocking_mutex::raw::CriticalSectionRawMutex, mutex::Mutex};
@@ -20,14 +19,16 @@ use embedded_layout::{
prelude::*,
};
use embedded_text::TextBox;
use userlib_sys::keyboard::{KeyCode, KeyState};
pub static SELECTIONS: Mutex<CriticalSectionRawMutex, SelectionList> =
Mutex::new(SelectionList::new());
pub async fn ui_handler() {
loop {
if let Some(event) = keyboard::read_keyboard_fifo().await {
if let KeyState::Pressed = event.state {
if let Some(event) = keyboard::read_keyboard_fifo().await
&& let KeyState::Pressed = event.state
{
match event.key {
KeyCode::Up => {
let mut selections = SELECTIONS.lock().await;
@@ -52,7 +53,6 @@ pub async fn ui_handler() {
_ => (),
}
}
}
let changed = SELECTIONS.lock().await.changed;
if changed {

View File

@@ -51,16 +51,15 @@ impl<'a> SelectionUi<'a> {
let selection;
loop {
let key = get_key();
if key.state == KeyState::Pressed {
if let Some(s) = self.update(display, key.key)? {
if key.state == KeyState::Pressed
&& let Some(s) = self.update(display, key.key)? {
selection = Some(s);
display
.clear(Rgb565::BLACK)
.map_err(|e| SelectionUiError::DisplayError(e))?;
.map_err(SelectionUiError::DisplayError)?;
break;
}
}
}
Ok(selection)
}
@@ -100,7 +99,7 @@ impl<'a> SelectionUi<'a> {
Rectangle::new(bounds.top_left, bounds.size)
.into_styled(PrimitiveStyle::with_fill(Rgb565::BLACK))
.draw(display)
.map_err(|e| SelectionUiError::DisplayError(e))?;
.map_err(SelectionUiError::DisplayError)?;
}
let mut views: Vec<Text<MonoTextStyle<Rgb565>>> = Vec::new();
@@ -119,7 +118,7 @@ impl<'a> SelectionUi<'a> {
layout
.draw(display)
.map_err(|e| SelectionUiError::DisplayError(e))?;
.map_err(SelectionUiError::DisplayError)?;
// draw selected box
if let Some(selected_bounds) = layout.inner().get(self.selection) {
@@ -127,7 +126,7 @@ impl<'a> SelectionUi<'a> {
Rectangle::new(selected_bounds.top_left, selected_bounds.size)
.into_styled(PrimitiveStyle::with_stroke(Rgb565::WHITE, 1))
.draw(display)
.map_err(|e| SelectionUiError::DisplayError(e))?;
.map_err(SelectionUiError::DisplayError)?;
self.last_bounds = Some(selected_bounds);
}
@@ -136,9 +135,9 @@ impl<'a> SelectionUi<'a> {
}
}
pub fn draw_text_center<'a, S>(
pub fn draw_text_center<S>(
display: &mut Display,
text: &'a str,
text: &str,
style: S,
) -> Result<Point, <Display as DrawTarget>::Error>
where

View File

@@ -83,7 +83,7 @@ pub fn main() {
.align_to(&display.bounding_box(), horizontal::Left, vertical::Center);
let result = if let Ok(result) = evaluate(&input[input_min..]) {
&format!(" = {}", result)
&format!(" = {result}")
} else {
" = Error"
};

View File

@@ -51,9 +51,9 @@ pub fn main() {
println!("file: {}", file);
if file.extension().unwrap_or("") == "bmp" || file.extension().unwrap_or("") == "BMP" {
let file_path = format!("/images/{}", file);
let file_path = format!("/images/{file}");
let read = read_file(&file_path, 0, &mut &mut bmp_buf[..]);
let read = read_file(&file_path, 0, &mut bmp_buf[..]);
if read > 0 {
let bmp = Bmp::from_slice(&bmp_buf).expect("failed to parse bmp");
@@ -74,7 +74,7 @@ pub fn main() {
let text_style = MonoTextStyle::new(&FONT_6X10, Rgb565::WHITE);
let text_y = y + bmp_h + 2; // 2px gap under image
Text::new(&file.base(), Point::new(cell_x + 2, text_y), text_style)
Text::new(file.base(), Point::new(cell_x + 2, text_y), text_style)
.draw(&mut display)
.unwrap();
@@ -85,11 +85,8 @@ pub fn main() {
loop {
let event = get_key();
if event.state != KeyState::Idle {
match event.key {
KeyCode::Esc => return,
_ => (),
if event.state != KeyState::Idle && event.key == KeyCode::Esc {
return;
}
};
}
}

View File

@@ -6,16 +6,16 @@ use alloc::{format, vec, vec::Vec};
use core::panic::PanicInfo;
use embedded_graphics::{
image::ImageDrawable,
mono_font::{ascii::FONT_6X10, MonoTextStyle},
mono_font::{MonoTextStyle, ascii::FONT_6X10},
pixelcolor::Rgb565,
prelude::{Point, RgbColor},
transform::Transform,
};
use selection_ui::{draw_text_center, SelectionUi, SelectionUiError};
use selection_ui::{SelectionUi, SelectionUiError, draw_text_center};
use tinygif::Gif;
use userlib::{
display::{Display, SCREEN_HEIGHT, SCREEN_WIDTH},
fs::{file_len, list_dir, read_file, Entries},
fs::{Entries, file_len, list_dir, read_file},
get_key, get_ms,
keyboard::{KeyCode, KeyState},
println, sleep,
@@ -44,7 +44,7 @@ pub fn main() {
let mut gifs = files.iter().map(|e| e.full_name()).collect::<Vec<&str>>();
gifs.sort();
let mut selection_ui = SelectionUi::new(&mut gifs);
let mut selection_ui = SelectionUi::new(&gifs);
let selection = match selection_ui.run_selection_ui(&mut display) {
Ok(maybe_sel) => maybe_sel,
Err(e) => match e {
@@ -87,14 +87,9 @@ pub fn main() {
if frame_num % 5 == 0 {
let event = get_key();
if event.state != KeyState::Idle {
match event.key {
KeyCode::Esc => {
if event.state != KeyState::Idle && event.key == KeyCode::Esc {
drop(buf);
return;
}
_ => (),
};
};
}
sleep(((frame.delay_centis as u64) * 10).saturating_sub(start));

View File

@@ -4,18 +4,18 @@
extern crate alloc;
use alloc::{string::String, vec::Vec};
use core::panic::PanicInfo;
use embedded_audio::{wav::Wav, AudioFile, PlatformFile, PlatformFileError};
use embedded_audio::{AudioFile, PlatformFile, PlatformFileError, wav::Wav};
use embedded_graphics::{
mono_font::{ascii::FONT_6X10, MonoTextStyle},
mono_font::{MonoTextStyle, ascii::FONT_6X10},
pixelcolor::Rgb565,
prelude::RgbColor,
};
use selection_ui::{draw_text_center, SelectionUi, SelectionUiError};
use selection_ui::{SelectionUi, SelectionUiError, draw_text_center};
use userlib::{
audio::{audio_buffer_ready, send_audio_buffer, AUDIO_BUFFER_LEN},
audio::{AUDIO_BUFFER_LEN, audio_buffer_ready, send_audio_buffer},
display::Display,
format,
fs::{file_len, list_dir, read_file, Entries},
fs::{Entries, file_len, list_dir, read_file},
get_key,
keyboard::{KeyCode, KeyState},
println,
@@ -45,7 +45,7 @@ pub fn main() {
let mut wavs = files.iter().map(|e| e.full_name()).collect::<Vec<&str>>();
wavs.sort();
let mut selection_ui = SelectionUi::new(&mut wavs);
let mut selection_ui = SelectionUi::new(&wavs);
let selection = match selection_ui.run_selection_ui(&mut display) {
Ok(maybe_sel) => maybe_sel,
Err(e) => match e {
@@ -72,7 +72,7 @@ pub fn main() {
.expect("Display Error");
let file_name = format!("/music/{}", wavs[selection.unwrap()]);
let file = File::new(String::from(file_name));
let file = File::new(file_name);
let mut wav = Wav::new(file).unwrap();
println!("sample rate: {}", wav.sample_rate());
println!("channels: {:?}", wav.channels() as u8);
@@ -90,11 +90,8 @@ pub fn main() {
}
let event = get_key();
if event.state == KeyState::Released {
match event.key {
KeyCode::Esc => return,
_ => (),
}
if event.state == KeyState::Released && event.key == KeyCode::Esc {
return;
}
}
}

View File

@@ -228,6 +228,12 @@ pub mod fs {
#[derive(Clone, Copy, Debug)]
pub struct Entries([[u8; MAX_ENTRY_NAME_LEN]; MAX_ENTRIES]);
impl Default for Entries {
fn default() -> Self {
Self::new()
}
}
impl Entries {
pub fn new() -> Self {
Self([[0; MAX_ENTRY_NAME_LEN]; MAX_ENTRIES])

View File

@@ -46,9 +46,9 @@ pub struct CLayout {
}
#[cfg(feature = "alloc")]
impl Into<Layout> for CLayout {
fn into(self) -> Layout {
unsafe { Layout::from_size_align_unchecked(self.size, self.alignment) }
impl From<CLayout> for Layout {
fn from(val: CLayout) -> Self {
unsafe { Layout::from_size_align_unchecked(val.size, val.alignment) }
}
}
@@ -106,7 +106,7 @@ pub extern "C" fn get_ms() -> u64 {
}
#[repr(C)]
#[derive(Copy, Clone)]
#[derive(Default, Copy, Clone)]
pub struct CPixel {
pub x: i32,
pub y: i32,
@@ -123,19 +123,22 @@ impl CPixel {
}
}
impl Into<CPixel> for Pixel<Rgb565> {
fn into(self) -> CPixel {
CPixel {
x: self.0.x,
y: self.0.y,
color: self.1.into_storage(),
}
impl From<CPixel> for Pixel<Rgb565> {
fn from(value: CPixel) -> Self {
Pixel(
Point::new(value.x, value.y),
RawU16::new(value.color).into(),
)
}
}
impl Into<Pixel<Rgb565>> for CPixel {
fn into(self) -> Pixel<Rgb565> {
Pixel(Point::new(self.x, self.y), RawU16::new(self.color).into())
impl From<Pixel<Rgb565>> for CPixel {
fn from(value: Pixel<Rgb565>) -> Self {
CPixel {
x: value.0.x,
y: value.0.y,
color: value.1.into_storage(),
}
}
}
@@ -171,12 +174,12 @@ pub mod keyboard {
pub mods: Modifiers,
}
impl Into<KeyEvent> for KeyEventC {
fn into(self) -> KeyEvent {
impl From<KeyEventC> for KeyEvent {
fn from(val: KeyEventC) -> Self {
KeyEvent {
key: self.key.into(),
state: self.state,
mods: self.mods,
key: val.key.into(),
state: val.state,
mods: val.mods,
}
}
}
@@ -188,12 +191,12 @@ pub mod keyboard {
pub mods: Modifiers,
}
impl Into<KeyEventC> for KeyEvent {
fn into(self) -> KeyEventC {
impl From<KeyEvent> for KeyEventC {
fn from(val: KeyEvent) -> Self {
KeyEventC {
key: self.key.into(),
state: self.state,
mods: self.mods,
key: val.key.into(),
state: val.state,
mods: val.mods,
}
}
}
@@ -267,9 +270,9 @@ pub mod keyboard {
Unknown(u8),
}
impl Into<u8> for KeyCode {
fn into(self) -> u8 {
match self {
impl From<KeyCode> for u8 {
fn from(val: KeyCode) -> Self {
match val {
KeyCode::JoyUp => 0x01,
KeyCode::JoyDown => 0x02,
KeyCode::JoyLeft => 0x03,