dac_stream/
dac_stream.rs

1extern crate ether_dream;
2
3use ether_dream::dac;
4
5fn main() {
6    println!("Listening for an Ether Dream DAC...");
7
8    let (dac_broadcast, source_addr) = ether_dream::recv_dac_broadcasts()
9        .expect("failed to bind to UDP socket")
10        .filter_map(Result::ok)
11        .next()
12        .unwrap();
13    let mac_address = dac::MacAddress(dac_broadcast.mac_address);
14
15    println!(
16        "Discovered DAC \"{}\" at \"{}\"! Connecting...",
17        mac_address, source_addr
18    );
19
20    // Establish the TCP connection.
21    let mut stream = dac::stream::connect(&dac_broadcast, source_addr.ip().clone()).unwrap();
22
23    // If we want to create an animation (in our case a moving sine wave) we need a frame rate.
24    let frames_per_second = 60.0;
25    // Lets use the DAC at an eighth the maximum scan rate.
26    let points_per_second = stream.dac().max_point_rate / 32;
27    // Determine the number of points per frame given our target frame and point rates.
28    let points_per_frame = (points_per_second as f32 / frames_per_second) as u16;
29
30    println!(
31        "Preparing for playback:\n\tframe_hz: {}\n\tpoint_hz: {}\n\tpoints_per_frame: {}\n",
32        frames_per_second, points_per_second, points_per_frame
33    );
34
35    // Prepare the DAC's playback engine and await the repsonse.
36    stream
37        .queue_commands()
38        .prepare_stream()
39        .submit()
40        .err()
41        .map(|err| {
42            eprintln!(
43                "err occurred when submitting PREPARE_STREAM \
44                      command and listening for response: {}",
45                err
46            );
47        });
48
49    println!("Beginning playback!");
50
51    // The sine wave used to generate points.
52    let mut sine_wave = SineWave {
53        point: 0,
54        points_per_frame,
55        frames_per_second,
56    };
57
58    // Queue the initial frame and tell the DAC to begin producing output.
59    let n_points = points_to_generate(stream.dac());
60    stream
61        .queue_commands()
62        .data(sine_wave.by_ref().take(n_points))
63        .begin(0, points_per_second)
64        .submit()
65        .err()
66        .map(|err| {
67            eprintln!(
68                "err occurred when submitting initial DATA and BEGIN \
69                      commands and listening for response: {}",
70                err
71            );
72        });
73
74    // Loop and continue to send points forever.
75    loop {
76        // Determine how many points the DAC can currently receive.
77        let n_points = points_to_generate(stream.dac());
78        if let Err(err) = stream
79            .queue_commands()
80            .data(sine_wave.by_ref().take(n_points))
81            .submit()
82        {
83            eprintln!(
84                "err occurred when submitting DATA command and listening \
85                      for response: {}",
86                err
87            );
88            break;
89        }
90    }
91
92    // Tell the DAC to stop producing output and return to idle. Wait for the response.
93    //
94    // Note that the DAC is commanded to stop on `Drop` if this is not called and any errors
95    // produced are ignored.
96    stream
97        .queue_commands()
98        .stop()
99        .submit()
100        .expect("err occurred when submitting STOP command and listening for response");
101}
102
103// Determine the number of points needed to fill the DAC.
104fn points_to_generate(dac: &ether_dream::dac::Dac) -> usize {
105    dac.buffer_capacity as usize - 1 - dac.status.buffer_fullness as usize
106}
107
108// An iterator that endlessly generates a sine wave of DAC points.
109//
110// The sine wave oscillates at a rate of once per second.
111struct SineWave {
112    point: u32,
113    points_per_frame: u16,
114    frames_per_second: f32,
115}
116
117impl Iterator for SineWave {
118    type Item = ether_dream::protocol::DacPoint;
119    fn next(&mut self) -> Option<Self::Item> {
120        let coloured_points_per_frame = self.points_per_frame - 1;
121        let i = (self.point % self.points_per_frame as u32) as u16;
122        let hz = 1.0;
123        let fract = i as f32 / coloured_points_per_frame as f32;
124        let phase = (self.point as f32 / coloured_points_per_frame as f32) / self.frames_per_second;
125        let amp = (hz * (fract + phase) * 2.0 * std::f32::consts::PI).sin();
126        let (r, g, b) = match i {
127            i if i == coloured_points_per_frame || i < 13 => (0, 0, 0),
128            _ => (std::u16::MAX, std::u16::MAX, std::u16::MAX),
129        };
130        let x_min = std::i16::MIN;
131        let x_max = std::i16::MAX;
132        let x = (x_min as f32 + fract * (x_max as f32 - x_min as f32)) as i16;
133        let y = (amp * x_max as f32) as i16;
134        let control = 0;
135        let (u1, u2) = (0, 0);
136        let p = ether_dream::protocol::DacPoint {
137            control,
138            x,
139            y,
140            i,
141            r,
142            g,
143            b,
144            u1,
145            u2,
146        };
147        self.point += 1;
148        Some(p)
149    }
150}