diff --git a/firmware/acid-firmware/src/db/mod.rs b/firmware/acid-firmware/src/db/mod.rs index e11b98f..d8d1e97 100644 --- a/firmware/acid-firmware/src/db/mod.rs +++ b/firmware/acid-firmware/src/db/mod.rs @@ -10,6 +10,7 @@ use ekv::{ }; use embassy_embedded_hal::{adapter::BlockingAsync, flash::partition::Partition}; use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; +use embassy_sync_old::blocking_mutex::raw::CriticalSectionRawMutex as CriticalSectionRawMutexOld; use embedded_storage_async::nor_flash::{NorFlash, ReadNorFlash}; use esp_hal::rng::Trng; use esp_storage::FlashStorage; @@ -102,11 +103,11 @@ impl ekv::flash::Flash for EkvFlash { } pub struct AcidDatabase { - db: Database, esp_sync::RawMutex>, + db: Database, CriticalSectionRawMutexOld>, } impl Deref for AcidDatabase { - type Target = Database, esp_sync::RawMutex>; + type Target = Database, CriticalSectionRawMutexOld>; fn deref(&self) -> &Self::Target { &self.db @@ -125,7 +126,7 @@ impl AcidDatabase { db_config.random_seed = Trng::try_new() .expect("A `TrngSource` was not initialized before constructing this `Trng`.") .random(); - let db = Database::<_, esp_sync::RawMutex>::new(EkvFlash::new(flash), db_config); + let db = Database::<_, CriticalSectionRawMutexOld>::new(EkvFlash::new(flash), db_config); #[cfg(feature = "format-db")] { diff --git a/firmware/acid-firmware/src/main.rs b/firmware/acid-firmware/src/main.rs index 282c220..4a14022 100644 --- a/firmware/acid-firmware/src/main.rs +++ b/firmware/acid-firmware/src/main.rs @@ -447,6 +447,8 @@ struct MainPeripherals { #[embassy_executor::task] async fn main_task(peripherals: MainPeripherals) { + // let _spawner = unsafe { Spawner::for_current_executor() }.await; + // Enable the TRNG source, so `Trng` can be constructed. let _trng_source = TrngSource::new(peripherals.RNG, peripherals.ADC1); @@ -769,12 +771,6 @@ async fn main_task(peripherals: MainPeripherals) { info!("Awaiting on all tasks..."); - // let spawner = unsafe { Spawner::for_current_executor() }.await; - - // peripherals - // .high_priority_task_spawner - // .must_spawn(run_bounce_buffers(framebuffer)); - framebuffer .bounce_buffers .take() @@ -816,11 +812,6 @@ async fn main_task(peripherals: MainPeripherals) { .await; } -#[embassy_executor::task] -async fn run_bounce_buffers(framebuffer: &'static mut Framebuffer) { - framebuffer.bounce_buffers.as_mut().unwrap().send().await; -} - async fn run_alloc_stats_reporter() { let mut psram_used_prev = 0; let mut heap_used_prev = 0; diff --git a/firmware/acid-firmware/src/ui/dpi.rs b/firmware/acid-firmware/src/ui/dpi.rs index a6c5171..63cc349 100644 --- a/firmware/acid-firmware/src/ui/dpi.rs +++ b/firmware/acid-firmware/src/ui/dpi.rs @@ -1,10 +1,8 @@ use core::{ alloc::Layout, cell::UnsafeCell, - marker::PhantomData, ops::{Deref, DerefMut}, - pin::Pin, - sync::atomic::{self, AtomicBool, AtomicU32, AtomicUsize}, + sync::atomic::{self, AtomicBool}, }; use alloc::{ @@ -14,37 +12,23 @@ use alloc::{ vec, }; use bytemuck::{AnyBitPattern, NoUninit}; -use embassy_sync::{ - channel::{Channel, TrySendError}, - signal::Signal, -}; -use embassy_time::{Duration, Instant, Timer, WithTimeout}; -use esp_alloc::MemoryCapability; use esp_hal::{ Blocking, dma::{ - self, AnyGdmaChannel, BufView, BurstConfig, DmaChannel, DmaChannelConvert, DmaDescriptor, - DmaDescriptorFlags, DmaEligible, DmaRxStreamBuf, DmaTxBuf, DmaTxBuffer, DmaTxInterrupt, - ExternalBurstConfig, InternalBurstConfig, Mem2Mem, SimpleMem2Mem, SimpleMem2MemTransfer, + self, BurstConfig, DmaDescriptor, DmaTxBuffer, Mem2Mem, SimpleMem2Mem, + SimpleMem2MemTransfer, }, - dma_descriptors, handler, + handler, interrupt::{self, Priority}, lcd_cam::lcd::dpi::{Dpi, DpiTransfer}, - peripherals::{DMA, DMA_CH0, Interrupt, Peripherals, SPI2}, + peripherals::{DMA, DMA_CH0, Interrupt}, ram, spi::master::AnySpi, }; -use esp_sync::RawMutex; -use i_slint_core::software_renderer::{Rgb565Pixel, TargetPixel}; -use indoc::{formatdoc, indoc}; -use log::{error, info, warn}; +use log::error; use ouroboros::self_referencing; -use rmk::{ - futures::{self, FutureExt, pin_mut}, - join_all, -}; -use crate::{PSRAM_ALLOCATOR, peripherals::st7701s::St7701s, util::DurationExt}; +use crate::PSRAM_ALLOCATOR; /// THIS IS TAKEN FROM https://github.com/esp-rs/esp-hal/blob/main/esp-hal/src/soc/esp32s3/mod.rs /// Write back a specific range of data in the cache. @@ -523,7 +507,6 @@ impl DmaBounce { let descriptors_per_frame = descriptors_per_window * windows_len; let descriptors_frame = Box::leak(vec![DmaDescriptor::EMPTY; descriptors_per_frame].into_boxed_slice()); - let descriptors_frame_ptr = descriptors_frame.as_ptr(); // Link up the descriptors. let mut next = if cyclic { @@ -570,7 +553,10 @@ impl DmaBounce { (descriptors_frame, descriptors_per_window) } - fn linear_descriptors_prepare( + /// Safety: + /// TX descriptors require read access to the buffer. + /// RX descriptors require write access to the buffer. + unsafe fn linear_descriptors_prepare( descriptors: &mut [DmaDescriptor], mut buffer: Option<&[u8]>, mut setup_desc: impl FnMut(&mut DmaDescriptor), @@ -591,48 +577,20 @@ impl DmaBounce { } } - fn linear_descriptors_prepare_mut( - descriptors: &mut [DmaDescriptor], - mut buffer: Option<&mut [u8]>, - mut setup_desc: impl FnMut(&mut DmaDescriptor), - ) { - for descriptor in descriptors.iter_mut() { - if let Some(inner_buffer) = buffer { - descriptor.buffer = inner_buffer.as_mut_ptr(); - buffer = Some(&mut inner_buffer[descriptor.size()..]); - } - (setup_desc)(descriptor); - } - - if let Some(buffer) = buffer { - assert!( - buffer.is_empty(), - "a buffer of an incompatible length was assigned to a descriptor set" - ); - } - } - fn enable_interrupts() { - // Enable interrupts for the peripheral - // interrupt::enable(INTERRUPT_INBOUND, dma_inbound_interrupt_handler.priority()).unwrap(); + // Enable interrupts for the peripheral, pt. 1. interrupt::enable( INTERRUPT_OUTBOUND, dma_outbound_interrupt_handler.priority(), ) .unwrap(); - // Bind the handler + // Bind the interrupt handler. unsafe { - // interrupt::bind_interrupt(INTERRUPT_INBOUND, dma_inbound_interrupt_handler.handler()); interrupt::bind_interrupt(INTERRUPT_OUTBOUND, dma_outbound_interrupt_handler.handler()); } - // Enable interrupts in the peripheral. - // DMA::regs() - // .ch(DMA_CHANNEL_INBOUND) - // .in_int() - // .ena() - // .modify(|_, w| w.in_done().bit(true)); + // Enable interrupts for the peripheral, pt. 2. DMA::regs() .ch(DMA_CHANNEL_OUTBOUND) .out_int() @@ -650,19 +608,21 @@ impl DmaBounce { let buffer_src_window = &self.swapchain_src.get_latest_framebuffer() [self.window_index_next * self.window_size..][..self.window_size]; - Self::linear_descriptors_prepare(self.src_descs, Some(buffer_src_window), |_desc| { - // No need to call `DmaDescriptor::reset_for_tx`, because - // 1. we don't rely on the ownership flag; - // 2. the EOF flag is already set during the construction of this buffer. - }); - // TODO: Precompute a descriptor list for each buffer, then use `None` instead of `Some(&mut *self.bounce_buffer_dst)`. - Self::linear_descriptors_prepare_mut( - self.bounce_dst_descs, - Some(&mut *self.bounce_buffer_dst), - |desc| { - desc.reset_for_rx(); - }, - ); + unsafe { + Self::linear_descriptors_prepare(self.src_descs, Some(buffer_src_window), |_desc| { + // No need to call `DmaDescriptor::reset_for_tx`, because + // 1. we don't rely on the ownership flag; + // 2. the EOF flag is already set during the construction of this buffer. + }); + // TODO: Precompute a descriptor list for each buffer, then use `None` instead of `Some(&mut *self.bounce_buffer_dst)`. + Self::linear_descriptors_prepare( + self.bounce_dst_descs, + Some(self.bounce_buffer_dst), + |desc| { + desc.reset_for_rx(); + }, + ); + } // Extend the lifetime to 'static because it is required by Mem2Mem. // @@ -702,19 +662,21 @@ impl DmaBounce { let buffer_src_window = &self.swapchain_src.get_latest_framebuffer() [self.window_index_next * self.window_size..][..self.window_size]; - Self::linear_descriptors_prepare(self.src_descs, Some(buffer_src_window), |_desc| { - // No need to call `DmaDescriptor::reset_for_tx`, because - // 1. we don't rely on the ownership flag; - // 2. the EOF flag is already set during the construction of this buffer. - }); - // TODO: Precompute a descriptor list for each buffer, then use `None` instead of `Some(&mut *self.bounce_buffer_dst)`. - Self::linear_descriptors_prepare_mut( - self.bounce_dst_descs, - Some(&mut *self.bounce_buffer_dst), - |desc| { - desc.reset_for_rx(); - }, - ); + unsafe { + Self::linear_descriptors_prepare(self.src_descs, Some(buffer_src_window), |_desc| { + // No need to call `DmaDescriptor::reset_for_tx`, because + // 1. we don't rely on the ownership flag; + // 2. the EOF flag is already set during the construction of this buffer. + }); + // TODO: Precompute a descriptor list for each buffer, then use `None` instead of `Some(&mut *self.bounce_buffer_dst)`. + Self::linear_descriptors_prepare( + self.bounce_dst_descs, + Some(self.bounce_buffer_dst), + |desc| { + desc.reset_for_rx(); + }, + ); + } { // Extend the lifetime to 'static because it is required by Mem2Mem. @@ -776,108 +738,6 @@ impl DmaBounce { } } - pub async fn send(&mut self) { - Self::enable_interrupts(); - - // Receive the first window, so that the outbound transfer can read valid data. - self.receive_window().await; - - let mut dma_tx_buffer = self.get_dma_tx_buffer(); - let mut transfer = self - .peripheral_dst - .take() - .unwrap() - .send(self.cyclic /* Send perpetually */, dma_tx_buffer) - .unwrap_or_else(|(error, _, _)| { - panic!("failed to begin the transmission of the first frame: {error:?}"); - }); - - let mut windows_skipped_total = 0; - - loop { - // warn!( - // "Receiving window: {} {}", - // self.window_index_next, self.frame_index_next - // ); - self.receive_window().await; - // warn!( - // "Window received: {} {}", - // self.window_index_next, self.frame_index_next - // ); - let windows_sent = WINDOWS_SENT - .wait() - .with_timeout(Duration::from_millis(100)) - .await - .unwrap_or_else(|_| { - error!("Timed out when waiting for skipped windows."); - 0 - }); - let windows_skipped = windows_sent as isize - 1; - - if windows_skipped != 0 { - self.increase_window_counter(windows_skipped); - windows_skipped_total += windows_skipped; - // error!( - // "Skipped {windows_skipped} windows. Windows skipped per frame: {:.2}%", - // 100.0 * windows_skipped_total as f32 - // / (self.windows_len * (self.frame_index_next + 1)) as f32 - // ); - } - - // warn!( - // "X: {} {} {}", - // windows_skipped, self.window_index_next, self.frame_index_next - // ); - - if !self.cyclic && (self.window_index_next == 1 || transfer.is_done()) { - if self.window_index_next > 1 { - self.increase_window_counter( - self.windows_len as isize - self.window_index_next as isize + 1, - ); - } else if self.window_index_next == 0 { - self.increase_window_counter(1); - } - - // TODO: Investigate why the DPI transfer isn't done at this point. - // The `DpiTransfer::wait()` below takes 0.001039 s. - // Perhaps it's the minimum screen refresh period? - // - // assert!(transfer.is_done()); - // if !transfer.is_done() { - // error!( - // "transfer is not done yet. {} {}", - // self.frame_index_next, self.window_index_next - // ); - // } - - let result; - let peripheral_dst; - // let start = Instant::now(); - (result, peripheral_dst, dma_tx_buffer) = transfer.wait(); - // let duration = Instant::now().duration_since(start); - // warn!("Waited for {} seconds", duration.display_as_secs()); - - if let Err(error) = result { - error!("DPI error during sending: {error:?}"); - } - - transfer = - peripheral_dst - .send(false, dma_tx_buffer) - .unwrap_or_else(|(error, _, _)| { - panic!("failed to begin the transmission of a frame: {error:?}"); - }); - - FRAMES_SKIPPED.signal( - FRAMES_SKIPPED - .try_take() - .map(|frames_skipped| frames_skipped + 1) - .unwrap_or_default(), - ); - } - } - } - fn get_dma_tx_buffer(&mut self) -> DmaTxBounceBuf { DmaTxBounceBuf { preparation: dma::Preparation { @@ -885,8 +745,10 @@ impl DmaBounce { direction: dma::TransferDirection::Out, accesses_psram: false, burst_transfer: self.burst_config, - check_owner: Some(false), // Possibly want to set this to false - auto_write_back: false, // Possibly true + // We don't care about ownership. + // Just yeet whatever the descriptors point to to the destination peripheral. + check_owner: Some(false), + auto_write_back: false, }, } } @@ -920,9 +782,6 @@ unsafe impl DmaTxBuffer for DmaTxBounceBuf { } } -/// Intended to be listened on by the renderer, to synchronize the refresh frequency with. -pub static FRAMES_SKIPPED: Signal = Signal::new(); -static WINDOWS_SENT: Signal = Signal::new(); static DMA_STATE: SyncUnsafeCell> = SyncUnsafeCell(UnsafeCell::new(None)); #[repr(transparent)] @@ -930,16 +789,6 @@ pub struct SyncUnsafeCell(UnsafeCell); unsafe impl Sync for SyncUnsafeCell {} -// #[derive(Clone, Copy)] -// struct DmaState { -// descriptors_ptr: *const DmaDescriptor, -// descriptors_per_window: usize, -// windows_per_frame: usize, -// last_window_index: usize, -// } - -// unsafe impl Sync for DmaState {} - #[handler(priority = Priority::Priority3)] #[ram] // Improves performance. fn dma_outbound_interrupt_handler() { @@ -971,7 +820,6 @@ fn dma_outbound_interrupt_handler() { let window_sent_index = unsafe { descriptor_ptr.offset_from_unsigned(dma_state.bounce_src_descs.as_ptr()) } / dma_state.descriptors_per_window; - // warn!("{window_sent_index}"); // The next window to be sent is `(window_sent_index + 1) % dma_state.windows_len`. // That is not the window we want to buffer, because the transmissions would race. // We instead want to buffer the next window: @@ -987,8 +835,6 @@ fn dma_outbound_interrupt_handler() { dma_state.window_index_next = window_index_next; - // warn!("{window_sent_index} {window_index_next}"); - let mut receiving_transfer = dma_state .receiving_transfer .take() @@ -997,14 +843,10 @@ fn dma_outbound_interrupt_handler() { .with_mut(|x| x.transfer.take()) .expect("no ongoing inner transfer to a bounce buffer present"); - // if !receiving_transfer.is_done() { - // error!("{window_sent_index}"); - // error!("the transfer to a bounce buffer has not finished yet, aborting"); - // } - if receiving_transfer.is_done() { drop(receiving_transfer); } else { + // error!("the transfer to a bounce buffer has not finished yet, waiting"); receiving_transfer.wait().unwrap(); } diff --git a/firmware/acid-firmware/src/ui/mod.rs b/firmware/acid-firmware/src/ui/mod.rs index ba82cf8..9651d8e 100644 --- a/firmware/acid-firmware/src/ui/mod.rs +++ b/firmware/acid-firmware/src/ui/mod.rs @@ -38,7 +38,6 @@ use crate::{ proxy::OUTPUT_STRING_CHANNEL, ui::{ backend::SlintBackend, - dpi::FRAMES_SKIPPED, messages::{ CallbackMessage, CallbackMessageLogin, CallbackMessageUserEdit, CallbackMessageUserSites, CallbackMessageUsers, LoginResult,