<commit_before>#[macro_use]
extern crate conrod_core;
extern crate nannou;
extern crate nannou_timeline as timeline;
extern crate pitch_calc;
extern crate time_calc;
#[macro_use]
extern crate serde;
extern crate serde_json;

use std::fs::File;
use std::io::prelude::*;

use nannou::prelude::*;
use nannou::ui::prelude::*;
use pitch_calc as pitch;
use std::iter::once;
use time_calc as time;
use timeline::track::automation::{BangValue as Bang, Envelope, Point, ToggleValue as Toggle};
use timeline::track::piano_roll;
use timeline::{bars, track};

const BPM: time::calc::Bpm = 140.0;
const ONE_SECOND_MS: time::calc::Ms = 1_000.0;
const PPQN: time::Ppqn = 9600;
const WIDTH: u32 = 800;
const HEIGHT: u32 = 600;

fn main() {
    nannou::app(model).update(update).run();
}

struct Model {
    _window: window::Id,
    ui: Ui,
    ids: Ids,
    timeline_data: TimelineData,
    playing: bool,
}

#[derive(Serialize, Deserialize)]
struct TimelineData {
    playhead_ticks: time::Ticks,
    bars: Vec<time::TimeSig>,
    notes: Vec<piano_roll::Note>,
    tempo_envelope: track::automation::numeric::Envelope<f32>,
    octave_envelope: track::automation::numeric::Envelope<i32>,
    toggle_envelope: track::automation::toggle::Envelope,
    bang_envelope: track::automation::bang::Envelope,
}

// Create all of our unique `WidgetId`s with the `widget_ids!` macro.
conrod_core::widget_ids! {
    struct Ids {
        window,
        ruler,
        timeline,
    }
}

fn model(app: &App) -> Model {
    let _window = app
        .new_window()
        .key_pressed(key_pressed)
        .with_dimensions(WIDTH, HEIGHT)
        .with_title("Timeline Demo")
        .view(view)
        .build()
        .unwrap();

    // Create the UI.
    let mut ui = app.new_ui().build().unwrap();
    let ids = Ids::new(ui.widget_id_generator());

    // Start the playhead at the beginning.
    let playhead_ticks = time::Ticks::from(0);

    // A sequence of bars with varying time signatures.
    let bars = vec![
        time::TimeSig { top: 4, bottom: 4 },
        time::TimeSig { top: 4, bottom: 4 },
        time::TimeSig { top: 6, bottom: 8 },
        time::TimeSig { top: 6, bottom: 8 },
        time::TimeSig { top: 4, bottom: 4 },
        time::TimeSig { top: 4, bottom: 4 },
        time::TimeSig { top: 7, bottom: 8 },
        time::TimeSig { top: 7, bottom: 8 },
    ];

    let notes = bars::WithStarts::new(bars.iter().cloned(), PPQN)
        .enumerate()
        .map(|(i, (time_sig, start))| {
            let end = start + time_sig.ticks_per_bar(PPQN);
            let period = timeline::Period { start, end };
            let pitch = pitch::Step((24 + (i * 5) % 12) as f32).to_letter_octave();
            piano_roll::Note { period, pitch }
        })
        .collect();

    let tempo_envelope = {
        let start = Point {
            ticks: time::Ticks(0),
            value: 20.0,
        };
        let points = bars::Periods::new(bars.iter().cloned(), PPQN)
            .enumerate()
            .map(|(i, period)| Point {
                ticks: period.end,
                value: 20.0 + (i + 1) as f32 * 60.0 % 220.0,
            });
        Envelope::from_points(once(start).chain(points), 20.0, 240.0)
    };

    let octave_envelope = {
        let start = Point {
            ticks: time::Ticks(0),
            value: 0,
        };
        let points = bars::WithStarts::new(bars.iter().cloned(), PPQN)
            .enumerate()
            .flat_map(|(i, (ts, mut start))| {
                let bar_end = start + ts.ticks_per_bar(PPQN);
                let mut j = 0;
                std::iter::from_fn(move || {
                    if start >= bar_end {
                        return None;
                    }

                    let end = start + time::Ticks(PPQN as _);
                    let end = if end > bar_end { bar_end } else { end };
                    let point = Point {
                        ticks: end,
                        value: 1 + ((i as i32 + j as i32) * 3) % 12,
                    };
                    start = end;
                    j += 1;
                    Some(point)
                })
            });
        Envelope::from_points(once(start).chain(points), 0, 12)
    };

    let toggle_envelope = {
        let start = Point {
            ticks: time::Ticks(0),
            value: Toggle(random()),
        };
        let points = bars::Periods::new(bars.iter().cloned(), PPQN).map(|period| Point {
            ticks: period.end,
            value: Toggle(random()),
        });
        Envelope::from_points(once(start).chain(points), Toggle(false), Toggle(true))
    };

    let bang_envelope = {
        let points = bars::Periods::new(bars.iter().cloned(), PPQN).map(|period| Point {
            ticks: period.start,
            value: Bang,
        });
        Envelope::from_points(points, Bang, Bang)
    };

    let timeline_data = TimelineData {
        playhead_ticks,
        bars,
        notes,
        tempo_envelope,
        octave_envelope,
        toggle_envelope,
        bang_envelope,
    };

    Model {
        _window,
        ui,
        ids,
        timeline_data,
        playing: false,
    }
}

fn update(_app: &App, model: &mut Model, update: Update) {
    let Model {
        ids,
        ui,
        timeline_data,
        playing,
        ..
    } = model;

    // Update the user interface.
    set_widgets(&mut ui.set_widgets(), ids, timeline_data);

    // Get the current bpm from the tempo_envelope automation track.
    use timeline::track::automation::EnvelopeTrait; // needed to use the .y(Ticks) method on the envelope
    let tempo_value = timeline_data.tempo_envelope.y(timeline_data.playhead_ticks);
    let current_bpm = tempo_value.unwrap_or(BPM as f32) as f64;

    // Update the playhead.
    let delta_secs = if *playing {
        update.since_last.secs()
    } else {
        0.0
    };
    let delta_ticks = time::Ms(delta_secs * ONE_SECOND_MS).to_ticks(current_bpm, PPQN);
    let total_duration_ticks =
        timeline::bars_duration_ticks(timeline_data.bars.iter().cloned(), PPQN);
    let previous_playhead_ticks = timeline_data.playhead_ticks.clone();
    timeline_data.playhead_ticks =
        (timeline_data.playhead_ticks + delta_ticks) % total_duration_ticks;

    // Check if a bang in the bang_envelope has banged.
    for bang_point in timeline_data.bang_envelope.points() {
        if bang_point.ticks > previous_playhead_ticks
            && bang_point.ticks <= timeline_data.playhead_ticks
        {
            println!("BANG!");
        }
    }

    // Check if a note is playing
    for note in &timeline_data.notes {
        if timeline_data.playhead_ticks >= note.period.start
            && timeline_data.playhead_ticks < note.period.end
        {
            println!("Note playing: {:?}", note.pitch);
        }
    }
}

fn view(app: &App, model: &Model, frame: &Frame) {
    model.ui.draw_to_frame(app, frame).unwrap();
}

// Update / draw the Ui.
fn set_widgets(ui: &mut UiCell, ids: &Ids, data: &mut TimelineData) {
    use timeline::Timeline;

    // Main window canvas.
    widget::Canvas::new()
        .border(0.0)
        .color(ui::color::DARK_CHARCOAL.alpha(0.5))
        .set(ids.window, ui);

    let TimelineData {
        playhead_ticks,
        bars,
        notes,
        tempo_envelope,
        octave_envelope,
        toggle_envelope,
        bang_envelope,
    } = data;

    let ticks = playhead_ticks.clone();
    let color = ui::color::LIGHT_BLUE;

    ////////////////////
    ///// TIMELINE /////
    ////////////////////
    //
    // Set the `Timeline` widget.
    //
    // This returns a context on which we can begin setting our tracks, playhead and scrollbar.
    //
    // The context is used in three stages:
    //
    // 1. `PinnedTracks` for setting tracks that should be pinned to the top of the timeline.
    // 2. `Tracks` for setting regular tracks.
    // 3. `Final` for setting the `Playhead` and `Scrollbar` widgets after all tracks are set.

    let context = Timeline::new(bars.iter().cloned(), PPQN)
        .playhead(ticks)
        .color(color)
        .wh_of(ids.window)
        .middle_of(ids.window)
        .border(1.0)
        .border_color(ui::color::CHARCOAL)
        .set(ids.timeline, ui);

    /////////////////////////
    ///// PINNED TRACKS /////
    /////////////////////////
    //
    // Pin the ruler track to the top of the timeline.
    //
    // All pinned tracks must be `set` prior to non-pinned tracks.
    {
        let ruler = track::Ruler::new(context.ruler, &context.bars, PPQN).color(color);
        let track = context.set_next_pinned_track(ruler, ui);
        for triggered in track.event {
            *playhead_ticks = triggered.ticks;
        }
    }

    //////////////////
    ///// TRACKS /////
    //////////////////

    // Now that we've finished setting the pinned tracks, move on to the `Tracks` context.
    let context = context.start_tracks(ui);

    {
        // Piano roll.
        let piano_roll = track::PianoRoll::new(&context.bars, PPQN, &notes[..]).color(color);
        let track = context.set_next_track(piano_roll, ui);
        for event in track.event {
            use timeline::track::piano_roll::Event;
            match event {
                Event::NoteOn(_note_idx) => (),
                Event::NoteOff(_note_idx) => (),
                Event::NotePlayed(_note_idx) => (),
            }
        }

        // A macro for common logic between tempo and octave "numeric" envelopes.
        macro_rules! numeric_automation {
            ($envelope:expr) => {
                let track = {
                    let automation =
                        track::automation::Numeric::new(&context.bars, PPQN, $envelope)
                            .color(color);
                    context.set_next_track(automation, ui)
                };
                for event in track.event {
                    use timeline::track::automation::numeric::Event;
                    match event {
                        Event::Interpolate(number) => println!("{}", number),
                        Event::Mutate(mutate) => mutate.apply($envelope),
                    }
                }
            };
        }

        // Tempo automation.
        numeric_automation!(tempo_envelope);
        // Octave automation.
        numeric_automation!(octave_envelope);

        // Toggle automation.
        let track = {
            let automation =
                track::automation::Toggle::new(&context.bars, PPQN, toggle_envelope).color(color);
            context.set_next_track(automation, ui)
        };
        for event in track.event {
            use timeline::track::automation::toggle::Event;
            match event {
                Event::Interpolate(_toggle) => (),
                Event::SwitchTo(_toggle) => (),
                Event::Mutate(mutate) => mutate.apply(toggle_envelope),
            }
        }

        // Bang automation.
        let track = {
            let automation =
                track::automation::Bang::new(&context.bars, PPQN, bang_envelope).color(color);
            context.set_next_track(automation, ui)
        };
        for event in track.event {
            use timeline::track::automation::bang::Event;
            match event {
                Event::Mutate(mutate) => mutate.apply(bang_envelope),
                _ => (),
            }
        }
    }

    ////////////////////////////////
    ///// PLAYHEAD & SCROLLBAR /////
    ////////////////////////////////

    // Now that all tracks have been set, finish up and set the `Playhead` and `Scrollbar`.
    let context = context.end_tracks();

    // Set the playhead after all tracks have been set.
    for event in context.set_playhead(ui) {
        use timeline::playhead::Event;
        match event {
            Event::Pressed => println!("Playhead pressed!"),
            Event::DraggedTo(ticks) => *playhead_ticks = ticks,
            Event::Released => println!("Playhead released!"),
        }
    }

    // Set the scrollbar if it is visible.
    context.set_scrollbar(ui);
}

