Modified the PTY implementation to be use channels

This commit is contained in:
transistor 2021-10-22 19:36:05 -07:00
parent 447b3727ed
commit 2ed528a140
6 changed files with 142 additions and 139 deletions

60
src/host/gfx.rs Normal file
View 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));
}
}

View File

@ -4,3 +4,5 @@ pub mod traits;
#[cfg(feature = "tty")]
pub mod tty;
pub mod gfx;

View File

@ -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));
}
}

View File

@ -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
}
}

View File

@ -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)
}

View File

@ -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;