231 lines
5.2 KiB
Rust
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);
|
|
}
|
|
}
|