fn key_pressed(_app: &App, model: &mut Model, key: Key) {
    match key {
        // Toggle play when space is pressed.
        Key::Space => {
            model.playing = !model.playing;
        }
        Key::R => {
            let bars = model.timeline_data.bars.clone();
            model.timeline_data.notes = bars::WithStarts::new(bars.iter().cloned(), PPQN)
                .enumerate()
                .map(|(i, (time_sig, start))| {
                    let end = start + time_sig.ticks_per_bar(PPQN);
                    let period = timeline::Period { start, end };
                    let pitch = pitch::Step((24 + (i * (random::<usize>() % 11)) % 12) as f32)
                        .to_letter_octave();
                    piano_roll::Note { period, pitch }
                })
                .collect();
        }
        Key::S => {
            // Save model.timeline_data to a JSON file.
            nannou::io::save_to_json("saved_timeline_data.json", &model.timeline_data).expect("Error saving file");
        }
        Key::L => {
            // Load the model.timeline_data from a JSON file.
            model.timeline_data = nannou::io::load_from_json("saved_timeline_data.json").expect("Error loading timeline data");
        }
        _ => {}
    }
}
<commit_msg>Fixes save/load paths in demo<commit_after>#[macro_use]
extern crate conrod_core;
extern crate nannou;
extern crate nannou_timeline as timeline;
extern crate pitch_calc;
extern crate time_calc;
#[macro_use]
extern crate serde;
extern crate serde_json;

use std::fs::File;
use std::io::prelude::*;

use nannou::prelude::*;
use nannou::ui::prelude::*;
use pitch_calc as pitch;
use std::iter::once;
use time_calc as time;
use timeline::track::automation::{BangValue as Bang, Envelope, Point, ToggleValue as Toggle};
use timeline::track::piano_roll;
use timeline::{bars, track};

const BPM: time::calc::Bpm = 140.0;
const ONE_SECOND_MS: time::calc::Ms = 1_000.0;
const PPQN: time::Ppqn = 9600;
const WIDTH: u32 = 800;
const HEIGHT: u32 = 600;

fn main() {
    nannou::app(model).update(update).run();
}

struct Model {
    _window: window::Id,
    ui: Ui,
    ids: Ids,
    timeline_data: TimelineData,
    playing: bool,
}

#[derive(Serialize, Deserialize)]
struct TimelineData {
    playhead_ticks: time::Ticks,
    bars: Vec<time::TimeSig>,
    notes: Vec<piano_roll::Note>,
    tempo_envelope: track::automation::numeric::Envelope<f32>,
    octave_envelope: track::automation::numeric::Envelope<i32>,
    toggle_envelope: track::automation::toggle::Envelope,
    bang_envelope: track::automation::bang::Envelope,
}

// Create all of our unique `WidgetId`s with the `widget_ids!` macro.
conrod_core::widget_ids! {
    struct Ids {
        window,
        ruler,
        timeline,
    }
}

fn model(app: &App) -> Model {
    let _window = app
        .new_window()
        .key_pressed(key_pressed)
        .with_dimensions(WIDTH, HEIGHT)
        .with_title("Timeline Demo")
        .view(view)
        .build()
        .unwrap();

    // Create the UI.
    let mut ui = app.new_ui().build().unwrap();
    let ids = Ids::new(ui.widget_id_generator());

    // Start the playhead at the beginning.
    let playhead_ticks = time::Ticks::from(0);

    // A sequence of bars with varying time signatures.
    let bars = vec![
        time::TimeSig { top: 4, bottom: 4 },
        time::TimeSig { top: 4, bottom: 4 },
        time::TimeSig { top: 6, bottom: 8 },
        time::TimeSig { top: 6, bottom: 8 },
        time::TimeSig { top: 4, bottom: 4 },
        time::TimeSig { top: 4, bottom: 4 },
        time::TimeSig { top: 7, bottom: 8 },
        time::TimeSig { top: 7, bottom: 8 },
    ];

    let notes = bars::WithStarts::new(bars.iter().cloned(), PPQN)
        .enumerate()
        .map(|(i, (time_sig, start))| {
            let end = start + time_sig.ticks_per_bar(PPQN);
            let period = timeline::Period { start, end };
            let pitch = pitch::Step((24 + (i * 5) % 12) as f32).to_letter_octave();
            piano_roll::Note { period, pitch }
        })
        .collect();

    let tempo_envelope = {
        let start = Point {
            ticks: time::Ticks(0),
            value: 20.0,
        };
        let points = bars::Periods::new(bars.iter().cloned(), PPQN)
            .enumerate()
            .map(|(i, period)| Point {
                ticks: period.end,
                value: 20.0 + (i + 1) as f32 * 60.0 % 220.0,
            });
        Envelope::from_points(once(start).chain(points), 20.0, 240.0)
    };

    let octave_envelope = {
        let start = Point {
            ticks: time::Ticks(0),
            value: 0,
        };
        let points = bars::WithStarts::new(bars.iter().cloned(), PPQN)
            .enumerate()
            .flat_map(|(i, (ts, mut start))| {
                let bar_end = start + ts.ticks_per_bar(PPQN);
                let mut j = 0;
                std::iter::from_fn(move || {
                    if start >= bar_end {
                        return None;
                    }

                    let end = start + time::Ticks(PPQN as _);
                    let end = if end > bar_end { bar_end } else { end };
                    let point = Point {
                        ticks: end,
                        value: 1 + ((i as i32 + j as i32) * 3) % 12,
                    };
                    start = end;
                    j += 1;
                    Some(point)
                })
            });
        Envelope::from_points(once(start).chain(points), 0, 12)
    };

    let toggle_envelope = {
        let start = Point {
            ticks: time::Ticks(0),
            value: Toggle(random()),
        };
        let points = bars::Periods::new(bars.iter().cloned(), PPQN).map(|period| Point {
            ticks: period.end,
            value: Toggle(random()),
        });
        Envelope::from_points(once(start).chain(points), Toggle(false), Toggle(true))
    };

    let bang_envelope = {
        let points = bars::Periods::new(bars.iter().cloned(), PPQN).map(|period| Point {
            ticks: period.start,
            value: Bang,
        });
        Envelope::from_points(points, Bang, Bang)
    };

    let timeline_data = TimelineData {
        playhead_ticks,
        bars,
        notes,
        tempo_envelope,
        octave_envelope,
        toggle_envelope,
        bang_envelope,
    };

    Model {
        _window,
        ui,
        ids,
        timeline_data,
        playing: false,
    }
}

fn update(_app: &App, model: &mut Model, update: Update) {
    let Model {
        ids,
        ui,
        timeline_data,
        playing,
        ..
    } = model;

    // Update the user interface.
    set_widgets(&mut ui.set_widgets(), ids, timeline_data);

    // Get the current bpm from the tempo_envelope automation track.
    use timeline::track::automation::EnvelopeTrait; // needed to use the .y(Ticks) method on the envelope
    let tempo_value = timeline_data.tempo_envelope.y(timeline_data.playhead_ticks);
    let current_bpm = tempo_value.unwrap_or(BPM as f32) as f64;

    // Update the playhead.
    let delta_secs = if *playing {
        update.since_last.secs()
    } else {
        0.0
    };
    let delta_ticks = time::Ms(delta_secs * ONE_SECOND_MS).to_ticks(current_bpm, PPQN);
    let total_duration_ticks =
        timeline::bars_duration_ticks(timeline_data.bars.iter().cloned(), PPQN);
    let previous_playhead_ticks = timeline_data.playhead_ticks.clone();
    timeline_data.playhead_ticks =
        (timeline_data.playhead_ticks + delta_ticks) % total_duration_ticks;

    // Check if a bang in the bang_envelope has banged.
    for bang_point in timeline_data.bang_envelope.points() {
        if bang_point.ticks > previous_playhead_ticks
            && bang_point.ticks <= timeline_data.playhead_ticks
        {
            println!("BANG!");
        }
    }

    // Check if a note is playing
    for note in &timeline_data.notes {
        if timeline_data.playhead_ticks >= note.period.start
            && timeline_data.playhead_ticks < note.period.end
        {
            println!("Note playing: {:?}", note.pitch);
        }
    }
}

fn view(app: &App, model: &Model, frame: &Frame) {
    model.ui.draw_to_frame(app, frame).unwrap();
}

