use byteorder::LittleEndian;
use byteorder::WriteBytesExt;
use error::EtherdreamError;
use point::PipelinePoint;
use point::SimplePoint;
use protocol::Begin;
use protocol::COMMAND_PING;
use protocol::COMMAND_PREPARE;
use protocol::CommandCode;
use protocol::DacResponse;
use protocol::Point;
use std::io::Read;
use std::io::Write;
use std::net::IpAddr;
use std::net::TcpStream;
use std::time::Duration;
pub struct Dac {
ip_address: IpAddr,
stream: TcpStream,
}
impl Dac {
pub fn new(ip_address: IpAddr) -> Dac {
let stream = TcpStream::connect((ip_address, 7765u16)).unwrap();
stream.set_read_timeout(Some(Duration::from_millis(500))).unwrap(); stream.set_write_timeout(Some(Duration::from_millis(500))).unwrap();
Dac {
ip_address: ip_address,
stream: stream,
}
}
pub fn get_ip_address(&self) -> &IpAddr {
&self.ip_address
}
pub fn play_function<F>(&mut self, mut make_points: F)
-> Result<(), EtherdreamError> where F: FnMut(u16) -> Vec<Point> {
let mut response = self.read_response()?;
self.try_prepare(response);
let mut started = false;
loop {
let num_points = 1799 - response.status.buffer_fullness;
let points = make_points(num_points);
let mut cmd : Vec<u8> = Vec::new();
cmd.push(0x64); cmd.write_u16::<LittleEndian>(num_points)?;
for point in points {
cmd.extend(point.serialize());
}
response = self.write_serialized_points(&cmd)?;
if !started {
response = self.begin()?;
started = true;
}
}
}
pub fn stream_pipeline_points<F>(&mut self, mut make_points: F)
-> Result<(), EtherdreamError> where F: FnMut(u16) -> Vec<PipelinePoint> {
let mut response = self.read_response()?;
self.try_prepare(response);
let mut started = false;
loop {
let num_points = 1799 - response.status.buffer_fullness;
let points = make_points(num_points);
let mut cmd : Vec<u8> = Vec::new();
cmd.push(0x64); cmd.write_u16::<LittleEndian>(num_points)?;
for point in points {
cmd.write_u16::<LittleEndian>(0)?; cmd.write_i16::<LittleEndian>(point.x as i16)?;
cmd.write_i16::<LittleEndian>(point.y as i16)?;
if point.is_blank {
cmd.write_u16::<LittleEndian>(0)?;
cmd.write_u16::<LittleEndian>(0)?;
cmd.write_u16::<LittleEndian>(0)?;
} else {
cmd.write_u16::<LittleEndian>(65535)?;
cmd.write_u16::<LittleEndian>(65535)?;
cmd.write_u16::<LittleEndian>(65535)?;
}
cmd.write_u16::<LittleEndian>(0)?; cmd.write_u16::<LittleEndian>(0)?; cmd.write_u16::<LittleEndian>(0)?; }
response = self.write_serialized_points(&cmd)?;
if !started {
response = self.begin()?;
started = true;
}
}
}
pub fn stream_simple_points<F>(&mut self, mut make_points: F)
-> Result<(), EtherdreamError> where F: FnMut(u16) -> Vec<SimplePoint> {
let mut response = self.read_response()?;
self.try_prepare(response);
let mut started = false;
#[inline(always)]
fn expand(color: u8) -> u16 {
(color as u16) * 257
}
loop {
let num_points = 1799 - response.status.buffer_fullness;
let points = make_points(num_points);
let mut cmd : Vec<u8> = Vec::new();
cmd.push(0x64); cmd.write_u16::<LittleEndian>(num_points)?;
for point in points {
cmd.write_u16::<LittleEndian>(0)?; cmd.write_i16::<LittleEndian>(point.x)?;
cmd.write_i16::<LittleEndian>(point.y)?;
if point.is_blank {
cmd.write_u16::<LittleEndian>(0)?;
cmd.write_u16::<LittleEndian>(0)?;
cmd.write_u16::<LittleEndian>(0)?;
} else {
cmd.write_u16::<LittleEndian>(expand(point.r))?;
cmd.write_u16::<LittleEndian>(expand(point.g))?;
cmd.write_u16::<LittleEndian>(expand(point.b))?;
}
cmd.write_u16::<LittleEndian>(0)?; cmd.write_u16::<LittleEndian>(0)?; cmd.write_u16::<LittleEndian>(0)?; }
response = self.write_serialized_points(&cmd)?;
if !started {
response = self.begin()?;
started = true;
}
}
}
fn hello(&mut self) -> Result<DacResponse, EtherdreamError> {
let _bytes = self.stream.write(&[COMMAND_PING])?;
self.read_response() }
fn prepare(&mut self) -> Result<DacResponse, EtherdreamError> {
let _bytes = self.stream.write(&[COMMAND_PREPARE])?;
self.read_expected_response(CommandCode::Prepare)
}
fn begin(&mut self) -> Result<DacResponse, EtherdreamError> {
let cmd = Begin { low_water_mark: 0, point_rate: 30_000 };
let _bytes = self.stream.write(&cmd.serialize())?;
self.read_expected_response(CommandCode::Begin)
}
fn clear_emergency_stop(&mut self) -> Result<DacResponse, EtherdreamError> {
let cmd = [ 0x63u8 ]; let _bytes = self.stream.write(&cmd)?;
self.read_response() }
fn try_prepare(&mut self, response: DacResponse) {
let response = match response.status.playback_flags {
0x1 | 0x2 | 0x4 | 0x6 => {
self.clear_emergency_stop().unwrap() },
_ => response,
};
if response.status.playback_flags != 0x0 && response.status.playback_flags != 0x1 {
println!("\nBad playback flags, must PREPARE: {}", response.status.playback_flags);
println!("\nSend prepare");
let resp = self.prepare().unwrap();
println!("Response: {:?}", resp);
if !resp.is_ack() {
println!("Failure!");
panic!("Non-ACK received");
}
return;
}
if response.status.playback_state == 0x2 {
println!("\nBad playback_state, must PREPARE: {}", response.status.playback_state);
println!("\nSend prepare");
let resp = self.prepare().unwrap();
println!("Response: {:?}", resp);
if !resp.is_ack() {
println!("Failure!");
panic!("Non-ACK received");
}
}
}
fn write_serialized_points(&mut self, serialized_points: &[u8])
-> Result<DacResponse, EtherdreamError> {
self.stream.write(&serialized_points)?;
self.read_expected_response(CommandCode::Data)
}
fn read_expected_response(&mut self, expected_command: CommandCode)
-> Result<DacResponse, EtherdreamError> {
let response = self.read_response()?;
if !response.acknowledgement.is_ack() {
return Err(EtherdreamError::ReceivedNack {
code: response.acknowledgement,
command: response.command,
});
}
if response.command != expected_command {
return Err(EtherdreamError::WrongResponse);
}
Ok(response)
}
fn read_response(&mut self) -> Result<DacResponse, EtherdreamError> {
let mut buf = [0; 22];
let _size = self.stream.read(&mut buf)?;
DacResponse::parse(&buf)
}
}