mirror of
https://github.com/transistorfet/moa.git
synced 2025-01-11 05:29:42 +00:00
Modified the PTY implementation to be use channels
This commit is contained in:
parent
447b3727ed
commit
2ed528a140
60
src/host/gfx.rs
Normal file
60
src/host/gfx.rs
Normal file
@ -0,0 +1,60 @@
|
||||
|
||||
use std::sync::{Arc, Mutex};
|
||||
|
||||
use crate::host::traits::WindowUpdater;
|
||||
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Frame {
|
||||
pub width: u32,
|
||||
pub height: u32,
|
||||
pub bitmap: Vec<u32>,
|
||||
}
|
||||
|
||||
pub struct FrameSwapper {
|
||||
pub current: Frame,
|
||||
pub previous: Frame,
|
||||
}
|
||||
|
||||
impl FrameSwapper {
|
||||
pub fn new() -> FrameSwapper {
|
||||
FrameSwapper {
|
||||
current: Frame { width: 0, height: 0, bitmap: vec![] },
|
||||
previous: Frame { width: 0, height: 0, bitmap: vec![] },
|
||||
}
|
||||
}
|
||||
|
||||
pub fn new_shared() -> Arc<Mutex<FrameSwapper>> {
|
||||
Arc::new(Mutex::new(FrameSwapper::new()))
|
||||
}
|
||||
|
||||
pub fn to_boxed(swapper: Arc<Mutex<FrameSwapper>>) -> Box<dyn WindowUpdater> {
|
||||
Box::new(FrameSwapperWrapper(swapper))
|
||||
}
|
||||
}
|
||||
|
||||
impl WindowUpdater for FrameSwapper {
|
||||
fn update_frame(&mut self, width: u32, height: u32, bitmap: &mut [u32]) {
|
||||
std::mem::swap(&mut self.current, &mut self.previous);
|
||||
if self.current.width != width || self.current.height != height {
|
||||
self.current.width = width;
|
||||
self.current.height = height;
|
||||
self.current.bitmap.resize((width * height) as usize, 0);
|
||||
self.previous = self.current.clone();
|
||||
return;
|
||||
}
|
||||
|
||||
for i in 0..(width as usize * height as usize) {
|
||||
bitmap[i] = self.current.bitmap[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct FrameSwapperWrapper(Arc<Mutex<FrameSwapper>>);
|
||||
|
||||
impl WindowUpdater for FrameSwapperWrapper {
|
||||
fn update_frame(&mut self, width: u32, height: u32, bitmap: &mut [u32]) {
|
||||
self.0.lock().map(|mut swapper| swapper.update_frame(width, height, bitmap));
|
||||
}
|
||||
}
|
||||
|
@ -4,3 +4,5 @@ pub mod traits;
|
||||
#[cfg(feature = "tty")]
|
||||
pub mod tty;
|
||||
|
||||
pub mod gfx;
|
||||
|
||||
|
@ -5,69 +5,17 @@ use crate::error::Error;
|
||||
|
||||
|
||||
pub trait Host {
|
||||
//fn create_pty(&self) -> Result<Box<dyn Tty>, Error>;
|
||||
fn add_window(&self, updater: Box<dyn WindowUpdater>) -> Result<(), Error>;
|
||||
//fn create_pty(&self) -> Tty;
|
||||
}
|
||||
|
||||
// TODO should you rename this Drawable, FrameUpdater, WindowUpdater?
|
||||
pub trait Tty {
|
||||
fn device_name(&self) -> String;
|
||||
fn read(&mut self) -> Option<u8>;
|
||||
fn write(&mut self, output: u8) -> bool;
|
||||
}
|
||||
|
||||
pub trait WindowUpdater: Send {
|
||||
fn update_frame(&mut self, width: u32, height: u32, bitmap: &mut [u32]);
|
||||
}
|
||||
|
||||
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Frame {
|
||||
pub width: u32,
|
||||
pub height: u32,
|
||||
pub bitmap: Vec<u32>,
|
||||
}
|
||||
|
||||
pub struct FrameSwapper {
|
||||
pub current: Frame,
|
||||
pub previous: Frame,
|
||||
}
|
||||
|
||||
impl FrameSwapper {
|
||||
pub fn new() -> FrameSwapper {
|
||||
FrameSwapper {
|
||||
current: Frame { width: 0, height: 0, bitmap: vec![] },
|
||||
previous: Frame { width: 0, height: 0, bitmap: vec![] },
|
||||
}
|
||||
}
|
||||
|
||||
pub fn new_shared() -> Arc<Mutex<FrameSwapper>> {
|
||||
Arc::new(Mutex::new(FrameSwapper::new()))
|
||||
}
|
||||
|
||||
pub fn to_boxed(swapper: Arc<Mutex<FrameSwapper>>) -> Box<dyn WindowUpdater> {
|
||||
Box::new(FrameSwapperWrapper(swapper))
|
||||
}
|
||||
}
|
||||
|
||||
impl WindowUpdater for FrameSwapper {
|
||||
fn update_frame(&mut self, width: u32, height: u32, bitmap: &mut [u32]) {
|
||||
std::mem::swap(&mut self.current, &mut self.previous);
|
||||
println!("{} {}", self.current.width, self.current.height);
|
||||
if self.current.width != width || self.current.height != height {
|
||||
self.current.width = width;
|
||||
self.current.height = height;
|
||||
self.current.bitmap.resize((width * height) as usize, 0);
|
||||
self.previous = self.current.clone();
|
||||
return;
|
||||
}
|
||||
|
||||
for i in 0..(width as usize * height as usize) {
|
||||
bitmap[i] = self.current.bitmap[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct FrameSwapperWrapper(Arc<Mutex<FrameSwapper>>);
|
||||
|
||||
impl WindowUpdater for FrameSwapperWrapper {
|
||||
fn update_frame(&mut self, width: u32, height: u32, bitmap: &mut [u32]) {
|
||||
self.0.lock().map(|mut swapper| swapper.update_frame(width, height, bitmap));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,5 +1,6 @@
|
||||
|
||||
use std::thread;
|
||||
use std::sync::mpsc;
|
||||
use std::time::Duration;
|
||||
use std::io::{Read, Write};
|
||||
use std::sync::{Arc, Mutex};
|
||||
@ -10,81 +11,58 @@ use nix::pty::{self, PtyMaster};
|
||||
use nix::fcntl::{fcntl, FcntlArg};
|
||||
|
||||
use crate::error::Error;
|
||||
use crate::host::traits::Tty;
|
||||
|
||||
|
||||
pub struct SimplePty {
|
||||
pub name: String,
|
||||
input: Option<u8>,
|
||||
output: Vec<u8>,
|
||||
input: mpsc::Receiver<u8>,
|
||||
output: mpsc::Sender<u8>,
|
||||
}
|
||||
|
||||
pub type SharedSimplePty = Arc<Mutex<SimplePty>>;
|
||||
|
||||
impl SimplePty {
|
||||
pub fn new_shared(name: String) -> SharedSimplePty {
|
||||
Arc::new(Mutex::new(SimplePty {
|
||||
pub fn new(name: String, input: mpsc::Receiver<u8>, output: mpsc::Sender<u8>) -> SimplePty {
|
||||
SimplePty {
|
||||
name,
|
||||
input: None,
|
||||
output: vec![],
|
||||
}))
|
||||
input,
|
||||
output,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn open() -> Result<SharedSimplePty, Error> {
|
||||
pub fn open() -> Result<SimplePty, Error> {
|
||||
let pty = pty::posix_openpt(OFlag::O_RDWR).and_then(|pty| {
|
||||
pty::grantpt(&pty)?;
|
||||
pty::unlockpt(&pty)?;
|
||||
fcntl(pty.as_raw_fd(), FcntlArg::F_SETFL(OFlag::O_NONBLOCK))?;
|
||||
Ok(pty)
|
||||
}).map_err(|_| Error::new("Error opening new pseudoterminal"))?;
|
||||
|
||||
let name = unsafe { pty::ptsname(&pty).map_err(|_| Error::new("Unable to get pty name"))? };
|
||||
let shared = SimplePty::new_shared(name);
|
||||
SimplePty::spawn_poller(pty, shared.clone());
|
||||
let (input_tx, input_rx) = mpsc::channel();
|
||||
let (output_tx, output_rx) = mpsc::channel();
|
||||
let shared = SimplePty::new(name.clone(), input_rx, output_tx);
|
||||
|
||||
SimplePty::spawn_poller(pty, name, input_tx, output_rx);
|
||||
Ok(shared)
|
||||
}
|
||||
|
||||
pub fn read(&mut self) -> Option<u8> {
|
||||
if self.input.is_some() {
|
||||
let input = self.input;
|
||||
self.input = None;
|
||||
input
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
pub fn write(&mut self, output: u8) -> bool {
|
||||
self.output.push(output);
|
||||
true
|
||||
}
|
||||
|
||||
fn spawn_poller(mut pty: PtyMaster, shared: SharedSimplePty) {
|
||||
fn spawn_poller(mut pty: PtyMaster, name: String, input_tx: mpsc::Sender<u8>, output_rx: mpsc::Receiver<u8>) {
|
||||
thread::spawn(move || {
|
||||
println!("pty: spawned reader for {}", shared.lock().unwrap().name);
|
||||
println!("pty: spawned reader for {}", name);
|
||||
|
||||
fcntl(pty.as_raw_fd(), FcntlArg::F_SETFL(OFlag::O_NONBLOCK)).unwrap();
|
||||
|
||||
let mut buf = [0; 1];
|
||||
loop {
|
||||
{
|
||||
let mut value = shared.lock().unwrap();
|
||||
if value.input.is_none() {
|
||||
match pty.read(&mut buf) {
|
||||
Ok(_) => {
|
||||
(*value).input = Some(buf[0]);
|
||||
},
|
||||
Err(err) if err.kind() == std::io::ErrorKind::WouldBlock => { },
|
||||
Err(err) => {
|
||||
println!("ERROR: {:?}", err);
|
||||
}
|
||||
}
|
||||
}
|
||||
match pty.read(&mut buf) {
|
||||
Ok(_) => {
|
||||
input_tx.send(buf[0]);
|
||||
},
|
||||
Err(err) if err.kind() == std::io::ErrorKind::WouldBlock => { },
|
||||
Err(err) => { println!("ERROR: {:?}", err); }
|
||||
}
|
||||
|
||||
if !value.output.is_empty() {
|
||||
match pty.write_all(value.output.as_slice()) {
|
||||
Ok(()) => { },
|
||||
_ => panic!(""),
|
||||
}
|
||||
(*value).output.clear();
|
||||
}
|
||||
while let Ok(data) = output_rx.try_recv() {
|
||||
pty.write_all(&[data]).unwrap();
|
||||
}
|
||||
|
||||
thread::sleep(Duration::from_millis(10));
|
||||
@ -93,3 +71,21 @@ impl SimplePty {
|
||||
}
|
||||
}
|
||||
|
||||
impl Tty for SimplePty {
|
||||
fn device_name(&self) -> String {
|
||||
self.name.clone()
|
||||
}
|
||||
|
||||
fn read(&mut self) -> Option<u8> {
|
||||
match self.input.try_recv() {
|
||||
Ok(data) => Some(data),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
fn write(&mut self, output: u8) -> bool {
|
||||
self.output.send(output);
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -9,29 +9,27 @@ use crate::peripherals::ata::AtaDevice;
|
||||
use crate::peripherals::mc68681::MC68681;
|
||||
|
||||
use crate::host::traits::Host;
|
||||
use crate::host::tty::SimplePty;
|
||||
|
||||
|
||||
pub fn build_computie<H: Host>(host: &H) -> Result<System, Error> {
|
||||
let mut system = System::new();
|
||||
|
||||
let monitor = MemoryBlock::load("binaries/monitor.bin").unwrap();
|
||||
for byte in monitor.contents.iter() {
|
||||
print!("{:02x} ", byte);
|
||||
}
|
||||
system.add_addressable_device(0x00000000, wrap_transmutable(monitor)).unwrap();
|
||||
let monitor = MemoryBlock::load("binaries/monitor.bin")?;
|
||||
system.add_addressable_device(0x00000000, wrap_transmutable(monitor))?;
|
||||
|
||||
let mut ram = MemoryBlock::new(vec![0; 0x00100000]);
|
||||
ram.load_at(0, "binaries/kernel.bin").unwrap();
|
||||
system.add_addressable_device(0x00100000, wrap_transmutable(ram)).unwrap();
|
||||
ram.load_at(0, "binaries/kernel.bin")?;
|
||||
system.add_addressable_device(0x00100000, wrap_transmutable(ram))?;
|
||||
|
||||
let mut ata = AtaDevice::new();
|
||||
ata.load("binaries/disk-with-partition-table.img").unwrap();
|
||||
system.add_addressable_device(0x00600000, wrap_transmutable(ata)).unwrap();
|
||||
ata.load("binaries/disk-with-partition-table.img")?;
|
||||
system.add_addressable_device(0x00600000, wrap_transmutable(ata))?;
|
||||
|
||||
let mut serial = MC68681::new();
|
||||
launch_terminal_emulator(serial.port_a.open().unwrap());
|
||||
launch_slip_connection(serial.port_b.open().unwrap());
|
||||
system.add_addressable_device(0x00700000, wrap_transmutable(serial)).unwrap();
|
||||
launch_terminal_emulator(serial.port_a.connect(Box::new(SimplePty::open()?))?);
|
||||
launch_slip_connection(serial.port_b.connect(Box::new(SimplePty::open()?))?);
|
||||
system.add_addressable_device(0x00700000, wrap_transmutable(serial))?;
|
||||
|
||||
|
||||
let mut cpu = M68k::new(M68kType::MC68010);
|
||||
@ -45,7 +43,7 @@ pub fn build_computie<H: Host>(host: &H) -> Result<System, Error> {
|
||||
//cpu.decoder.dump_disassembly(&mut system, 0x100000, 0x2000);
|
||||
//cpu.decoder.dump_disassembly(&mut system, 0x2ac, 0x200);
|
||||
|
||||
system.add_interruptable_device(wrap_transmutable(cpu)).unwrap();
|
||||
system.add_interruptable_device(wrap_transmutable(cpu))?;
|
||||
|
||||
Ok(system)
|
||||
}
|
||||
@ -53,21 +51,21 @@ pub fn build_computie<H: Host>(host: &H) -> Result<System, Error> {
|
||||
pub fn build_computie_k30<H: Host>(host: &H) -> Result<System, Error> {
|
||||
let mut system = System::new();
|
||||
|
||||
let monitor = MemoryBlock::load("binaries/monitor-68030.bin").unwrap();
|
||||
system.add_addressable_device(0x00000000, wrap_transmutable(monitor)).unwrap();
|
||||
let monitor = MemoryBlock::load("binaries/monitor-68030.bin")?;
|
||||
system.add_addressable_device(0x00000000, wrap_transmutable(monitor))?;
|
||||
|
||||
let mut ram = MemoryBlock::new(vec![0; 0x00100000]);
|
||||
ram.load_at(0, "binaries/kernel-68030.bin").unwrap();
|
||||
system.add_addressable_device(0x00100000, wrap_transmutable(ram)).unwrap();
|
||||
ram.load_at(0, "binaries/kernel-68030.bin")?;
|
||||
system.add_addressable_device(0x00100000, wrap_transmutable(ram))?;
|
||||
|
||||
let mut ata = AtaDevice::new();
|
||||
ata.load("binaries/disk-with-partition-table.img").unwrap();
|
||||
system.add_addressable_device(0x00600000, wrap_transmutable(ata)).unwrap();
|
||||
ata.load("binaries/disk-with-partition-table.img")?;
|
||||
system.add_addressable_device(0x00600000, wrap_transmutable(ata))?;
|
||||
|
||||
let mut serial = MC68681::new();
|
||||
launch_terminal_emulator(serial.port_a.open().unwrap());
|
||||
//launch_slip_connection(serial.port_b.open().unwrap());
|
||||
system.add_addressable_device(0x00700000, wrap_transmutable(serial)).unwrap();
|
||||
launch_terminal_emulator(serial.port_a.connect(Box::new(SimplePty::open()?))?);
|
||||
//launch_slip_connection(serial.port_b.connect(Box::new(SimplePty::open()?))?);
|
||||
system.add_addressable_device(0x00700000, wrap_transmutable(serial))?;
|
||||
|
||||
|
||||
let mut cpu = M68k::new(M68kType::MC68030);
|
||||
@ -81,7 +79,7 @@ pub fn build_computie_k30<H: Host>(host: &H) -> Result<System, Error> {
|
||||
//cpu.decoder.dump_disassembly(&mut system, 0x100000, 0x2000);
|
||||
//cpu.decoder.dump_disassembly(&mut system, 0x2ac, 0x200);
|
||||
|
||||
system.add_interruptable_device(wrap_transmutable(cpu)).unwrap();
|
||||
system.add_interruptable_device(wrap_transmutable(cpu))?;
|
||||
|
||||
Ok(system)
|
||||
}
|
||||
|
@ -3,7 +3,7 @@ use crate::error::Error;
|
||||
use crate::system::System;
|
||||
use crate::devices::{Clock, Address, Steppable, Addressable, Transmutable, MAX_READ};
|
||||
|
||||
use crate::host::tty::{SimplePty, SharedSimplePty};
|
||||
use crate::host::traits::Tty;
|
||||
|
||||
|
||||
const REG_MR1A_MR2A: Address = 0x01;
|
||||
@ -71,7 +71,7 @@ const ISR_CH_A_TX_READY: u8 = 0x01;
|
||||
const DEV_NAME: &'static str = "mc68681";
|
||||
|
||||
pub struct MC68681Port {
|
||||
pub tty: Option<SharedSimplePty>,
|
||||
pub tty: Option<Box<dyn Tty>>,
|
||||
pub status: u8,
|
||||
|
||||
pub tx_enabled: bool,
|
||||
@ -93,16 +93,15 @@ impl MC68681Port {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn open(&mut self) -> Result<String, Error> {
|
||||
let pty = SimplePty::open()?;
|
||||
let name = pty.lock().unwrap().name.clone();
|
||||
pub fn connect(&mut self, pty: Box<dyn Tty>) -> Result<String, Error> {
|
||||
let name = pty.device_name();
|
||||
println!("{}: opening pts {}", DEV_NAME, name);
|
||||
self.tty = Some(pty);
|
||||
Ok(name)
|
||||
}
|
||||
|
||||
pub fn send_byte(&mut self, data: u8) {
|
||||
self.tty.as_mut().map(|tty| tty.lock().unwrap().write(data));
|
||||
self.tty.as_mut().map(|tty| tty.write(data));
|
||||
self.set_tx_status(false);
|
||||
}
|
||||
|
||||
@ -123,7 +122,7 @@ impl MC68681Port {
|
||||
pub fn check_rx(&mut self) -> Result<bool, Error> {
|
||||
if self.rx_enabled && (self.status & SR_RX_READY) == 0 && self.tty.is_some() {
|
||||
let tty = self.tty.as_mut().unwrap();
|
||||
let result = tty.lock().unwrap().read();
|
||||
let result = tty.read();
|
||||
match result {
|
||||
Some(input) => {
|
||||
self.input = input;
|
||||
|
Loading…
x
Reference in New Issue
Block a user