// Update / draw the Ui.
fn set_widgets(ui: &mut UiCell, ids: &Ids, data: &mut TimelineData) {
    use timeline::Timeline;

    // Main window canvas.
    widget::Canvas::new()
        .border(0.0)
        .color(ui::color::DARK_CHARCOAL.alpha(0.5))
        .set(ids.window, ui);

    let TimelineData {
        playhead_ticks,
        bars,
        notes,
        tempo_envelope,
        octave_envelope,
        toggle_envelope,
        bang_envelope,
    } = data;

    let ticks = playhead_ticks.clone();
    let color = ui::color::LIGHT_BLUE;

    ////////////////////
    ///// TIMELINE /////
    ////////////////////
    //
    // Set the `Timeline` widget.
    //
    // This returns a context on which we can begin setting our tracks, playhead and scrollbar.
    //
    // The context is used in three stages:
    //
    // 1. `PinnedTracks` for setting tracks that should be pinned to the top of the timeline.
    // 2. `Tracks` for setting regular tracks.
    // 3. `Final` for setting the `Playhead` and `Scrollbar` widgets after all tracks are set.

    let context = Timeline::new(bars.iter().cloned(), PPQN)
        .playhead(ticks)
        .color(color)
        .wh_of(ids.window)
        .middle_of(ids.window)
        .border(1.0)
        .border_color(ui::color::CHARCOAL)
        .set(ids.timeline, ui);

    /////////////////////////
    ///// PINNED TRACKS /////
    /////////////////////////
    //
    // Pin the ruler track to the top of the timeline.
    //
    // All pinned tracks must be `set` prior to non-pinned tracks.
    {
        let ruler = track::Ruler::new(context.ruler, &context.bars, PPQN).color(color);
        let track = context.set_next_pinned_track(ruler, ui);
        for triggered in track.event {
            *playhead_ticks = triggered.ticks;
        }
    }

    //////////////////
    ///// TRACKS /////
    //////////////////

    // Now that we've finished setting the pinned tracks, move on to the `Tracks` context.
    let context = context.start_tracks(ui);

    {
        // Piano roll.
        let piano_roll = track::PianoRoll::new(&context.bars, PPQN, &notes[..]).color(color);
        let track = context.set_next_track(piano_roll, ui);
        for event in track.event {
            use timeline::track::piano_roll::Event;
            match event {
                Event::NoteOn(_note_idx) => (),
                Event::NoteOff(_note_idx) => (),
                Event::NotePlayed(_note_idx) => (),
            }
        }

        // A macro for common logic between tempo and octave "numeric" envelopes.
        macro_rules! numeric_automation {
            ($envelope:expr) => {
                let track = {
                    let automation =
                        track::automation::Numeric::new(&context.bars, PPQN, $envelope)
                            .color(color);
                    context.set_next_track(automation, ui)
                };
                for event in track.event {
                    use timeline::track::automation::numeric::Event;
                    match event {
                        Event::Interpolate(number) => println!("{}", number),
                        Event::Mutate(mutate) => mutate.apply($envelope),
                    }
                }
            };
        }

        // Tempo automation.
        numeric_automation!(tempo_envelope);
        // Octave automation.
        numeric_automation!(octave_envelope);

        // Toggle automation.
        let track = {
            let automation =
                track::automation::Toggle::new(&context.bars, PPQN, toggle_envelope).color(color);
            context.set_next_track(automation, ui)
        };
        for event in track.event {
            use timeline::track::automation::toggle::Event;
            match event {
                Event::Interpolate(_toggle) => (),
                Event::SwitchTo(_toggle) => (),
                Event::Mutate(mutate) => mutate.apply(toggle_envelope),
            }
        }

        // Bang automation.
        let track = {
            let automation =
                track::automation::Bang::new(&context.bars, PPQN, bang_envelope).color(color);
            context.set_next_track(automation, ui)
        };
        for event in track.event {
            use timeline::track::automation::bang::Event;
            match event {
                Event::Mutate(mutate) => mutate.apply(bang_envelope),
                _ => (),
            }
        }
    }

    ////////////////////////////////
    ///// PLAYHEAD & SCROLLBAR /////
    ////////////////////////////////

    // Now that all tracks have been set, finish up and set the `Playhead` and `Scrollbar`.
    let context = context.end_tracks();

    // Set the playhead after all tracks have been set.
    for event in context.set_playhead(ui) {
        use timeline::playhead::Event;
        match event {
            Event::Pressed => println!("Playhead pressed!"),
            Event::DraggedTo(ticks) => *playhead_ticks = ticks,
            Event::Released => println!("Playhead released!"),
        }
    }

    // Set the scrollbar if it is visible.
    context.set_scrollbar(ui);
}

fn key_pressed(_app: &App, model: &mut Model, key: Key) {
    match key {
        // Toggle play when space is pressed.
        Key::Space => {
            model.playing = !model.playing;
        }
        Key::R => {
            let bars = model.timeline_data.bars.clone();
            model.timeline_data.notes = bars::WithStarts::new(bars.iter().cloned(), PPQN)
                .enumerate()
                .map(|(i, (time_sig, start))| {
                    let end = start + time_sig.ticks_per_bar(PPQN);
                    let period = timeline::Period { start, end };
                    let pitch = pitch::Step((24 + (i * (random::<usize>() % 11)) % 12) as f32)
                        .to_letter_octave();
                    piano_roll::Note { period, pitch }
                })
                .collect();
        }
        Key::S => {
            // Save model.timeline_data to a JSON file.
            nannou::io::save_to_json("./saved_timeline_data.json", &model.timeline_data).expect("Error saving file");
        }
        Key::L => {
            // Load the model.timeline_data from a JSON file.
            model.timeline_data = nannou::io::load_from_json("./saved_timeline_data.json").expect("Error loading timeline data");
        }
        _ => {}
    }
}
<|endoftext|>


<commit_before>#![feature(async_await)]
use futures::{FutureExt, StreamExt, TryFutureExt};

use tg_botapi::methods::ParseMode;
use tg_botapi::types::{Message, UpdateType};
use tg_botapi::Bot;

use std::env;

fn main() {
    let token = env::var("TOKEN")
        .expect("No bot token provided, please set the environment variable TOKEN");

    tokio::run(run_bot(token).boxed().unit_error().compat());
}

async fn run_bot(token: impl Into<String>) {
    let bot = Bot::new(token);

    let mut updates = bot.start_polling();

    while let Some(update) = updates.next().await {
        match update.update_type {
            UpdateType::Message(message) => {
                tokio::spawn(
                    handle_message(bot.clone(), message)
                        .boxed()
                        .unit_error()
                        .compat(),
                );
            }

            _ => {}
        }
    }
}

async fn handle_message(bot: Bot, msg: Message) {
    if let Some(text) = msg.get_text() {
        let mut req = msg.reply(text);
        req.parse_mode = ParseMode::Markdown;

        bot.send(&req).await.unwrap();
    }
}
<commit_msg>Fix echo example imports<commit_after>#![feature(async_await)]
use futures::{FutureExt, StreamExt, TryFutureExt};

use tg_botapi::types::{ParseMode, Message, UpdateType};
use tg_botapi::Bot;

use std::env;

fn main() {
    let token = env::var("TOKEN")
        .expect("No bot token provided, please set the environment variable TOKEN");

    tokio::run(run_bot(token).boxed().unit_error().compat());
}

async fn run_bot(token: impl Into<String>) {
    let bot = Bot::new(token);

    let mut updates = bot.start_polling();

    while let Some(update) = updates.next().await {
        match update.update_type {
            UpdateType::Message(message) => {
                tokio::spawn(
                    handle_message(bot.clone(), message)
                        .boxed()
                        .unit_error()
                        .compat(),
                );
            }

            _ => {}
        }
    }
}

async fn handle_message(bot: Bot, msg: Message) {
    if let Some(text) = msg.get_text() {
        let mut req = msg.reply(text);
        req.parse_mode = ParseMode::Markdown;

        bot.send(&req).await.unwrap();
    }
}
<|endoftext|>


<commit_before>///
/// This example parses, sorts and groups the iris dataset
/// and does some simple manipulations.
///
/// Iterators and itertools functionality are used throughout.
///
///

extern crate itertools;

use itertools::Itertools;
use std::str::FromStr;
use std::collections::HashMap;

static DATA: &'static str = include_str!("iris.data");

#[derive(Clone, Debug)]
struct Iris {
    name: String,
    data: [f32; 4],
}

#[derive(Clone, Debug)]
enum ParseError {
    Numeric(<f32 as FromStr>::Err),
    Other(&'static str),
}

/// Parse an Iris from a comma-separated line
impl FromStr for Iris {
    type Err = ParseError;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        let mut iris = Iris { name: "".into(), data: [0.; 4] };
        let mut parts = s.split(",").map(str::trim);

        // using Iterator::by_ref()
        for (index, part) in parts.by_ref().take(4).enumerate() {
            iris.data[index] = try!(part.parse::<f32>().map_err(ParseError::Numeric));
        }
        if let Some(name) = parts.next() {
            iris.name = name.into();
        } else {
            return Err(ParseError::Other("Missing name"))
        }
        Ok(iris)
    }
}

fn main() {
    // using itertools::Itertools::fold_results to create the result of parsing
    let irises = DATA.lines()
                     .map(str::parse)
                     .fold_results(Vec::new(), |mut v, iris: Iris| {
                         v.push(iris);
                         v
                     }).unwrap();

    // Sort them and group them
    let mut irises = irises;
    irises.sort_by(|a, b| Ord::cmp(&a.name, &b.name));

    // using Iterator::cycle()
    let mut plot_symbols = "+ox".chars().cycle();
    let mut symbolmap = HashMap::new();

    // using itertools::Itertools::group_by
    for (species, species_data) in irises.iter().group_by(|iris| &iris.name) {
        // assign a plot symbol
        symbolmap.entry(species).or_insert_with(|| {
            plot_symbols.next().unwrap()
        });

        println!("Species = {} has symbol {}", species, symbolmap[species]);

        for column in 0..4 {
            for &iris in &species_data {
                print!("{:>3.1}, ", iris.data[column]);
            }
            println!("");
        }

    }

    // Look at all combinations of the four columns
    //
    // See https://en.wikipedia.org/wiki/Iris_flower_data_set
    //
    // using itertools::Itertools::combinations
    for (a, b) in (0..4).combinations() {
        println!("Column {} vs {}:", a, b);
        let n = 30;
        let mut plot = vec![' '; n * n];

        // using itertools::Itertools::fold1
        let min_max = |vec: &[Iris], col| {
            vec.iter()
               .map(move |iris| iris.data[col])
               .map(|x| (x, x))
               .fold1(|(min, max), (elt, _)|
                   (f32::min(min, elt), f32::max(max, elt))
               ).expect("Can't find min/max of empty iterator")
        };
        let (min_x, max_x) = min_max(&irises, a);
        let (min_y, max_y) = min_max(&irises, b);

        for (symbol, x, y) in irises.iter()
            .map(|ir| (symbolmap[&ir.name], ir.data[a], ir.data[b]))
        {
            // round to the grid
            let ix = ((x - min_x) / (max_x - min_x) * ((n - 1) as f32)) as usize;
            let iy = ((y - min_y) / (max_y - min_y) * ((n - 1) as f32)) as usize;
            let iy = n - 1 - iy; // reverse y axis' direction

            plot[n * iy + ix] = symbol;
        }

        // render plot
        //
        // using itertools::Itertools::join
        for line in plot.chunks(n) {
            println!("{}", line.iter().join(" "))
        }
    }
}
<commit_msg>examples: Improve iris from From impl<commit_after>///
/// This example parses, sorts and groups the iris dataset
/// and does some simple manipulations.
///
/// Iterators and itertools functionality are used throughout.
///
///

