Skip to content

Commit 3dbfca6

Browse files
committed
Adds standard-input.
It's not nice, because I put the keyboard decoding into a static mut. Really, this should be in a mutex. But to make a mutex you need compare-and-swap, and ARMv6-M doesn't have that, and the work-around is very hardware specific. So, I think we need a critical-section implementation for the OS which uses the BIOS to acquire and release the lock. We can then use atomic-polyfill to provide compare-and-swap as we do on the Neotron Pico BIOS. Also I lost the serial input because that's currently in the menu context and we can't access that from OS API callbacks.
1 parent c19314c commit 3dbfca6

File tree

5 files changed

+142
-107
lines changed

5 files changed

+142
-107
lines changed

Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ panic = "abort"
4444
neotron-common-bios = "0.10"
4545
pc-keyboard = "0.7"
4646
r0 = "1.0"
47+
heapless = "0.7"
4748
postcard = "1.0"
4849
serde = { version = "1.0", default-features = false }
4950
menu = "0.3"

src/commands/input.rs

Lines changed: 9 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
//! Input related commands for Neotron OS
22
3-
use crate::{bios, osprintln, Ctx, API};
3+
use crate::{osprintln, Ctx};
44

55
pub static KBTEST_ITEM: menu::Item<Ctx> = menu::Item {
66
item_type: menu::ItemType::Callback {
@@ -12,43 +12,15 @@ pub static KBTEST_ITEM: menu::Item<Ctx> = menu::Item {
1212
};
1313

1414
/// Called when the "kbtest" command is executed.
15-
fn kbtest(_menu: &menu::Menu<Ctx>, _item: &menu::Item<Ctx>, _args: &[&str], ctx: &mut Ctx) {
16-
let api = API.get();
15+
fn kbtest(_menu: &menu::Menu<Ctx>, _item: &menu::Item<Ctx>, _args: &[&str], _ctx: &mut Ctx) {
16+
osprintln!("Press ESC to quit");
1717
loop {
18-
match (api.hid_get_event)() {
19-
bios::ApiResult::Ok(bios::FfiOption::Some(bios::hid::HidEvent::KeyPress(code))) => {
20-
let pckb_ev = pc_keyboard::KeyEvent {
21-
code,
22-
state: pc_keyboard::KeyState::Down,
23-
};
24-
if let Some(ev) = ctx.keyboard.process_keyevent(pckb_ev) {
25-
osprintln!("Code={code:?} State=Down Decoded={ev:?}");
26-
} else {
27-
osprintln!("Code={code:?} State=Down Decoded=None");
28-
}
29-
if code == pc_keyboard::KeyCode::Escape {
30-
break;
31-
}
32-
}
33-
bios::ApiResult::Ok(bios::FfiOption::Some(bios::hid::HidEvent::KeyRelease(code))) => {
34-
let pckb_ev = pc_keyboard::KeyEvent {
35-
code,
36-
state: pc_keyboard::KeyState::Up,
37-
};
38-
if let Some(ev) = ctx.keyboard.process_keyevent(pckb_ev) {
39-
osprintln!("Code={code:?} State=Up Decoded={ev:?}");
40-
} else {
41-
osprintln!("Code={code:?} State=Up Decoded=None");
42-
}
43-
}
44-
bios::ApiResult::Ok(bios::FfiOption::Some(bios::hid::HidEvent::MouseInput(
45-
_ignore,
46-
))) => {}
47-
bios::ApiResult::Ok(bios::FfiOption::None) => {
48-
// Do nothing
49-
}
50-
bios::ApiResult::Err(e) => {
51-
osprintln!("Failed to get HID events: {:?}", e);
18+
if let Some(ev) = unsafe { crate::STD_INPUT.get_raw() } {
19+
osprintln!("Event: {ev:?}");
20+
if ev == pc_keyboard::DecodedKey::RawKey(pc_keyboard::KeyCode::Escape)
21+
|| ev == pc_keyboard::DecodedKey::Unicode('\u{001b}')
22+
{
23+
break;
5224
}
5325
}
5426
}

src/lib.rs

Lines changed: 119 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,121 @@ static mut SERIAL_CONSOLE: Option<SerialConsole> = None;
4747
/// If so, don't panic if a serial write fails.
4848
static IS_PANIC: AtomicBool = AtomicBool::new(false);
4949

50+
/// Our keyboard controller
51+
static mut STD_INPUT: StdInput = StdInput::new();
52+
53+
struct StdInput {
54+
keyboard: pc_keyboard::EventDecoder<pc_keyboard::layouts::AnyLayout>,
55+
buffer: heapless::spsc::Queue<u8, 16>,
56+
}
57+
58+
impl StdInput {
59+
const fn new() -> StdInput {
60+
StdInput {
61+
keyboard: pc_keyboard::EventDecoder::new(
62+
pc_keyboard::layouts::AnyLayout::Uk105Key(pc_keyboard::layouts::Uk105Key),
63+
pc_keyboard::HandleControl::MapLettersToUnicode,
64+
),
65+
buffer: heapless::spsc::Queue::new(),
66+
}
67+
}
68+
69+
fn get_buffered_data(&mut self, buffer: &mut [u8]) -> usize {
70+
// If there is some data, get it.
71+
let mut count = 0;
72+
for slot in buffer.iter_mut() {
73+
if let Some(n) = self.buffer.dequeue() {
74+
*slot = n;
75+
count += 1;
76+
}
77+
}
78+
count
79+
}
80+
81+
/// Gets a raw event from the keyboard
82+
fn get_raw(&mut self) -> Option<pc_keyboard::DecodedKey> {
83+
let api = API.get();
84+
match (api.hid_get_event)() {
85+
bios::ApiResult::Ok(bios::FfiOption::Some(bios::hid::HidEvent::KeyPress(code))) => {
86+
let pckb_ev = pc_keyboard::KeyEvent {
87+
code,
88+
state: pc_keyboard::KeyState::Down,
89+
};
90+
self.keyboard.process_keyevent(pckb_ev)
91+
}
92+
bios::ApiResult::Ok(bios::FfiOption::Some(bios::hid::HidEvent::KeyRelease(code))) => {
93+
let pckb_ev = pc_keyboard::KeyEvent {
94+
code,
95+
state: pc_keyboard::KeyState::Up,
96+
};
97+
self.keyboard.process_keyevent(pckb_ev)
98+
}
99+
bios::ApiResult::Ok(bios::FfiOption::Some(bios::hid::HidEvent::MouseInput(
100+
_ignore,
101+
))) => None,
102+
bios::ApiResult::Ok(bios::FfiOption::None) => {
103+
// Do nothing
104+
None
105+
}
106+
bios::ApiResult::Err(_e) => None,
107+
}
108+
}
109+
110+
/// Gets some input bytes, as UTF-8.
111+
///
112+
/// The data you get might be cut in the middle of a UTF-8 character.
113+
fn get_data(&mut self, buffer: &mut [u8]) -> usize {
114+
let count = self.get_buffered_data(buffer);
115+
if buffer.len() == 0 || count > 0 {
116+
return count;
117+
}
118+
119+
// Nothing buffered - ask the keyboard for something
120+
let decoded_key = self.get_raw();
121+
122+
match decoded_key {
123+
Some(pc_keyboard::DecodedKey::Unicode(mut ch)) => {
124+
if ch == '\n' {
125+
ch = '\r';
126+
}
127+
let mut buffer = [0u8; 6];
128+
let s = ch.encode_utf8(&mut buffer);
129+
for b in s.as_bytes() {
130+
// This will always fit
131+
self.buffer.enqueue(*b).unwrap();
132+
}
133+
}
134+
Some(pc_keyboard::DecodedKey::RawKey(pc_keyboard::KeyCode::ArrowRight)) => {
135+
// Load the ANSI sequence for a right arrow
136+
for b in b"\x1b[0;77b" {
137+
// This will always fit
138+
self.buffer.enqueue(*b).unwrap();
139+
}
140+
}
141+
_ => {
142+
// Drop anything else
143+
}
144+
}
145+
146+
// if let Some((uart_dev, _serial_conf)) = menu.context.config.get_serial_console() {
147+
// while !self.buffer.is_full() {
148+
// let mut buffer = [0u8];
149+
// let wrapper = neotron_common_bios::FfiBuffer::new(&mut buffer);
150+
// match (api.serial_read)(uart_dev, wrapper, neotron_common_bios::FfiOption::None) {
151+
// neotron_common_bios::ApiResult::Ok(n) if n >= 0 => {
152+
// self.buffer.enqueue(buffer[0]).unwrap();
153+
// }
154+
// _ => {
155+
// break;
156+
// }
157+
// }
158+
// }
159+
// }
160+
161+
self.get_buffered_data(buffer)
162+
}
163+
}
164+
50165
// ===========================================================================
51166
// Macros
52167
// ===========================================================================
@@ -176,7 +291,6 @@ impl core::fmt::Write for SerialConsole {
176291

177292
pub struct Ctx {
178293
config: config::Config,
179-
keyboard: pc_keyboard::EventDecoder<pc_keyboard::layouts::AnyLayout>,
180294
tpa: program::TransientProgramArea,
181295
}
182296

@@ -287,10 +401,6 @@ pub extern "C" fn os_main(api: &bios::Api) -> ! {
287401

288402
let mut ctx = Ctx {
289403
config,
290-
keyboard: pc_keyboard::EventDecoder::new(
291-
pc_keyboard::layouts::AnyLayout::Uk105Key(pc_keyboard::layouts::Uk105Key),
292-
pc_keyboard::HandleControl::MapLettersToUnicode,
293-
),
294404
tpa: unsafe {
295405
// We have to trust the values given to us by the BIOS. If it lies, we will crash.
296406
program::TransientProgramArea::new(tpa_start, tpa_size)
@@ -310,68 +420,10 @@ pub extern "C" fn os_main(api: &bios::Api) -> ! {
310420
let mut menu = menu::Runner::new(&commands::OS_MENU, &mut buffer, ctx);
311421

312422
loop {
313-
match (api.hid_get_event)() {
314-
bios::ApiResult::Ok(bios::FfiOption::Some(bios::hid::HidEvent::KeyPress(code))) => {
315-
let pckb_ev = pc_keyboard::KeyEvent {
316-
code,
317-
state: pc_keyboard::KeyState::Down,
318-
};
319-
if let Some(pc_keyboard::DecodedKey::Unicode(mut ch)) =
320-
menu.context.keyboard.process_keyevent(pckb_ev)
321-
{
322-
if ch == '\n' {
323-
ch = '\r';
324-
}
325-
let mut buffer = [0u8; 6];
326-
let s = ch.encode_utf8(&mut buffer);
327-
for b in s.as_bytes() {
328-
menu.input_byte(*b);
329-
}
330-
}
331-
}
332-
bios::ApiResult::Ok(bios::FfiOption::Some(bios::hid::HidEvent::KeyRelease(code))) => {
333-
let pckb_ev = pc_keyboard::KeyEvent {
334-
code,
335-
state: pc_keyboard::KeyState::Up,
336-
};
337-
if let Some(pc_keyboard::DecodedKey::Unicode(ch)) =
338-
menu.context.keyboard.process_keyevent(pckb_ev)
339-
{
340-
let mut buffer = [0u8; 6];
341-
let s = ch.encode_utf8(&mut buffer);
342-
for b in s.as_bytes() {
343-
menu.input_byte(*b);
344-
}
345-
}
346-
}
347-
bios::ApiResult::Ok(bios::FfiOption::Some(bios::hid::HidEvent::MouseInput(
348-
_ignore,
349-
))) => {}
350-
bios::ApiResult::Ok(bios::FfiOption::None) => {
351-
// Do nothing
352-
}
353-
bios::ApiResult::Err(e) => {
354-
osprintln!("Failed to get HID events: {:?}", e);
355-
}
356-
}
357-
if let Some((uart_dev, _serial_conf)) = menu.context.config.get_serial_console() {
358-
loop {
359-
let mut buffer = [0u8; 8];
360-
let wrapper = neotron_common_bios::FfiBuffer::new(&mut buffer);
361-
match (api.serial_read)(uart_dev, wrapper, neotron_common_bios::FfiOption::None) {
362-
neotron_common_bios::ApiResult::Ok(n) if n == 0 => {
363-
break;
364-
}
365-
neotron_common_bios::ApiResult::Ok(n) => {
366-
for b in &buffer[0..n] {
367-
menu.input_byte(*b);
368-
}
369-
}
370-
_ => {
371-
break;
372-
}
373-
}
374-
}
423+
let mut buffer = [0u8; 16];
424+
let count = unsafe { STD_INPUT.get_data(&mut buffer) };
425+
for b in &buffer[0..count] {
426+
menu.input_byte(*b);
375427
}
376428
(api.power_idle)();
377429
}

src/program.rs

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -337,10 +337,19 @@ extern "C" fn api_write(
337337
///
338338
/// If you hit the end of the file, you might get less data than you asked for.
339339
extern "C" fn api_read(
340-
_fd: neotron_api::file::Handle,
341-
_buffer: neotron_api::FfiBuffer,
340+
fd: neotron_api::file::Handle,
341+
mut buffer: neotron_api::FfiBuffer,
342342
) -> neotron_api::Result<usize> {
343-
neotron_api::Result::Err(neotron_api::Error::Unimplemented)
343+
if fd == neotron_api::file::Handle::new_stdin() {
344+
if let Some(buffer) = buffer.as_mut_slice() {
345+
let count = unsafe { crate::STD_INPUT.get_data(buffer) };
346+
Ok(count).into()
347+
} else {
348+
neotron_api::Result::Err(neotron_api::Error::DeviceSpecific)
349+
}
350+
} else {
351+
neotron_api::Result::Err(neotron_api::Error::BadHandle)
352+
}
344353
}
345354

346355
/// Move the file offset (for the given file handle) to the given position.

0 commit comments

Comments
 (0)