flfire/src/lib.rs

300 lines
9.3 KiB
Rust

extern crate libusb;
const FIRE_VENDOR: u16 = 0x09e8;
const FIRE_PRODUCT: u16 = 0x0043;
pub fn get_fires<'a>(context: &libusb::Context) -> Vec<libusb::Device> {
let devs = context.devices().expect("Failed to get connected devices");
devs.iter().filter(|d| {
if let Ok(desc) = d.device_descriptor() {
if desc.vendor_id() == FIRE_VENDOR && desc.product_id() == FIRE_PRODUCT {
true
} else {
false
}
} else {
false
}
}).collect::<Vec<_>>()
}
pub fn claim_fires<'a>(fires: &'a [libusb::Device]) -> Vec<libusb::DeviceHandle<'a>> {
let mut handles = fires.iter().map(|dev| dev.open().expect("Failed to access a FIRE")).collect::<Vec<_>>();
handles.iter_mut().for_each(|h| {
let _ = h.detach_kernel_driver(1); // Allowed to fail due to for example no attached kernel driver
h.claim_interface(1).expect("Failed to claim a FIRE");
});
handles
}
const INPUT_BLOCKS: usize = 5;
pub fn get_input(fires: &[libusb::DeviceHandle], timeout: std::time::Duration) -> Vec<[u8; INPUT_BLOCKS * 4]> {
let mut res = Vec::with_capacity(fires.len());
for h in fires.iter() {
let mut buf = [0u8; INPUT_BLOCKS*4];
match h.read_bulk(0x81, &mut buf, timeout) {
Ok(_) => {},
Err(e) => {
match e {
libusb::Error::Timeout => {},
_ => panic!("Failed to read FIRE {}", e),
}
},
}
res.push(buf);
}
res
}
const UNKNOWN_EXTRA: usize = 2;
pub fn render_pixelbuf(buf: &[u8], width: usize, height: usize, x: usize, y: usize) -> Vec<u8> {
let write_mode = 0x0e;
let mut res: Vec<u8> = Vec::new();
let out_buf = pix8_to_pix7(&transform_pixel_buffer(buf, width));
let block_rem = (out_buf.len() - 2) % 3;
let length = out_buf.len() + (2 - block_rem) + 2 + UNKNOWN_EXTRA;
// Insert the header
let first = out_buf[0];
res.extend_from_slice(&[0x04,0xf0,0x47,0x7f,0x04,0x43,write_mode,
(length >> 7) as u8,0x04,(length & 0b111_1111) as u8,
(y / 8) as u8,((y+height) / 8 - 1) as u8,0x04,x as u8,(x+width-1) as u8, first]);
// And the pixel buffer
res.extend_from_slice(&[0x0f, out_buf[1], 0x0, 0x0]);
for (i, v) in out_buf[2..].iter().enumerate() {
if (i % 3) == 0 {
res.push(0x04);
}
res.push(*v);
}
if block_rem > 0 {
// There is a partial block left, change the last block
// to the termination sequence
let pos = res.len() - block_rem - 1;
res[pos] = 0x07;
for _ in 0..(2-block_rem) {
res.push(0x00);
}
} else {
// Just add the termination sequence
res.push(0x07);
res.push(0x00);
res.push(0x00);
}
res.push(0xf7);
res
}
fn reverse_byte(b: u8) -> u8 {
let mut r = 0u8;
for s in 0..8 {
r |= (b >> s & 1) << (7 - s)
}
r
}
struct Bitbuffer<'a> { // NOTE Could be an iterator
buf: &'a [u8],
index: usize,
shift: usize,
}
impl<'a> Bitbuffer<'a> {
fn new(buf: &'a [u8]) -> Self {
Self {
buf,
index: 0,
shift: 7,
}
}
fn pop_bit(&mut self) -> Option<u8> {
if self.index >= self.buf.len() {
None
} else {
let bit = (self.buf[self.index] >> self.shift) & 0b1;
if self.shift == 0 {
self.shift = 7;
self.index += 1;
} else {
self.shift -= 1;
}
Some(bit)
}
}
fn has_more(&self) -> bool {
self.index < self.buf.len()
}
}
fn pix8_to_pix7(buf: &[u8]) -> Vec<u8> {
let mut res = Vec::with_capacity(buf.len() * 8 / 7);
let mut bitbuf = Bitbuffer::new(&buf);
loop {
let mut byte = 0;
for _ in 0..7 {
byte <<= 1;
byte |= bitbuf.pop_bit().unwrap_or(0);
}
res.push(byte);
if !bitbuf.has_more() {
break;
}
}
res
}
fn transform_pixel_buffer(buf: &[u8], width: usize) -> Vec<u8> {
let mut res = Vec::with_capacity(buf.len());
let dwidth = width / 8;
for line in 0..(buf.len() / width) {
for x_bit in 0..width {
let mut byte = 0;
for y in 0..8 {
let val = *buf.get(line * 8 * dwidth
+ y * dwidth
+ x_bit / 8).unwrap_or(&0);
byte <<= 1;
byte |= (reverse_byte(val) >> (x_bit % 8)) & 0b1;
}
res.push(reverse_byte(byte));
}
}
res
}
const clear_screen: [u8; 16 * 8] = [
0x04,0xf0,0x47,0x7f,0x04,0x43,0x08,0x00,
0x04,0x03,0x00,0x00,0x06,0x00,0xf7,0x00,
0x04,0xf0,0x47,0x7f,0x04,0x43,0x08,0x00,
0x04,0x03,0x00,0x00,0x06,0x01,0xf7,0x00,
0x04,0xf0,0x47,0x7f,0x04,0x43,0x08,0x00,
0x04,0x03,0x00,0x00,0x06,0x02,0xf7,0x00,
0x04,0xf0,0x47,0x7f,0x04,0x43,0x08,0x00,
0x04,0x03,0x00,0x00,0x06,0x03,0xf7,0x00,
0x04,0xf0,0x47,0x7f,0x04,0x43,0x08,0x00,
0x04,0x03,0x00,0x00,0x06,0x04,0xf7,0x00,
0x04,0xf0,0x47,0x7f,0x04,0x43,0x08,0x00,
0x04,0x03,0x00,0x00,0x06,0x05,0xf7,0x00,
0x04,0xf0,0x47,0x7f,0x04,0x43,0x08,0x00,
0x04,0x03,0x00,0x00,0x06,0x06,0xf7,0x00,
0x04,0xf0,0x47,0x7f,0x04,0x43,0x08,0x00,
0x04,0x03,0x00,0x00,0x06,0x07,0xf7,0x00
];
pub fn read_pbm(path: &str) -> (usize, usize, Vec<u8>) {
let data = std::fs::read(path).unwrap();
let s = String::from_utf8(data).unwrap();
let mut iter = s.split_whitespace();
assert_eq!(iter.next(), Some("P1"));
let w = iter.next().unwrap().parse::<usize>().unwrap();
let h = iter.next().unwrap().parse::<usize>().unwrap();
let mut res = Vec::with_capacity(w * h);
let mut bit = 0;
let mut byte = 0;
for e in iter {
byte <<= 1;
byte |= if e == "1" { 1 } else { 0 };
bit += 1;
if bit == 8 {
res.push(byte);
bit = 0;
}
}
assert_eq!(w/8*h, res.len(), "Image data has invalid or incompatible dimensions");
(w, h, res)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn byte_reverse_1() {
assert_eq!(reverse_byte(0b11001010), 0b01010011);
}
#[test]
fn pix8_to_pix7_1() {
assert_eq!(&pix8_to_pix7(&[0,255,0,255,0,255,0,255]),
&[0b0000000, 0b0111111, 0b1100000, 0b0001111,
0b1111000, 0b0000011, 0b1111110, 0b0000000,
0b1111111, 0b1000000])
}
#[test]
fn transform_pixel_buffer_1() {
assert_eq!(&transform_pixel_buffer(&[0b00000000,
0b11111111,
0b10101010,
0b01010101,
0b10101010,
0b11110000,
0b00001111,
0b11111111], 8),
&[0b10110110,0b10101010,0b10110110,0b10101010,
0b11010110,0b11001010,0b11010110,0b11001010]);
}
#[test]
fn transform_pixel_buffer_2() {
assert_eq!(&transform_pixel_buffer(&[0b00000000,0b00000000,
0b11111111,0b11111111,
0b10101010,0b10101010,
0b01010101,0b01010101,
0b10101010,0b10101010,
0b11110000,0b11110000,
0b00001111,0b00001111,
0b11111111,0b11111111,
0b00000000,0b00000000,
0b11111111,0b11111111,
0b10101010,0b10101010,
0b01010101,0b01010101,
0b10101010,0b10101010,
0b11110000,0b11110000,
0b00001111,0b00001111,
0b11111111,0b11111111], 16),
&[0b10110110,0b10101010,0b10110110,0b10101010,
0b11010110,0b11001010,0b11010110,0b11001010,
0b10110110,0b10101010,0b10110110,0b10101010,
0b11010110,0b11001010,0b11010110,0b11001010,
0b10110110,0b10101010,0b10110110,0b10101010,
0b11010110,0b11001010,0b11010110,0b11001010,
0b10110110,0b10101010,0b10110110,0b10101010,
0b11010110,0b11001010,0b11010110,0b11001010]);
}
#[test]
fn bitbuffer_1() {
let bits = [0b10100101, 0b00001111];
let mut bitbuf = Bitbuffer::new(&bits);
for s in 0..8 {
assert_eq!(bitbuf.pop_bit(), Some((bits[0] >> (7 - s)) & 0b1));
}
for s in 0..8 {
assert_eq!(bitbuf.pop_bit(), Some((bits[1] >> (7 - s)) & 0b1));
}
assert_eq!(bitbuf.pop_bit(), None);
}
}