memoribbon/memoribbon.rs

231 lines
5.2 KiB
Rust

use std::env::args;
use std::process::exit;
use std::io::prelude::*;
use std::fs::File;
use std::io;
static FILTER_STRENGTH:u8 = 200; // how severely to low-pass the incoming data
static OVERSAMPLE_FACTOR:usize = 10; // how many samples long are each bit in the decoder input?
static INVERT:bool = false; // whether or not the source inverts the samples
struct StreamCoder {
encoder:[u16;256],
decoder:[Option<u8>;65536],
}
fn streamcoder_gen() -> StreamCoder {
let mut output_a:[u16;256] = [0x0000;256];
let mut output_b:[Option<u8>;65536] = [None;65536];
let mut a:u8 = 0;
let mut b:u16 = 0;
loop {
let mut score:i8 = 0;
let mut max_consec:u8 = 0;
let mut consec:u8 = 0;
let mut state:bool = false;
for i in 0..16 {
let thisbit = b & (0x01 << i) != 0x00;
if thisbit != state {
state = thisbit;
consec = 1;
} else {
consec += 1;
}
if consec > max_consec {
max_consec = consec;
}
if thisbit {
score += 1;
} else {
score -= 1;
}
}
let mut errors:[u16;16] = [0x0000;16];
let mut errorcollide:bool = false;
for i in 0..16 {
errors[i] = b ^ (0x01 << i);
if output_b[errors[i] as usize] != None {
errorcollide = true;
}
}
if score == 0 && max_consec <= 8 && !errorcollide {
output_a[a as usize] = b;
output_b[b as usize] = Some(a);
for error in errors.iter() {
output_b[*error as usize] = Some(a);
}
if a == 0xFF {
break;
} else {
a += 1;
}
}
b += 1;
}
return StreamCoder {
encoder:output_a,
decoder:output_b,
};
}
fn code_bits(n:u16) -> [bool;16] {
let mut output:[bool;16] = [false;16];
for i in 0..16 {
output[i] = (n >> i) & 0x01 == 0x01;
}
return output;
}
fn bits_code(b:&[bool]) -> u16 {
let mut output:u16 = 0;
if b.len() < 16 {
return 0;
}
for i in 0..16 {
if b[i] {
output += (0x01 << i) as u16;
}
}
return output;
}
impl StreamCoder {
fn encode(&self,byte:u8) -> [bool;16] {
return code_bits(self.encoder[byte as usize]);
}
fn decode(&self,states:&[bool]) -> u8 {
return match self.decoder[bits_code(states) as usize] {
None => 0x20,
Some(b) => b,
};
}
}
fn main() {
let argv = args().collect::<Vec<String>>();
if argv.len() != 4 {
eprintln!("usage: memoribbon [d/e] [input file] [output file]");
exit(1);
}
let mode:&str = argv[1].trim_matches('-');
let mut ioinput:Box<dyn Read> = match argv[2].as_str() {
"-" => Box::new(io::stdin()),
_ => match File::open(&argv[2]) {
Err(why) => {
eprintln!("couldn't open file {} for reading: {}",argv[2],why);
exit(1);
},
Ok(f) => Box::new(f),
},
};
let mut iooutput:Box<dyn Write> = match argv[3].as_str() {
"-" => Box::new(io::stdout()),
_ => match File::create(&argv[3]) {
Err(why) => {
eprintln!("couldn't open file {} for writing: {}",argv[3],why);
exit(1);
},
Ok(f) => Box::new(f),
},
};
let coder = streamcoder_gen();
if mode == "e" {
match iooutput.write_all(&[0x80;1000]) {
Err(why) => {
eprintln!("write failed: {}",why);
exit(1);
},
Ok(_) => (),
};
let mut ibuffer:[u8;1] = [0x00];
loop {
match ioinput.read_exact(&mut ibuffer) {
Err(why) => match why.kind() {
io::ErrorKind::UnexpectedEof => break,
_ => {
eprintln!("read failed: {}",why);
exit(1);
}
},
Ok(_) => (),
};
let mut payload:Vec<u8> = Vec::with_capacity(18*OVERSAMPLE_FACTOR);
let bits = coder.encode(ibuffer[0]);
for i in 0..16 {
payload.append(&mut match bits[i] {
true => vec![0xFF;OVERSAMPLE_FACTOR],
false => vec![0x00;OVERSAMPLE_FACTOR],
});
}
payload.append(&mut vec![0x80;OVERSAMPLE_FACTOR*2]);
match iooutput.write_all(&payload) {
Err(why) => {
eprintln!("write failed: {}",why);
exit(1);
},
Ok(_) => (),
};
}
} else if mode == "d" {
let mut ibuffer:[u8;1] = [0x00];
let mut filterstate:u16 = 0x0080;
let mut logicstate:i8 = 0;
let mut sampleclock:usize = 1;
let mut outbits:Vec<bool> = Vec::with_capacity(16);
let mut outbyte:Option<u8> = None;
loop {
match ioinput.read_exact(&mut ibuffer) {
Err(why) => match why.kind() {
io::ErrorKind::UnexpectedEof => break,
_ => {
eprintln!("read failed: {}",why);
exit(1);
}
},
Ok(_) => (),
};
filterstate = filterstate*(FILTER_STRENGTH as u16)/0x00FF + ((0x00FF-FILTER_STRENGTH as u16)*ibuffer[0] as u16)/0x00FF;
let newlogicstate = match (filterstate > 170,filterstate < 85) {
(true,false) => 1,
(false,true) => -1,
_ => 0,
};
if logicstate != newlogicstate {
sampleclock = OVERSAMPLE_FACTOR/5;
}
logicstate = newlogicstate;
if (sampleclock + OVERSAMPLE_FACTOR/2) % OVERSAMPLE_FACTOR == 0 {
match logicstate {
1 => outbits.push(true ^ INVERT),
-1 => outbits.push(false ^ INVERT),
_ => if outbits.len() > 0 {
outbyte = Some(0x20);
outbits.clear();
},
};
}
if outbits.len() >= 16 {
outbyte = Some(coder.decode(&outbits));
outbits.clear();
}
if let Some(byte) = outbyte {
match iooutput.write_all(&[byte]) {
Err(why) => {
eprintln!("write failed: {}",why);
exit(1);
},
Ok(_) => (),
};
outbyte = None;
}
sampleclock += 1;
}
} else {
eprintln!("unknown mode operation `{}`",mode);
exit(1);
}
}