extern crate itertools;

use itertools::Itertools;
use std::str::FromStr;
use std::collections::HashMap;
use std::num::ParseFloatError;

static DATA: &'static str = include_str!("iris.data");

#[derive(Clone, Debug)]
struct Iris {
    name: String,
    data: [f32; 4],
}

#[derive(Clone, Debug)]
enum ParseError {
    Numeric(<f32 as FromStr>::Err),
    Other(&'static str),
}

impl From<ParseFloatError> for ParseError {
    fn from(err: ParseFloatError) -> Self {
        ParseError::Numeric(err)
    }
}

/// Parse an Iris from a comma-separated line
impl FromStr for Iris {
    type Err = ParseError;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        let mut iris = Iris { name: "".into(), data: [0.; 4] };
        let mut parts = s.split(",").map(str::trim);

        // using Iterator::by_ref()
        for (index, part) in parts.by_ref().take(4).enumerate() {
            iris.data[index] = try!(part.parse::<f32>());
        }
        if let Some(name) = parts.next() {
            iris.name = name.into();
        } else {
            return Err(ParseError::Other("Missing name"))
        }
        Ok(iris)
    }
}

fn main() {
    // using itertools::Itertools::fold_results to create the result of parsing
    let irises = DATA.lines()
                     .map(str::parse)
                     .fold_results(Vec::new(), |mut v, iris: Iris| {
                         v.push(iris);
                         v
                     }).unwrap();

    // Sort them and group them
    let mut irises = irises;
    irises.sort_by(|a, b| Ord::cmp(&a.name, &b.name));

    // using Iterator::cycle()
    let mut plot_symbols = "+ox".chars().cycle();
    let mut symbolmap = HashMap::new();

    // using itertools::Itertools::group_by
    for (species, species_data) in irises.iter().group_by(|iris| &iris.name) {
        // assign a plot symbol
        symbolmap.entry(species).or_insert_with(|| {
            plot_symbols.next().unwrap()
        });

        println!("Species = {} has symbol {}", species, symbolmap[species]);

        for column in 0..4 {
            for &iris in &species_data {
                print!("{:>3.1}, ", iris.data[column]);
            }
            println!("");
        }

    }

    // Look at all combinations of the four columns
    //
    // See https://en.wikipedia.org/wiki/Iris_flower_data_set
    //
    // using itertools::Itertools::combinations
    for (a, b) in (0..4).combinations() {
        println!("Column {} vs {}:", a, b);
        let n = 30;
        let mut plot = vec![' '; n * n];

        // using itertools::Itertools::fold1
        let min_max = |vec: &[Iris], col| {
            vec.iter()
               .map(move |iris| iris.data[col])
               .map(|x| (x, x))
               .fold1(|(min, max), (elt, _)|
                   (f32::min(min, elt), f32::max(max, elt))
               ).expect("Can't find min/max of empty iterator")
        };
        let (min_x, max_x) = min_max(&irises, a);
        let (min_y, max_y) = min_max(&irises, b);

        for (symbol, x, y) in irises.iter()
            .map(|ir| (symbolmap[&ir.name], ir.data[a], ir.data[b]))
        {
            // round to the grid
            let ix = ((x - min_x) / (max_x - min_x) * ((n - 1) as f32)) as usize;
            let iy = ((y - min_y) / (max_y - min_y) * ((n - 1) as f32)) as usize;
            let iy = n - 1 - iy; // reverse y axis' direction

            plot[n * iy + ix] = symbol;
        }

        // render plot
        //
        // using itertools::Itertools::join
        for line in plot.chunks(n) {
            println!("{}", line.iter().join(" "))
        }
    }
}
<|endoftext|>


<commit_before>#[macro_use] extern crate nom;
extern crate vqa_parser;

use vqa_parser::{VQAHeader, SND2Chunk};
use vqa_parser::{form_chunk, vqa_header, snd2_chunk};

named!(parse_vqaheader<VQAHeader>,
    do_parse!(
        form_chunk            >>
        tag!("WVQA")          >>
        vqaheader: vqa_header >>
        (
            vqaheader
        )
    )
);

named!(next_snd2_chunk<SND2Chunk>,
    do_parse!(
        take_until!("SND2") >>
        chunk: snd2_chunk   >>
        (chunk)
    )
);

named!(all_snd2_chunks<Vec<SND2Chunk>>,
    many0!(
        next_snd2_chunk
    )
);

fn main() {
    let vqa_wwlogo = include_bytes!("wwlogo.vqa");

    let vqa = parse_vqaheader(vqa_wwlogo).unwrap().1;
    let snd2_chunks = all_snd2_chunks(vqa_wwlogo).unwrap().1;

    println!("{:#?}", vqa);
    println!("parsed {} snd2 chunks", snd2_chunks.len());
}
<commit_msg>play the sound samples!<commit_after>#[macro_use] extern crate nom;
extern crate vqa_parser;
extern crate portaudio;

use vqa_parser::{VQAHeader, SND2Chunk};
use vqa_parser::{form_chunk, vqa_header, snd2_chunk};
use vqa_parser::audio::CodecState;
use portaudio::PortAudio;

use std::collections::VecDeque;

named!(parse_vqaheader<VQAHeader>,
    do_parse!(
        form_chunk            >>
        tag!("WVQA")          >>
        vqaheader: vqa_header >>
        (
            vqaheader
        )
    )
);

named!(next_snd2_chunk<SND2Chunk>,
    do_parse!(
        take_until!("SND2") >>
        chunk: snd2_chunk   >>
        (chunk)
    )
);

named!(all_snd2_chunks<Vec<SND2Chunk>>,
    many0!(
        next_snd2_chunk
    )
);

fn main() {
    let vqa_wwlogo = include_bytes!("wwlogo.vqa");

    let vqa = parse_vqaheader(vqa_wwlogo).unwrap().1;
    let snd2_chunks = all_snd2_chunks(vqa_wwlogo).unwrap().1;

    println!("{:#?}", vqa);
    println!("parsed {} snd2 chunks", snd2_chunks.len());

    play_chunks(&snd2_chunks);
}

fn get_samples(chunks: &Vec<SND2Chunk>) -> VecDeque<i16> {
    let mut samples = VecDeque::new();

    let mut ch1_state = CodecState::new();
    let mut ch2_state = CodecState::new();
    for chunk in chunks {
        let left = vqa_parser::audio::decompress(&mut ch1_state, &chunk.data[..chunk.data.len()/2]);
        let right = vqa_parser::audio::decompress(&mut ch2_state, &chunk.data[..chunk.data.len()/2]);

        // interleave data
        for i in 0..left.len() {
            samples.push_back(left[i] as i16);
            samples.push_back(right[i] as i16);
        }
    }

    samples
}

fn play_chunks(chunks: &Vec<SND2Chunk>) {
    const CHANNELS: i32 = 2;
    const SAMPLE_RATE: f64 = 22050.0;
    const FRAMES_PER_BUFFER: u32 = 256;

    let pa = PortAudio::new().unwrap();
    let settings = pa.default_output_stream_settings(CHANNELS, SAMPLE_RATE, FRAMES_PER_BUFFER).unwrap();

    let mut sampledata = get_samples(chunks);

    // This routine will be called by the PortAudio engine when audio is needed. It may called at
    // interrupt level on some machines so don't do anything that could mess up the system like
    // dynamic resource allocation or IO.
    let callback = move |portaudio::OutputStreamCallbackArgs { buffer, frames, .. }| {
        let mut idx = 0;
        for _ in 0..frames {
            if sampledata.len() > 0 {
                buffer[idx]   = sampledata.pop_front().unwrap();
                buffer[idx+1] = sampledata.pop_front().unwrap();
            }
            idx += 2;
        }

        if sampledata.len() == 0 {
            return portaudio::Complete;
        } else {
            return portaudio::Continue;
        }
    };

    let mut stream = pa.open_non_blocking_stream(settings, callback).unwrap();

    stream.start().unwrap();
    pa.sleep(10 * 1_000);
    stream.stop().unwrap();
    stream.close().unwrap();
}
<|endoftext|>


<commit_before>#![feature(io, std_misc, core)]

extern crate portaudio;

use portaudio::{pa, stream, hostapi, device};

fn main()
{
    println!("version: {} \"{}\"", pa::version(), pa::version_text());
    println!("init: {:?}", pa::initialize());

    print_info();
    doit();

    println!("term: {:?}", pa::terminate());
}

fn print_info()
{
    match hostapi::get_count()
    {
        Ok(api_count) => {
            for i in (0 .. api_count)
            {
                let name = match hostapi::get_info(i)
                {
                    None => "???".to_string(),
                    Some(ha) => ha.name,
                };
                println!("api {}: {}", i, name);
            }
        },
        _ => {},
    }

    match device::get_count()
    {
        Ok(device_count) => {
            for i in (0 .. device_count)
            {
                let name = match device::get_info(i)
                {
                    None => "???".to_string(),
                    Some(d) => d.name,
                };
                println!("dev {}: {}", i, name);
            }
        },
        _ => {},
    }
}

fn doit()
{
    callback_demo();
    write_demo();
    mixed_demo();
}

