use crate::backend::{DacBackend, FifoBackend, WriteOutcome};
use crate::device::{DacCapabilities, DacType};
use crate::error::{Error, Result};
use crate::point::LaserPoint;
use crate::protocols::lasercube_wifi::dac::{stream, Addressed};
use crate::protocols::lasercube_wifi::protocol::{DeviceInfo, Point as LasercubePoint};
use std::net::SocketAddr;
pub struct LasercubeWifiBackend {
addressed: Addressed,
stream: Option<stream::Stream>,
caps: DacCapabilities,
point_buffer: Vec<LasercubePoint>,
}
impl LasercubeWifiBackend {
pub fn new(addressed: Addressed) -> Self {
let caps = super::capabilities_for_buffer(addressed.max_buffer_space);
Self {
addressed,
stream: None,
caps,
point_buffer: Vec::new(),
}
}
pub fn from_discovery(info: &DeviceInfo, source_addr: SocketAddr) -> Self {
Self::new(Addressed::from_discovery(info, source_addr))
}
}
impl DacBackend for LasercubeWifiBackend {
fn dac_type(&self) -> DacType {
DacType::LasercubeWifi
}
fn caps(&self) -> &DacCapabilities {
&self.caps
}
fn connect(&mut self) -> Result<()> {
let stream = stream::connect(&self.addressed).map_err(Error::backend)?;
self.stream = Some(stream);
Ok(())
}
fn disconnect(&mut self) -> Result<()> {
if let Some(stream) = &mut self.stream {
let _ = stream.stop();
}
self.stream = None;
Ok(())
}
fn is_connected(&self) -> bool {
self.stream.is_some()
}
fn stop(&mut self) -> Result<()> {
if let Some(stream) = &mut self.stream {
stream.stop().map_err(Error::backend)?;
}
Ok(())
}
fn set_shutter(&mut self, open: bool) -> Result<()> {
if let Some(stream) = &mut self.stream {
stream.set_output(open).map_err(Error::backend)?;
}
Ok(())
}
}
impl FifoBackend for LasercubeWifiBackend {
fn try_write_points(&mut self, pps: u32, points: &[LaserPoint]) -> Result<WriteOutcome> {
let stream = self
.stream
.as_mut()
.ok_or_else(|| Error::disconnected("Not connected"))?;
stream.set_rate(pps).map_err(Error::backend)?;
if points.len() > stream.safe_writable_points() as usize {
return Ok(WriteOutcome::WouldBlock);
}
self.point_buffer.clear();
self.point_buffer
.extend(points.iter().map(LasercubePoint::from));
stream
.write_frame(&self.point_buffer, pps)
.map_err(Error::backend)?;
Ok(WriteOutcome::Written)
}
fn queued_points(&self) -> Option<u64> {
self.stream
.as_ref()
.map(|s| s.estimated_buffer_fullness() as u64)
}
}