ether_dream/
lib.rs

1//! A full implementation of the Ether Dream laser protocol.
2
3#[macro_use]
4extern crate bitflags;
5extern crate byteorder;
6
7pub mod dac;
8pub mod protocol;
9
10use protocol::{ReadBytes, SizeBytes};
11use std::{io, net};
12
13/// An iterator that listens and waits for broadcast messages from DACs on the network and yields
14/// them as they are received on the inner UDP socket.
15///
16/// Yields an `io::Error` if:
17///
18/// - An error occurred when receiving on the inner UDP socket.
19/// - A `DacBroadcast` could not be read from the received bytes.
20pub struct RecvDacBroadcasts {
21    udp_socket: net::UdpSocket,
22    buffer: [u8; RecvDacBroadcasts::BUFFER_LEN],
23}
24
25impl RecvDacBroadcasts {
26    /// The size of the inner buffer used to receive broadcast messages.
27    pub const BUFFER_LEN: usize = protocol::DacBroadcast::SIZE_BYTES;
28}
29
30/// Produces a `RecvDacBroadcasts` instance that listens and waits for broadcast messages from DACs
31/// on the network and yields them as they are received on the inner UDP socket.
32///
33/// This function returns an `io::Error` if it could not bind to the broadcast address
34/// `255.255.255.255:<protocol::BROADCAST_PORT>`.
35///
36/// The produced iterator yields an `io::Error` if:
37///
38/// - An error occurred when receiving on the inner UDP socket. This may include `TimedOut` or
39/// `WouldBlock` if either of the `set_timeout` or `set_nonblocking` methods have been called.
40/// - A `DacBroadcast` could not be read from the received bytes.
41///
42/// ## Example
43///
44/// ```no_run
45/// extern crate ether_dream;
46///
47/// fn main() {
48///     let dac_broadcasts = ether_dream::recv_dac_broadcasts().expect("failed to bind to UDP socket");
49///     for dac_broadcast in dac_broadcasts {
50///         println!("{:#?}", dac_broadcast);
51///     }
52/// }
53/// ```
54pub fn recv_dac_broadcasts() -> io::Result<RecvDacBroadcasts> {
55    let broadcast_port = protocol::BROADCAST_PORT;
56    let broadcast_addr = net::SocketAddrV4::new([0, 0, 0, 0].into(), broadcast_port);
57    let udp_socket = net::UdpSocket::bind(broadcast_addr)?;
58    let buffer = [0; RecvDacBroadcasts::BUFFER_LEN];
59    Ok(RecvDacBroadcasts { udp_socket, buffer })
60}
61
62impl RecvDacBroadcasts {
63    /// Attempt to read the next broadcast.
64    ///
65    /// This method may or may not block depending on whether `set_nonblocking` has been called. By
66    /// default, this method will block.
67    pub fn next_broadcast(&mut self) -> io::Result<(protocol::DacBroadcast, net::SocketAddr)> {
68        let RecvDacBroadcasts {
69            ref mut buffer,
70            ref mut udp_socket,
71        } = *self;
72        let (_len, src_addr) = udp_socket.recv_from(buffer)?;
73        let mut bytes = &buffer[..];
74        let dac_broadcast = bytes.read_bytes::<protocol::DacBroadcast>()?;
75        Ok((dac_broadcast, src_addr))
76    }
77
78    /// Set the timeout for the inner UDP socket used for reading broadcasts.
79    ///
80    /// See the [`std::net::UdpSocket::set_read_timeout`
81    /// docs](https://doc.rust-lang.org/std/net/struct.UdpSocket.html#method.set_read_timeout) for
82    /// details.
83    pub fn set_timeout(&self, duration: Option<std::time::Duration>) -> io::Result<()> {
84        self.udp_socket.set_read_timeout(duration)
85    }
86
87    /// Moves the inner UDP socket into or out of nonblocking mode.
88    ///
89    /// See the
90    /// [`std::net::UdpSocket::set_nonblocking`](https://doc.rust-lang.org/std/net/struct.UdpSocket.html#method.set_nonblocking)
91    /// for details.
92    pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> {
93        self.udp_socket.set_nonblocking(nonblocking)
94    }
95}
96
97impl Iterator for RecvDacBroadcasts {
98    type Item = io::Result<(protocol::DacBroadcast, net::SocketAddr)>;
99    fn next(&mut self) -> Option<Self::Item> {
100        Some(self.next_broadcast())
101    }
102}