Skip to content

Commit

Permalink
Get read working
Browse files Browse the repository at this point in the history
  • Loading branch information
Dhole committed Sep 9, 2017
1 parent f901f7f commit 35a4532
Showing 1 changed file with 133 additions and 44 deletions.
177 changes: 133 additions & 44 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,8 @@ fn main() {
.version("0.1")
.about("Gameboy cartridge read/writer")
.author("Dhole")
.arg(Arg::with_name("baud")
.arg(
Arg::with_name("baud")
.help("Set the baud rate")
.short("b")
.long("baud")
Expand All @@ -45,28 +46,33 @@ fn main() {
.validator(|baud| match baud.parse::<usize>() {
Ok(_) => Ok(()),
Err(e) => Err(format!("{}", e)),
}))
.arg(Arg::with_name("serial")
.help("Set the serial device")
.short("s")
.long("serial")
.value_name("DEVICE")
.default_value("/dev/ttyACM0")
.takes_value(true)
.required(false))
.arg(Arg::with_name("board")
.help("Set the development board: generic, st")
.short("d")
.long("board")
.value_name("BOARD")
.default_value("st")
.takes_value(true)
.required(false)
.validator(|board| match board.as_str() {
"generic" => Ok(()),
"st" => Ok(()),
board => Err(format!("Invalid development board: {}", board)),
}))
}),
)
.arg(
Arg::with_name("serial")
.help("Set the serial device")
.short("s")
.long("serial")
.value_name("DEVICE")
.default_value("/dev/ttyACM0")
.takes_value(true)
.required(false),
)
.arg(
Arg::with_name("board")
.help("Set the development board: generic, st")
.short("d")
.long("board")
.value_name("BOARD")
.default_value("st")
.takes_value(true)
.required(false)
.validator(|board| match board.as_str() {
"generic" => Ok(()),
"st" => Ok(()),
board => Err(format!("Invalid development board: {}", board)),
}),
)
.get_matches();

let serial = matches.value_of("serial").unwrap();
Expand All @@ -86,7 +92,8 @@ fn main() {
process::exit(1);
}
};
port_raw.configure(&serial::PortSettings {
port_raw
.configure(&serial::PortSettings {
baud_rate: serial::BaudRate::from_speed(baud),
char_size: serial::Bits8,
parity: serial::ParityNone,
Expand All @@ -97,11 +104,19 @@ fn main() {
println!("Error configuring {}: {}", serial, e);
process::exit(1);
});
port_raw.set_timeout(Duration::from_secs(3600 * 24)).unwrap_or_else(|e| {
println!("Error setting timeout for {}: {}", serial, e);

port_clear(&mut port_raw).unwrap_or_else(|e| {
println!("Error clearing port {}: {}", serial, e);
process::exit(1);
});

port_raw
.set_timeout(Duration::from_secs(3600 * 24))
.unwrap_or_else(|e| {
println!("Error setting timeout for {}: {}", serial, e);
process::exit(1);
});

dev_reset(board).unwrap_or_else(|e| {
println!("Error resetting development board: {}", e);
process::exit(1);
Expand All @@ -111,6 +126,25 @@ fn main() {
gb_rw(&mut port).unwrap();
}

/// port_clear will reset the port timeout!
fn port_clear<T: SerialPort>(mut port: &mut T) -> Result<(), io::Error> {
port.set_timeout(Duration::from_millis(100))?;
let mut buf = vec![0; 16];
loop {
match port.read(&mut buf) {
Ok(0) => break,
Ok(_) => continue,
Err(e) => {
if e.kind() == ErrorKind::TimedOut {
break;
}
return Err(e);
}
}
}
return Ok(());
}

fn dev_reset(board: Board) -> Result<(), io::Error> {
match board {
Board::Generic => {
Expand All @@ -121,9 +155,13 @@ fn dev_reset(board: Board) -> Result<(), io::Error> {
let output = Command::new("st-flash").arg("reset").output()?;
println!("{}", String::from_utf8_lossy(&output.stderr));
if !output.status.success() {
return Err(Error::new(ErrorKind::Other,
format!("st-flash returned with error code {:?}",
output.status.code())));
return Err(Error::new(
ErrorKind::Other,
format!(
"st-flash returned with error code {:?}",
output.status.code()
),
));
}
}
}
Expand All @@ -141,6 +179,28 @@ enum Cmd {
}
}

enum_from_primitive! {
#[derive(Debug, PartialEq)]
enum ReplyCmd {
Ack,
Nack,
}
}

fn cmd_read(addr_start: u16, addr_end: u16) -> Vec<u8> {
let addr_start_lo = (addr_start & 0xff) as u8;
let addr_start_hi = ((addr_start & 0xff00) >> 8) as u8;
let addr_end_lo = (addr_end & 0xff) as u8;
let addr_end_hi = ((addr_end & 0xff00) >> 8) as u8;
return vec![
Cmd::Read as u8,
addr_start_lo,
addr_start_hi,
addr_end_lo,
addr_end_hi,
];
}

fn gb_rw<T: SerialPort>(mut port: &mut BufStream<T>) -> Result<(), io::Error> {
let mut buf = Vec::new();
loop {
Expand All @@ -152,31 +212,60 @@ fn gb_rw<T: SerialPort>(mut port: &mut BufStream<T>) -> Result<(), io::Error> {
}
println!("Connected!");

// try!(port.write_all(b"s"));
try!(port.write_all(vec![Cmd::Read as u8, 0x00, 0x00, 0x00, 0x01].as_slice()));
try!(port.flush());
let addr_start = 0x0000 as u16;
let addr_end = 0x4000 as u16;
port.write_all(cmd_read(addr_start, addr_end).as_slice())?;
port.flush()?;

let mut buf = vec![0; 16];
let mut n = 0;
loop {
print!("{:06x} ", n);
port.read_exact(&mut buf)?;
//let mut ack = vec![0];
//port.read_exact(&mut ack)?;
//match ReplyCmd::from_u8(ack[0]) {
// Some(ReplyCmd::Ack) => {}
// Some(ReplyCmd::Nack) => {
// return Err(Error::new(ErrorKind::Other, "Board replied NACK"));
// }
// None => {
// return Err(Error::new(ErrorKind::Other, "Board reply is invalid"));
// }
//}

let mut buf = vec![0; (addr_end - addr_start) as usize];
//let mut buf = vec![0; 0x600];
port.read_exact(&mut buf)?;
print_hex(&buf, 0x0000);
println!();

return Ok(());
}

fn print_hex(buf: &[u8], addr_start: u16) {
//for n in (0..100).step_by(16) { // Unstable :(
for n in (0..div_round_up(buf.len(), 16)).map(|n| n * 16) {
print!("{:06x} ", (addr_start as usize) + n);
for i in 0..16 {
print!("{:02x} ", buf[i]);
if n + i < buf.len() {
print!("{:02x} ", buf[n + i])
} else {
print!(" ")
}
if i == 7 {
print!(" ");
}
}
print!(" |");
for b in &buf {
let mut c = *b as char;
if *b < 32 || *b > 126 {
c = '.'
}
for i in 0..16 {
let c = if n + i < buf.len() {
let b = buf[n + i];
if b < 32 || b > 126 { '.' } else { b as char }
} else {
' '
};
print!("{}", c);
}
print!("|\n");
n += 16;
}
}

fn div_round_up(x: usize, y: usize) -> usize {
return (x + y - 1) / y;
}

0 comments on commit 35a4532

Please sign in to comment.