[kbd] Implement keyboard and adapter
This commit is contained in:
@@ -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<u16>,
|
||||
pub frame_buffer: Arc<Mutex<Box<[bool; 64 * 32]>>>,
|
||||
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<Mutex<Box<[bool; Device::FRAME_BUFFER_SIZE]>>>) -> Device {
|
||||
pub fn new(timer: Timer, fb: Arc<Mutex<Box<[bool; Device::FRAME_BUFFER_SIZE]>>>, 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 {
|
||||
|
68
src/device/keyboard.rs
Normal file
68
src/device/keyboard.rs
Normal file
@@ -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<KeyboardEvent>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||
pub enum KeyboardEvent {
|
||||
KeyUp(u8),
|
||||
KeyDown(u8),
|
||||
}
|
||||
|
||||
impl Keyboard {
|
||||
pub fn new(keyboard_event_receiver: std::sync::mpsc::Receiver<KeyboardEvent>) -> 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);
|
||||
}
|
||||
}
|
@@ -1,6 +1,7 @@
|
||||
pub mod timer;
|
||||
mod device;
|
||||
pub mod keyboard;
|
||||
mod sound;
|
||||
pub mod instruction;
|
||||
mod device;
|
||||
|
||||
pub use device::*;
|
||||
|
26
src/main.rs
26
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<Mutex<Box<[bool; 2048]>>>, receiver: Receiver<()>) {
|
||||
let mut device = Device::new(timer, frame_buffer);
|
||||
fn do_device_loop(mut timer: Timer, frame_buffer: Arc<Mutex<Box<[bool; 2048]>>>, 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<Mutex<Box<[bool; 2048]>>>,
|
||||
} 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<Mutex<Box<[bool; 2048]>>> {
|
||||
Arc::new(Mutex::new(vec![false; Device::FRAME_BUFFER_SIZE].into_boxed_slice().try_into().unwrap()))
|
||||
fn get_frame_buffer_references() -> (Arc<Mutex<Box<[bool; 2048]>>>, Arc<Mutex<Box<[bool; 2048]>>>) {
|
||||
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;
|
||||
|
34
src/sdl_keyboard_adapter.rs
Normal file
34
src/sdl_keyboard_adapter.rs
Normal file
@@ -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<KeyboardEvent>,
|
||||
}
|
||||
|
||||
impl SdlKeyboardAdapter {
|
||||
fn new(keyboard_event_sender: Sender<KeyboardEvent>) -> 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<u8> {
|
||||
self.keyboard_event_sender.send(KeyUp(keycode))?;
|
||||
Ok(keycode)
|
||||
}
|
||||
pub fn send_key_down(&self, keycode: u8) -> EmulatorResult<u8> {
|
||||
self.keyboard_event_sender.send(KeyDown(keycode))?;
|
||||
Ok(keycode)
|
||||
}
|
||||
|
||||
}
|
@@ -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<T> = Result<T, EmulatorError>;
|
||||
|
||||
@@ -43,3 +45,9 @@ impl<T> From<PoisonError<T>> for EmulatorError{
|
||||
Self::MutexInvalidState(value.to_string())
|
||||
}
|
||||
}
|
||||
|
||||
impl From<SendError<KeyboardEvent>> for EmulatorError{
|
||||
fn from(value: SendError<KeyboardEvent>) -> Self {
|
||||
Self::IOError(format!("Failed to communicate keyboard stats to main thread: {}",value))
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user