mirror of
https://github.com/saymrwulf/xous-core.git
synced 2026-11-13 07:48:30 +00:00
add a graphics test routine for OQC
invoked via the GAM, callable exactly once per boot for up to 60 seconds.
This commit is contained in:
parent
f0dd512d7d
commit
4882016d08
11 changed files with 162 additions and 10 deletions
1
Cargo.lock
generated
1
Cargo.lock
generated
|
|
@ -843,6 +843,7 @@ dependencies = [
|
|||
"num-traits",
|
||||
"rkyv 0.4.3",
|
||||
"susres",
|
||||
"ticktimer-server",
|
||||
"trng",
|
||||
"utralib",
|
||||
"xous",
|
||||
|
|
|
|||
|
|
@ -152,6 +152,9 @@ pub(crate) enum Opcode {
|
|||
/// Turn on Devboot Flag
|
||||
Devboot,
|
||||
|
||||
/// Show a test pattern. Can only call this once (to prevent abuse)
|
||||
TestPattern,
|
||||
|
||||
Quit,
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -320,6 +320,13 @@ impl Gam {
|
|||
ena, 0, 0, 0,)
|
||||
).map(|_| ())
|
||||
}
|
||||
pub fn selftest(&self, duration_ms: usize) {
|
||||
send_message(
|
||||
self.conn,
|
||||
Message::new_blocking_scalar(Opcode::TestPattern.to_usize().unwrap(), duration_ms, 0, 0, 0),
|
||||
)
|
||||
.expect("couldn't self test");
|
||||
}
|
||||
}
|
||||
|
||||
use core::sync::atomic::{AtomicU32, Ordering};
|
||||
|
|
|
|||
|
|
@ -642,6 +642,7 @@ fn xmain() -> ! {
|
|||
|
||||
let mut powerdown_requested = false;
|
||||
let mut last_time: u64 = ticktimer.elapsed_ms();
|
||||
let mut did_test = false; // allow one go at the test pattern
|
||||
log::trace!("entering main loop");
|
||||
|
||||
#[cfg(not(any(target_os = "none", target_os = "xous")))]
|
||||
|
|
@ -1017,6 +1018,18 @@ fn xmain() -> ! {
|
|||
if ena != 0 { gfx.set_devboot(true).expect("couldn't send devboot message"); }
|
||||
else { gfx.set_devboot(false).expect("couldn't send devboot message"); }
|
||||
}),
|
||||
Some(Opcode::TestPattern) => msg_blocking_scalar_unpack!(msg, duration_ms, _, _, _, {
|
||||
if !did_test {
|
||||
did_test = true;
|
||||
let checked_duration = if duration_ms > 60_000 {
|
||||
60_000
|
||||
} else {
|
||||
duration_ms
|
||||
};
|
||||
gfx.selftest(checked_duration);
|
||||
}
|
||||
xous::return_scalar(msg.sender, 1).expect("couldn't ack self test");
|
||||
}),
|
||||
Some(Opcode::Quit) => break,
|
||||
None => {log::error!("unhandled message {:?}", msg);}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ log-server = {path = "../log-server"}
|
|||
xous = {path = "../../xous-rs"}
|
||||
susres = {path = "../susres"}
|
||||
trng = {path = "../trng"}
|
||||
ticktimer-server = {path = "../ticktimer-server"}
|
||||
|
||||
xous-ipc = {path = "../../xous-ipc"}
|
||||
xous-names = {path = "../xous-names"}
|
||||
|
|
|
|||
|
|
@ -95,6 +95,9 @@ pub(crate) enum Opcode {
|
|||
BulkReadFonts,
|
||||
RestartBulkRead,
|
||||
|
||||
/// generates a test pattern
|
||||
TestPattern,
|
||||
|
||||
/// SuspendResume callback
|
||||
SuspendResume,
|
||||
|
||||
|
|
|
|||
|
|
@ -3,10 +3,10 @@ use susres::{ManagedMem, RegManager, RegOrField, SuspendResume};
|
|||
use utralib::generated::*;
|
||||
use xous::MemoryRange;
|
||||
|
||||
const FB_WIDTH_WORDS: usize = 11;
|
||||
pub const FB_WIDTH_WORDS: usize = 11;
|
||||
const FB_WIDTH_PIXELS: usize = 336;
|
||||
const FB_LINES: usize = 536;
|
||||
const FB_SIZE: usize = FB_WIDTH_WORDS * FB_LINES; // 44 bytes by 536 lines
|
||||
pub const FB_LINES: usize = 536;
|
||||
pub const FB_SIZE: usize = FB_WIDTH_WORDS * FB_LINES; // 44 bytes by 536 lines
|
||||
const CONFIG_CLOCK_FREQUENCY: u32 = 100_000_000;
|
||||
|
||||
pub struct XousDisplay {
|
||||
|
|
@ -170,7 +170,7 @@ impl XousDisplay {
|
|||
unsafe { &mut *(self.fb.as_mut_ptr() as *mut [u32; FB_SIZE]) }
|
||||
}
|
||||
|
||||
pub fn blit_screen(&mut self, bmp: [u32; FB_SIZE]) {
|
||||
pub fn blit_screen(&mut self, bmp: &[u32]) {
|
||||
let framebuffer = self.fb.as_mut_ptr() as *mut u32;
|
||||
|
||||
for words in 0..FB_SIZE {
|
||||
|
|
@ -183,6 +183,10 @@ impl XousDisplay {
|
|||
while self.busy() {}
|
||||
}
|
||||
|
||||
pub fn as_slice(&self) -> &[u32] {
|
||||
&self.fb.as_slice::<u32>()[..FB_SIZE]
|
||||
}
|
||||
|
||||
/// Beneath this line are pure-HAL layer, and should not be user-visible
|
||||
|
||||
///
|
||||
|
|
|
|||
|
|
@ -8,7 +8,9 @@ const HEIGHT: usize = 536;
|
|||
|
||||
/// Width of the screen in 32-bit words
|
||||
const WIDTH_WORDS: usize = 11;
|
||||
const FB_SIZE: usize = WIDTH_WORDS * HEIGHT; // 44 bytes by 536 lines
|
||||
pub const FB_WIDTH_WORDS: usize = WIDTH_WORDS;
|
||||
pub const FB_LINES: usize = HEIGHT;
|
||||
pub const FB_SIZE: usize = WIDTH_WORDS * HEIGHT; // 44 bytes by 536 lines
|
||||
|
||||
const MAX_FPS: u64 = 60;
|
||||
const DARK_COLOUR: u32 = 0xB5B5AD;
|
||||
|
|
@ -83,11 +85,14 @@ impl XousDisplay {
|
|||
Point::new(WIDTH as i16, HEIGHT as i16)
|
||||
}
|
||||
|
||||
pub fn blit_screen(&mut self, bmp: [u32; FB_SIZE]) {
|
||||
pub fn blit_screen(&mut self, bmp: &[u32]) {
|
||||
for (dest, src) in self.emulated_buffer.iter_mut().zip(bmp.iter()) {
|
||||
*dest = *src;
|
||||
}
|
||||
}
|
||||
pub fn as_slice(&self) -> &[u32] {
|
||||
&self.emulated_buffer
|
||||
}
|
||||
|
||||
pub fn native_buffer(&mut self) -> &mut [u32; FB_SIZE] {
|
||||
&mut self.emulated_buffer
|
||||
|
|
|
|||
|
|
@ -244,6 +244,14 @@ impl Gfx {
|
|||
)
|
||||
.expect("couldn't reset bulk read");
|
||||
}
|
||||
|
||||
pub fn selftest(&self, duration_ms: usize) {
|
||||
send_message(
|
||||
self.conn,
|
||||
Message::new_blocking_scalar(Opcode::TestPattern.to_usize().unwrap(), duration_ms, 0, 0, 0),
|
||||
)
|
||||
.expect("couldn't self test");
|
||||
}
|
||||
}
|
||||
|
||||
use core::sync::atomic::{AtomicU32, Ordering};
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@ mod fontmap;
|
|||
use api::BulkRead;
|
||||
|
||||
fn draw_boot_logo(display: &mut XousDisplay) {
|
||||
display.blit_screen(poweron::LOGO_MAP);
|
||||
display.blit_screen(&poweron::LOGO_MAP);
|
||||
}
|
||||
|
||||
#[cfg(any(target_os = "none", target_os = "xous"))]
|
||||
|
|
@ -566,7 +566,7 @@ fn xmain() -> ! {
|
|||
.expect("could not return QueryGlyphProps request");
|
||||
}),
|
||||
Some(Opcode::DrawSleepScreen) => msg_scalar_unpack!(msg, _, _, _, _, {
|
||||
display.blit_screen(logo::LOGO_MAP);
|
||||
display.blit_screen(&logo::LOGO_MAP);
|
||||
display.update();
|
||||
display.redraw();
|
||||
}),
|
||||
|
|
@ -613,12 +613,118 @@ fn xmain() -> ! {
|
|||
bulkread.from_offset += readlen as u32;
|
||||
buf.replace(bulkread).unwrap();
|
||||
}
|
||||
Some(Opcode::TestPattern) => msg_blocking_scalar_unpack!(msg, duration, _, _, _, {
|
||||
let mut stashmem = xous::syscall::map_memory(
|
||||
None,
|
||||
None,
|
||||
((backend::FB_SIZE * 4) + 4096) & !4095,
|
||||
xous::MemoryFlags::R | xous::MemoryFlags::W,
|
||||
).expect("couldn't map stash frame buffer");
|
||||
let stash = &mut stashmem.as_slice_mut()[..backend::FB_SIZE];
|
||||
for (&src, dst) in display.as_slice().iter().zip(stash.iter_mut()) {
|
||||
*dst = src;
|
||||
}
|
||||
for lines in 0..backend::FB_LINES { // mark all lines dirty
|
||||
stash[lines * backend::FB_WIDTH_WORDS + (backend::FB_WIDTH_WORDS - 1)] |= 0x1_0000;
|
||||
}
|
||||
|
||||
let ticktimer = ticktimer_server::Ticktimer::new().unwrap();
|
||||
let start_time = ticktimer.elapsed_ms();
|
||||
let mut testmem = xous::syscall::map_memory(
|
||||
None,
|
||||
None,
|
||||
((backend::FB_SIZE * 4) + 4096) & !4095,
|
||||
xous::MemoryFlags::R | xous::MemoryFlags::W,
|
||||
).expect("couldn't map stash frame buffer");
|
||||
let testpat = &mut testmem.as_slice_mut()[..backend::FB_SIZE];
|
||||
const DWELL: usize = 1000;
|
||||
while ticktimer.elapsed_ms() - start_time < duration as u64 {
|
||||
// all black
|
||||
for w in testpat.iter_mut() {
|
||||
*w = 0;
|
||||
}
|
||||
for lines in 0..backend::FB_LINES { // mark dirty bits
|
||||
testpat[lines * backend::FB_WIDTH_WORDS + (backend::FB_WIDTH_WORDS - 1)] |= 0x1_0000;
|
||||
}
|
||||
display.blit_screen(testpat);
|
||||
display.update();
|
||||
display.redraw();
|
||||
ticktimer.sleep_ms(DWELL).unwrap();
|
||||
|
||||
// all white
|
||||
for w in testpat.iter_mut() {
|
||||
*w = 0xFFFF_FFFF;
|
||||
}
|
||||
// dirty bits already set
|
||||
display.blit_screen(testpat);
|
||||
display.update();
|
||||
display.redraw();
|
||||
ticktimer.sleep_ms(DWELL).unwrap();
|
||||
|
||||
// vertical bars
|
||||
for lines in 0..backend::FB_LINES {
|
||||
for words in 0..backend::FB_WIDTH_WORDS {
|
||||
testpat[lines * backend::FB_WIDTH_WORDS + words] = 0xaaaa_aaaa;
|
||||
}
|
||||
}
|
||||
display.blit_screen(testpat);
|
||||
display.update();
|
||||
display.redraw();
|
||||
ticktimer.sleep_ms(DWELL).unwrap();
|
||||
|
||||
for lines in 0..backend::FB_LINES {
|
||||
for words in 0..backend::FB_WIDTH_WORDS {
|
||||
testpat[lines * backend::FB_WIDTH_WORDS + words] = 0x5555_5555;
|
||||
}
|
||||
}
|
||||
display.blit_screen(testpat);
|
||||
display.update();
|
||||
display.redraw();
|
||||
ticktimer.sleep_ms(DWELL).unwrap();
|
||||
|
||||
// horiz bars
|
||||
for lines in 0..backend::FB_LINES {
|
||||
for words in 0..backend::FB_WIDTH_WORDS {
|
||||
if lines % 2 == 0 {
|
||||
testpat[lines * backend::FB_WIDTH_WORDS + words] = 0x0;
|
||||
} else {
|
||||
testpat[lines * backend::FB_WIDTH_WORDS + words] = 0xffff_ffff;
|
||||
}
|
||||
}
|
||||
testpat[lines * backend::FB_WIDTH_WORDS + (backend::FB_WIDTH_WORDS - 1)] |= 0x1_0000;
|
||||
}
|
||||
display.blit_screen(testpat);
|
||||
display.update();
|
||||
display.redraw();
|
||||
ticktimer.sleep_ms(DWELL).unwrap();
|
||||
|
||||
for lines in 0..backend::FB_LINES {
|
||||
for words in 0..backend::FB_WIDTH_WORDS {
|
||||
if lines % 2 == 1 {
|
||||
testpat[lines * backend::FB_WIDTH_WORDS + words] = 0x0;
|
||||
} else {
|
||||
testpat[lines * backend::FB_WIDTH_WORDS + words] = 0xffff_ffff;
|
||||
}
|
||||
}
|
||||
testpat[lines * backend::FB_WIDTH_WORDS + (backend::FB_WIDTH_WORDS - 1)] |= 0x1_0000;
|
||||
}
|
||||
display.blit_screen(testpat);
|
||||
display.update();
|
||||
display.redraw();
|
||||
ticktimer.sleep_ms(DWELL).unwrap();
|
||||
|
||||
}
|
||||
display.blit_screen(stash);
|
||||
|
||||
xous::return_scalar(msg.sender, duration).expect("couldn't ack test pattern");
|
||||
}),
|
||||
Some(Opcode::Quit) => break,
|
||||
None => {
|
||||
log::error!("received opcode scalar that is not handled");
|
||||
}
|
||||
}
|
||||
display.update();
|
||||
display.redraw();
|
||||
}
|
||||
log::trace!("main loop exit, destroying servers");
|
||||
xns.unregister_server(sid).unwrap();
|
||||
|
|
|
|||
|
|
@ -400,14 +400,14 @@ impl<'a> ShellCmdApi<'a> for Test {
|
|||
"oqc" => {
|
||||
env.llio.wfi_override(true).unwrap();
|
||||
//xous::rsyscall(xous::SysCall::IncreaseHeap(65536, xous::MemoryFlags::R | xous::MemoryFlags::W)).expect("couldn't increase our heap");
|
||||
/* // temp clear so renode can run
|
||||
ret.clear();
|
||||
#[cfg(any(target_os = "none", target_os = "xous"))]
|
||||
if 0x362f093 != self.jtag.get_id().unwrap() {
|
||||
write!(ret, "FAIL: JTAG self access").unwrap();
|
||||
return Ok(Some(ret));
|
||||
}
|
||||
#[cfg(any(target_os = "none", target_os = "xous"))]
|
||||
env.com.set_backlight(196, 196).unwrap();
|
||||
*/
|
||||
log::info!("building modal");
|
||||
const OQC_SERVER: &str = "_OQC server_";
|
||||
let kbdtest_sid = env.xns.register_name(OQC_SERVER, Some(1)).unwrap();
|
||||
|
|
@ -425,6 +425,7 @@ impl<'a> ShellCmdApi<'a> for Test {
|
|||
GlyphStyle::Small,
|
||||
8
|
||||
);
|
||||
test_modal.gam.selftest(18_000);
|
||||
log::info!("making helper");
|
||||
test_modal.spawn_helper(kbdtest_sid, test_modal.sid,
|
||||
TestOp::ModalRedraw.to_u32().unwrap(),
|
||||
|
|
|
|||
Loading…
Reference in a new issue