Code cleanup

This commit is contained in:
Jakub Hlusička 2026-02-24 23:07:51 +01:00
parent 95464568c7
commit 2ea4e57857
4 changed files with 55 additions and 222 deletions

View file

@ -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<T: NorFlash + ReadNorFlash> ekv::flash::Flash for EkvFlash<T> {
}
pub struct AcidDatabase {
db: Database<EkvFlash<PartitionAcid>, esp_sync::RawMutex>,
db: Database<EkvFlash<PartitionAcid>, CriticalSectionRawMutexOld>,
}
impl Deref for AcidDatabase {
type Target = Database<EkvFlash<PartitionAcid>, esp_sync::RawMutex>;
type Target = Database<EkvFlash<PartitionAcid>, 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")]
{

View file

@ -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;

View file

@ -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<RawMutex, usize> = Signal::new();
static WINDOWS_SENT: Signal<RawMutex, usize> = Signal::new();
static DMA_STATE: SyncUnsafeCell<Option<DmaBounce>> = SyncUnsafeCell(UnsafeCell::new(None));
#[repr(transparent)]
@ -930,16 +789,6 @@ pub struct SyncUnsafeCell<T>(UnsafeCell<T>);
unsafe impl<T> Sync for SyncUnsafeCell<T> {}
// #[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();
}

View file

@ -38,7 +38,6 @@ use crate::{
proxy::OUTPUT_STRING_CHANNEL,
ui::{
backend::SlintBackend,
dpi::FRAMES_SKIPPED,
messages::{
CallbackMessage, CallbackMessageLogin, CallbackMessageUserEdit,
CallbackMessageUserSites, CallbackMessageUsers, LoginResult,