fn callback_demo()
{
    let mut callback = |&mut: _input: &[f32], output: &mut [f32], _time: stream::StreamTimeInfo, _flags: stream::StreamCallbackFlags| -> stream::StreamCallbackResult
    {
        static mut lp: f32 = 0.0;
        static mut rp: f32 = 0.0;

        let mut left_phase = unsafe { lp };
        let mut right_phase = unsafe { rp };

        for i in (0 .. output.len() / 2)
        {
            output[i*2] = left_phase;
            output[i*2+1] = right_phase;

            left_phase += 0.01;
            if left_phase >= 1.0 { left_phase -= 2.0; }

            right_phase += 0.03;
            if right_phase >= 1.0 { right_phase -= 2.0; }
        }

        unsafe { lp = left_phase; }
        unsafe { rp = right_phase; }

        stream::StreamCallbackResult::Continue
    };

    let mut finished_callback = |&mut :| println!("Finshed callback called");
    let mut stream = match stream::Stream::open_default(0, 2, 44100f64, stream::FRAMES_PER_BUFFER_UNSPECIFIED, Some(&mut callback as &mut stream::StreamCallback<_, _>))
    {
        Err(v) => { println!("Err({:?})", v); return },
        Ok(stream) => stream,
    };
    println!("finished_callback: {:?}", stream.set_finished_callback(&mut finished_callback));
    println!("start: {:?}", stream.start());
    std::old_io::timer::sleep(std::time::duration::Duration::seconds(1));
    println!("stop: {:?}", stream.stop());

    println!("finished_callback: {:?}", stream.unset_finished_callback());
    println!("start: {:?}", stream.start());
    std::old_io::timer::sleep(std::time::duration::Duration::seconds(1));
    println!("stop: {:?}", stream.stop());
}

fn write_demo()
{
    let stream = match stream::Stream::open_default(0, 2, 44100f64, stream::FRAMES_PER_BUFFER_UNSPECIFIED, None)
    {
        Err(v) => { println!("Err({:?})", v); return },
        Ok(stream) => stream,
    };

    println!("start: {:?}", stream.start());
    println!("write: {:?}", stream.write(get_buffer(44100*3).as_slice()));
    println!("stop: {:?}", stream.stop());
}

fn get_buffer(len: usize) -> Vec<f32>
{
    let mut left = 0.0f32;
    let mut right = 0.0f32;
    let mut result = Vec::with_capacity(len);
    for _ in (0 .. len / 2)
    {
        result.push(left);
        result.push(right);
        left += 0.03;
        right += 0.01;
        if left >= 1.0 { left -= 2.0; }
        if right >= 1.0 { right -= 2.0; }
    }
    result
}

fn mixed_demo()
{
    let in_idx = match device::get_default_input_index()
    {
        Ok(i) => i,
        Err(_) => return,
    };
    let out_idx = match device::get_default_output_index()
    {
        Ok(o) => o,
        Err(_) => return,
    };
    let in_lat = match device::get_info(in_idx)
    {
        None => return,
        Some(d) => d.default_low_input_latency,
    };
    let out_lat = match device::get_info(out_idx)
    {
        None => return,
        Some(d) => d.default_low_output_latency,
    };
    let input: stream::StreamParameters<f32> = stream::StreamParameters { device: in_idx, channel_count: 2, suggested_latency: in_lat };
    let output: stream::StreamParameters<i8> = stream::StreamParameters { device: out_idx, channel_count: 2, suggested_latency: out_lat };

    let supported = stream::is_format_supported(input, output, 44100f64);
    println!("support? {:?}", supported);
    if supported.is_err() { return }

    let stream = match stream::Stream::open(input, output, 44100f64, stream::FRAMES_PER_BUFFER_UNSPECIFIED, stream::StreamFlags::empty(), None)
    {
        Ok(s) => s,
        Err(o) => { println!("stream: Err({:?})", o); return },
    };

    let buffer = get_buffer(2*44100).into_iter().map(|v| (v * 127.0) as i8).collect::<Vec<i8>>();
    println!("start: {:?}", stream.start());
    println!("write: {:?}", stream.write(buffer.as_slice()));
    println!("stop: {:?}", stream.stop());
}
<commit_msg>Fix closure syntax<commit_after>#![feature(io, std_misc, core)]

extern crate portaudio;

use portaudio::{pa, stream, hostapi, device};

fn main()
{
    println!("version: {} \"{}\"", pa::version(), pa::version_text());
    println!("init: {:?}", pa::initialize());

    print_info();
    doit();

    println!("term: {:?}", pa::terminate());
}

fn print_info()
{
    match hostapi::get_count()
    {
        Ok(api_count) => {
            for i in (0 .. api_count)
            {
                let name = match hostapi::get_info(i)
                {
                    None => "???".to_string(),
                    Some(ha) => ha.name,
                };
                println!("api {}: {}", i, name);
            }
        },
        _ => {},
    }

    match device::get_count()
    {
        Ok(device_count) => {
            for i in (0 .. device_count)
            {
                let name = match device::get_info(i)
                {
                    None => "???".to_string(),
                    Some(d) => d.name,
                };
                println!("dev {}: {}", i, name);
            }
        },
        _ => {},
    }
}

fn doit()
{
    callback_demo();
    write_demo();
    mixed_demo();
}

fn callback_demo()
{
    let mut callback = |_input: &[f32], output: &mut [f32], _time: stream::StreamTimeInfo, _flags: stream::StreamCallbackFlags| -> stream::StreamCallbackResult
    {
        static mut lp: f32 = 0.0;
        static mut rp: f32 = 0.0;

        let mut left_phase = unsafe { lp };
        let mut right_phase = unsafe { rp };

        for i in (0 .. output.len() / 2)
        {
            output[i*2] = left_phase;
            output[i*2+1] = right_phase;

            left_phase += 0.01;
            if left_phase >= 1.0 { left_phase -= 2.0; }

            right_phase += 0.03;
            if right_phase >= 1.0 { right_phase -= 2.0; }
        }

        unsafe { lp = left_phase; }
        unsafe { rp = right_phase; }

        stream::StreamCallbackResult::Continue
    };

    let mut finished_callback = || println!("Finshed callback called");
    let mut stream = match stream::Stream::open_default(0, 2, 44100f64, stream::FRAMES_PER_BUFFER_UNSPECIFIED, Some(&mut callback as &mut stream::StreamCallback<_, _>))
    {
        Err(v) => { println!("Err({:?})", v); return },
        Ok(stream) => stream,
    };
    println!("finished_callback: {:?}", stream.set_finished_callback(&mut finished_callback));
    println!("start: {:?}", stream.start());
    std::old_io::timer::sleep(std::time::duration::Duration::seconds(1));
    println!("stop: {:?}", stream.stop());

    println!("finished_callback: {:?}", stream.unset_finished_callback());
    println!("start: {:?}", stream.start());
    std::old_io::timer::sleep(std::time::duration::Duration::seconds(1));
    println!("stop: {:?}", stream.stop());
}

fn write_demo()
{
    let stream = match stream::Stream::open_default(0, 2, 44100f64, stream::FRAMES_PER_BUFFER_UNSPECIFIED, None)
    {
        Err(v) => { println!("Err({:?})", v); return },
        Ok(stream) => stream,
    };

    println!("start: {:?}", stream.start());
    println!("write: {:?}", stream.write(get_buffer(44100*3).as_slice()));
    println!("stop: {:?}", stream.stop());
}

fn get_buffer(len: usize) -> Vec<f32>
{
    let mut left = 0.0f32;
    let mut right = 0.0f32;
    let mut result = Vec::with_capacity(len);
    for _ in (0 .. len / 2)
    {
        result.push(left);
        result.push(right);
        left += 0.03;
        right += 0.01;
        if left >= 1.0 { left -= 2.0; }
        if right >= 1.0 { right -= 2.0; }
    }
    result
}

fn mixed_demo()
{
    let in_idx = match device::get_default_input_index()
    {
        Ok(i) => i,
        Err(_) => return,
    };
    let out_idx = match device::get_default_output_index()
    {
        Ok(o) => o,
        Err(_) => return,
    };
    let in_lat = match device::get_info(in_idx)
    {
        None => return,
        Some(d) => d.default_low_input_latency,
    };
    let out_lat = match device::get_info(out_idx)
    {
        None => return,
        Some(d) => d.default_low_output_latency,
    };
    let input: stream::StreamParameters<f32> = stream::StreamParameters { device: in_idx, channel_count: 2, suggested_latency: in_lat };
    let output: stream::StreamParameters<i8> = stream::StreamParameters { device: out_idx, channel_count: 2, suggested_latency: out_lat };

    let supported = stream::is_format_supported(input, output, 44100f64);
    println!("support? {:?}", supported);
    if supported.is_err() { return }

    let stream = match stream::Stream::open(input, output, 44100f64, stream::FRAMES_PER_BUFFER_UNSPECIFIED, stream::StreamFlags::empty(), None)
    {
        Ok(s) => s,
        Err(o) => { println!("stream: Err({:?})", o); return },
    };

    let buffer = get_buffer(2*44100).into_iter().map(|v| (v * 127.0) as i8).collect::<Vec<i8>>();
    println!("start: {:?}", stream.start());
    println!("write: {:?}", stream.write(buffer.as_slice()));
    println!("stop: {:?}", stream.stop());
}
<|endoftext|>


<commit_before>extern crate vr;

fn print_matrix_4x4(offset: u32, mat: [[f32; 4]; 4]) {
    let off: String = (0..offset).map(|_| ' ').collect();
    println!("{:?}",        mat[0]);
    println!("{}{:?}", off, mat[1]);
    println!("{}{:?}", off, mat[2]);
    println!("{}{:?}", off, mat[3]);
}

fn print_matrix_4x3(offset: u32, mat: [[f32; 4]; 3]) {
    let off: String = (0..offset).map(|_| ' ').collect();
    println!("{:?}",        mat[0]);
    println!("{}{:?}", off, mat[1]);
    println!("{}{:?}", off, mat[2]);
}

