modify fast dma test for clocking option

This commit is contained in:
bunnie 2025-02-08 05:20:25 +08:00
parent 019f342c98
commit 72763dc3c7
5 changed files with 290 additions and 1 deletions

View file

@ -0,0 +1,37 @@
use enum_dispatch::enum_dispatch;
use super::*;
#[enum_dispatch(ActionApi)]
pub enum ActionType {
#[cfg(feature = "textentry")]
TextEntry,
#[cfg(feature = "bip39entry")]
Bip39Entry,
#[cfg(feature = "radiobuttons")]
RadioButtons,
#[cfg(feature = "checkboxes")]
CheckBoxes,
#[cfg(feature = "slider")]
Slider,
#[cfg(feature = "notification")]
Notification,
#[cfg(feature = "ditherpunk")]
Image,
#[cfg(feature = "consoleinput")]
ConsoleInput,
}
/* TODO: turn Modal into a trait */
#[enum_dispatch]
pub trait ActionApi<Modal> {
/// Returns the height of the widget for layout use
fn height(&self, glyph_height: i16, margin: i16, _modal: &Modal) -> i16 { glyph_height + margin * 2 }
/// Triggers a redraw of the action object
fn redraw(&self, _at_height: i16, _modal: &Modal) { unimplemented!() }
fn close(&mut self) {}
fn is_password(&self) -> bool { false }
/// navigation is one of '∴' | '←' | '→' | '↑' | '↓'
fn key_action(&mut self, _key: char) -> Option<ValidatorErr> { None }
fn set_action_opcode(&mut self, _op: u32) {}
}

View file

@ -0,0 +1,6 @@
pub mod textentry;
pub use textentry::*;
pub mod payload;
pub use payload::*;
pub mod action;
pub use action::*;

View file

@ -0,0 +1,116 @@
use zeroize::Zeroize;
use super::*;
/// We use a new type for item names, so that it's easy to resize this as needed.
#[derive(Debug, Clone, rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)]
pub struct ItemName(String);
impl ItemName {
pub fn new(name: &str) -> Self { ItemName(String::from(name)) }
pub fn as_str(&self) -> &str { self.0.as_str() }
}
#[derive(Debug, rkyv::Archive, rkyv::Serialize, rkyv::Deserialize, Copy, Clone, Eq, PartialEq, Default)]
pub struct Bip39EntryPayload {
// up to 32 bytes (256 bits) could be entered
pub data: [u8; 32],
// the actual length entered is reported here
pub len: u32,
}
#[derive(Debug, rkyv::Archive, rkyv::Serialize, rkyv::Deserialize, Clone, Eq, PartialEq, Default)]
pub struct TextEntryPayload {
dirty: bool,
pub content: String,
pub placeholder: Option<String>,
pub placeholder_persist: bool,
pub insertion_point: Option<usize>,
}
impl TextEntryPayload {
pub fn new() -> Self {
TextEntryPayload {
dirty: Default::default(),
content: Default::default(),
placeholder: Default::default(),
placeholder_persist: false,
insertion_point: None,
}
}
pub fn new_with_fields(content: String, placeholder: Option<String>) -> Self {
TextEntryPayload {
dirty: false,
content,
placeholder,
placeholder_persist: false,
insertion_point: None,
}
}
/// Ensures that 0's are written to the storage of this struct, and not optimized out; important for
/// password fields.
pub fn volatile_clear(&mut self) { self.content.zeroize(); }
pub fn as_str(&self) -> &str { self.content.as_str() }
}
#[derive(Debug, Copy, Clone, rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)]
pub struct SliderPayload(pub u32);
impl SliderPayload {
pub fn new(value: u32) -> Self { SliderPayload(value) }
}
#[derive(Debug, Clone, rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)]
pub struct RadioButtonPayload(pub ItemName); // returns the name of the item corresponding to the radio button selection
impl RadioButtonPayload {
pub fn new(name: &str) -> Self { RadioButtonPayload(ItemName::new(name)) }
pub fn as_str(&self) -> &str { self.0.as_str() }
pub fn clear(&mut self) { self.0.0.clear(); }
}
#[derive(Debug, Clone, rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)]
pub struct CheckBoxPayload(pub [Option<ItemName>; MAX_ITEMS]); // returns a list of potential items that could be selected
impl CheckBoxPayload {
pub fn new() -> Self { CheckBoxPayload([const { None }; MAX_ITEMS]) }
pub fn payload(self) -> [Option<ItemName>; MAX_ITEMS] { self.0 }
pub fn contains(&self, name: &str) -> bool {
for maybe_item in self.0.iter() {
if let Some(item) = maybe_item {
if item.as_str() == name {
return true;
}
}
}
false
}
pub fn add(&mut self, name: &str) -> bool {
if self.contains(name) {
return true;
}
for maybe_item in self.0.iter_mut() {
if maybe_item.is_none() {
*maybe_item = Some(ItemName::new(name));
return true;
}
}
false
}
pub fn remove(&mut self, name: &str) -> bool {
for maybe_item in self.0.iter_mut() {
if let Some(item) = maybe_item {
if item.as_str() == name {
*maybe_item = None;
return true;
}
}
}
false
}
}

