Finish binary file loading

This commit is contained in:
pjht 2024-01-31 11:28:56 -06:00
parent 9a2e02e1ee
commit 189fd790c1
Signed by: pjht
GPG Key ID: CA239FC6934E6F3A
4 changed files with 142 additions and 39 deletions

126
src/load_bin_window.rs Normal file
View File

@ -0,0 +1,126 @@
use std::{fmt::Display, path::PathBuf};
use eframe::egui::{self, DragValue};
use egui_modal::Modal;
use rfd::FileDialog;
use crate::{state::EmuState, window::Window};
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
enum BinaryType {
Raw,
IntelHex,
}
impl Display for BinaryType {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::Raw => f.write_str("Raw"),
Self::IntelHex => f.write_str("Intel HEX"),
}
}
}
pub struct LoadBinWindow {
path: Option<PathBuf>,
ftype: BinaryType,
start_addr: u16,
}
impl LoadBinWindow {
pub fn new(ctx: &egui::Context) -> Self {
Modal::new(ctx, "load_bin_modal").open();
Self {
path: None,
ftype: BinaryType::Raw,
start_addr: 0,
}
}
fn choose_file(&mut self) {
let ihex_exts = ["hex", "mcs", "int", "ihex", "ihe", "ihx"];
let file = FileDialog::new()
.add_filter(
"Binary files",
&["bin", "img", "hex", "mcs", "int", "ihex", "ihe", "ihx"],
)
.add_filter("All files", &["*"])
.pick_file();
let Some(file) = file else {
return;
};
if file
.extension()
.map_or(false, |ext| ihex_exts.contains(&ext.to_str().unwrap_or("")))
{
self.ftype = BinaryType::IntelHex;
} else {
self.ftype = BinaryType::Raw;
}
self.path = Some(file);
}
fn load_file(&self, state: &mut EmuState) {
let path = self.path.as_ref().unwrap();
match self.ftype {
BinaryType::Raw => {
let bin = std::fs::read(path).unwrap();
state.write_binary(self.start_addr as usize, bin);
}
BinaryType::IntelHex => {
let data = std::fs::read_to_string(path).unwrap();
for record in ihex::Reader::new(&data) {
let record = record.unwrap();
match record {
ihex::Record::Data { offset, value } => {
state.write_binary(offset as usize, value);
}
ihex::Record::StartLinearAddress(_) => todo!(),
ihex::Record::EndOfFile => (),
_ => unimplemented!(),
};
}
}
}
}
}
impl Window for LoadBinWindow {
fn draw(&mut self, ctx: &egui::Context, state: &mut EmuState) -> bool {
let modal = Modal::new(ctx, "load_bin_modal");
modal.show(|ui| {
modal.title(ui, "Load binary");
ui.horizontal(|ui| {
if ui.button("Choose file").clicked() {
self.choose_file();
}
ui.label(format!(
"{}",
self.path.as_ref().map_or("".into(), |x| x
.file_name()
.map_or("".into(), |x| x.to_string_lossy().to_string()))
));
});
egui::ComboBox::from_label("File type")
.selected_text(format!("{}", self.ftype))
.show_ui(ui, |ui| {
ui.selectable_value(&mut self.ftype, BinaryType::Raw, "Raw");
ui.selectable_value(&mut self.ftype, BinaryType::IntelHex, "Intel HEX");
});
ui.horizontal(|ui| {
ui.set_enabled(self.ftype != BinaryType::IntelHex);
ui.add(DragValue::new(&mut self.start_addr).clamp_range(0..=65535));
ui.label("Start address");
});
modal.buttons(ui, |ui| {
modal.caution_button(ui, "Cancel");
ui.add_enabled_ui(self.path.is_some(), |ui| {
if modal.suggested_button(ui, "Load").clicked() {
self.load_file(state);
}
})
});
});
!modal.is_open()
}
}

View File

@ -2,10 +2,11 @@ mod audio;
mod card;
mod cpu;
mod frontpanel;
mod ram;
mod window;
mod state;
mod load_bin_window;
mod option_window;
mod ram;
mod state;
mod window;
use std::collections::HashMap;
@ -15,6 +16,7 @@ use eframe::{
NativeOptions,
};
use frontpanel::Textures;
use load_bin_window::LoadBinWindow;
use option_window::OptionWindow;
use rfd::FileDialog;
use serde::{Deserialize, Serialize};
@ -56,12 +58,11 @@ struct AltairEmulator {
windows: HashMap<&'static str, Box<dyn Window>>,
}
impl AltairEmulator {
fn new(cc: &eframe::CreationContext<'_>) -> Self {
let audio_tx = AudioThread::init();
let options = if cc.storage.unwrap().get_string("options").is_none() {
Options::default()
Options::default()
} else {
eframe::get_value(cc.storage.unwrap(), "options").unwrap()
};
@ -89,37 +90,8 @@ impl AltairEmulator {
ui.close_menu();
}
if ui.button("Load binary file").clicked() {
let ihex_exts = ["hex", "mcs", "int", "ihex", "ihe", "ihx"];
let file = FileDialog::new()
.add_filter(
"Binary files",
&["bin", "img", "hex", "mcs", "int", "ihex", "ihe", "ihx"],
)
.add_filter("All files", &["*"])
.pick_file();
if let Some(file) = file {
if file
.extension()
.map_or(false, |ext| ihex_exts.contains(&ext.to_str().unwrap_or("")))
{
let data = std::fs::read_to_string(file).unwrap();
for record in ihex::Reader::new(&data) {
let record = record.unwrap();
match record {
ihex::Record::Data { offset, value } => {
self.state.write_binary(offset as usize, value);
}
ihex::Record::StartLinearAddress(_) => todo!(),
ihex::Record::EndOfFile => (),
_ => unimplemented!(),
};
}
} else {
// Raw binary
todo!();
}
self.state.update_fp();
}
self.windows
.insert("load_bin_window", Box::new(LoadBinWindow::new(ui.ctx())));
}
});
});

View File

@ -1,7 +1,7 @@
use eframe::egui::{self, Slider};
use egui_modal::Modal;
use crate::{Options, state::EmuState, window::Window};
use crate::{state::EmuState, window::Window, Options};
pub struct OptionWindow {
options: Options,

View File

@ -2,7 +2,12 @@ use std::sync::mpsc::Sender;
use rand::RngCore;
use crate::{cpu::{I8080, Status, MemCycle}, audio::AudioMessage, Options, frontpanel::{FrontpanelState, FrontpanelInteraction, ActionSwitch, switch::SwitchState}};
use crate::{
audio::AudioMessage,
cpu::{MemCycle, Status, I8080},
frontpanel::{switch::SwitchState, ActionSwitch, FrontpanelInteraction, FrontpanelState},
Options,
};
pub struct EmuState {
mem: [u8; 65536],
@ -23,7 +28,7 @@ impl EmuState {
running: false,
audio_tx,
options,
fp_state: FrontpanelState::new()
fp_state: FrontpanelState::new(),
};
slf.apply_options();
slf