Skip to content

Commit 3fb5a82

Browse files
committed
Add ANSI helpers and rand/srand.
1 parent 9ed1d4b commit 3fb5a82

File tree

2 files changed

+129
-3
lines changed

2 files changed

+129
-3
lines changed

src/console.rs

Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
//! Helper functions for sending ANSI sequences
2+
3+
// ============================================================================
4+
// Imports
5+
// ============================================================================
6+
7+
use core::fmt::Write;
8+
9+
use crate::File;
10+
11+
// ============================================================================
12+
// Types
13+
// ============================================================================
14+
15+
/// Represents a position on a screen.
16+
///
17+
/// A position is 0-indexed. That is (0, 0) is the top-left corner.
18+
///
19+
/// Translation to 1-based is performed before sending the ANSI sequences.
20+
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
21+
pub struct Position {
22+
pub row: u8,
23+
pub col: u8,
24+
}
25+
26+
impl Position {
27+
pub const fn origin() -> Position {
28+
Position { row: 0, col: 0 }
29+
}
30+
}
31+
32+
/// Represents a Select Graphic Rendition parameter you can send in an SGR ANSI
33+
/// sequence.
34+
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
35+
#[repr(u8)]
36+
pub enum SgrParam {
37+
Reset = 0,
38+
Bold = 1,
39+
Reverse = 7,
40+
NotBold = 22,
41+
NotReverse = 27,
42+
FgBlack = 30,
43+
FgRed = 31,
44+
FgGreen = 32,
45+
FgYellow = 33,
46+
FgBlue = 34,
47+
FgMagenta = 35,
48+
FgCyan = 36,
49+
FgWhite = 37,
50+
BgBlack = 40,
51+
BgRed = 41,
52+
BgGreen = 42,
53+
BgYellow = 43,
54+
BgBlue = 44,
55+
BgMagenta = 45,
56+
BgCyan = 46,
57+
BgWhite = 47,
58+
}
59+
60+
// ============================================================================
61+
// Functions
62+
// ============================================================================
63+
64+
/// Erase the screen
65+
pub fn clear_screen(f: &mut File) {
66+
let _ = f.write_str("\u{001b}[2J");
67+
}
68+
69+
/// Turn the cursor on
70+
pub fn cursor_on(f: &mut File) {
71+
let _ = f.write_str("\u{001b}[?25h");
72+
}
73+
74+
/// Turn the cursor off
75+
pub fn cursor_off(f: &mut File) {
76+
let _ = f.write_str("\u{001b}[?25l");
77+
}
78+
79+
/// Move the cursor to the given position
80+
pub fn move_cursor(f: &mut File, pos: Position) {
81+
let _ = write!(f, "\u{001b}[{};{}H", 1 + pos.row, 1 + pos.col);
82+
}
83+
84+
/// Change the background
85+
///
86+
/// Only values 0..8 will work.
87+
pub fn set_sgr<T>(f: &mut File, values: T)
88+
where
89+
T: IntoIterator<Item = SgrParam>,
90+
{
91+
let _ = write!(f, "\u{001b}[");
92+
let mut iter = values.into_iter();
93+
if let Some(value) = iter.next() {
94+
let _ = write!(f, "{}", value as u8);
95+
}
96+
while let Some(value) = iter.next() {
97+
let _ = write!(f, ";{}", value as u8);
98+
}
99+
let _ = write!(f, "m");
100+
}
101+
102+
// ============================================================================
103+
// End of File
104+
// ============================================================================

src/lib.rs

Lines changed: 25 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@ pub use neotron_api::{path, Api, Error};
1616

1717
use neotron_api as api;
1818

19+
pub mod console;
20+
1921
#[cfg(not(target_os = "none"))]
2022
mod fake_os_api;
2123

@@ -315,10 +317,8 @@ pub const fn stderr() -> File {
315317
}
316318

317319
/// Delay for some milliseconds
320+
#[cfg(target_os = "none")]
318321
pub fn delay(period: core::time::Duration) {
319-
#[cfg(not(target_os = "none"))]
320-
std::thread::sleep(period);
321-
322322
// TODO: sleep on real hardware?
323323
for _ in 0..period.as_micros() {
324324
for _ in 0..50 {
@@ -327,6 +327,28 @@ pub fn delay(period: core::time::Duration) {
327327
}
328328
}
329329

330+
/// Delay for some milliseconds
331+
#[cfg(not(target_os = "none"))]
332+
pub fn delay(period: core::time::Duration) {
333+
std::thread::sleep(period);
334+
}
335+
336+
static RAND_STATE: core::sync::atomic::AtomicU16 = core::sync::atomic::AtomicU16::new(0);
337+
338+
/// Seed the 16-bit psuedorandom number generator
339+
pub fn srand(seed: u16) {
340+
RAND_STATE.store(seed, core::sync::atomic::Ordering::Relaxed);
341+
}
342+
343+
/// Get a 16-bit psuedorandom number
344+
pub fn rand() -> u16 {
345+
let mut state = RAND_STATE.load(core::sync::atomic::Ordering::Relaxed);
346+
let bit = ((state >> 0) ^ (state >> 2) ^ (state >> 3) ^ (state >> 5)) & 0x01;
347+
state = (state >> 1) | (bit << 15);
348+
RAND_STATE.store(state, core::sync::atomic::Ordering::Relaxed);
349+
state
350+
}
351+
330352
/// Get the API structure so we can call APIs manually.
331353
///
332354
/// If you managed to not have `app_entry` called on start-up, this will panic.

0 commit comments

Comments
 (0)