fn main() {
    let ivr = match vr::IVRSystem::init() {
        Ok(ivr) => ivr,
        Err(err) => {
            println!("Failed to create IVR subsystem {:?}", err);
            return;
        }
    };

    println!("IVR was created");
    println!("\tbounds: {:?}", ivr.bounds());
    println!("\trecommended size: {:?}", ivr.recommended_render_target_size());
    println!("\teye output: {:?} {:?}", ivr.eye_viewport(vr::Eye::Left), ivr.eye_viewport(vr::Eye::Right));
    println!("\tvsync: {:?}", ivr.time_since_last_vsync());

    print!("\tprojection matrix left  ");
    print_matrix_4x4(31, ivr.projection_matrix(vr::Eye::Left, 0.1, 100.));
    print!("\tprojection matrix right ");
    print_matrix_4x4(31, ivr.projection_matrix(vr::Eye::Right, 0.1, 100.));

    print!("\teye_to_head ");
    print_matrix_4x3(8+12, ivr.eye_to_head_transform(vr::Eye::Left));

    print!("\tposes ");
    print_matrix_4x3(8+6, ivr.tracked_devices(0.).as_slice()[0].to_device);

    println!("Distortion example");
    for u in 0..2 {
        for v in 0..2 {
            let pos = ivr.compute_distortion(
                vr::Eye::Left,
                u as f32 / 4.,
                v as f32 / 4.,
            );
            print!("\t({:2.4}, {:2.4}) ", pos.red[0], pos.red[1]);
        }
        println!("");
    }

    println!("Trying to create a compositor");
    match ivr.compositor() {
        Err(err) => println!("Could not create compositor {:?}", err),
        Ok(comp) => {
            println!("\tCreated one!");
            println!("\tis fullscreen    = {}", comp.is_fullscreen());
            println!("\tis vsync         = {}", comp.get_vsync());
            println!("\tcan render scene = {}", comp.can_render_scene());
            println!("\tgamma value      = {}", comp.get_gamma());
        }
    }

    println!("Done! \\o/");

}<commit_msg>fixed lib name 2<commit_after>extern crate openvr;

fn print_matrix_4x4(offset: u32, mat: [[f32; 4]; 4]) {
    let off: String = (0..offset).map(|_| ' ').collect();
    println!("{:?}",        mat[0]);
    println!("{}{:?}", off, mat[1]);
    println!("{}{:?}", off, mat[2]);
    println!("{}{:?}", off, mat[3]);
}

fn print_matrix_4x3(offset: u32, mat: [[f32; 4]; 3]) {
    let off: String = (0..offset).map(|_| ' ').collect();
    println!("{:?}",        mat[0]);
    println!("{}{:?}", off, mat[1]);
    println!("{}{:?}", off, mat[2]);
}

fn main() {
    let ivr = match vr::IVRSystem::init() {
        Ok(ivr) => ivr,
        Err(err) => {
            println!("Failed to create IVR subsystem {:?}", err);
            return;
        }
    };

    println!("IVR was created");
    println!("\tbounds: {:?}", ivr.bounds());
    println!("\trecommended size: {:?}", ivr.recommended_render_target_size());
    println!("\teye output: {:?} {:?}", ivr.eye_viewport(vr::Eye::Left), ivr.eye_viewport(vr::Eye::Right));
    println!("\tvsync: {:?}", ivr.time_since_last_vsync());

    print!("\tprojection matrix left  ");
    print_matrix_4x4(31, ivr.projection_matrix(vr::Eye::Left, 0.1, 100.));
    print!("\tprojection matrix right ");
    print_matrix_4x4(31, ivr.projection_matrix(vr::Eye::Right, 0.1, 100.));

    print!("\teye_to_head ");
    print_matrix_4x3(8+12, ivr.eye_to_head_transform(vr::Eye::Left));

    print!("\tposes ");
    print_matrix_4x3(8+6, ivr.tracked_devices(0.).as_slice()[0].to_device);

    println!("Distortion example");
    for u in 0..2 {
        for v in 0..2 {
            let pos = ivr.compute_distortion(
                vr::Eye::Left,
                u as f32 / 4.,
                v as f32 / 4.,
            );
            print!("\t({:2.4}, {:2.4}) ", pos.red[0], pos.red[1]);
        }
        println!("");
    }

    println!("Trying to create a compositor");
    match ivr.compositor() {
        Err(err) => println!("Could not create compositor {:?}", err),
        Ok(comp) => {
            println!("\tCreated one!");
            println!("\tis fullscreen    = {}", comp.is_fullscreen());
            println!("\tis vsync         = {}", comp.get_vsync());
            println!("\tcan render scene = {}", comp.can_render_scene());
            println!("\tgamma value      = {}", comp.get_gamma());
        }
    }

    println!("Done! \\o/");

}
<|endoftext|>


<commit_before>//! Wrapper for DPDK's environment abstraction layer (EAL).
use ffi;
use std::convert::TryFrom;
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::{Arc, RwLock};
use thiserror::Error;

#[derive(Debug)]
struct EalSharedInner {} // TODO Remove this if unnecessary

#[derive(Debug)]
struct EalInner {
    shared: RwLock<EalSharedInner>,
}

#[derive(Debug, Clone)]
pub struct Eal {
    inner: Arc<EalInner>,
}

#[derive(Debug, Error)]
pub enum EalError {
    #[error("EAL instance should be only created once")]
    Singleton,
    #[error("EAL function returned an error code: {}", code)]
    ErrorCode { code: i32 },
}

impl Eal {
    /// Create an `Eal` instance (DPDK's environment abstraction layer).
    ///
    /// It takes command-line arguments and returns unused arguments.
    ///
    /// DPDK does not recommand users to repeat initialize and clear.
    /// https://doc.dpdk.org/api/rte__eal_8h.html#a7a745887f62a82dc83f1524e2ff2a236
    /// "It is expected that common usage of this function is to call it just before terminating the process."
    #[inline]
    pub fn new(args: &mut Vec<String>) -> Result<Self, EalError> {
        Ok(Eal {
            inner: Arc::new(EalInner::new(args)?),
        })
    }
}

//static INITIALIZED: AtomicBool = AtomicBool::new(false);

impl EalInner {
    const INITIALIZED: AtomicBool = AtomicBool::new(false);
    // Create `EalInner`.
    #[inline]
    fn new(args: &mut Vec<String>) -> Result<Self, EalError> {
        if EalInner::INITIALIZED
            .compare_exchange(false, true, Ordering::Acquire, Ordering::Relaxed)
            .is_err()
        {
            return Err(EalError::Singleton);
        }

        // 1. DPDK returns number of consumed argc
        // Safety: foriegn function (safe unless there is a bug)
        let ret = unsafe { ffi::run_with_args(dpdk_sys::rte_eal_init, &*args) };
        if ret < 0 {
            Err(EalError::ErrorCode { code: ret })
        } else {
            // 2. Strip first n args and return the remaining
            let _: Vec<_> = args.drain(..usize::try_from(ret).unwrap()).collect();
            Ok(EalInner {
                shared: RwLock::new(EalSharedInner {}),
            })
        }
    }
}

impl Drop for EalInner {
    #[inline]
    fn drop(&mut self) {
        // TODO: Release lock when repeating `eal_init` and `eal_cleanup` is stabilized.
        // See `Eal::new` for more information.
        EalInner::INITIALIZED.store(false, Ordering::Release);

        // Safety: foriegn function (safe unless there is a bug)
        unsafe {
            let ret = dpdk_sys::rte_eal_cleanup();
            assert_eq!(ret, 0);
        }
    }
}
<commit_msg>do not release lock for now<commit_after>//! Wrapper for DPDK's environment abstraction layer (EAL).
use ffi;
use std::convert::TryFrom;
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::{Arc, RwLock};
use thiserror::Error;

#[derive(Debug)]
struct EalSharedInner {} // TODO Remove this if unnecessary

#[derive(Debug)]
struct EalInner {
    shared: RwLock<EalSharedInner>,
}

#[derive(Debug, Clone)]
pub struct Eal {
    inner: Arc<EalInner>,
}

#[derive(Debug, Error)]
pub enum EalError {
    #[error("EAL instance should be only created once")]
    Singleton,
    #[error("EAL function returned an error code: {}", code)]
    ErrorCode { code: i32 },
}

impl Eal {
    /// Create an `Eal` instance (DPDK's environment abstraction layer).
    ///
    /// It takes command-line arguments and returns unused arguments.
    ///
    /// DPDK does not recommand users to repeat initialize and clear.
    /// https://doc.dpdk.org/api/rte__eal_8h.html#a7a745887f62a82dc83f1524e2ff2a236
    /// "It is expected that common usage of this function is to call it just before terminating the process."
    #[inline]
    pub fn new(args: &mut Vec<String>) -> Result<Self, EalError> {
        Ok(Eal {
            inner: Arc::new(EalInner::new(args)?),
        })
    }
}

//static INITIALIZED: AtomicBool = AtomicBool::new(false);

impl EalInner {
    const INITIALIZED: AtomicBool = AtomicBool::new(false);
    // Create `EalInner`.
    #[inline]
    fn new(args: &mut Vec<String>) -> Result<Self, EalError> {
        if EalInner::INITIALIZED
            .compare_exchange(false, true, Ordering::Acquire, Ordering::Relaxed)
            .is_err()
        {
            return Err(EalError::Singleton);
        }

        // 1. DPDK returns number of consumed argc
        // Safety: foriegn function (safe unless there is a bug)
        let ret = unsafe { ffi::run_with_args(dpdk_sys::rte_eal_init, &*args) };
        if ret < 0 {
            Err(EalError::ErrorCode { code: ret })
        } else {
            // 2. Strip first n args and return the remaining
            let _: Vec<_> = args.drain(..usize::try_from(ret).unwrap()).collect();
            Ok(EalInner {
                shared: RwLock::new(EalSharedInner {}),
            })
        }
    }
}

impl Drop for EalInner {
    #[inline]
    fn drop(&mut self) {
        // TODO: Release lock when repeating `eal_init` and `eal_cleanup` is stabilized.
        // See `Eal::new` for more information.
        // EalInner::INITIALIZED.store(false, Ordering::Release);

        // Safety: foriegn function (safe unless there is a bug)
        unsafe {
            let ret = dpdk_sys::rte_eal_cleanup();
            assert_eq!(ret, 0);
        }
    }
}
<|endoftext|>


<commit_before>use core::cmp;
use spin::Mutex;

use io::{Io, Pio, ReadOnly, WriteOnly};

pub static PS2: Mutex<Ps2> = Mutex::new(Ps2::new());

pub unsafe fn init() {
    PS2.lock().init();
}

bitflags! {
    flags StatusFlags: u8 {
        const OUTPUT_FULL = 1,
        const INPUT_FULL = 1 << 1,
        const SYSTEM = 1 << 2,
        const COMMAND = 1 << 3,
        // Chipset specific
        const KEYBOARD_LOCK = 1 << 4,
        // Chipset specific
        const SECOND_OUTPUT_FULL = 1 << 5,
        const TIME_OUT = 1 << 6,
        const PARITY = 1 << 7
    }
}

