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}