#![feature(c_size_t)] use chrono::{Datelike, Local, Timelike}; use sdl2::event::Event; use sdl2::keyboard::{Keycode, Mod}; use sdl2::pixels::PixelFormatEnum; use sdl2::rect::Rect; use sdl2::render::{BlendMode, Canvas, Texture, TextureCreator}; use sdl2::video::{Window, WindowContext}; use socket::Socket; use std::io::{self, Read, Write}; use std::mem::MaybeUninit; use std::sync::mpsc; use std::{fs, ptr, thread, time::Duration}; use uxn::{DeviceHandler, Uxn}; use wintap::Tap; mod args; #[macro_use] mod report; mod socket; mod symbols; use crate::socket::Connection; use self::args::*; use self::symbols::*; const RAM_SIZE: usize = 65536; const ZERO_PAGE_SIZE: usize = 256; const DEFAULT_WIDTH: u16 = 64 * 8; const DEFAULT_HEIGHT: u16 = 40 * 8; const PAD: u32 = 4; fn main() { let args = Args::parse(); let _symbols = args.symbols_path.map(|path| { Symbols::from_path(&path).unwrap_or_else(|inner| { exit_with_error!("Could not parse symbols from `{}`: {inner}", path.display()); }) }); let mut ram = [0u8; RAM_SIZE]; let rom = fs::read(&args.rom_path).unwrap_or_else(|inner| { exit_with_error!("Could not read `{}`: {inner}", args.rom_path.display()) }); if rom.len() > RAM_SIZE - ZERO_PAGE_SIZE { exit_with_error!("ROM is too large to fit in RAM"); } unsafe { ptr::copy_nonoverlapping(rom.as_ptr(), ram[ZERO_PAGE_SIZE..].as_mut_ptr(), rom.len()); } // let (stdin_tx, stdin_rx) = mpsc::channel(); // thread::spawn(move || { // for byte in io::stdin().bytes().flat_map(|res| res.ok()) { // if stdin_tx.send(byte).is_err() { // break; // } // } // }); // let zoom = args.zoom.unwrap_or(1); // let sdl_context = sdl2::init().unwrap_or_else(|inner| { // exit_with_error!("Could not initialize SDL2: {inner}"); // }); // let video_subsystem = sdl_context.video().unwrap_or_else(|inner| { // exit_with_error!("Could not initialize SDL2 video subsystem: {inner}"); // }); // let window = video_subsystem // .window("Daikon", 0, 0) // .position_centered() // .allow_highdpi() // .build() // .unwrap_or_else(|inner| { // exit_with_error!("Could not create SDL2 window: {inner}"); // }) // .tap(); // let canvas = window.into_canvas().build().unwrap_or_else(|inner| { // exit_with_error!("Could not build SDL2 renderer: {inner}"); // }); // let texture_creator = canvas.texture_creator(); // let screen_handler = Sdl2ScreenHandler::new(canvas, &texture_creator, zoom); // let mut varvara = Varvara { // system: System::default(), // console: Console::new(ConsoleHandler {}), // // screen: Screen::new(screen_handler), // controller: Controller::default(), // mouse: Mouse::default(), // file0: File::default(), // file1: File::default(), // datetime: Datetime::new(ChronoDatetimeHandler), // }; // varvara.screen.set_size(DEFAULT_WIDTH, DEFAULT_HEIGHT); const PORT: u16 = 80; let mut uxn = Uxn::new().with_ram(ram); let mut handler = Handler::default(); uxn.run(0x100, &mut handler).unwrap(); let socket = Socket::new(PORT, 64).unwrap_or_else(|inner| { exit_with_error!("Could not create a socket: {inner}"); }); eprintln!("Listening on http://localhost:{PORT}/"); loop { if handler.vector != 0 { let connection = match socket.accept() { Ok(connection) => connection, Err(inner) => { warning!("Error while accepting the connection: {inner}"); continue; } }; handler.connection.replace(connection); uxn.run(handler.vector, &mut handler).unwrap(); let connection = handler.connection.take().unwrap(); connection.close().unwrap_or_else(|inner| { warning!("Error while closing the connection: {inner}"); }); } } // let mut event_pump = sdl_context.event_pump().unwrap_or_else(|inner| { // exit_with_error!("Could not create SDL2 event pump: {inner}"); // }); // 'event_loop: loop { // for event in event_pump.poll_iter() { // match event { // Event::Quit { .. } => break 'event_loop, // Event::MouseMotion { x, y, .. } => { // let x = (x - PAD as i32).clamp(0, varvara.screen.width() as i32 - 1) as u16; // let y = (y - PAD as i32).clamp(0, varvara.screen.height() as i32 - 1) as u16; // varvara.mouse.set_position(x, y); // if let Some(addr) = varvara.mouse.vector() { // uxn.run(addr.get(), &mut varvara).unwrap(); // } // } // Event::MouseButtonDown { mouse_btn, .. } => { // varvara.mouse.set_state(mouse_btn as u8); // if let Some(addr) = varvara.mouse.vector() { // uxn.run(addr.get(), &mut varvara).unwrap(); // } // } // Event::MouseButtonUp { mouse_btn, .. } => { // varvara.mouse.reset_state(mouse_btn as u8); // if let Some(addr) = varvara.mouse.vector() { // uxn.run(addr.get(), &mut varvara).unwrap(); // } // } // Event::MouseWheel { x, y, .. } => { // varvara.mouse.set_scroll(x as i16 as u16, -y as i16 as u16); // if let Some(addr) = varvara.mouse.vector() { // uxn.run(addr.get(), &mut varvara).unwrap(); // } // varvara.mouse.set_scroll(0, 0); // } // Event::KeyDown { // keycode: Some(keycode), // keymod, // .. // } => { // if let Some(key) = get_key(keycode, keymod) { // varvara.controller.set_key(key); // if let Some(addr) = varvara.controller.vector() { // uxn.run(addr.get(), &mut varvara).unwrap(); // } // varvara.controller.set_key(0); // } else if let Some(button) = get_button(keycode) { // varvara.controller.set_button(button); // } // } // Event::KeyUp { // keycode: Some(keycode), // .. // } => { // if let Some(button) = get_button(keycode) { // varvara.controller.reset_button(button); // } // } // _ => {} // } // } // while let Ok(byte) = stdin_rx.try_recv() { // varvara.console.set_read(byte); // if let Some(addr) = varvara.console.vector() { // uxn.run(addr.get(), &mut varvara).unwrap(); // } // } // if let Some(addr) = varvara.screen.vector() { // uxn.run(addr.get(), &mut varvara).unwrap(); // } // varvara.screen.redraw(); // thread::sleep(Duration::new(0, 1_000_000_000u32 / 60)); // } } // struct ConsoleHandler {} // impl console::Handler for ConsoleHandler { // fn on_write(&mut self, val: u8) { // io::stdout().lock().write(&[val]).unwrap(); // } // fn on_error(&mut self, val: u8) { // io::stderr().lock().write(&[val]).unwrap(); // } // } // struct Sdl2ScreenHandler<'a> { // canvas: Canvas, // texture_creator: &'a TextureCreator, // texture: MaybeUninit>, // zoom: u32, // } // impl<'a> Sdl2ScreenHandler<'a> { // pub fn new( // canvas: Canvas, // texture_creator: &'a TextureCreator, // zoom: u32, // ) -> Self { // Self { // canvas, // texture_creator, // texture: MaybeUninit::uninit(), // zoom, // } // } // } // impl<'a> screen::Handler for Sdl2ScreenHandler<'a> { // fn on_resize(&mut self, width: u32, height: u32) { // self.canvas // .window_mut() // .set_size( // (width + PAD * 2) * self.zoom, // (height + PAD * 2) * self.zoom, // ) // .unwrap_or_else(|inner| { // exit_with_error!("Could not set size for SDL2 window: {inner}"); // }); // self.canvas // .set_logical_size(width + PAD * 2, height + PAD * 2) // .unwrap_or_else(|inner| { // exit_with_error!("Could not set logical size for SDL2 renderer: {inner}"); // }); // let mut tex = self // .texture_creator // .create_texture_static(PixelFormatEnum::RGB888, width, height) // .unwrap_or_else(|inner| { // exit_with_error!("Could not create SDL2 texture: {inner}"); // }); // tex.set_blend_mode(BlendMode::None); // self.texture.write(tex); // } // fn on_redraw(&mut self, bytes: &[u8], width: u32, height: u32) { // let texture = unsafe { self.texture.assume_init_mut() }; // texture // .update(None, bytes, width as usize * std::mem::size_of::()) // .unwrap_or_else(|inner| { // exit_with_error!("Could not update SDL2 texture: {inner}"); // }); // self.canvas.clear(); // self.canvas // .copy( // &texture, // None, // Rect::new(PAD as i32, PAD as i32, width as u32, height as u32), // ) // .unwrap_or_else(|inner| { // exit_with_error!("Could not copy texture to SDL2 canvas: {inner}"); // }); // self.canvas.present(); // } // } // pub fn get_key(keycode: Keycode, keymod: Mod) -> Option { // if (keycode as i32) < 0x20 || keycode == Keycode::Delete { // return Some(keycode as u8); // } // if !(keymod & (Mod::LCTRLMOD | Mod::RCTRLMOD)).is_empty() { // if (keycode as i32) < (Keycode::A as i32) { // return Some(keycode as u8); // } else if (keycode as i32) <= (Keycode::Z as i32) { // return Some( // (keycode as i32 - (keymod & (Mod::LSHIFTMOD | Mod::RSHIFTMOD)).bits() as i32 * 0x20) // as u8, // ); // } // } // None // } // pub fn get_button(keycode: Keycode) -> Option { // match keycode { // Keycode::LCtrl => Some(0x01), // Keycode::LAlt => Some(0x02), // Keycode::LShift => Some(0x04), // Keycode::Home => Some(0x08), // Keycode::Up => Some(0x10), // Keycode::Down => Some(0x20), // Keycode::Left => Some(0x40), // Keycode::Right => Some(0x80), // _ => None, // } // } // struct ChronoDatetimeHandler; // impl datetime::Handler for ChronoDatetimeHandler { // fn year(&self) -> u16 { // Local::now().year() as u16 // } // fn month(&self) -> u8 { // Local::now().month0() as u8 // } // fn day(&self) -> u8 { // Local::now().day() as u8 // } // fn hour(&self) -> u8 { // Local::now().hour() as u8 // } // fn minute(&self) -> u8 { // Local::now().minute() as u8 // } // fn second(&self) -> u8 { // Local::now().second() as u8 // } // fn day_of_year(&self) -> u16 { // Local::now().ordinal0() as u16 // } // fn day_of_week(&self) -> u8 { // Local::now().weekday().num_days_from_sunday() as u8 // } // fn is_dst(&self) -> u8 { // -1 as i8 as u8 // } // } #[derive(Default)] struct Handler { vector: u16, len: u16, read: u16, write: u16, success: u16, error: u8, connection: Option, } impl DeviceHandler for Handler { fn device_in(&mut self, _: &mut Uxn, addr: u8) -> u8 { match addr { 0xf0 => self.vector.msb(), 0xf1 => self.vector.lsb(), 0xf2 => self.len.msb(), 0xf3 => self.len.lsb(), 0xf4 => self.read.msb(), 0xf5 => self.read.lsb(), 0xf6 => self.write.msb(), 0xf7 => self.write.lsb(), 0xf8 => self.success.msb(), 0xf9 => self.success.lsb(), 0xfa => self.error, _ => todo!("{addr:02x} DEI"), } } fn device_out(&mut self, uxn: &mut Uxn, addr: u8, val: u8) { // eprintln!("{val:02x} {addr:02x} DEO"); match addr { 0xf0 => self.vector.set_msb(val), 0xf1 => self.vector.set_lsb(val), 0xf2 => self.len.set_msb(val), 0xf3 => self.len.set_lsb(val), 0xf4 => self.read.set_msb(val), 0xf5 => { self.read.set_lsb(val); if let Some(connection) = self.connection.as_mut() { let buf = &mut uxn.ram[self.read as usize..self.read as usize + self.len as usize]; match connection.read(buf) { Ok(n) => { self.success = n as u16; self.error = 0; } Err(_) => { self.success = 0; self.error = 1; } } } } 0xf6 => self.write.set_msb(val), 0xf7 => { self.write.set_lsb(val); if let Some(connection) = self.connection.as_mut() { let buf = &uxn.ram[self.write as usize..self.write as usize + self.len as usize]; match connection.write(buf) { Ok(n) => { self.success = n as u16; self.error = 0; } Err(_) => { self.success = 0; self.error = 1; } } } } 0xf8 => self.success.set_msb(val), 0xf9 => self.success.set_lsb(val), 0xfa => self.error = val, _ => todo!("{val:02x} {addr:02x} DEO"), } } } trait Short { fn msb(&self) -> u8; fn lsb(&self) -> u8; fn set_msb(&mut self, msb: u8); fn set_lsb(&mut self, lsb: u8); } impl Short for u16 { fn msb(&self) -> u8 { ((*self & 0xff00) >> 8) as u8 } fn lsb(&self) -> u8 { (*self & 0x00ff) as u8 } fn set_msb(&mut self, msb: u8) { *self = ((msb as u16) << 8) | (*self & 0x00ff); } fn set_lsb(&mut self, lsb: u8) { *self = (*self & 0xff00) | (lsb as u16); } }