View file

@ -0,0 +1,127 @@
use core::cell::Cell;
use core::fmt::Write;
use std::cell::RefCell;
use super::*;
const MAX_FIELDS: i16 = 10;
pub const MAX_ITEMS: usize = 8;
pub type ValidatorErr = String;
pub type Payloads = [TextEntryPayload; MAX_FIELDS as usize];
#[derive(Debug, rkyv::Archive, rkyv::Serialize, rkyv::Deserialize, Clone, Eq, PartialEq, Default)]
pub struct TextEntryPayloads(Payloads, usize);
impl TextEntryPayloads {
pub fn first(&self) -> TextEntryPayload { self.0[0].clone() }
pub fn content(&self) -> Vec<TextEntryPayload> { self.0[..self.1].to_vec() }
}
#[derive(Debug, Copy, Clone, num_derive::FromPrimitive, num_derive::ToPrimitive)]
pub enum TextEntryVisibility {
/// text is fully visible
Visible = 0,
/// only last chars are shown of text entry, the rest obscured with *
LastChars = 1,
/// all chars hidden as *
Hidden = 2,
}
#[derive(Clone)]
pub struct TextEntry {
pub is_password: bool,
pub visibility: TextEntryVisibility,
pub action_conn: xous::CID,
pub action_opcode: u32,
// validator borrows the text entry payload, and returns an error message if something didn't go well.
// validator takes as ragument the current action_payload, and the current action_opcode
pub validator: Option<fn(TextEntryPayload, u32) -> Option<ValidatorErr>>,
pub action_payloads: Vec<TextEntryPayload>,
max_field_amount: u32,
selected_field: i16,
field_height: Cell<i16>,
/// track if keys were hit since initialized: this allows us to clear the default text,
/// instead of having it re-appear every time the text area is cleared
keys_hit: [bool; MAX_FIELDS as usize],
// gam: crate::Gam, // no GAM field because this needs to be a clone-capable structure. We create a GAM
// handle when we need it.
/// Stores the allowed height of a given text line, based on the contents and the space available
/// in the box. The height of a given line may be limited to make sure there is enough space for
/// later lines to be rendered.
action_payloads_allowed_heights: RefCell<Vec<i16>>,
}
impl Default for TextEntry {
fn default() -> Self {
Self {
is_password: Default::default(),
visibility: TextEntryVisibility::Visible,
action_conn: Default::default(),
action_opcode: Default::default(),
validator: Default::default(),
selected_field: Default::default(),
action_payloads: Default::default(),
max_field_amount: 0,
field_height: Cell::new(0),
keys_hit: [false; MAX_FIELDS as usize],
action_payloads_allowed_heights: RefCell::new(Vec::new()),
}
}
}
impl TextEntry {
pub fn new(
is_password: bool,
visibility: TextEntryVisibility,
action_conn: xous::CID,
action_opcode: u32,
action_payloads: Vec<TextEntryPayload>,
validator: Option<fn(TextEntryPayload, u32) -> Option<ValidatorErr>>,
) -> Self {
if action_payloads.len() as i16 > MAX_FIELDS {
panic!("can't have more than {} fields, found {}", MAX_FIELDS, action_payloads.len());
}
Self {
is_password,
visibility,
action_conn,
action_opcode,
action_payloads,
validator,
..Default::default()
}
}
pub fn reset_action_payloads(&mut self, fields: u32, placeholders: Option<[Option<(String, bool)>; 10]>) {
let mut payload = vec![TextEntryPayload::default(); fields as usize];
if let Some(placeholders) = placeholders {
for (index, element) in payload.iter_mut().enumerate() {
if let Some((p, persist)) = &placeholders[index] {
element.placeholder = Some(p.to_string());
element.placeholder_persist = *persist;
} else {
element.placeholder = None;
element.placeholder_persist = false;
}
element.insertion_point = None;
}
}
self.action_payloads = payload;
self.max_field_amount = fields;
self.keys_hit = [false; MAX_FIELDS as usize];
}
fn get_bullet_margin(&self) -> i16 {
if self.action_payloads.len() > 1 {
17 // this is the margin for drawing the selection bullet
} else {
0 // no selection bullet
}
}
}

View file

@ -543,7 +543,7 @@ bio_code!(dma_u16_code, DMA_U16_START, DMA_U16_END,
/// Multi-core DMA copy. More performant, but uses two cores for address generation in
/// parallel with the copy master.
pub fn dma_multicore() -> usize {
pub fn dma_multicore(clkmode: u8) -> usize {
let mut passing = 0;
print!("DMA fast\r");
// clear prior test config state
@ -555,6 +555,9 @@ pub fn dma_multicore() -> usize {
// reset all the fifos
bio_ss.bio.wo(utra::bio_bdma::SFR_FIFO_CLR, 0xF);
// setup clocking mode option
bio_ss.bio.rmwf(SFR_CONFIG_CLOCKING_MODE, clkmode as u32);
// stop all the machines, so that code can be loaded
bio_ss.bio.wo(utra::bio_bdma::SFR_CTRL, 0x0);
bio_ss.load_code(dma_mc_copy_code(), 0, BioCore::Core2);