From be03b5aff24196b7187d4dbd84e78fb42b957174 Mon Sep 17 00:00:00 2001 From: Atreya Bain Date: Tue, 5 Mar 2024 18:37:57 +0530 Subject: [PATCH] [kbd] Implement keyboard and adapter --- src/device/device.rs | 11 ++++-- src/device/keyboard.rs | 68 +++++++++++++++++++++++++++++++++++++ src/device/mod.rs | 3 +- src/main.rs | 26 +++++++++----- src/sdl_keyboard_adapter.rs | 34 +++++++++++++++++++ src/util.rs | 8 +++++ 6 files changed, 138 insertions(+), 12 deletions(-) create mode 100644 src/device/keyboard.rs create mode 100644 src/sdl_keyboard_adapter.rs diff --git a/src/device/device.rs b/src/device/device.rs index 0d00b00..5ea0af8 100644 --- a/src/device/device.rs +++ b/src/device/device.rs @@ -6,7 +6,9 @@ use std::thread::{JoinHandle, sleep}; use std::time::Duration; use rand::random; use crate::device::instruction::Instruction; +use crate::device::keyboard::Keyboard; use crate::device::timer::Timer; +use crate::util::EmulatorResult; pub struct Device { @@ -16,6 +18,7 @@ pub struct Device { pub stack: Vec, pub frame_buffer: Arc>>, pub super_chip8_mode: bool, + pub device_keyboard: Keyboard, } impl Device { @@ -23,7 +26,7 @@ impl Device { pub const FRAME_BUFFER_WIDTH: usize = 64; pub const FRAME_BUFFER_HEIGHT: usize = 32; pub const FRAME_BUFFER_SIZE: usize = Self::FRAME_BUFFER_WIDTH * Self::FRAME_BUFFER_HEIGHT; - pub fn new(timer: Timer, fb: Arc>>) -> Device { + pub fn new(timer: Timer, fb: Arc>>, device_keyboard: Keyboard) -> Device { let memory = vec![0u8; Self::DEVICE_MEMORY_SIZE].into_boxed_slice().try_into().unwrap(); log::trace!("Successfully initiated device memory"); Device { @@ -33,6 +36,7 @@ impl Device { stack: Vec::with_capacity(16), timer, super_chip8_mode: false, + device_keyboard } } } @@ -59,13 +63,16 @@ impl Device { const FONT_DEFAULT_MEM_LOCATION_START: usize = 0x50; const FONT_DEFAULT_MEM_LOCATION_END: usize = 0x9F; const ROM_START: usize = 0x200; - pub fn cycle(&mut self) { + pub fn cycle(&mut self) ->EmulatorResult<()>{ + self.device_keyboard.update_keyboard()?; + let pc = self.registers.pc as usize; let instr_slice = self.memory.get(pc..pc + 2).expect("Failed to get memory"); self.registers.pc += 2; let instruction = Instruction::decode_instruction(instr_slice); self.execute_instruction(instruction); + Ok(()) } /// convert the 2 indices into one fn get_framebuffer_index(x: usize, y: usize) -> usize { diff --git a/src/device/keyboard.rs b/src/device/keyboard.rs new file mode 100644 index 0000000..b597f82 --- /dev/null +++ b/src/device/keyboard.rs @@ -0,0 +1,68 @@ +use std::sync::mpsc::TryRecvError; +use crate::util::{EmulatorError, EmulatorResult}; + + +// display thread sends these to the device thread. + +// device thread updates on key up and down? + + +pub struct Keyboard { + bitflags: u16, + keyboard_event_receiver: std::sync::mpsc::Receiver, +} + +#[derive(Clone, Debug, Eq, PartialEq)] +pub enum KeyboardEvent { + KeyUp(u8), + KeyDown(u8), +} + +impl Keyboard { + pub fn new(keyboard_event_receiver: std::sync::mpsc::Receiver) -> Keyboard { + Keyboard { + bitflags: 0, + keyboard_event_receiver, + } + } + + /// Update keyboard based on pending keyboard events + pub fn update_keyboard(&mut self) -> EmulatorResult<()> { + loop { + let keyboard_event_recv_res = self.keyboard_event_receiver.try_recv(); + match keyboard_event_recv_res { + Ok(event) => { + log::warn!("Processing {:?}",event); + self.update_keyboard_state(event); + } + Err(TryRecvError::Empty) => { + break Ok(()); + } + Err(TryRecvError::Disconnected) => { + break Err(EmulatorError::IOError("Keyboard updater disconnected".into())); + } + } + } + } + + + /// Query if key is down + pub fn query_key_down(&self, key_num: u8) -> bool { + (self.bitflags | 1 << key_num) == (1 << key_num) + } + + fn update_keyboard_state(&mut self, keyboard_event: KeyboardEvent) { + match keyboard_event { + KeyboardEvent::KeyUp(key) => { self.key_up(key) } + KeyboardEvent::KeyDown(key) => { self.key_down(key) } + } + } + fn key_down(&mut self, x: u8) { + self.bitflags |= 1 << x; + log::trace!("Key Down - state {}",self.bitflags); + } + fn key_up(&mut self, x: u8) { + self.bitflags &= !((1 << x) as u16); + log::debug!("Key Up - state {}",self.bitflags); + } +} \ No newline at end of file diff --git a/src/device/mod.rs b/src/device/mod.rs index 7d0ff85..17e513a 100644 --- a/src/device/mod.rs +++ b/src/device/mod.rs @@ -1,6 +1,7 @@ pub mod timer; -mod device; +pub mod keyboard; mod sound; pub mod instruction; +mod device; pub use device::*; diff --git a/src/main.rs b/src/main.rs index 7e101a9..ca36f6d 100644 --- a/src/main.rs +++ b/src/main.rs @@ -16,15 +16,18 @@ use sdl2::render::WindowCanvas; use simple_logger::SimpleLogger; use device::timer::Timer; use crate::device::Device; +use crate::device::keyboard::Keyboard; use crate::util::EmulatorResult; use crate::kb_map::get_key_index; use crate::sdl_graphics_adapter::SdlGraphicsAdapter; +use crate::sdl_keyboard_adapter::SdlKeyboardAdapter; mod args; mod device; mod kb_map; mod sdl_graphics_adapter; mod util; +mod sdl_keyboard_adapter; fn main() -> EmulatorResult<()> { SimpleLogger::new().with_level(LevelFilter::Info).env().init().unwrap(); @@ -33,13 +36,14 @@ fn main() -> EmulatorResult<()> { let mut timer = Timer::new(); timer.start(); - let frame_buffer_for_display = get_frame_buffer(); - let frame_buffer_for_device = Arc::clone(&frame_buffer_for_display); + let (frame_buffer_for_display, frame_buffer_for_device) = get_frame_buffer_references(); + + let (sdl_kb_adapter,device_keyboard) = SdlKeyboardAdapter::new_keyboard(); let (termination_signal_sender, termination_signal_sender_receiver) = std::sync::mpsc::channel(); - + let compute_handle = thread::Builder::new().name("Compute".to_string()).spawn(move || { - do_device_loop(timer, frame_buffer_for_device, termination_signal_sender_receiver); + do_device_loop(timer, frame_buffer_for_device, termination_signal_sender_receiver, device_keyboard); })?; let (mut canvas, mut event_pump) = try_initiate_sdl(8f32)?; @@ -59,11 +63,13 @@ fn main() -> EmulatorResult<()> { } Event::KeyDown { keycode: Some(x), repeat: false, .. } => { if let Some(key_val) = get_key_index(x) { + sdl_kb_adapter.send_key_down(key_val)?; log::info!("Key+ {}",key_val) } } Event::KeyUp { keycode: Some(x), repeat: false, .. } => { if let Some(key_val) = get_key_index(x) { + sdl_kb_adapter.send_key_up(key_val)?; log::info!("Key- {}",key_val) } } @@ -87,8 +93,8 @@ fn main() -> EmulatorResult<()> { Ok(()) } -fn do_device_loop(mut timer: Timer, frame_buffer: Arc>>, receiver: Receiver<()>) { - let mut device = Device::new(timer, frame_buffer); +fn do_device_loop(mut timer: Timer, frame_buffer: Arc>>, receiver: Receiver<()>, device_keyboard: Keyboard) { + let mut device = Device::new(timer, frame_buffer, device_keyboard); device.set_default_font(); { let rom = load_rom(); @@ -102,15 +108,17 @@ fn do_device_loop(mut timer: Timer, frame_buffer: Arc>>, } else if let Err(std::sync::mpsc::TryRecvError::Disconnected) = val { panic!("Disconnected"); } - device.cycle(); + device.cycle().expect("Failed to execute"); // Put a bit of delay to slow down execution thread::sleep(Duration::from_nanos(500)) } } -fn get_frame_buffer() -> Arc>> { - Arc::new(Mutex::new(vec![false; Device::FRAME_BUFFER_SIZE].into_boxed_slice().try_into().unwrap())) +fn get_frame_buffer_references() -> (Arc>>, Arc>>) { + let arc = Arc::new(Mutex::new(vec![false; Device::FRAME_BUFFER_SIZE].into_boxed_slice().try_into().unwrap())); + let arc2 = Arc::clone(&arc); + (arc,arc2) } const ROM_SIZE: usize = 4096 - 0x200; diff --git a/src/sdl_keyboard_adapter.rs b/src/sdl_keyboard_adapter.rs new file mode 100644 index 0000000..f9613a9 --- /dev/null +++ b/src/sdl_keyboard_adapter.rs @@ -0,0 +1,34 @@ +use std::sync::mpsc::Sender; +use crate::device::keyboard::{Keyboard, KeyboardEvent}; +use crate::device::keyboard::KeyboardEvent::{KeyDown, KeyUp}; +use crate::util::EmulatorResult; + +#[derive(Debug)] +pub struct SdlKeyboardAdapter { + keyboard_event_sender: Sender, +} + +impl SdlKeyboardAdapter { + fn new(keyboard_event_sender: Sender) -> SdlKeyboardAdapter { + SdlKeyboardAdapter { + keyboard_event_sender + } + } + /// Creates a paired keyboard and adapter. + pub fn new_keyboard()->(SdlKeyboardAdapter, Keyboard){ + let (sender,receiver) = std::sync::mpsc::channel(); + let sdl2_kb_adapter = Self::new(sender); + let device_kb = Keyboard::new(receiver); + (sdl2_kb_adapter,device_kb) + } + + pub fn send_key_up(&self, keycode: u8) -> EmulatorResult { + self.keyboard_event_sender.send(KeyUp(keycode))?; + Ok(keycode) + } + pub fn send_key_down(&self, keycode: u8) -> EmulatorResult { + self.keyboard_event_sender.send(KeyDown(keycode))?; + Ok(keycode) + } + +} diff --git a/src/util.rs b/src/util.rs index 227aa8e..5d84b88 100644 --- a/src/util.rs +++ b/src/util.rs @@ -1,6 +1,8 @@ +use std::sync::mpsc::SendError; use std::sync::PoisonError; use sdl2::IntegerOrSdlError; use sdl2::video::WindowBuildError; +use crate::device::keyboard::KeyboardEvent; pub type EmulatorResult = Result; @@ -43,3 +45,9 @@ impl From> for EmulatorError{ Self::MutexInvalidState(value.to_string()) } } + +impl From> for EmulatorError{ + fn from(value: SendError) -> Self { + Self::IOError(format!("Failed to communicate keyboard stats to main thread: {}",value)) + } +} \ No newline at end of file