bitflags! {
    flags ConfigFlags: u8 {
        const FIRST_INTERRUPT = 1,
        const SECOND_INTERRUPT = 1 << 1,
        const POST_PASSED = 1 << 2,
        // 1 << 3 should be zero
        const CONFIG_RESERVED_3 = 1 << 3,
        const FIRST_DISABLED = 1 << 4,
        const SECOND_DISABLED = 1 << 5,
        const FIRST_TRANSLATE = 1 << 6,
        // 1 << 7 should be zero
        const CONFIG_RESERVED_7 = 1 << 7,
    }
}

#[repr(u8)]
#[allow(dead_code)]
enum Command {
    ReadConfig = 0x20,
    WriteConfig = 0x60,
    DisableSecond = 0xA7,
    EnableSecond = 0xA8,
    TestSecond = 0xA9,
    TestController = 0xAA,
    TestFirst = 0xAB,
    Diagnostic = 0xAC,
    DisableFirst = 0xAD,
    EnableFirst = 0xAE,
    WriteSecond = 0xD4
}

#[repr(u8)]
#[allow(dead_code)]
enum KeyboardCommand {
    EnableReporting = 0xF4,
    SetDefaults = 0xF6,
    Reset = 0xFF
}

#[repr(u8)]
enum KeyboardCommandData {
    ScancodeSet = 0xF0
}

#[repr(u8)]
#[allow(dead_code)]
enum MouseCommand {
    GetDeviceId = 0xF2,
    EnableReporting = 0xF4,
    SetDefaults = 0xF6,
    Reset = 0xFF
}

#[repr(u8)]
enum MouseCommandData {
    SetSampleRate = 0xF3,
}

bitflags! {
    flags MousePacketFlags: u8 {
        const LEFT_BUTTON = 1,
        const RIGHT_BUTTON = 1 << 1,
        const MIDDLE_BUTTON = 1 << 2,
        const ALWAYS_ON = 1 << 3,
        const X_SIGN = 1 << 4,
        const Y_SIGN = 1 << 5,
        const X_OVERFLOW = 1 << 6,
        const Y_OVERFLOW = 1 << 7
    }
}

pub struct Ps2 {
    data: Pio<u8>,
    status: ReadOnly<Pio<u8>>,
    command: WriteOnly<Pio<u8>>,
    key: [u8; 3],
    key_i: usize,
    mouse: [u8; 4],
    mouse_i: usize,
    mouse_extra: bool,
    mouse_x: usize,
    mouse_y: usize
}

impl Ps2 {
    const fn new() -> Ps2 {
        Ps2 {
            data: Pio::new(0x60),
            status: ReadOnly::new(Pio::new(0x64)),
            command: WriteOnly::new(Pio::new(0x64)),
            key: [0; 3],
            key_i: 0,
            mouse: [0; 4],
            mouse_i: 0,
            mouse_extra: false,
            mouse_x: 0,
            mouse_y: 0
        }
    }

    fn status(&mut self) -> StatusFlags {
        StatusFlags::from_bits_truncate(self.status.read())
    }

    fn wait_write(&mut self) {
        while self.status().contains(INPUT_FULL) {}
    }

    fn wait_read(&mut self) {
        while ! self.status().contains(OUTPUT_FULL) {}
    }

    fn flush_read(&mut self) {
        while self.status().contains(OUTPUT_FULL) {
            print!("FLUSH: {:X}\n", self.data.read());
        }
    }

    fn command(&mut self, command: Command) {
        self.wait_write();
        self.command.write(command as u8);
    }

    fn read(&mut self) -> u8 {
        self.wait_read();
        self.data.read()
    }

    fn write(&mut self, data: u8) {
        self.wait_write();
        self.data.write(data);
    }

    fn config(&mut self) -> ConfigFlags {
        self.command(Command::ReadConfig);
        ConfigFlags::from_bits_truncate(self.read())
    }

    fn set_config(&mut self, config: ConfigFlags) {
        self.command(Command::WriteConfig);
        self.write(config.bits());
    }

    fn keyboard_command(&mut self, command: KeyboardCommand) -> u8 {
        self.write(command as u8);
        self.read()
    }

    fn keyboard_command_data(&mut self, command: KeyboardCommandData, data: u8) -> u8 {
        self.write(command as u8);
        assert_eq!(self.read(), 0xFA);
        self.write(data as u8);
        self.read()
    }

    fn mouse_command(&mut self, command: MouseCommand) -> u8 {
        self.command(Command::WriteSecond);
        self.write(command as u8);
        self.read()
    }

    fn mouse_command_data(&mut self, command: MouseCommandData, data: u8) -> u8 {
        self.command(Command::WriteSecond);
        self.write(command as u8);
        assert_eq!(self.read(), 0xFA);
        self.command(Command::WriteSecond);
        self.write(data as u8);
        self.read()
    }

    fn init(&mut self) {
        // Disable devices
        self.command(Command::DisableFirst);
        self.command(Command::DisableSecond);

        // Clear remaining data
        self.flush_read();

        // Disable clocks, disable interrupts, and disable translate
        {
            let mut config = self.config();
            config.insert(FIRST_DISABLED);
            config.insert(SECOND_DISABLED);
            config.remove(FIRST_TRANSLATE);
            config.remove(FIRST_INTERRUPT);
            config.remove(SECOND_INTERRUPT);
            self.set_config(config);
        }

        // Perform the self test
        self.command(Command::TestController);
        assert_eq!(self.read(), 0x55);

        // Enable devices
        self.command(Command::EnableFirst);
        self.command(Command::EnableSecond);

        // Reset keyboard
        assert_eq!(self.keyboard_command(KeyboardCommand::Reset), 0xFA);
        assert_eq!(self.read(), 0xAA);
        self.flush_read();

        // Set scancode set to 2
        assert_eq!(self.keyboard_command_data(KeyboardCommandData::ScancodeSet, 2), 0xFA);

        // Reset mouse and set up scroll
        // TODO: Check for ack
        assert_eq!(self.mouse_command(MouseCommand::Reset), 0xFA);
        assert_eq!(self.read(), 0xAA);
        assert_eq!(self.read(), 0x00);
        self.flush_read();

        // Enable extra packet on mouse
        assert_eq!(self.mouse_command_data(MouseCommandData::SetSampleRate, 200), 0xFA);
        assert_eq!(self.mouse_command_data(MouseCommandData::SetSampleRate, 100), 0xFA);
        assert_eq!(self.mouse_command_data(MouseCommandData::SetSampleRate, 80), 0xFA);
        assert_eq!(self.mouse_command(MouseCommand::GetDeviceId), 0xFA);
        let mouse_id = self.read();
        self.mouse_extra = mouse_id == 3;

        // Enable extra buttons, TODO
        /*
        if self.mouse_extra {
            print!("SAMPLE 200 {:X}\n", self.mouse_command_data(MouseCommandData::SetSampleRate, 200));
            print!("SAMPLE 200 {:X}\n", self.mouse_command_data(MouseCommandData::SetSampleRate, 200));
            print!("SAMPLE 80 {:X}\n", self.mouse_command_data(MouseCommandData::SetSampleRate, 80));
            print!("GET ID {:X}\n", self.mouse_command(MouseCommand::GetDeviceId));
            let mouse_id = self.read();
            print!("MOUSE ID: {:X} == 0x04\n", mouse_id);
        }
        */

        // Set sample rate to maximum
        assert_eq!(self.mouse_command_data(MouseCommandData::SetSampleRate, 200), 0xFA);

        // Enable data reporting
        assert_eq!(self.keyboard_command(KeyboardCommand::EnableReporting), 0xFA);
        assert_eq!(self.mouse_command(MouseCommand::EnableReporting), 0xFA);

        // Enable clocks and interrupts
        {
            let mut config = self.config();
            config.remove(FIRST_DISABLED);
            config.remove(SECOND_DISABLED);
            config.insert(FIRST_INTERRUPT);
            config.insert(SECOND_INTERRUPT);
            self.set_config(config);
        }
    }

    pub fn on_keyboard(&mut self) {
        let scancode = self.data.read();
        self.key[self.key_i] = scancode;
        self.key_i += 1;
        if self.key_i >= self.key.len() || scancode < 0xE0 {
            println!("KEY: {:X} {:X} {:X}", self.key[0], self.key[1], self.key[2]);

            self.key = [0; 3];
            self.key_i = 0;
        }
    }

    pub fn on_mouse(&mut self) {
        self.mouse[self.mouse_i] = self.data.read();
        self.mouse_i += 1;
        if self.mouse_i >= self.mouse.len() || (!self.mouse_extra && self.mouse_i >= 3) {
            let flags = MousePacketFlags::from_bits_truncate(self.mouse[0]);

            assert!(flags.contains(ALWAYS_ON));

            if ! flags.contains(X_OVERFLOW) && ! flags.contains(Y_OVERFLOW) {
                let mut dx = self.mouse[1] as isize;
                if flags.contains(X_SIGN) {
                    dx -= 0x100;
                }

                let mut dy = self.mouse[2] as isize;
                if flags.contains(Y_SIGN) {
                    dy -= 0x100;
                }

                let _extra = if self.mouse_extra {
                    self.mouse[3]
                } else {
                    0
                };

                //print!("MOUSE {:?}, {}, {}, {}\n", flags, dx, dy, extra);

                if let Some(ref mut display) = *super::display::DISPLAY.lock() {
                    self.mouse_x = cmp::max(0, cmp::min(display.width as isize - 1, self.mouse_x as isize + dx)) as usize;
                    self.mouse_y = cmp::max(0, cmp::min(display.height as isize - 1, self.mouse_y as isize - dy)) as usize;
                    let offset = self.mouse_y * display.width + self.mouse_x;
                    display.onscreen[offset as usize] = 0xFF0000;
                }
            }

            self.mouse = [0; 4];
            self.mouse_i = 0;
        }
    }
}
<commit_msg>Log bad mouse events<commit_after>use core::cmp;
use spin::Mutex;

use io::{Io, Pio, ReadOnly, WriteOnly};

pub static PS2: Mutex<Ps2> = Mutex::new(Ps2::new());

pub unsafe fn init() {
    PS2.lock().init();
}

