use crate::color::*;
use std::io::Write;
use std::*;
const PORT: u16 = 5577;
pub struct Bulb {
conn: Option<net::TcpStream>,
ip: net::IpAddr,
}
impl Bulb {
pub fn new(ip: net::IpAddr) -> Bulb {
let mut b = Bulb { conn: None, ip };
let _ = b.connection();
b
}
fn connection(&mut self) -> io::Result<&mut net::TcpStream> {
if let Some(ref mut conn) = self.conn {
return Ok(conn);
}
let conn = net::TcpStream::connect((self.ip, PORT))?;
conn.set_read_timeout(Some(time::Duration::from_millis(100)))?;
self.conn = Some(conn);
Ok(self.conn.as_mut().unwrap())
}
pub fn set_constant_color(&mut self, pix: Pixel) -> io::Result<()> {
self.send_with_checksum(&[0x31, pix.r, pix.g, pix.b, 0x00, 0x00, 0x0f])
}
fn send_with_checksum(&mut self, data: &[u8]) -> io::Result<()> {
let rs = if let Ok(conn) = self.connection() {
let checksum = data.iter().fold(0, |accum, b| accum + u32::from(*b)) as u8;
let buf: Vec<u8> = data.iter().cloned().chain(iter::once(checksum)).collect();
conn.write_all(&buf)
} else {
Ok(())
};
if rs.is_err() {
self.conn = None;
}
rs
}
}
pub struct Display {
pub bulbs: Vec<Bulb>,
pub buf: Vec<u8>,
}
impl io::Write for Display {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
let need = self.bulbs.len() * 3;
let n = self.buf.write(buf)?;
if self.buf.len() >= need {
self.flush()?;
}
Ok(n)
}
fn flush(&mut self) -> io::Result<()> {
for (bulb, chunk) in self.bulbs.iter_mut().zip(self.buf.chunks(3)) {
let _ = bulb.set_constant_color(Pixel {
r: chunk[0],
g: chunk[1],
b: chunk[2],
});
}
self.buf.clear();
Ok(())
}
}