use std::io::{stdin, Read, Write};
use std::os::unix::io::{AsRawFd, FromRawFd};
use std::{cell::RefCell, convert::Infallible, fs::File, process::Command, time::Duration};
use embedded_graphics_core::{pixelcolor::Rgb888, prelude::*};
use embedded_graphics_simulator::{
OutputSettingsBuilder, SimulatorDisplay, SimulatorEvent, Window,
};
use embedded_term::Console;
use libc::{self, winsize};
use mio::{unix::EventedFd, Events, Poll, PollOpt, Ready, Token};
use pty::fork::Fork;
use termios::{cfmakeraw, tcsetattr, Termios, TCSANOW};
const DISPLAY_SIZE: Size = Size::new(800, 600);
fn main() {
let fork = Fork::from_ptmx().unwrap();
if let Ok(mut master) = fork.is_parent() {
env_logger::init();
let display = SimulatorDisplay::<Rgb888>::new(DISPLAY_SIZE);
let display = RefCell::new(display);
let mut console = Console::on_frame_buffer(DisplayWrapper(&display));
let poll = Poll::new().unwrap();
poll.register(
&EventedFd(&master.as_raw_fd()),
Token(0),
Ready::readable(),
PollOpt::edge(),
)
.unwrap();
let fd = stdin().as_raw_fd();
let mut termios = Termios::from_fd(fd).unwrap();
cfmakeraw(&mut termios);
tcsetattr(fd, TCSANOW, &termios).unwrap();
let ws = winsize {
ws_row: console.rows() as libc::c_ushort,
ws_col: console.columns() as libc::c_ushort,
ws_xpixel: DISPLAY_SIZE.width as libc::c_ushort,
ws_ypixel: DISPLAY_SIZE.height as libc::c_ushort,
};
let res = unsafe { libc::ioctl(master.as_raw_fd(), libc::TIOCSWINSZ, &ws as *const _) };
if res < 0 {
panic!(
"ioctl TIOCSWINSZ failed: {}",
std::io::Error::last_os_error()
);
}
let mut stdin = unsafe { File::from_raw_fd(fd) };
poll.register(
&EventedFd(&fd),
Token(1),
Ready::readable(),
PollOpt::edge(),
)
.unwrap();
let mut events = Events::with_capacity(1024);
let output_settings = OutputSettingsBuilder::new().build();
let mut window = Window::new("Example", &output_settings);
loop {
poll.poll(&mut events, Some(Duration::from_millis(10)))
.unwrap();
let mut buffer = [0u8; 10240];
for event in events.iter() {
match event.token() {
Token(0) => {
let len = master.read(&mut buffer).unwrap();
for c in &buffer[..len] {
console.write_byte(*c);
}
}
Token(1) => {
let len = stdin.read(&mut buffer).unwrap();
master.write_all(&buffer[..len]).unwrap();
}
_ => unreachable!(),
}
}
while let Some(byte) = console.pop_report() {
master.write_all(&[byte]).unwrap();
}
window.update(&display.borrow_mut());
if window.events().any(|e| e == SimulatorEvent::Quit) {
break;
}
}
} else {
let mut args = std::env::args_os();
args.next(); let name = args.next().unwrap();
Command::new(name)
.args(args)
.status()
.expect("could not execute program");
}
}
struct DisplayWrapper<'a>(&'a RefCell<SimulatorDisplay<Rgb888>>);
impl DrawTarget for DisplayWrapper<'_> {
type Color = Rgb888;
type Error = Infallible;
fn draw_iter<I>(&mut self, pixels: I) -> Result<(), Self::Error>
where
I: IntoIterator<Item = Pixel<Self::Color>>,
{
self.0.borrow_mut().draw_iter(pixels)
}
}
impl OriginDimensions for DisplayWrapper<'_> {
fn size(&self) -> Size {
self.0.borrow().size()
}
}