1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
//! A cross-platform laser DAC detection and streaming API.

pub extern crate ether_dream;

pub mod dac;
#[cfg(feature = "ffi")]
pub mod ffi;
#[cfg(feature = "ilda-idtf")]
pub mod ilda_idtf;
pub mod point;
pub mod stream;
pub mod util;

pub use dac::{DetectDacs, DetectDacsAsync, DetectedDac, DetectedDacCallback, Id as DacId};
pub use point::{Point, RawPoint};
pub use stream::frame::Frame;
pub use stream::frame::Stream as FrameStream;
pub use stream::raw::Stream as RawStream;
pub use stream::raw::{Buffer, StreamError, StreamErrorAction};

use std::io;
use std::sync::Arc;
use std::time::Duration;

/// A general API that allows for detecting and enumerating laser DACs on a network and
/// establishing new streams of communication with them.
pub struct Api {
    inner: Arc<Inner>,
}

// The inner state of the `Api` that can be easily shared between laser threads in an `Arc`.
//
// This is useful for allowing streams to re-scan and find their associated DAC in the case it
// drops out for some reason.
pub(crate) struct Inner;

impl Api {
    /// Instantiate the laser API.
    pub fn new() -> Self {
        Api {
            inner: Arc::new(Inner),
        }
    }

    /// An iterator yielding laser DACs available on the system as they are discovered.
    ///
    /// Currently, the only laser protocol supported is the ether dream protocol. Thus, this
    /// enumerates ether dream DACs that are discovered on the LAN.
    ///
    /// **Note** that the produced iterator will iterate forever and never terminate unless
    /// `set_timeout` is called on the returned `DetectDacs` instance.
    pub fn detect_dacs(&self) -> io::Result<DetectDacs> {
        self.inner.detect_dacs()
    }

    /// Block and wait until the DAC with the given `Id` is detected.
    pub fn detect_dac(&self, id: DacId) -> io::Result<DetectedDac> {
        self.inner.detect_dac(id)
    }

    /// Spawn a thread for DAC detection.
    ///
    /// Calls the given `callback` with broadcasts as they are received.
    ///
    /// The thread is closed when the returned `DetectDacsAsync` instance is dropped.
    pub fn detect_dacs_async<F>(
        &self,
        timeout: Option<Duration>,
        callback: F,
    ) -> io::Result<DetectDacsAsync>
    where
        F: 'static + DetectedDacCallback + Send,
    {
        self.inner.detect_dacs_async(timeout, callback)
    }

    /// Begin building a new laser frame stream.
    ///
    /// The stream will call the `render` function each time new points are needed to feed the
    /// laser DAC buffer. The rate at which this will be called depends on the `point_hz`,
    /// `frame_hz` and the `latency_points`.
    pub fn new_frame_stream<M, F>(&self, model: M, render: F) -> stream::frame::Builder<M, F>
    where
        F: stream::frame::RenderFn<M>,
    {
        let api_inner = self.inner.clone();
        let builder = Default::default();
        let frame_hz = None;
        let interpolation_conf = Default::default();
        let enable_optimisations = stream::DEFAULT_ENABLE_OPTIMISATIONS;
        let enable_draw_reorder = stream::DEFAULT_ENABLE_DRAW_REORDER;
        let process_raw = stream::frame::default_process_raw_fn;
        let stream_error = stream::raw::default_stream_error_fn;
        stream::frame::Builder {
            api_inner,
            builder,
            model,
            render,
            process_raw,
            stream_error,
            frame_hz,
            interpolation_conf,
            enable_optimisations,
            enable_draw_reorder,
        }
    }

    /// Begin building a new laser raw stream.
    ///
    /// The raw stream will call the given `render` function with a request for as many points as
    /// the DAC currently might need to fill the buffer based on the stream latency.
    pub fn new_raw_stream<M, F>(&self, model: M, render: F) -> stream::raw::Builder<M, F>
    where
        F: stream::raw::RenderFn<M>,
    {
        let api_inner = self.inner.clone();
        let builder = Default::default();
        let stream_error = stream::raw::default_stream_error_fn;
        stream::raw::Builder {
            api_inner,
            builder,
            model,
            render,
            stream_error,
        }
    }
}

impl Inner {
    /// See the `Api::detect_dacs` docs.
    pub(crate) fn detect_dacs(&self) -> io::Result<DetectDacs> {
        dac::detect_dacs()
    }

    /// Block and wait until the DAC with the given `Id` is detected.
    pub(crate) fn detect_dac(&self, id: DacId) -> io::Result<DetectedDac> {
        for res in self.detect_dacs()? {
            let dac = res?;
            if dac.id() == id {
                return Ok(dac);
            }
        }
        unreachable!("DAC detection iterator should never return `None`")
    }

    /// See the `Api::detect_dacs_async` docs.
    fn detect_dacs_async<F>(
        &self,
        timeout: Option<Duration>,
        callback: F,
    ) -> io::Result<DetectDacsAsync>
    where
        F: 'static + DetectedDacCallback + Send,
    {
        dac::detect_dacs_async(timeout, callback)
    }
}

impl AsRef<Point> for Point {
    fn as_ref(&self) -> &Point {
        self
    }
}