mirror of
https://github.com/saymrwulf/xous-core.git
synced 2026-11-15 08:30:02 +00:00
modify fast dma test for clocking option
This commit is contained in:
parent
019f342c98
commit
72763dc3c7
5 changed files with 290 additions and 1 deletions
37
libs/ux-api/src/widgets/action.rs
Normal file
37
libs/ux-api/src/widgets/action.rs
Normal 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) {}
|
||||
}
|
||||
6
libs/ux-api/src/widgets/mod.rs
Normal file
6
libs/ux-api/src/widgets/mod.rs
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
pub mod textentry;
|
||||
pub use textentry::*;
|
||||
pub mod payload;
|
||||
pub use payload::*;
|
||||
pub mod action;
|
||||
pub use action::*;
|
||||
116
libs/ux-api/src/widgets/payload.rs
Normal file
116
libs/ux-api/src/widgets/payload.rs
Normal 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
|
||||
}
|
||||
}
|
||||
127
libs/ux-api/src/widgets/textentry.rs
Normal file
127
libs/ux-api/src/widgets/textentry.rs
Normal 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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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);
|
||||
|
|
|
|||
Loading…
Reference in a new issue