bitflags! {
    flags StatusFlags: u8 {
        const OUTPUT_FULL = 1,
        const INPUT_FULL = 1 << 1,
        const SYSTEM = 1 << 2,
        const COMMAND = 1 << 3,
        // Chipset specific
        const KEYBOARD_LOCK = 1 << 4,
        // Chipset specific
        const SECOND_OUTPUT_FULL = 1 << 5,
        const TIME_OUT = 1 << 6,
        const PARITY = 1 << 7
    }
}

bitflags! {
    flags ConfigFlags: u8 {
        const FIRST_INTERRUPT = 1,
        const SECOND_INTERRUPT = 1 << 1,
        const POST_PASSED = 1 << 2,
        // 1 << 3 should be zero
        const CONFIG_RESERVED_3 = 1 << 3,
        const FIRST_DISABLED = 1 << 4,
        const SECOND_DISABLED = 1 << 5,
        const FIRST_TRANSLATE = 1 << 6,
        // 1 << 7 should be zero
        const CONFIG_RESERVED_7 = 1 << 7,
    }
}

#[repr(u8)]
#[allow(dead_code)]
enum Command {
    ReadConfig = 0x20,
    WriteConfig = 0x60,
    DisableSecond = 0xA7,
    EnableSecond = 0xA8,
    TestSecond = 0xA9,
    TestController = 0xAA,
    TestFirst = 0xAB,
    Diagnostic = 0xAC,
    DisableFirst = 0xAD,
    EnableFirst = 0xAE,
    WriteSecond = 0xD4
}

#[repr(u8)]
#[allow(dead_code)]
enum KeyboardCommand {
    EnableReporting = 0xF4,
    SetDefaults = 0xF6,
    Reset = 0xFF
}

#[repr(u8)]
enum KeyboardCommandData {
    ScancodeSet = 0xF0
}

#[repr(u8)]
#[allow(dead_code)]
enum MouseCommand {
    GetDeviceId = 0xF2,
    EnableReporting = 0xF4,
    SetDefaults = 0xF6,
    Reset = 0xFF
}

#[repr(u8)]
enum MouseCommandData {
    SetSampleRate = 0xF3,
}

bitflags! {
    flags MousePacketFlags: u8 {
        const LEFT_BUTTON = 1,
        const RIGHT_BUTTON = 1 << 1,
        const MIDDLE_BUTTON = 1 << 2,
        const ALWAYS_ON = 1 << 3,
        const X_SIGN = 1 << 4,
        const Y_SIGN = 1 << 5,
        const X_OVERFLOW = 1 << 6,
        const Y_OVERFLOW = 1 << 7
    }
}

pub struct Ps2 {
    data: Pio<u8>,
    status: ReadOnly<Pio<u8>>,
    command: WriteOnly<Pio<u8>>,
    key: [u8; 3],
    key_i: usize,
    mouse: [u8; 4],
    mouse_i: usize,
    mouse_extra: bool,
    mouse_x: usize,
    mouse_y: usize
}

impl Ps2 {
    const fn new() -> Ps2 {
        Ps2 {
            data: Pio::new(0x60),
            status: ReadOnly::new(Pio::new(0x64)),
            command: WriteOnly::new(Pio::new(0x64)),
            key: [0; 3],
            key_i: 0,
            mouse: [0; 4],
            mouse_i: 0,
            mouse_extra: false,
            mouse_x: 0,
            mouse_y: 0
        }
    }

    fn status(&mut self) -> StatusFlags {
        StatusFlags::from_bits_truncate(self.status.read())
    }

    fn wait_write(&mut self) {
        while self.status().contains(INPUT_FULL) {}
    }

    fn wait_read(&mut self) {
        while ! self.status().contains(OUTPUT_FULL) {}
    }

    fn flush_read(&mut self) {
        while self.status().contains(OUTPUT_FULL) {
            print!("FLUSH: {:X}\n", self.data.read());
        }
    }

    fn command(&mut self, command: Command) {
        self.wait_write();
        self.command.write(command as u8);
    }

    fn read(&mut self) -> u8 {
        self.wait_read();
        self.data.read()
    }

    fn write(&mut self, data: u8) {
        self.wait_write();
        self.data.write(data);
    }

    fn config(&mut self) -> ConfigFlags {
        self.command(Command::ReadConfig);
        ConfigFlags::from_bits_truncate(self.read())
    }

    fn set_config(&mut self, config: ConfigFlags) {
        self.command(Command::WriteConfig);
        self.write(config.bits());
    }

    fn keyboard_command(&mut self, command: KeyboardCommand) -> u8 {
        self.write(command as u8);
        self.read()
    }

    fn keyboard_command_data(&mut self, command: KeyboardCommandData, data: u8) -> u8 {
        self.write(command as u8);
        assert_eq!(self.read(), 0xFA);
        self.write(data as u8);
        self.read()
    }

    fn mouse_command(&mut self, command: MouseCommand) -> u8 {
        self.command(Command::WriteSecond);
        self.write(command as u8);
        self.read()
    }

    fn mouse_command_data(&mut self, command: MouseCommandData, data: u8) -> u8 {
        self.command(Command::WriteSecond);
        self.write(command as u8);
        assert_eq!(self.read(), 0xFA);
        self.command(Command::WriteSecond);
        self.write(data as u8);
        self.read()
    }

    fn init(&mut self) {
        // Disable devices
        self.command(Command::DisableFirst);
        self.command(Command::DisableSecond);

        // Clear remaining data
        self.flush_read();

        // Disable clocks, disable interrupts, and disable translate
        {
            let mut config = self.config();
            config.insert(FIRST_DISABLED);
            config.insert(SECOND_DISABLED);
            config.remove(FIRST_TRANSLATE);
            config.remove(FIRST_INTERRUPT);
            config.remove(SECOND_INTERRUPT);
            self.set_config(config);
        }

        // Perform the self test
        self.command(Command::TestController);
        assert_eq!(self.read(), 0x55);

        // Enable devices
        self.command(Command::EnableFirst);
        self.command(Command::EnableSecond);

        // Reset keyboard
        assert_eq!(self.keyboard_command(KeyboardCommand::Reset), 0xFA);
        assert_eq!(self.read(), 0xAA);
        self.flush_read();

        // Set scancode set to 2
        assert_eq!(self.keyboard_command_data(KeyboardCommandData::ScancodeSet, 2), 0xFA);

        // Reset mouse and set up scroll
        // TODO: Check for ack
        assert_eq!(self.mouse_command(MouseCommand::Reset), 0xFA);
        assert_eq!(self.read(), 0xAA);
        assert_eq!(self.read(), 0x00);
        self.flush_read();

        // Enable extra packet on mouse
        assert_eq!(self.mouse_command_data(MouseCommandData::SetSampleRate, 200), 0xFA);
        assert_eq!(self.mouse_command_data(MouseCommandData::SetSampleRate, 100), 0xFA);
        assert_eq!(self.mouse_command_data(MouseCommandData::SetSampleRate, 80), 0xFA);
        assert_eq!(self.mouse_command(MouseCommand::GetDeviceId), 0xFA);
        let mouse_id = self.read();
        self.mouse_extra = mouse_id == 3;

        // Enable extra buttons, TODO
        /*
        if self.mouse_extra {
            print!("SAMPLE 200 {:X}\n", self.mouse_command_data(MouseCommandData::SetSampleRate, 200));
            print!("SAMPLE 200 {:X}\n", self.mouse_command_data(MouseCommandData::SetSampleRate, 200));
            print!("SAMPLE 80 {:X}\n", self.mouse_command_data(MouseCommandData::SetSampleRate, 80));
            print!("GET ID {:X}\n", self.mouse_command(MouseCommand::GetDeviceId));
            let mouse_id = self.read();
            print!("MOUSE ID: {:X} == 0x04\n", mouse_id);
        }
        */

        // Set sample rate to maximum
        assert_eq!(self.mouse_command_data(MouseCommandData::SetSampleRate, 200), 0xFA);

        // Enable data reporting
        assert_eq!(self.keyboard_command(KeyboardCommand::EnableReporting), 0xFA);
        assert_eq!(self.mouse_command(MouseCommand::EnableReporting), 0xFA);

        // Enable clocks and interrupts
        {
            let mut config = self.config();
            config.remove(FIRST_DISABLED);
            config.remove(SECOND_DISABLED);
            config.insert(FIRST_INTERRUPT);
            config.insert(SECOND_INTERRUPT);
            self.set_config(config);
        }
    }

    pub fn on_keyboard(&mut self) {
        let scancode = self.data.read();
        self.key[self.key_i] = scancode;
        self.key_i += 1;
        if self.key_i >= self.key.len() || scancode < 0xE0 {
            //println!("KEY: {:X} {:X} {:X}", self.key[0], self.key[1], self.key[2]);

            self.key = [0; 3];
            self.key_i = 0;
        }
    }

    pub fn on_mouse(&mut self) {
        self.mouse[self.mouse_i] = self.data.read();
        self.mouse_i += 1;
        if self.mouse_i >= self.mouse.len() || (!self.mouse_extra && self.mouse_i >= 3) {
            let flags = MousePacketFlags::from_bits_truncate(self.mouse[0]);

            if flags.contains(ALWAYS_ON) && ! flags.contains(X_OVERFLOW) && ! flags.contains(Y_OVERFLOW) {
                let mut dx = self.mouse[1] as isize;
                if flags.contains(X_SIGN) {
                    dx -= 0x100;
                }

                let mut dy = self.mouse[2] as isize;
                if flags.contains(Y_SIGN) {
                    dy -= 0x100;
                }

                let _extra = if self.mouse_extra {
                    self.mouse[3]
                } else {
                    0
                };

                //print!("MOUSE {:?}, {}, {}, {}\n", flags, dx, dy, extra);

                if let Some(ref mut display) = *super::display::DISPLAY.lock() {
                    self.mouse_x = cmp::max(0, cmp::min(display.width as isize - 1, self.mouse_x as isize + dx)) as usize;
                    self.mouse_y = cmp::max(0, cmp::min(display.height as isize - 1, self.mouse_y as isize - dy)) as usize;
                    let offset = self.mouse_y * display.width + self.mouse_x;
                    display.onscreen[offset as usize] = 0xFF0000;
                }
            } else {
                println!("BAD MOUSE {:?}", self.mouse);
            }

            self.mouse = [0; 4];
            self.mouse_i = 0;
        }
    }
}
<|endoftext|>