<commit_before>#[macro_use]
extern crate glium;
extern crate image;
extern crate nalgebra;
extern crate num;

mod steve;

const VERT_PROG: &'static str = include_str!("vert.glsl");

const FRAG_PROG: &'static str = include_str!("frag.glsl");

use glium::{Surface, VertexBuffer, Frame, Program};
use glium::index::NoIndices;
use glium::texture::srgb_texture2d::SrgbTexture2d;
use glium::uniforms::{MagnifySamplerFilter, Uniforms, AsUniformValue};
use glium::draw_parameters::DepthTest;
use glium::backend::glutin_backend::GlutinFacade;
use glium::index::PrimitiveType;
use glium::vertex::BufferCreationError;
use glium::glutin::{Event, ElementState, VirtualKeyCode};
use std::f32::consts::{FRAC_PI_2, PI};
use std::thread::sleep_ms;
use nalgebra::{Rot3, Iso3, Vec3, Persp3, ToHomogeneous, Mat4};
use num::traits::{Zero, One};

enum NextAction {
    Quit,
}

fn handle_input(turn_rate: &mut f32, state: ElementState, vk_opt: &Option<VirtualKeyCode>) -> Option<NextAction> {
    let mut next_action = None;
    let new_turn_rate = match *vk_opt {
        Some(vk) => match (vk, state) {
            (VirtualKeyCode::Right, ElementState::Pressed)  => PI / 200.0,
            (VirtualKeyCode::Left, ElementState::Pressed)  => -PI / 200.0,
            (VirtualKeyCode::Right, ElementState::Released) => 0.0f32,
            (VirtualKeyCode::Left, ElementState::Released) => 0.0f32,
            (VirtualKeyCode::Q, ElementState::Released) => { next_action =  Some(NextAction::Quit); 0.0f32},
            _ => 0.0f32
        },
        None => 0.0f32
    };
    *turn_rate = new_turn_rate;
    next_action
}

pub struct ModelPiece {
    vbo: VertexBuffer<steve::Vertex>,
    prim: PrimitiveType,
    bone: Option<Vec3<f32>>,
}

impl ModelPiece {
    fn new(display: &GlutinFacade, verts: &[steve::Vertex], prim: PrimitiveType, bone: Option<Vec3<f32>>) -> Result<Self, BufferCreationError> {
        let vertex_buffer = match VertexBuffer::new(display, verts) {
            Ok(vbo) => vbo,
            Err(e) => return Err(e),
        };
        Ok(ModelPiece{vbo: vertex_buffer, prim: prim, bone: bone})
    }

    fn make_anim_matrix(self: &Self, anim_angle: f32) -> Mat4<f32> {
        match self.bone {
            Some(bone) => {
                let trans1 = Iso3::new(-bone, Vec3::zero()).to_homogeneous();
                let rot3 = Rot3::new(Vec3::new(0.0, anim_angle, 0.0)).to_homogeneous();
                let trans2 = Iso3::new(bone, Vec3::zero()).to_homogeneous();
                trans2 * rot3 * trans1},
            None => Mat4::<f32>::one()
        }
    }

    fn draw<U>(self: &Self, target: &mut Frame, shader_prog: &Program, uniforms: &U, params: &glium::draw_parameters::DrawParameters) where U: Uniforms {
        let ibo = NoIndices(self.prim);
        target.draw(&self.vbo, ibo, shader_prog, uniforms, params).unwrap();
    }
}

macro_rules! implement_uniforms {
    ($struct_name:ident, $($field_name:ident),+) => (
        impl<'b> glium::uniforms::Uniforms for $struct_name<'b> {
            #[inline]
            fn visit_values<'a, F: FnMut(&str, glium::uniforms::UniformValue<'a>)>(&'a self, mut output: F) {
                $(
                    output(stringify!($field_name), self.$field_name.as_uniform_value());
                )+
            }
        }
    );

    ($struct_name:ident, $($field_name:ident),+,) => (
        implement_uniforms!($struct_name, $($field_name),+);
    );
}

#[derive(Copy, Clone)]
struct PlayerModelUniforms<'a> {
    model: Mat4<f32>,
    view:  Mat4<f32>,
    projection:  Mat4<f32>,
    tex: &'a glium::uniforms::Sampler<'a, SrgbTexture2d>,
}

implement_uniforms!(PlayerModelUniforms, model, view, projection, tex);

pub struct PlayerModel {
    head: ModelPiece,
    torso: ModelPiece,

    larm: ModelPiece,
    rarm: ModelPiece,

    lleg: ModelPiece,
    rleg: ModelPiece,

    texture: SrgbTexture2d,
}

impl PlayerModel {
    fn draw(self: &Self, target: &mut Frame, shader_prog: &Program, t: f32, do_anim: bool) {
        let perspective = {
            let (width, height) = target.get_dimensions();
            let aspect_ratio = width as f32 / height as f32;
            //println!("Aspect ratio: {} ({} x {})", aspect_ratio, height, width);

            let fov: f32 = 3.141592 / 3.0;
            let zfar = 1024.0;
            let znear = 0.1;

            Persp3::new(aspect_ratio, fov, znear, zfar).to_mat()
        };

        let rot1 = Rot3::new(Vec3::new(-FRAC_PI_2, 0.0, 0.0)).to_homogeneous();
        let rot2 = Rot3::new(Vec3::new(0.0, FRAC_PI_2, 0.0)).to_homogeneous();

        let trans_final = Iso3::new(Vec3::new(0.0, 0.0, 100.0), Vec3::zero()).to_homogeneous();

        let model = trans_final * rot2 * rot1;
        let view: Mat4<f32> = Mat4::one();

        let mut uniforms = PlayerModelUniforms{
            model: model,
            view: view,
            projection: perspective,
            tex: &self.texture.sampled().magnify_filter(MagnifySamplerFilter::Nearest),
        };

        let params = glium::DrawParameters {
            depth: glium::Depth {
                test: DepthTest::IfLess,
                write: true,
                .. Default::default()
            },
            .. Default::default()
        };

        self.head.draw(target, shader_prog, &uniforms, &params);
        self.torso.draw(target, shader_prog, &uniforms, &params);

        let anim_matrix = self.larm.make_anim_matrix(if do_anim { -FRAC_PI_2 * t.sin() } else { 0.0 });
        let model = trans_final * rot2 * rot1 * anim_matrix;
        uniforms.model = model;
        self.larm.draw(target, shader_prog, &uniforms, &params);

        let anim_matrix = self.rarm.make_anim_matrix(if do_anim { FRAC_PI_2 * t.sin() } else { 0.0 });
        let model = trans_final * rot2 * rot1 * anim_matrix;
        uniforms.model = model;
        self.rarm.draw(target, shader_prog, &uniforms, &params);

        let anim_matrix = self.lleg.make_anim_matrix(if do_anim { FRAC_PI_2 * t.sin() } else { 0.0 });
        let model = trans_final * rot2 * rot1 * anim_matrix;
        uniforms.model = model;
        self.lleg.draw(target, shader_prog, &uniforms, &params);

        let anim_matrix = self.rleg.make_anim_matrix(if do_anim { -FRAC_PI_2 * t.sin() } else { 0.0 });
        let model = trans_final * rot2 * rot1 * anim_matrix;
        uniforms.model = model;
        self.rleg.draw(target, shader_prog, &uniforms, &params);
    }
}

fn mainloop(display: &GlutinFacade) {
    use std::io::Cursor;

    let image = image::load(Cursor::new(&include_bytes!("steve.png")[..]),
                            image::PNG).unwrap();

    let player = PlayerModel{
        head: ModelPiece::new(display, &steve::HEAD, PrimitiveType::TrianglesList, None).unwrap(),
        torso: ModelPiece::new(display, &steve::TORSO, PrimitiveType::TrianglesList, None).unwrap(),

        larm: ModelPiece::new(display, &steve::LARM, PrimitiveType::TrianglesList, Some(*steve::LARM_BONE)).unwrap(),
        rarm: ModelPiece::new(display, &steve::RARM, PrimitiveType::TrianglesList, Some(*steve::RARM_BONE)).unwrap(),

        lleg: ModelPiece::new(display, &steve::LLEG, PrimitiveType::TrianglesList, Some(*steve::LLEG_BONE)).unwrap(),
        rleg: ModelPiece::new(display, &steve::RLEG, PrimitiveType::TrianglesList, Some(*steve::RLEG_BONE)).unwrap(),

        texture: SrgbTexture2d::new(display, image).unwrap(),
    };

    let shader_prog = Program::from_source(display, VERT_PROG, FRAG_PROG, None).unwrap();

    let mut t = 0.0f32;
    let anim_rate = 0.02f32;
    let mut turn_rate = 0.0f32;

    loop {
        t += anim_rate;

        for ev in display.poll_events() {
            match ev {
                Event::Closed => return,
                Event::KeyboardInput(state, _, vk_opt) => match handle_input(&mut turn_rate, state, &vk_opt) {
                    Some(NextAction::Quit) => return,
                    None => ()
                },
                _ => ()
            }
        }

        //let (width, height) = display.get_framebuffer_dimensions();
        //println!("Framebuffer dimensions: {} x {}", width, height);
        let mut target = display.draw();
        target.clear_color_and_depth((0.0, 0.0, 1.0, 1.0), 1.0);

        player.draw(&mut target, &shader_prog, t, true);

        target.finish().unwrap();
        sleep_ms(16);
    }
}

fn main() {
    use glium::{DisplayBuild, GliumCreationError};
    use glium::glutin::{WindowBuilder, GlRequest, Api, GlProfile};
    let display_option = WindowBuilder::new()
        .with_gl(GlRequest::Specific(Api::OpenGl, (3, 3)))
        .with_gl_profile(GlProfile::Core)
        .with_depth_buffer(24)
        .with_vsync()
        .build_glium();
    println!("If there was a message about an error just now, ignore it.  I think the driver's on crack.");
    match display_option {
        Ok(display) => mainloop(&display),
        Err(creation_error) => match creation_error {
            GliumCreationError::BackendCreationError(_) => println!("Oh, crap!"),
            GliumCreationError::IncompatibleOpenGl(msg) => println!("Incompatible OpenGL: {}", msg)
        }
    }
}
<commit_msg>Better rotation<commit_after>#[macro_use]
extern crate glium;
extern crate image;
extern crate nalgebra;
extern crate num;

mod steve;

const VERT_PROG: &'static str = include_str!("vert.glsl");

const FRAG_PROG: &'static str = include_str!("frag.glsl");

use glium::{Surface, VertexBuffer, Frame, Program};
use glium::index::NoIndices;
use glium::texture::srgb_texture2d::SrgbTexture2d;
use glium::uniforms::{MagnifySamplerFilter, Uniforms, AsUniformValue};
use glium::draw_parameters::DepthTest;
use glium::backend::glutin_backend::GlutinFacade;
use glium::index::PrimitiveType;
use glium::vertex::BufferCreationError;
use glium::glutin::{Event, ElementState, VirtualKeyCode};
use std::f32::consts::{FRAC_PI_2, PI};
use std::thread::sleep_ms;
use nalgebra::{Rot3, Iso3, Vec3, Persp3, ToHomogeneous, Mat4};
use num::traits::{Zero, One};

enum NextAction {
    Quit,
}

fn handle_input(turn_rate_y: &mut f32, turn_rate_x: &mut f32, state: ElementState, vk_opt: &Option<VirtualKeyCode>) -> Option<NextAction> {
    let mut next_action = None;
    match *vk_opt {
        Some(vk) => match (vk, state) {
            (VirtualKeyCode::Right, ElementState::Pressed)  => *turn_rate_y = PI / 200.0,
            (VirtualKeyCode::Left, ElementState::Pressed)  => *turn_rate_y = -PI / 200.0,
            (VirtualKeyCode::Right, ElementState::Released) => *turn_rate_y = 0.0f32,
            (VirtualKeyCode::Left, ElementState::Released) => *turn_rate_y = 0.0f32,

            (VirtualKeyCode::Up, ElementState::Pressed)  => *turn_rate_x = PI / 200.0,
            (VirtualKeyCode::Down, ElementState::Pressed)  => *turn_rate_x = -PI / 200.0,
            (VirtualKeyCode::Up, ElementState::Released) => *turn_rate_x = 0.0f32,
            (VirtualKeyCode::Down, ElementState::Released) => *turn_rate_x = 0.0f32,

            (VirtualKeyCode::Q, ElementState::Released) => next_action =  Some(NextAction::Quit),
            _ => ()
        },
        None => ()
    };
    next_action
}

pub struct ModelPiece {
    vbo: VertexBuffer<steve::Vertex>,
    prim: PrimitiveType,
    bone: Option<Vec3<f32>>,
}

impl ModelPiece {
    fn new(display: &GlutinFacade, verts: &[steve::Vertex], prim: PrimitiveType, bone: Option<Vec3<f32>>) -> Result<Self, BufferCreationError> {
        let vertex_buffer = match VertexBuffer::new(display, verts) {
            Ok(vbo) => vbo,
            Err(e) => return Err(e),
        };
        Ok(ModelPiece{vbo: vertex_buffer, prim: prim, bone: bone})
    }

    fn make_anim_matrix(self: &Self, anim_angle: f32) -> Mat4<f32> {
        match self.bone {
            Some(bone) => {
                let trans1 = Iso3::new(-bone, Vec3::zero()).to_homogeneous();
                let rot3 = Rot3::new(Vec3::new(0.0, anim_angle, 0.0)).to_homogeneous();
                let trans2 = Iso3::new(bone, Vec3::zero()).to_homogeneous();
                trans2 * rot3 * trans1},
            None => Mat4::<f32>::one()
        }
    }

    fn draw<U>(self: &Self, target: &mut Frame, shader_prog: &Program, uniforms: &U, params: &glium::draw_parameters::DrawParameters) where U: Uniforms {
        let ibo = NoIndices(self.prim);
        target.draw(&self.vbo, ibo, shader_prog, uniforms, params).unwrap();
    }
}

macro_rules! implement_uniforms {
    ($struct_name:ident, $($field_name:ident),+) => (
        impl<'b> glium::uniforms::Uniforms for $struct_name<'b> {
            #[inline]
            fn visit_values<'a, F: FnMut(&str, glium::uniforms::UniformValue<'a>)>(&'a self, mut output: F) {
                $(
                    output(stringify!($field_name), self.$field_name.as_uniform_value());
                )+
            }
        }
    );

    ($struct_name:ident, $($field_name:ident),+,) => (
        implement_uniforms!($struct_name, $($field_name),+);
    );
}

#[derive(Copy, Clone)]
struct PlayerModelUniforms<'a> {
    model: Mat4<f32>,
    view:  Mat4<f32>,
    projection:  Mat4<f32>,
    tex: &'a glium::uniforms::Sampler<'a, SrgbTexture2d>,
}

implement_uniforms!(PlayerModelUniforms, model, view, projection, tex);

pub struct PlayerModel {
    head: ModelPiece,
    torso: ModelPiece,

    larm: ModelPiece,
    rarm: ModelPiece,

    lleg: ModelPiece,
    rleg: ModelPiece,

    texture: SrgbTexture2d,
}

impl PlayerModel {
    fn draw(self: &Self, target: &mut Frame, shader_prog: &Program, t: f32, angle_y: f32, angle_x: f32, do_anim: bool) {
        let perspective = {
            let (width, height) = target.get_dimensions();
            let aspect_ratio = width as f32 / height as f32;
            //println!("Aspect ratio: {} ({} x {})", aspect_ratio, height, width);

            let fov: f32 = 3.141592 / 3.0;
            let zfar = 1024.0;
            let znear = 0.1;

            Persp3::new(aspect_ratio, fov, znear, zfar).to_mat()
        };

        let rot1 = Rot3::new(Vec3::new(-FRAC_PI_2, 0.0, 0.0)).to_homogeneous();
        let rot2 = Rot3::new(Vec3::new(0.0, FRAC_PI_2, 0.0)).to_homogeneous();

        let trans_final = Vec3::new(0.0, 0.0, 100.0);
        let trans_final_mat = Iso3::new(trans_final, Vec3::zero()).to_homogeneous();
        let inv_trans_final_mat = Iso3::new(-trans_final, Vec3::zero()).to_homogeneous();

        let model = trans_final_mat * rot2 * rot1;
        let view_rot1 = Rot3::new(Vec3::new(0.0, angle_y, 0.0)).to_homogeneous();
        let view_rot2 = Rot3::new(Vec3::new(angle_x, 0.0, 0.0)).to_homogeneous();
        let view = trans_final_mat * view_rot2 * view_rot1 * inv_trans_final_mat;

        let mut uniforms = PlayerModelUniforms{
            model: model,
            view: view,
            projection: perspective,
            tex: &self.texture.sampled().magnify_filter(MagnifySamplerFilter::Nearest),
        };

        let params = glium::DrawParameters {
            depth: glium::Depth {
                test: DepthTest::IfLess,
                write: true,
                .. Default::default()
            },
            .. Default::default()
        };

        self.head.draw(target, shader_prog, &uniforms, &params);
        self.torso.draw(target, shader_prog, &uniforms, &params);

        let anim_matrix = self.larm.make_anim_matrix(if do_anim { -FRAC_PI_2 * t.sin() } else { 0.0 });
        let model = trans_final_mat * rot2 * rot1 * anim_matrix;
        uniforms.model = model;
        self.larm.draw(target, shader_prog, &uniforms, &params);

        let anim_matrix = self.rarm.make_anim_matrix(if do_anim { FRAC_PI_2 * t.sin() } else { 0.0 });
        let model = trans_final_mat * rot2 * rot1 * anim_matrix;
        uniforms.model = model;
        self.rarm.draw(target, shader_prog, &uniforms, &params);

        let anim_matrix = self.lleg.make_anim_matrix(if do_anim { FRAC_PI_2 * t.sin() } else { 0.0 });
        let model = trans_final_mat * rot2 * rot1 * anim_matrix;
        uniforms.model = model;
        self.lleg.draw(target, shader_prog, &uniforms, &params);

        let anim_matrix = self.rleg.make_anim_matrix(if do_anim { -FRAC_PI_2 * t.sin() } else { 0.0 });
        let model = trans_final_mat * rot2 * rot1 * anim_matrix;
        uniforms.model = model;
        self.rleg.draw(target, shader_prog, &uniforms, &params);
    }
}

fn mainloop(display: &GlutinFacade) {
    use std::io::Cursor;

    let image = image::load(Cursor::new(&include_bytes!("steve.png")[..]),
                            image::PNG).unwrap();

    let player = PlayerModel{
        head: ModelPiece::new(display, &steve::HEAD, PrimitiveType::TrianglesList, None).unwrap(),
        torso: ModelPiece::new(display, &steve::TORSO, PrimitiveType::TrianglesList, None).unwrap(),

        larm: ModelPiece::new(display, &steve::LARM, PrimitiveType::TrianglesList, Some(*steve::LARM_BONE)).unwrap(),
        rarm: ModelPiece::new(display, &steve::RARM, PrimitiveType::TrianglesList, Some(*steve::RARM_BONE)).unwrap(),

        lleg: ModelPiece::new(display, &steve::LLEG, PrimitiveType::TrianglesList, Some(*steve::LLEG_BONE)).unwrap(),
        rleg: ModelPiece::new(display, &steve::RLEG, PrimitiveType::TrianglesList, Some(*steve::RLEG_BONE)).unwrap(),

        texture: SrgbTexture2d::new(display, image).unwrap(),
    };

    let shader_prog = Program::from_source(display, VERT_PROG, FRAG_PROG, None).unwrap();

    let mut t = 0.0f32;
    let mut angle_y = 0.0f32;
    let mut angle_x = 0.0f32;

    let anim_rate = 0.04f32;
    let mut turn_rate_y = 0.0f32;
    let mut turn_rate_x = 0.0f32;

    loop {
        t += anim_rate;
        angle_y += turn_rate_y;
        angle_x += turn_rate_x;

        for ev in display.poll_events() {
            match ev {
                Event::Closed => return,
                Event::KeyboardInput(state, _, vk_opt) => match handle_input(&mut turn_rate_y, &mut turn_rate_x, state, &vk_opt) {
                    Some(NextAction::Quit) => return,
                    None => ()
                },
                _ => ()
            }
        }

        //let (width, height) = display.get_framebuffer_dimensions();
        //println!("Framebuffer dimensions: {} x {}", width, height);
        let mut target = display.draw();
        target.clear_color_and_depth((0.0, 0.0, 1.0, 1.0), 1.0);

        player.draw(&mut target, &shader_prog, t, angle_y, angle_x, true);

        target.finish().unwrap();
        sleep_ms(16);
    }
}

fn main() {
    use glium::{DisplayBuild, GliumCreationError};
    use glium::glutin::{WindowBuilder, GlRequest, Api, GlProfile};
    let display_option = WindowBuilder::new()
        .with_gl(GlRequest::Specific(Api::OpenGl, (3, 3)))
        .with_gl_profile(GlProfile::Core)
        .with_depth_buffer(24)
        .with_vsync()
        .build_glium();
    println!("If there was a message about an error just now, ignore it.  I think the driver's on crack.");
    match display_option {
        Ok(display) => mainloop(&display),
        Err(creation_error) => match creation_error {
            GliumCreationError::BackendCreationError(_) => println!("Oh, crap!"),
            GliumCreationError::IncompatibleOpenGl(msg) => println!("Incompatible OpenGL: {}", msg)
        }
    }
}
<|endoftext|>


<commit_before>
mod stdout_writer;

extern crate clap;
extern crate xor_utils;
extern crate hex;
extern crate base64;

#[macro_use] extern crate log;
extern crate env_logger;

use clap::{App, Arg, ArgMatches};
use std::io;
use std::fs;
use std::path::Path;
use std::fs::{File, OpenOptions, DirEntry};
use std::io::{Write, Read};
use xor_utils::Xor;

/// The mode is used in conjunction with the "recursive" option and determines how file names
/// will be processed when renaming files.
/// When in "encrypt" mode, file names are XOR'd then hexified.
/// When in "decrypt" mode, file names are unhexified then XOR'd.
enum Mode {
    Encrypt,
    Decrypt
}

static ABOUT: &str = "
XOR encrypt files or directories using a supplied key.

In it's simplest form, reads input from stdin, encrypts it against a key and writes the result to stdout.
The \"key\" option can be either a path to a file or a string of characters.

When the \"recursive\" option is used, files under a given directory are recursively encrypted.
Files are renamed by XORing the original name against the provided key, then hexifying the result.
To decrypt you must use the \"mode\" option with the value \"d\", files are then renamed by unhexifying then XORing.
";

fn main() {
    env_logger::init().unwrap();

    // Parse arguments and provide help.
    let matches = App::new("xor")
        .version("1.4.0")
        .about(ABOUT)
        .author("Gavyn Riebau")
        .arg(Arg::with_name("key")
             .help("The file containing the key data, or a provided string, against which input will be XOR'd.\nThis should be larger than the given input data or will need to be repeated to encode the input data.")
             .long("key")
             .short("k")
             .required(true)
             .value_name("KEY"))
        /*
        .arg(Arg::with_name("force")
             .help("Don't show warning prompt if the key size is too small and key bytes will have to be re-used.\nRe-using key bytes makes the encryption vulnerable to being decrypted.")
             .long("force")
             .short("f"))
             */
        .arg(Arg::with_name("decrypt")
             .help("Decrypt directory names rather than encrypting them.\nApplies when using the \"recursive\" option to encrypt a directory.\nWhen set, directory names are decrypted by unhexifying then XORing.\nWhen not set, directory names are encrypted by XORing then hexifying.")
             .long("decrypt")
             .short("d"))
        .arg(Arg::with_name("input")
             .help("The file from which input data will be read, if omitted, and the \"recursive\" option isn't used, input will be read from stdin.")
             .long("input")
             .short("i")
             .required(false)
             .value_name("FILE"))
        .arg(Arg::with_name("recursive")
             .help("Recursively encrypt / decrypt files and subfolders starting at the given directory.\nFiles and directory names will be encrypted / decrypted according to the \"mode\" argument.\nNames are xor encrypted then converted to a hex string.")
             .long("recursive")
             .short("r")
             .value_name("DIRECTORY")
             .conflicts_with("input")
             .conflicts_with("output"))
        .arg(Arg::with_name("output")
             .help("The file to which encoded data will be written, if omitted output will be written to stdout.\nIt's recommended to write output to a file for cases where the encoded data contains non-unicode characters which would otherwise not be printed to the console.")
             .long("output")
             .short("o")
             .required(false)
             .value_name("FILE"))
         .get_matches();

    // Parse the mode of operation, defaulting to encrypt mode.
    let mode = if matches.is_present("decrypt") {
        Mode::Decrypt
    } else {
        Mode::Encrypt
    };

    // Read all the key bytes into memory.
    let key_bytes = get_key_bytes(&matches);

    if matches.is_present("recursive") {
        trace!("Recursively encrypting files and folders.");

        let starting_dir_name = matches.value_of("recursive").unwrap();
        let starting_dir = Path::new(starting_dir_name);

        encrypt_path(starting_dir, &key_bytes, &mode);
    } else {

        let input : Box<Read> = if matches.is_present("input") {
            trace!("Reading input from a file.");
            Box::new(File::open(matches.value_of("input").unwrap()).unwrap())
        } else {
            trace!("Reading input from stdin.");
            Box::new(io::stdin())
        };

        let output : Box<Write> = if matches.is_present("output") {
            trace!("Writting output to a file.");
            Box::new(OpenOptions::new()
                .write(true)
                .create(true)
                .truncate(true)
                .open(matches.value_of("output").unwrap())
                .unwrap())
        } else {
            trace!("Writting output to stdout.");
            Box::new(stdout_writer::StdoutWriter{})
        };

        encrypt_reader(input, &key_bytes, output);
    }
}

/// XOR's all the bytes from reader against the provided key then writes the result to the output
/// writer.
fn encrypt_reader(mut input : Box<Read>, key : &Vec<u8>, mut output : Box<Write>) {
    let encoded_bytes = input.by_ref().xor(&key);
    let _ = output.write_all(encoded_bytes.as_slice());
    output.flush().unwrap();
}

fn encrypt_path(p : &Path, key : &Vec<u8>, mode : &Mode) {
    for item in fs::read_dir(p).unwrap() {
        match item {
            Ok(entry) => xor_entry(&entry, key, mode),
            Err(err) => info!("Failed to read entry because: {}", err)
        }
    }
}

fn xor_entry(entry : &DirEntry, key : &Vec<u8>, mode : &Mode) {
    match entry.file_type() {
        Ok(entry_type) => {
            if entry_type.is_dir() {
                xor_dir(entry, key, mode);
            } else if entry_type.is_file() {
                xor_file(entry, key, mode);
            } else if entry_type.is_symlink() {
                xor_symlink(entry, key, mode);
            }
        },
        Err(err) => info!("Failed to get filetype for DirEntry {:?} because: {}", entry, err)
    }
}

fn xor_file(entry : &DirEntry, key : &Vec<u8>, mode : &Mode) {
    debug!("Encrypting file {:?}", entry);

    match File::open(entry.path()) {
        Ok(mut file) => {
            let mut reader = &mut file as &mut Read;
            let cypher_text = reader.xor(&key);

            let output = OpenOptions::new()
                .write(true)
                .truncate(true)
                .open(entry.path());

            match output {
                Ok(mut writer) => {
                    match writer.write_all(cypher_text.as_slice()) {
                        Ok(_) => {},
                        Err(err) => info!("Failed to write encrypted bytes to file because: {}", err)
                    }
                },
                Err(err) => info!("Failed to open file with truncate option for DirEntry {:?} because: {}", entry, err)
            }
        },
        Err(err) => info!("Failed to open file for DirEntry {:?} because: {}", entry, err)
    }

    rename_entry(entry, key, mode);
}

fn xor_symlink(entry : &DirEntry, key : &Vec<u8>, mode : &Mode) {
    debug!("Encrypting symlink {:?}", entry);

    rename_entry(entry, key, mode);
}

fn xor_dir(entry : &DirEntry, key : &Vec<u8>, mode : &Mode) {
    debug!("Encrypting dir {:?}", entry);

    match fs::read_dir(entry.path()) {
        Ok(entries) => {
            for child in entries {
                if let Ok(child) = child {
                    xor_entry(&child, key, mode);
                }
            }
        },
        Err(e) => {
            let mut stderr = io::stderr();
            let _ = stderr.write_fmt(format_args!("Failed to read directory: {}", e));
        }
    }

    rename_entry(entry, key, mode);
}

/// Renames a directory entry.
/// When "mode" is Mode::Encrypt, the name of the entry is XOR'd then hexlified.
/// When "mode" is Mode::Decrypt, the name of the entry is unhexlified then XOR'd.
fn rename_entry(entry : &DirEntry, key : &Vec<u8>, mode : &Mode) {
    let file_name = entry.file_name();

    if let Some(original_name) = file_name.to_str() {
        debug!("original_name: {}", original_name);

        let key_repeated = repeat_key(key, original_name.len());

        // If in Encrypt mode use the filename as is.
        // If in Decrypt mode unhexify the filename before getting it's bytes.
        let input_bytes = match *mode {
            Mode::Encrypt => original_name.to_string().into_bytes(),
            Mode::Decrypt => from_hex_string(String::from(original_name))
        };

        // Xor encrypt the name.
        let mut encrypted = Vec::with_capacity(input_bytes.len());
        for (d, k) in input_bytes.iter().zip(key_repeated) {
            encrypted.push(d ^ k);
        }

        // If in Encrypt mode hexify the filename.
        // If in Decrypt mode just use the filename as is.
        let replaced_name = match *mode {
            Mode::Encrypt => to_hex_string(encrypted),
            Mode::Decrypt => String::from_utf8(encrypted).unwrap()
        };
        debug!("replaced_name: {}", replaced_name);

        let full_path_buf = entry.path();
        let full_path = full_path_buf.as_path();
        let parent_path = full_path.parent().unwrap();

        let src_file_path_buf = parent_path.join(original_name);
        let dst_file_path_buf = parent_path.join(replaced_name);

        let src_file_path = src_file_path_buf.as_path();
        let dst_file_path = dst_file_path_buf.as_path();

        debug!("Moving {:?} to {:?}", src_file_path, dst_file_path);

        match fs::rename(src_file_path, dst_file_path) {
            Ok(_) => {},
            Err(e) => info!("Failed to rename file because: {}", e)
        }
    }
}

/// Create a vector of bytes equal in length to the name of the file.
/// If the key is too small it'll be repeated to make up the required length.
fn repeat_key(key : &Vec<u8>, required_len : usize) -> Vec<u8> {
    let mut key_repeated = Vec::with_capacity(required_len);

    while key_repeated.len() < required_len {
        for &b in key {
            key_repeated.push(b);

            if key_repeated.len() == required_len {
                break;
            }
        }
    }

    key_repeated
}

fn to_hex_string(bytes: Vec<u8>) -> String {
    let strings: Vec<String> = bytes
        .iter()
        .map(|b| format!("{:02X}", b))
        .collect();

    strings.join("")
}

fn from_hex_string(hex : String) -> Vec<u8> {
    hex::FromHex::from_hex(hex).unwrap()
}

fn get_key_bytes<'a>(matches: &'a ArgMatches<'a>) -> Vec<u8> {
    let mut key_bytes : Vec<u8> = Vec::new();

    let key = matches.value_of("key").unwrap();

    // If the key is a file, read the contents of the file.
    // Otherwise if key is a string, use the string bytes.
    if Path::new(key).exists() {
        File::open(key).unwrap().read_to_end(&mut key_bytes).unwrap();
    } else {
        key_bytes = key.to_string().into_bytes();
    }

    key_bytes
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn to_hex_string_works() {
        let input_string = String::from("hello");
        let input_bytes = input_string.into_bytes();

        let hex_string = to_hex_string(input_bytes);
        assert_eq!(hex_string, "68656C6C6F");
    }

    #[test]
    fn from_hex_string_works() {
        let input_string = String::from("68656C6C6F");
        let ascii_bytes = from_hex_string(input_string);
        let expected_bytes = vec![104, 101, 108, 108, 111];

        assert_eq!(expected_bytes, ascii_bytes);
    }

}

<commit_msg>Minor refactoring and added some comments<commit_after>
mod stdout_writer;

extern crate clap;
extern crate xor_utils;
extern crate hex;
extern crate base64;

#[macro_use] extern crate log;
extern crate env_logger;

use clap::{App, Arg, ArgMatches};
use std::io;
use std::fs;
use std::path::Path;
use std::fs::{File, OpenOptions, DirEntry};
use std::io::{Write, Read};
use xor_utils::Xor;

/// The mode is used in conjunction with the "recursive" option and determines how file names
/// will be processed when renaming files.
/// When in "encrypt" mode, file names are XOR'd then hexified.
/// When in "decrypt" mode, file names are unhexified then XOR'd.
enum Mode {
    Encrypt,
    Decrypt
}

static ABOUT: &str = "
XOR encrypt files or directories using a supplied key.

In it's simplest form, reads input from stdin, encrypts it against a key and writes the result to stdout.
The \"key\" option can be either a path to a file or a string of characters.

When the \"recursive\" option is used, files under a given directory are recursively encrypted.
Files are renamed by XORing the original name against the provided key, then hexifying the result.
To decrypt you must use the \"decrypt\" flag, files are then renamed by unhexifying then XORing.
";

fn main() {
    env_logger::init().unwrap();

    // Parse arguments and provide help.
    let matches = App::new("xor")
        .version("1.4.0")
        .about(ABOUT)
        .author("Gavyn Riebau")
        .arg(Arg::with_name("key")
             .help("The file containing the key data, or a provided string, against which input will be XOR'd.\nThis should be larger than the given input data or will need to be repeated to encode the input data.")
             .long("key")
             .short("k")
             .required(true)
             .value_name("KEY"))
        /*
        .arg(Arg::with_name("force")
             .help("Don't show warning prompt if the key size is too small and key bytes will have to be re-used.\nRe-using key bytes makes the encryption vulnerable to being decrypted.")
             .long("force")
             .short("f"))
             */
        .arg(Arg::with_name("decrypt")
             .help("Decrypt directory names rather than encrypting them.\nApplies when using the \"recursive\" option to encrypt a directory.\nWhen set, directory names are decrypted by unhexifying then XORing.\nWhen not set, directory names are encrypted by XORing then hexifying.")
             .long("decrypt")
             .short("d"))
        .arg(Arg::with_name("input")
             .help("The file from which input data will be read, if omitted, and the \"recursive\" option isn't used, input will be read from stdin.")
             .long("input")
             .short("i")
             .required(false)
             .value_name("FILE"))
        .arg(Arg::with_name("recursive")
             .help("Recursively encrypt / decrypt files and subfolders starting at the given directory.\nFiles and directory names will be encrypted / decrypted according to the \"mode\" argument.\nNames are xor encrypted then converted to a hex string.")
             .long("recursive")
             .short("r")
             .value_name("DIRECTORY")
             .conflicts_with("input")
             .conflicts_with("output"))
        .arg(Arg::with_name("output")
             .help("The file to which encoded data will be written, if omitted output will be written to stdout.\nIt's recommended to write output to a file for cases where the encoded data contains non-unicode characters which would otherwise not be printed to the console.")
             .long("output")
             .short("o")
             .required(false)
             .value_name("FILE"))
         .get_matches();

    // Parse the mode of operation, defaulting to encrypt mode.
    let mode = if matches.is_present("decrypt") {
        Mode::Decrypt
    } else {
        Mode::Encrypt
    };

    // Read all the key bytes into memory.
    let key_bytes = get_key_bytes(&matches);

    if matches.is_present("recursive") {
        trace!("Recursively encrypting files and folders.");

        let starting_dir_name = matches.value_of("recursive").unwrap();
        let starting_dir = Path::new(starting_dir_name);

        encrypt_path(starting_dir, &key_bytes, &mode);
    } else {

        let input : Box<Read> = if matches.is_present("input") {
            trace!("Reading input from a file.");
            Box::new(File::open(matches.value_of("input").unwrap()).unwrap())
        } else {
            trace!("Reading input from stdin.");
            Box::new(io::stdin())
        };

        let output : Box<Write> = if matches.is_present("output") {
            trace!("Writting output to a file.");
            Box::new(OpenOptions::new()
                .write(true)
                .create(true)
                .truncate(true)
                .open(matches.value_of("output").unwrap())
                .unwrap())
        } else {
            trace!("Writting output to stdout.");
            Box::new(stdout_writer::StdoutWriter{})
        };

        encrypt_reader(input, &key_bytes, output);
    }
}

/// XOR's all the bytes from reader against the provided key then writes the result to the output
/// writer.
fn encrypt_reader(mut input : Box<Read>, key : &Vec<u8>, mut output : Box<Write>) {
    let encoded_bytes = input.by_ref().xor(&key);
    let _ = output.write_all(encoded_bytes.as_slice());
    output.flush().unwrap();
}

fn encrypt_path(p : &Path, key : &Vec<u8>, mode : &Mode) {
    for item in fs::read_dir(p).unwrap() {
        match item {
            Ok(entry) => xor_entry(&entry, key, mode),
            Err(err) => info!("Failed to read entry because: {}", err)
        }
    }
}

fn xor_entry(entry : &DirEntry, key : &Vec<u8>, mode : &Mode) {
    match entry.file_type() {
        Ok(entry_type) => {
            if entry_type.is_dir() {
                xor_dir(entry, key, mode);
            } else if entry_type.is_file() {
                xor_file(entry, key, mode);
            } else if entry_type.is_symlink() {
                xor_symlink(entry, key, mode);
            }
        },
        Err(err) => info!("Failed to get filetype for DirEntry {:?} because: {}", entry, err)
    }
}

fn xor_file(entry : &DirEntry, key : &Vec<u8>, mode : &Mode) {
    debug!("Encrypting file {:?}", entry);

    match File::open(entry.path()) {
        Ok(mut file) => {
            let mut reader = &mut file as &mut Read;
            let cypher_text = reader.xor(&key);

            let output = OpenOptions::new()
                .write(true)
                .truncate(true)
                .open(entry.path());

            match output {
                Ok(mut writer) => {
                    match writer.write_all(cypher_text.as_slice()) {
                        Ok(_) => {},
                        Err(err) => info!("Failed to write encrypted bytes to file because: {}", err)
                    }
                },
                Err(err) => info!("Failed to open file with truncate option for DirEntry {:?} because: {}", entry, err)
            }
        },
        Err(err) => info!("Failed to open file for DirEntry {:?} because: {}", entry, err)
    }

    rename_entry(entry, key, mode);
}

fn xor_symlink(entry : &DirEntry, key : &Vec<u8>, mode : &Mode) {
    debug!("Encrypting symlink {:?}", entry);

    rename_entry(entry, key, mode);
}

fn xor_dir(entry : &DirEntry, key : &Vec<u8>, mode : &Mode) {
    debug!("Encrypting dir {:?}", entry);

    match fs::read_dir(entry.path()) {
        Ok(entries) => {
            for child in entries {
                if let Ok(child) = child {
                    xor_entry(&child, key, mode);
                }
            }
        },
        Err(e) => {
            let mut stderr = io::stderr();
            let _ = stderr.write_fmt(format_args!("Failed to read directory: {}", e));
        }
    }

    rename_entry(entry, key, mode);
}

/// Renames a directory entry.
/// When "mode" is Mode::Encrypt, the name of the entry is XOR'd then hexlified.
/// When "mode" is Mode::Decrypt, the name of the entry is unhexlified then XOR'd.
fn rename_entry(entry : &DirEntry, key : &Vec<u8>, mode : &Mode) {
    let file_name = entry.file_name();

    if let Some(original_name) = file_name.to_str() {
        debug!("original_name: {}", original_name);

        let key_repeated = repeat_key(key, original_name.len());

        // If in Encrypt mode use the filename as is.
        // If in Decrypt mode unhexify the filename before getting it's bytes.
        let input_bytes = match *mode {
            Mode::Encrypt => original_name.to_string().into_bytes(),
            Mode::Decrypt => from_hex_string(String::from(original_name))
        };

        // Xor encrypt the name.
        let mut encrypted = Vec::with_capacity(input_bytes.len());
        for (d, k) in input_bytes.iter().zip(key_repeated) {
            encrypted.push(d ^ k);
        }

        // If in Encrypt mode hexify the filename.
        // If in Decrypt mode just use the filename as is.
        let replaced_name = match *mode {
            Mode::Encrypt => to_hex_string(encrypted),
            Mode::Decrypt => String::from_utf8(encrypted).unwrap()
        };
        debug!("replaced_name: {}", replaced_name);

        let full_path_buf = entry.path();
        let full_path = full_path_buf.as_path();
        let parent_path = full_path.parent().unwrap();

        let src_file_path_buf = parent_path.join(original_name);
        let dst_file_path_buf = parent_path.join(replaced_name);

        let src_file_path = src_file_path_buf.as_path();
        let dst_file_path = dst_file_path_buf.as_path();

        debug!("Moving {:?} to {:?}", src_file_path, dst_file_path);

        match fs::rename(src_file_path, dst_file_path) {
            Ok(_) => {},
            Err(e) => info!("Failed to rename file because: {}", e)
        }
    }
}

/// Create a vector of bytes equal in length to the name of the file.
/// If the key is too small it'll be repeated to make up the required length.
fn repeat_key(key : &Vec<u8>, required_len : usize) -> Vec<u8> {
    let mut key_repeated = Vec::with_capacity(required_len);

    while key_repeated.len() < required_len {
        for &b in key {
            key_repeated.push(b);

            if key_repeated.len() == required_len {
                break;
            }
        }
    }

    key_repeated
}

fn to_hex_string(bytes: Vec<u8>) -> String {
    let strings: Vec<String> = bytes
        .iter()
        .map(|b| format!("{:02X}", b))
        .collect();

    strings.join("")
}

fn from_hex_string(hex : String) -> Vec<u8> {
    hex::FromHex::from_hex(hex).unwrap()
}

fn get_key_bytes<'a>(matches: &'a ArgMatches<'a>) -> Vec<u8> {
    let mut key_bytes : Vec<u8> = Vec::new();

    let key = matches.value_of("key").unwrap();

    // If the key is a file, read the contents of the file.
    // Otherwise if key is a string, use the string bytes.
    if Path::new(key).exists() {
        File::open(key).unwrap().read_to_end(&mut key_bytes).unwrap();
    } else {
        key_bytes = key.to_string().into_bytes();
    }

    key_bytes
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn to_hex_string_works() {
        let input_string = String::from("hello");
        let input_bytes = input_string.into_bytes();

        let hex_string = to_hex_string(input_bytes);
        assert_eq!(hex_string, "68656C6C6F");
    }

    #[test]
    fn from_hex_string_works() {
        let input_string = String::from("68656C6C6F");
        let ascii_bytes = from_hex_string(input_string);
        let expected_bytes = vec![104, 101, 108, 108, 111];

        assert_eq!(expected_bytes, ascii_bytes);
    }

}

<|endoftext|>


<commit_before>extern crate image;
extern crate dungenon;

use std::io;
use dungenon::level::Level;
use dungenon::tile::Tile;
use dungenon::generator::MazeGen;

use image::png::PNGEncoder;
use image::RgbaImage;

fn main() {
    println!("Initializing level...");
    let mut level = init_level();

    println!("This is the dungenon-drawer. \nType Help for list of commands.");
    loop {
        println!("Enter command:");
        let mut command = String::new();
        io::stdin().read_line(&mut command)
        .expect("Failed to read line");
        println!("{}", command);
        match command.trim() {
            "dungeon" => carve_dungeon(&mut level),
            "maze" => carve_maze(&mut level),
            "room" => carve_rooms(&mut level),
            "reset" => level = init_level(),
            "export" => {
                png_export(&mut level);
            },
            "print" => print_level(&level),
            "help" => {
                println!("Help command is not implemented yet!");
            }
            "exit" => break,
            _ => println!("Invalid command"),
        }
    }
}

fn init_level() -> Level {
    println!("Input level width: ");
    let mut x = usize_from_cmd();

    println!("Input level height: ");
    let mut y = usize_from_cmd();

    Level::new_filled_with(Some(Tile::Wall), x, y)
}

fn carve_dungeon(level: &mut Level) {
    println!("Not implemented.");
}

fn carve_maze(level: &mut Level) {
    println!("Input MazeGen startpos x coordinate: ");
    let mut x = usize_from_cmd();

    println!("Input MazeGen startpos y coordinate: ");
    let mut y = usize_from_cmd();
    let mut mazegen = MazeGen::new(x,y);
    level.apply(|m| mazegen.generate(m));
}

fn carve_rooms(level: &mut Level) {
    println!("Not implemented.");
}

fn png_export(level: &mut Level) {
    let mut level_image = RgbaImage::new(level.get_height(), level.get_height());
    for y in 0 .. level.get_width() {
        for x in 0 .. level.get_height() {

        }
    }
}

fn print_level(level: &Level) {
    let mut string = String::new();
    for y in 0 .. level.get_width() {
        for x in 0 .. level.get_height() {
            match level[(x,y)] {
                Some(ref tile) => {
                    match tile {
                        &Tile::Wall => string.push('#'),
                        &Tile::Floor => string.push(' '),
                        &Tile::Void => string.push('*'),
                    }
                },
                None => string.push('*'),
            }
        }
        string.push('\n');
    }
    println!("{}", &string);
}

fn usize_from_cmd() -> usize {
    let mut num = String::new();

    io::stdin().read_line(&mut num)
        .expect("failed to read line");

    let num: usize = num.trim().parse()
        .expect("Please type a number!");
    num
}
<commit_msg>png export almost done<commit_after>extern crate image;
extern crate dungenon;

use std::io;
use std::path::PathBuf;

use dungenon::level::Level;
use dungenon::tile::Tile;
use dungenon::generator::MazeGen;

use image::RgbImage;
use image::Rgb;

fn main() {
    println!("Initializing level...");
    let mut level = init_level();

    println!("This is the dungenon-drawer. \nType Help for list of commands.");
    loop {
        println!("Enter command:");
        let mut command = string_from_cmd();
        println!("{}", command);
        match command.trim() {
            "dungeon" => carve_dungeon(&mut level),
            "maze" => carve_maze(&mut level),
            "room" => carve_rooms(&mut level),
            "reset" => level = init_level(),
            "export" => {
                png_export(&mut level);
            },
            "print" => print_level(&level),
            "help" => {
                println!("Help command is not implemented yet!");
            }
            "exit" => break,
            _ => println!("Invalid command"),
        }
    }
}

fn init_level() -> Level {
    println!("Input level width: ");
    let mut x = usize_from_cmd();

    println!("Input level height: ");
    let mut y = usize_from_cmd();

    Level::new_filled_with(Some(Tile::Wall), x, y)
}

fn carve_dungeon(level: &mut Level) {
    println!("Not implemented.");
}

fn carve_maze(level: &mut Level) {
    println!("Input MazeGen startpos x coordinate: ");
    let mut x = usize_from_cmd();

    println!("Input MazeGen startpos y coordinate: ");
    let mut y = usize_from_cmd();
    let mut mazegen = MazeGen::new(x,y);
    level.apply(|m| mazegen.generate(m));
}

fn carve_rooms(level: &mut Level) {
    println!("Not implemented.");
}

fn png_export(level: &mut Level) {
    let mut level_image = RgbImage::new(level.get_height(), level.get_height());
    for y in 0 .. level.get_width() {
        for x in 0 .. level.get_height() {
            level_image.put_pixel(x as u32, y as u32, tile_to_color(&level[(x,y)]));
        }
    }
    let mut p = PathBuf::new();
    println!("Enter png name:");
    p.push(&string_from_cmd());
    p.set_extension("png");
    level_image.save(p.as_path());
}

fn tile_to_color(tile: &Option<Tile>) -> Rgb<u8> {
    match tile {
        &Some(ref tile) => {
            match tile {
                &Tile::Wall => return image::Rgb([200 as u8, 200 as u8, 200 as u8]),
                &Tile::Floor => return image::Rgb([127 as u8, 127 as u8, 127 as u8]),
                &Tile::Void => return image::Rgb([0 as u8, 0 as u8, 0 as u8]),
            }
        },
        &None => return image::Rgb([0 as u8, 0 as u8, 0 as u8]),
    }

}

fn print_level(level: &Level) {
    let mut string = String::new();
    for y in 0 .. level.get_width() {
        for x in 0 .. level.get_height() {
            match level[(x,y)] {
                Some(ref tile) => {
                    match tile {
                        &Tile::Wall => string.push('#'),
                        &Tile::Floor => string.push(' '),
                        &Tile::Void => string.push('*'),
                    }
                },
                None => string.push('*'),
            }
        }
        string.push('\n');
    }
    println!("{}", &string);
}

fn usize_from_cmd() -> usize {
    let mut num = String::new();

    io::stdin().read_line(&mut num)
        .expect("failed to read line");

    let num: usize = num.trim().parse()
        .expect("Please type a number!");
    num
}

fn string_from_cmd() -> String {
    let mut string = String::new();
    io::stdin().read_line(&mut string)
    .expect("Failed to read line");
    string
}
<|endoftext|>


<commit_before>extern crate num;
extern crate portaudio;
extern crate rtlsdr;

use portaudio as pa;
use rtlsdr::{RTLSDRDevice, RTLSDRError};
use num::complex::Complex;
use std::env;
use std::collections::VecDeque;
use std::f32::consts::PI;
use std::error::Error;

// Threading libraries.
use std::thread;
use std::sync::mpsc::channel;

// Make sure that the buffer size is radix-2, otherwise the read_sync function
// will fail with an error code of -8.
const BUF_SIZE: usize = 1048576;

// Most other sample rates fail, but this one works for my particular device.
// I will investigate exactly what's happening here and generate a list of
// possible sample rates (if there are others besides this one).
const SAMPLE_RATE: u32 = 2800000;

// Here is the sample rate of the output waveform we'll try to use.
const SAMPLE_RATE_AUDIO: f64 = 48000.0;

const DEVIATION: u32 = 2500;

// I've read someplace that you may want to add an offset due to some bad noise
// on the center frequency from DC. I'll see if this helps later.
const F_OFFSET: u32 = 250000;

// The bandwidth of the received signal.
const BANDWIDTH: u32 = 200000;

// The number of channels being used for audio.
const CHANNELS: i32 = 2;

fn main() {
    match run() {
        Ok(()) => (),
        Err(e) => println!("ERROR: {}", e),
    }
}

struct RTLSDR {
    rtlsdr: RTLSDRDevice,
}

unsafe impl Send for RTLSDR {}

fn run() -> Result<(), Box<Error>> {
    let sdr_index: i32 = env::args()
        .nth(1)
        .expect("Please specify the SDR index")
        .parse::<i32>()?;
    let fm_freq_mhz: f32 = env::args()
        .nth(2)
        .expect("Please specify a center frequency (MHz).")
        .parse::<f32>()?;

    // Initialize the PortAudio class.
    let audio = try!(pa::PortAudio::new());
    let settings =
        try!(audio.default_output_stream_settings(CHANNELS,
                                                  SAMPLE_RATE_AUDIO,
                                                  BUF_SIZE as u32));
    let mut stream = try!(audio.open_blocking_stream(settings));
    try!(stream.start());

    let fm_freq: u32 = (fm_freq_mhz * 1e6) as u32;
    let mut sdr = RTLSDR { rtlsdr: init_sdr(sdr_index, fm_freq).unwrap() };

    // TODO: we need to figure out the appropriate decimation here. I've seen
    // talk that we decimate based on the bandwidth but after decimation the
    // audio signal comes out much slower. Changing the decimation value
    // seems to affect the speed of the audio, so I need to establish the
    // relationship here. Just playing with the decimation value, 30 seems
    // to work well but I need to figure out _why_.
    let dec_rate = (SAMPLE_RATE as f64 / BANDWIDTH as f64) as usize;
    let dec_rate = 30;
    println!("dec rate is {}", dec_rate);
    let (tx, rx) = channel();

    thread::spawn(move || {
        loop {
            // Read the samples and decimate down to match the sample rate of
            // the audio that'll be going out.
            let tx = tx.clone();
            let bytes = sdr.rtlsdr.read_sync(BUF_SIZE).unwrap();
            let iq_vec = average_filter(decimate(read_samples(bytes,
                                                              SAMPLE_RATE,
                                                              fm_freq)
                                                         .unwrap()
                                                         .as_slice(),
                                                 dec_rate));

            // After decimation, demodulate the signal and send out of the
            // thread to the receiver.
            let demod_iq = demod_fm(iq_vec);
            tx.send(demod_iq).unwrap();
        }
    });

    loop {
        // Get the write stream and write our samples to the stream.
        let mut demod_iq = rx.recv().unwrap();
        let out_frames = match stream.write_available() {
            Ok(available) => {
                match available {
                    pa::StreamAvailable::Frames(frames) => frames as u32,
                    _ => return Err(Box::new(pa::error::Error::NullCallback)),
                }
            }
            Err(e) => return Err(Box::new(e)),
        };

        let buffer_frames = (demod_iq.len() / CHANNELS as usize) as u32;
        let write_frames = std::cmp::min(buffer_frames, out_frames);
        let n_write_samples = write_frames as usize * CHANNELS as usize;

        stream
            .write(write_frames,
                   |output| for ix in 0..n_write_samples as usize {
                       output[ix] = demod_iq.pop_front().unwrap();
                   })?;
    }
}

fn init_sdr(sdr_index: i32, fm_freq: u32) -> Result<RTLSDRDevice, RTLSDRError> {
    let mut sdr = try!(rtlsdr::open(sdr_index));
    try!(sdr.set_center_freq(fm_freq));
    try!(sdr.set_sample_rate(SAMPLE_RATE));
    try!(sdr.set_tuner_bandwidth(BANDWIDTH));
    try!(sdr.set_agc_mode(true));
    try!(sdr.reset_buffer());
    Ok(sdr)
}

fn decimate_queue<T: Copy>(signal: VecDeque<T>,
                           dec_rate: usize)
                           -> VecDeque<T> {
    let mut ix = 0;
    let mut signal_dec = VecDeque::<T>::new();
    while ix < signal.len() {
        signal_dec.push_back(*(signal.get(ix).unwrap()));
        ix += dec_rate;
    }
    signal_dec
}

fn decimate(signal: &[Complex<f32>], dec_rate: usize) -> Vec<Complex<f32>> {
    let mut ix = 0;
    let new_size = (signal.len() / dec_rate + 1) as usize;
    let mut signal_dec = Vec::<Complex<f32>>::with_capacity(new_size);
    while ix < signal.len() {
        signal_dec.push(signal[ix]);
        ix += dec_rate;
    }
    signal_dec
}

fn read_samples(bytes: Vec<u8>,
                sample_freq: u32,
                offset: u32)
                -> Option<Vec<Complex<f32>>> {
    let j: Complex<f32> = Complex::i();
    let mut fc_ds: Complex<f32> =
        (-j * 2.0 * PI * offset as f32 / sample_freq as f32) as Complex<f32>;
    fc_ds = fc_ds.exp();

    // First, check that we've been given an even number of bytes. Not sure
    // what to do if we don't get I and Q.
    let bytes_len = bytes.len();
    if bytes_len % 2 != 0 {
        println!("Received an odd number of samples.");
        return None;

    }
    let mut iq_vec: Vec<Complex<f32>> = Vec::with_capacity(bytes_len / 2);

    // Write the values to the complex value and normalize from [0, 255] to
    // [-1, 1]. If we don't normalize, it seems we don't get anything.
    for iq in bytes.chunks(2) {
        let iq_cmplx = Complex::new((iq[0] as f32 - 127.0) / 127.0,
                                    (iq[1] as f32 - 127.0) / 127.0) *
                       fc_ds;
        iq_vec.push(iq_cmplx);
    }
    Some(iq_vec)
}

fn demod_fm(iq: Vec<Complex<f32>>) -> VecDeque<f32> {
    let mut demod_queue: VecDeque<f32> = VecDeque::with_capacity(iq.len());
    let mut prev = iq[0];
    for ix in 0..iq.len() {
        demod_queue.push_back((prev.conj() * iq[ix]).arg());
        prev = iq[ix];
    }
    demod_queue
}

fn average_filter(samples: Vec<Complex<f32>>) -> Vec<Complex<f32>> {
    let beta: f32 = 0.5;
    let mut sampl = samples.clone();
    let mut prev: Complex<f32> = Complex::new(0.0, 0.0);
    for samp in sampl.iter_mut() {
        *samp = beta * (*samp) + (1.0 - beta) * prev;
        prev = *samp;
    }
    sampl.to_vec()
}
<commit_msg>Added gain to lower the volume of the demodulated signal<commit_after>extern crate num;
extern crate portaudio;
extern crate rtlsdr;

use portaudio as pa;
use rtlsdr::{RTLSDRDevice, RTLSDRError};
use num::complex::Complex;
use std::env;
use std::collections::VecDeque;
use std::f32::consts::PI;
use std::error::Error;

// Threading libraries.
use std::thread;
use std::sync::mpsc::channel;

// Make sure that the buffer size is radix-2, otherwise the read_sync function
// will fail with an error code of -8.
const SDR_BUF_SIZE: usize = 524288;

// Separating out the buffer sizes seems to help some.
const BUF_SIZE: usize = 262144;

// Most other sample rates fail, but this one works for my particular device.
// I will investigate exactly what's happening here and generate a list of
// possible sample rates (if there are others besides this one).
const SAMPLE_RATE: u32 = 2800000;

// Here is the sample rate of the output waveform we'll try to use.
const SAMPLE_RATE_AUDIO: f64 = 48000.0;

const DEVIATION: u32 = 2500;

// I've read someplace that you may want to add an offset due to some bad noise
// on the center frequency from DC. I'll see if this helps later.
const F_OFFSET: u32 = 250000;

// The bandwidth of the received signal.
const BANDWIDTH: u32 = 200000;

// The number of channels being used for audio.
const CHANNELS: i32 = 2;

fn main() {
    match run() {
        Ok(()) => (),
        Err(e) => println!("ERROR: {}", e),
    }
}

struct RTLSDR {
    rtlsdr: RTLSDRDevice,
}

unsafe impl Send for RTLSDR {}

fn run() -> Result<(), Box<Error>> {
    let sdr_index: i32 = env::args()
        .nth(1)
        .expect("Please specify the SDR index")
        .parse::<i32>()?;
    let fm_freq_mhz: f32 = env::args()
        .nth(2)
        .expect("Please specify a center frequency (MHz).")
        .parse::<f32>()?;

    // Initialize the PortAudio class.
    let audio = try!(pa::PortAudio::new());
    let settings =
        try!(audio.default_output_stream_settings(CHANNELS,
                                                  SAMPLE_RATE_AUDIO,
                                                  BUF_SIZE as u32));
    let mut stream = try!(audio.open_blocking_stream(settings));
    try!(stream.start());

    let fm_freq: u32 = (fm_freq_mhz * 1e6) as u32;
    let mut sdr = RTLSDR { rtlsdr: init_sdr(sdr_index, fm_freq).unwrap() };

    // TODO: we need to figure out the appropriate decimation here. I've seen
    // talk that we decimate based on the bandwidth but after decimation the
    // audio signal comes out much slower. Changing the decimation value
    // seems to affect the speed of the audio, so I need to establish the
    // relationship here. Just playing with the decimation value, 30 seems
    // to work well but I need to figure out _why_.
    let dec_rate = (SAMPLE_RATE as f64 / BANDWIDTH as f64) as usize;
    let dec_rate = 30;
    println!("dec rate is {}", dec_rate);
    let (tx, rx) = channel();

    thread::spawn(move || {
        loop {
            // Read the samples and decimate down to match the sample rate of
            // the audio that'll be going out.
            let tx = tx.clone();
            let bytes = sdr.rtlsdr.read_sync(SDR_BUF_SIZE).unwrap();
            let iq_vec = average_filter(decimate(read_samples(bytes,
                                                              SAMPLE_RATE,
                                                              fm_freq)
                                                         .unwrap()
                                                         .as_slice(),
                                                 dec_rate));

            // After decimation, demodulate the signal and send out of the
            // thread to the receiver.
            let demod_iq = demod_fm(iq_vec);
            tx.send(demod_iq).unwrap();
        }
    });

    loop {
        // Get the write stream and write our samples to the stream.
        let mut demod_iq = rx.recv().unwrap();
        let out_frames = match stream.write_available() {
            Ok(available) => {
                match available {
                    pa::StreamAvailable::Frames(frames) => frames as u32,
                    _ => return Err(Box::new(pa::error::Error::NullCallback)),
                }
            }
            Err(e) => return Err(Box::new(e)),
        };

        let buffer_frames = (demod_iq.len() / CHANNELS as usize) as u32;
        let write_frames = std::cmp::min(buffer_frames, out_frames);
        if write_frames == 0 {
            println!("write frames is 0, are we not generating fast enough?");
        }
        let n_write_samples = write_frames as usize * CHANNELS as usize;

        stream
            .write(write_frames,
                   |output| for ix in 0..n_write_samples as usize {
                       output[ix] = demod_iq.pop_front().unwrap();
                   })?;
    }
}

fn init_sdr(sdr_index: i32, fm_freq: u32) -> Result<RTLSDRDevice, RTLSDRError> {
    let mut sdr = try!(rtlsdr::open(sdr_index));
    try!(sdr.set_center_freq(fm_freq));
    try!(sdr.set_sample_rate(SAMPLE_RATE));
    try!(sdr.set_tuner_bandwidth(BANDWIDTH));
    try!(sdr.set_agc_mode(true));
    try!(sdr.reset_buffer());
    Ok(sdr)
}

fn decimate_queue<T: Copy>(signal: VecDeque<T>,
                           dec_rate: usize)
                           -> VecDeque<T> {
    let mut ix = 0;
    let mut signal_dec = VecDeque::<T>::new();
    while ix < signal.len() {
        signal_dec.push_back(*(signal.get(ix).unwrap()));
        ix += dec_rate;
    }
    signal_dec
}

fn decimate(signal: &[Complex<f32>], dec_rate: usize) -> Vec<Complex<f32>> {
    let mut ix = 0;
    let new_size = (signal.len() / dec_rate + 1) as usize;
    let mut signal_dec = Vec::<Complex<f32>>::with_capacity(new_size);
    while ix < signal.len() {
        signal_dec.push(signal[ix]);
        ix += dec_rate;
    }
    signal_dec
}

fn read_samples(bytes: Vec<u8>,
                sample_freq: u32,
                offset: u32)
                -> Option<Vec<Complex<f32>>> {
    let j: Complex<f32> = Complex::i();
    let mut fc_ds: Complex<f32> =
        (-j * 2.0 * PI * offset as f32 / sample_freq as f32) as Complex<f32>;
    fc_ds = fc_ds.exp();

    // First, check that we've been given an even number of bytes. Not sure
    // what to do if we don't get I and Q.
    let bytes_len = bytes.len();
    if bytes_len % 2 != 0 {
        println!("Received an odd number of samples.");
        return None;

    }
    let mut iq_vec: Vec<Complex<f32>> = Vec::with_capacity(bytes_len / 2);

    // Write the values to the complex value and normalize from [0, 255] to
    // [-1, 1]. If we don't normalize, it seems we don't get anything.
    for iq in bytes.chunks(2) {
        let iq_cmplx = Complex::new((iq[0] as f32 - 127.0) / 127.0,
                                    (iq[1] as f32 - 127.0) / 127.0) *
                       fc_ds;
        iq_vec.push(iq_cmplx);
    }
    Some(iq_vec)
}

fn demod_fm(iq: Vec<Complex<f32>>) -> VecDeque<f32> {
    let mut demod_queue: VecDeque<f32> = VecDeque::with_capacity(iq.len());
    let gain = 0.01;
    let mut prev = iq[0];
    for ix in 0..iq.len() {
        demod_queue.push_back((prev.conj() * iq[ix]).arg() * gain);
        prev = iq[ix];
    }
    demod_queue
}

fn average_filter(samples: Vec<Complex<f32>>) -> Vec<Complex<f32>> {
    let beta: f32 = 0.5;
    let mut sampl = samples.clone();
    let mut prev: Complex<f32> = Complex::new(0.0, 0.0);
    for samp in sampl.iter_mut() {
        *samp = beta * (*samp) + (1.0 - beta) * prev;
        prev = *samp;
    }
    sampl.to_vec()
}
<|endoftext|>


<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

// Needed to derive `Serialize` on ServiceProperties
#![feature(custom_derive, plugin)]
#![plugin(serde_macros)]

// Needed for IntoIter in context.rs
#![feature(collections)]

extern crate core;
extern crate getopts;
#[macro_use]
extern crate iron;
extern crate mio;
extern crate mount;
extern crate router;
extern crate serde;
extern crate staticfile;
extern crate uuid;

mod context;
mod dummy_adapter;
mod events;
mod http_server;
mod service;
mod controler;

use context::Context;
use controler::Controler;
use core::borrow::BorrowMut;
use getopts::Options;
use std::env;

fn print_usage(program: &str, opts: Options) {
    let brief = format!("Usage: {} [options]", program);
    print!("{}", opts.usage(&brief));
}

fn main() {
    let args: Vec<String> = env::args().collect();
    let program = args[0].clone();

    let mut opts = Options::new();
    opts.optflag("v", "verbose", "Toggle verbose output");
    opts.optopt("n", "name", "Set local host name", "HOSTNAME");
    opts.optflag("h", "help", "Print this help menu");
    let matches = match opts.parse(&args[1..]) {
        Ok(m) => { m }
        Err(_) => {
            print_usage(&program, opts);
            return;
        }
    };
    if matches.opt_present("h") {
        print_usage(&program, opts);
        return;
    }

    if let Ok(mut event_loop) = mio::EventLoop::new() {
        let sender = event_loop.channel();

        let context = Context::shared(matches.opt_present("v"),
                                      matches.opt_str("n"));
        let mut controler = Controler::new(sender, context);
        controler.start();

        event_loop.run(controler.borrow_mut())
                  .unwrap_or_else(|_| {  panic!("Starting the event loop failed!"); });
    } else {
        panic!("Creating the event loop failed!");
    }
}
<commit_msg>Use built-in syntax for borrow_mut().<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

// Needed to derive `Serialize` on ServiceProperties
#![feature(custom_derive, plugin)]
#![plugin(serde_macros)]

// Needed for IntoIter in context.rs
#![feature(collections)]

extern crate core;
extern crate getopts;
#[macro_use]
extern crate iron;
extern crate mio;
extern crate mount;
extern crate router;
extern crate serde;
extern crate staticfile;
extern crate uuid;

mod context;
mod dummy_adapter;
mod events;
mod http_server;
mod service;
mod controler;

use context::Context;
use controler::Controler;
use getopts::Options;
use std::env;

fn print_usage(program: &str, opts: Options) {
    let brief = format!("Usage: {} [options]", program);
    print!("{}", opts.usage(&brief));
}

fn main() {
    let args: Vec<String> = env::args().collect();
    let program = args[0].clone();

    let mut opts = Options::new();
    opts.optflag("v", "verbose", "Toggle verbose output");
    opts.optopt("n", "name", "Set local host name", "HOSTNAME");
    opts.optflag("h", "help", "Print this help menu");
    let matches = match opts.parse(&args[1..]) {
        Ok(m) => { m }
        Err(_) => {
            print_usage(&program, opts);
            return;
        }
    };
    if matches.opt_present("h") {
        print_usage(&program, opts);
        return;
    }

    if let Ok(mut event_loop) = mio::EventLoop::new() {
        let sender = event_loop.channel();

        let context = Context::shared(matches.opt_present("v"),
                                      matches.opt_str("n"));
        let mut controler = Controler::new(sender, context);
        controler.start();

        event_loop.run(&mut controler)
                  .unwrap_or_else(|_| {  panic!("Starting the event loop failed!"); });
    } else {
        panic!("Creating the event loop failed!");
    }
}
<|endoftext|>


<commit_before>/*
 * The MIT License (MIT)
 *
 * Copyright (c) 2015 Andres Vahter (andres.vahter@gmail.com)
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */

// import local modules
extern crate doppler;
use doppler::usage;
use doppler::usage::Mode::{ConstMode, TrackMode};
use doppler::usage::InputType::{I16, F32};
use doppler::dsp;

// import external modules
use std::process::exit;
use std::io;
use std::io::prelude::*;
use std::io::BufReader;
use std::io::BufWriter;

extern crate time;
extern crate gpredict;
use gpredict::predict;
use gpredict::tle;

const SPEED_OF_LIGHT_M_S: f64 = 299792458.;
const BUFFER_SIZE: usize = 8192;

macro_rules! println_stderr(
    ($($arg:tt)*) => (
        match writeln!(&mut ::std::io::stderr(), $($arg)* ) {
            Ok(_) => {},
            Err(x) => panic!("Unable to write to stderr: {}", x),
        }
    )
);

fn main() {
    let args = usage::args();

    println_stderr!("doppler {} andres.vahter@gmail.com\n\n", env!("CARGO_PKG_VERSION"));

    let mut stdin = BufReader::with_capacity(BUFFER_SIZE*2, io::stdin());
    let mut stdout = BufWriter::new(io::stdout());
    let mut outbuf: [u8; BUFFER_SIZE] = [0; BUFFER_SIZE];

    let mut shift = |intype: doppler::usage::InputType, shift_hz: f64, samplerate: u32| {
        let invec = stdin.by_ref().bytes().take(BUFFER_SIZE).collect::<Result<Vec<u8>,_>>().ok().expect("doppler collect error");

        let freq_shift_fn: fn(&[u8], f64, u32, &mut[u8]) -> (usize, usize) =
            match intype {
                I16 => { dsp::shift_frequency_i16},
                F32 => { dsp::shift_frequency_f32},
        };
        let (sample_count, buflen)  = freq_shift_fn(&invec[..],
                                                   shift_hz,
                                                   samplerate,
                                                   &mut outbuf);

        stdout.write(&outbuf[0 .. buflen]).map_err(|e|{println_stderr!("doppler stdout.write error: {:?}", e)}).unwrap();
        stdout.flush().map_err(|e|{println_stderr!("doppler stdout.flush error: {:?}", e)}).unwrap();
        (false, sample_count)
    };

    match *args.mode.as_ref().unwrap() {
        ConstMode => {
            println_stderr!("constant shift mode");
            println_stderr!("\tIQ samplerate   : {}", args.samplerate.as_ref().unwrap());
            println_stderr!("\tIQ input type   : {}", args.inputtype.as_ref().unwrap());
            println_stderr!("\tIQ output type  : i16\n");
            println_stderr!("\tfrequency shift : {} Hz", args.constargs.shift.as_ref().unwrap());

            let intype = args.inputtype.unwrap();
            let shift_hz = args.constargs.shift.unwrap() as f64;
            let samplerate = args.samplerate.unwrap();

            loop {
                let stop_and_count: (bool, usize) = shift(intype, shift_hz, samplerate);
                if stop_and_count.0 {
                    break;
                }
            }
        }

        TrackMode => {
            println_stderr!("tracking mode");
            println_stderr!("\tIQ samplerate   : {}", args.samplerate.as_ref().unwrap());
            println_stderr!("\tIQ input type   : {}", args.inputtype.as_ref().unwrap());
            println_stderr!("\tIQ output type  : i16\n");
            println_stderr!("\tTLE file        : {}", args.trackargs.tlefile.as_ref().unwrap());
            println_stderr!("\tTLE name        : {}", args.trackargs.tlename.as_ref().unwrap());
            println_stderr!("\tlocation        : {:?}", args.trackargs.location.as_ref().unwrap());
            if args.trackargs.time.is_some() {
                println_stderr!("\ttime            : {:.3}", args.trackargs.time.unwrap().to_utc().rfc3339());
            }
            println_stderr!("\tfrequency       : {} Hz", args.trackargs.frequency.as_ref().unwrap());
            println_stderr!("\toffset          : {} Hz\n\n\n", args.trackargs.offset.unwrap_or(0));

            let l = args.trackargs.location.unwrap();
            let location: predict::Location = predict::Location{lat_deg: l.lat, lon_deg: l.lon, alt_m: l.alt};
            let tlename = args.trackargs.tlename.as_ref().unwrap();
            let tlefile = args.trackargs.tlefile.as_ref().unwrap();

            let tle = match tle::create_tle_from_file(&tlename, &tlefile) {
                Ok(t) => {t},
                Err(e) => {
                    println_stderr!("{}", e);
                    exit(1);
                }
            };

            let mut predict: predict::Predict = predict::Predict::new(tle, location);
            let intype = args.inputtype.unwrap();

            let samplerate = args.samplerate.unwrap();
            let mut last_time: time::Tm = time::now_utc();

            match args.trackargs.time {
                Some(start_time) => {
                    let mut sample_count = 0;
                    let mut dt = time::Duration::seconds(0);
                    last_time = start_time;

                    loop {
                        predict.update(Some(start_time + dt));
                        let doppler_hz = (predict.sat.range_rate_km_sec * 1000 as f64 / SPEED_OF_LIGHT_M_S as f64) * args.trackargs.frequency.unwrap() as f64 * (-1.0);

                        // advance time based on how many samples are read in
                        dt = time::Duration::seconds((sample_count as f32 / samplerate as f32) as i64);
                        if start_time + dt - last_time >= time::Duration::seconds(5) {
                            last_time = start_time + dt;
                            println_stderr!("time                : {:}", (start_time + dt).to_utc().rfc3339());
                            println_stderr!("az                  : {:.2}°", predict.sat.az_deg);
                            println_stderr!("el                  : {:.2}°", predict.sat.el_deg);
                            println_stderr!("range               : {:.0} km", predict.sat.range_km);
                            println_stderr!("range rate          : {:.3} km/sec", predict.sat.range_rate_km_sec);
                            println_stderr!("doppler@{:.3} MHz : {:.2} Hz\n", args.trackargs.frequency.unwrap() as f64 / 1000_000_f64, doppler_hz);
                        }

                        let (stop, count): (bool, usize) = shift(intype, doppler_hz, samplerate);
                        if stop {
                            break;
                        }

                        sample_count += count;
                    }
                }

                None => {
                    loop {
                        predict.update(None);
                        let doppler_hz = (predict.sat.range_rate_km_sec * 1000 as f64 / SPEED_OF_LIGHT_M_S as f64) * args.trackargs.frequency.unwrap() as f64 * (-1.0);

                        if time::now_utc() - last_time >= time::Duration::seconds(1) {
                            last_time = time::now_utc();
                            println_stderr!("time                : {:}", time::now_utc().to_utc().rfc3339());
                            println_stderr!("az                  : {:.2}°", predict.sat.az_deg);
                            println_stderr!("el                  : {:.2}°", predict.sat.el_deg);
                            println_stderr!("range               : {:.0} km", predict.sat.range_km);
                            println_stderr!("range rate          : {:.3} km/sec", predict.sat.range_rate_km_sec);
                            println_stderr!("doppler@{:.3} MHz : {:.2} Hz\n", args.trackargs.frequency.unwrap() as f64 / 1000_000_f64, doppler_hz);
                        }

                        let (stop, _): (bool, usize) = shift(intype, doppler_hz, samplerate);
                        if stop {
                            break;
                        }
                    }
                }
            };
        }
    }
}
<commit_msg>stop program if stdin EOF reached<commit_after>/*
 * The MIT License (MIT)
 *
 * Copyright (c) 2015 Andres Vahter (andres.vahter@gmail.com)
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */

// import local modules
extern crate doppler;
use doppler::usage;
use doppler::usage::Mode::{ConstMode, TrackMode};
use doppler::usage::InputType::{I16, F32};
use doppler::dsp;

// import external modules
use std::process::exit;
use std::io;
use std::io::prelude::*;
use std::io::BufReader;
use std::io::BufWriter;

extern crate time;
extern crate gpredict;
use gpredict::predict;
use gpredict::tle;

const SPEED_OF_LIGHT_M_S: f64 = 299792458.;
const BUFFER_SIZE: usize = 8192;

macro_rules! println_stderr(
    ($($arg:tt)*) => (
        match writeln!(&mut ::std::io::stderr(), $($arg)* ) {
            Ok(_) => {},
            Err(x) => panic!("Unable to write to stderr: {}", x),
        }
    )
);

fn main() {
    let args = usage::args();

    println_stderr!("doppler {} andres.vahter@gmail.com\n\n", env!("CARGO_PKG_VERSION"));

    let mut stdin = BufReader::with_capacity(BUFFER_SIZE*2, io::stdin());
    let mut stdout = BufWriter::new(io::stdout());
    let mut outbuf: [u8; BUFFER_SIZE] = [0; BUFFER_SIZE];

    let mut shift = |intype: doppler::usage::InputType, shift_hz: f64, samplerate: u32| {
        let invec = stdin.by_ref().bytes().take(BUFFER_SIZE).collect::<Result<Vec<u8>,_>>().ok().expect("doppler collect error");

        let freq_shift_fn: fn(&[u8], f64, u32, &mut[u8]) -> (usize, usize) =
            match intype {
                I16 => { dsp::shift_frequency_i16},
                F32 => { dsp::shift_frequency_f32},
        };
        let (sample_count, buflen)  = freq_shift_fn(&invec[..],
                                                   shift_hz,
                                                   samplerate,
                                                   &mut outbuf);

        stdout.write(&outbuf[0 .. buflen]).map_err(|e|{println_stderr!("doppler stdout.write error: {:?}", e)}).unwrap();
        stdout.flush().map_err(|e|{println_stderr!("doppler stdout.flush error: {:?}", e)}).unwrap();
        (invec.len() != BUFFER_SIZE, sample_count)
    };

    match *args.mode.as_ref().unwrap() {
        ConstMode => {
            println_stderr!("constant shift mode");
            println_stderr!("\tIQ samplerate   : {}", args.samplerate.as_ref().unwrap());
            println_stderr!("\tIQ input type   : {}", args.inputtype.as_ref().unwrap());
            println_stderr!("\tIQ output type  : i16\n");
            println_stderr!("\tfrequency shift : {} Hz", args.constargs.shift.as_ref().unwrap());

            let intype = args.inputtype.unwrap();
            let shift_hz = args.constargs.shift.unwrap() as f64;
            let samplerate = args.samplerate.unwrap();

            loop {
                let stop_and_count: (bool, usize) = shift(intype, shift_hz, samplerate);
                if stop_and_count.0 {
                    break;
                }
            }
        }

        TrackMode => {
            println_stderr!("tracking mode");
            println_stderr!("\tIQ samplerate   : {}", args.samplerate.as_ref().unwrap());
            println_stderr!("\tIQ input type   : {}", args.inputtype.as_ref().unwrap());
            println_stderr!("\tIQ output type  : i16\n");
            println_stderr!("\tTLE file        : {}", args.trackargs.tlefile.as_ref().unwrap());
            println_stderr!("\tTLE name        : {}", args.trackargs.tlename.as_ref().unwrap());
            println_stderr!("\tlocation        : {:?}", args.trackargs.location.as_ref().unwrap());
            if args.trackargs.time.is_some() {
                println_stderr!("\ttime            : {:.3}", args.trackargs.time.unwrap().to_utc().rfc3339());
            }
            println_stderr!("\tfrequency       : {} Hz", args.trackargs.frequency.as_ref().unwrap());
            println_stderr!("\toffset          : {} Hz\n\n\n", args.trackargs.offset.unwrap_or(0));

            let l = args.trackargs.location.unwrap();
            let location: predict::Location = predict::Location{lat_deg: l.lat, lon_deg: l.lon, alt_m: l.alt};
            let tlename = args.trackargs.tlename.as_ref().unwrap();
            let tlefile = args.trackargs.tlefile.as_ref().unwrap();

            let tle = match tle::create_tle_from_file(&tlename, &tlefile) {
                Ok(t) => {t},
                Err(e) => {
                    println_stderr!("{}", e);
                    exit(1);
                }
            };

            let mut predict: predict::Predict = predict::Predict::new(tle, location);
            let intype = args.inputtype.unwrap();

            let samplerate = args.samplerate.unwrap();
            let mut last_time: time::Tm = time::now_utc();

            match args.trackargs.time {
                Some(start_time) => {
                    let mut sample_count = 0;
                    let mut dt = time::Duration::seconds(0);
                    last_time = start_time;

                    loop {
                        predict.update(Some(start_time + dt));
                        let doppler_hz = (predict.sat.range_rate_km_sec * 1000 as f64 / SPEED_OF_LIGHT_M_S as f64) * args.trackargs.frequency.unwrap() as f64 * (-1.0);

                        // advance time based on how many samples are read in
                        dt = time::Duration::seconds((sample_count as f32 / samplerate as f32) as i64);
                        if start_time + dt - last_time >= time::Duration::seconds(5) {
                            last_time = start_time + dt;
                            println_stderr!("time                : {:}", (start_time + dt).to_utc().rfc3339());
                            println_stderr!("az                  : {:.2}°", predict.sat.az_deg);
                            println_stderr!("el                  : {:.2}°", predict.sat.el_deg);
                            println_stderr!("range               : {:.0} km", predict.sat.range_km);
                            println_stderr!("range rate          : {:.3} km/sec", predict.sat.range_rate_km_sec);
                            println_stderr!("doppler@{:.3} MHz : {:.2} Hz\n", args.trackargs.frequency.unwrap() as f64 / 1000_000_f64, doppler_hz);
                        }

                        let (stop, count): (bool, usize) = shift(intype, doppler_hz, samplerate);
                        if stop {
                            break;
                        }

                        sample_count += count;
                    }
                }

                None => {
                    loop {
                        predict.update(None);
                        let doppler_hz = (predict.sat.range_rate_km_sec * 1000 as f64 / SPEED_OF_LIGHT_M_S as f64) * args.trackargs.frequency.unwrap() as f64 * (-1.0);

                        if time::now_utc() - last_time >= time::Duration::seconds(1) {
                            last_time = time::now_utc();
                            println_stderr!("time                : {:}", time::now_utc().to_utc().rfc3339());
                            println_stderr!("az                  : {:.2}°", predict.sat.az_deg);
                            println_stderr!("el                  : {:.2}°", predict.sat.el_deg);
                            println_stderr!("range               : {:.0} km", predict.sat.range_km);
                            println_stderr!("range rate          : {:.3} km/sec", predict.sat.range_rate_km_sec);
                            println_stderr!("doppler@{:.3} MHz : {:.2} Hz\n", args.trackargs.frequency.unwrap() as f64 / 1000_000_f64, doppler_hz);
                        }

                        let (stop, _): (bool, usize) = shift(intype, doppler_hz, samplerate);
                        if stop {
                            break;
                        }
                    }
                }
            };
        }
    }
}
<|endoftext|>


<commit_before>extern crate byteorder;

use std::io::Cursor;
use byteorder::{ReadBytesExt, WriteBytesExt, BigEndian};
use std::io::prelude::*;
use std::net::TcpStream;

#[derive(Copy, Clone, Debug)]
struct RocketErr {
}

enum RocketState {
    NewCommand,
    IncompleteCommand(usize),
    CompleteCommand,
}

struct Rocket {
    stream: TcpStream,
    state: RocketState,
    cmd: Vec<u8>,
}

impl Rocket {
    pub fn new() -> Result<Rocket, RocketErr> {
        Rocket::connect("localhost", 1338)
    }

    pub fn connect(host: &str, port: u16) -> Result<Rocket, RocketErr> {
        let stream = TcpStream::connect((host, port)).expect("Failed to connect");

        let mut rocket = Rocket {
            stream: stream,
            state: RocketState::NewCommand,
            cmd: vec![],
        };

        rocket.handshake().expect("Failed to handshake");

        rocket.stream.set_nonblocking(true).unwrap();

        Ok(rocket)
    }

    pub fn get_track(&mut self, track: &str) {
        let mut buf = vec![2];
        buf.write_u32::<BigEndian>(track.len() as u32).unwrap();
        buf.extend_from_slice(&track.as_bytes());
        self.stream.write(&buf).unwrap();
    }

    pub fn set_row(&mut self, row: u32) {
        let mut buf = vec![3];
        buf.write_u32::<BigEndian>(row).unwrap();
        self.stream.write(&buf).unwrap();
    }

    pub fn poll_events(&mut self) {
        match self.state {
            RocketState::NewCommand => {
                let mut buf = [0;1];
                if let Ok(_) = self.stream.read_exact(&mut buf) {
                    self.cmd.extend_from_slice(&buf);
                    match self.cmd[0] {
                        0 => self.state = RocketState::IncompleteCommand(4+4+4+1), //SET_KEY
                        1 => self.state = RocketState::IncompleteCommand(4+4), //DELETE_KEY
                        3 => self.state = RocketState::IncompleteCommand(4), //SET_ROW
                        4 => self.state = RocketState::IncompleteCommand(1), //PAUSE
                        5 => self.state = RocketState::CompleteCommand, //SAVE_TRACKS
                        _ => self.state = RocketState::CompleteCommand,
                    }
                }
            },
            RocketState::IncompleteCommand(bytes) => {
                let mut buf = vec![0;bytes];
                if let Ok(bytes_read) = self.stream.read(&mut buf) {
                    self.cmd.extend_from_slice(&buf);
                    if bytes-bytes_read > 0 {
                        self.state = RocketState::IncompleteCommand(bytes-bytes_read);
                    } else {
                        self.state = RocketState::CompleteCommand;
                    }
                }
            },
            RocketState::CompleteCommand => {
                {
                    let mut cursor = Cursor::new(&self.cmd);
                    let cmd = cursor.read_u8().unwrap();
                    match cmd {
                        0 => {
                            let track = cursor.read_u32::<BigEndian>().unwrap();
                            let row = cursor.read_u32::<BigEndian>().unwrap();
                            let value = cursor.read_f32::<BigEndian>().unwrap();
                            let interpolation = cursor.read_u8().unwrap();
                                // 0 == step
                                // 1 == linear
                                // 2 == smooth
                                // 3 == ramp
                            println!("SET_KEY (track: {:?}) (row: {:?}) (value: {:?}) (interpolation: {:?})", track, row, value, interpolation);
                        },
                        1 => {
                            let track = cursor.read_u32::<BigEndian>().unwrap();
                            let row = cursor.read_u32::<BigEndian>().unwrap();
                            println!("DELETE_KEY (track: {:?}) (row: {:?})", track, row);
                        },
                        3 => {
                            let row = cursor.read_u32::<BigEndian>().unwrap();
                            println!("SET_ROW (row: {:?})", row);
                        },
                        4 => {
                            let flag = cursor.read_u8().unwrap();
                                // 0 or 1
                            println!("PAUSE {:?}", flag);
                        },
                        5 => {
                            println!("SAVE_TRACKS");
                        },
                        _ => println!("Unknown {:?}", cmd),
                    }
                }

                self.cmd.clear();
                self.state = RocketState::NewCommand;
            },
        }
    }

    fn handshake(&mut self) -> Result<(), RocketErr> {
        let client_greeting = "hello, synctracker!";
        let server_greeting = "hello, demo!";

        self.stream.write(client_greeting.as_bytes()).expect("Failed to write client greeting");
        let mut buf = [0;12];
        self.stream.read_exact(&mut buf).expect("Failed to read server greeting");
        let read_greeting = std::str::from_utf8(&buf).expect("Failed to convert buf to utf8");
        if read_greeting == server_greeting {
            Ok(())
        } else {
            Err(RocketErr{})
        }
    }
}

fn main() {
    let mut rocket = Rocket::new().unwrap();
    rocket.get_track("test");
    rocket.get_track("test2");
    rocket.get_track("a:test2");
    rocket.set_row(5);

    loop {
        rocket.poll_events();
        std::thread::sleep_ms(1);
    }
}
<commit_msg>Basics for Tracks/Keys<commit_after>extern crate byteorder;

use std::io::Cursor;
use byteorder::{ReadBytesExt, WriteBytesExt, BigEndian};
use std::io::prelude::*;
use std::net::TcpStream;

#[derive(Debug)]
enum Interpolation {
    Step   = 0,
    Linear = 1,
    Smooth = 2,
    Ramp   = 3,
}

impl From<u8> for Interpolation {
    fn from(raw: u8) -> Interpolation {
        match raw {
            0 => Interpolation::Step,
            1 => Interpolation::Linear,
            2 => Interpolation::Smooth,
            3 => Interpolation::Ramp,
            _ => Interpolation::Step,
        }
    }
}

#[derive(Debug)]
struct Key {
    row: u32,
    value: f32,
    interpolation: Interpolation,
}

#[derive(Debug)]
struct Track {
    name: String,
    keys: Vec<Key>,
}

impl Track {
    fn new<S: Into<String>>(name: S) -> Track {
        Track {
            name: name.into(),
            keys: Vec::new(),
        }
    }

    //TODO set_key(&mut self, key: Key)
    //TODO delete_key(&mut self, row: u32)
    //TODO get_value(row: f32) -> f32
    //  This should work with half-rows
}

#[derive(Copy, Clone, Debug)]
struct RocketErr {
}

enum RocketState {
    NewCommand,
    IncompleteCommand(usize),
    CompleteCommand,
}

struct Rocket {
    stream: TcpStream,
    state: RocketState,
    cmd: Vec<u8>,
    tracks: Vec<Track>,
    row: u32,
    paused: bool,
}

impl Rocket {
    pub fn new() -> Result<Rocket, RocketErr> {
        Rocket::connect("localhost", 1338)
    }

    pub fn connect(host: &str, port: u16) -> Result<Rocket, RocketErr> {
        let stream = TcpStream::connect((host, port)).expect("Failed to connect");

        let mut rocket = Rocket {
            stream: stream,
            state: RocketState::NewCommand,
            cmd: Vec::new(),
            tracks: Vec::new(),
            row: 0,
            paused: true,
        };

        rocket.handshake().expect("Failed to handshake");

        rocket.stream.set_nonblocking(true).unwrap();

        Ok(rocket)
    }

    pub fn get_row(&self) -> u32 {
        self.row
    }

    pub fn is_paused(&self) -> bool {
        self.paused
    }

    pub fn get_track(&mut self, name: &str) -> &Track {
        if !self.tracks.iter().any(|t| t.name == name) {

            // Send GET_TRACK message
            let mut buf = vec![2];
            buf.write_u32::<BigEndian>(name.len() as u32).unwrap();
            buf.extend_from_slice(&name.as_bytes());
            self.stream.write(&buf).unwrap();

            self.tracks.push(Track::new(name));
        }
        self.tracks.iter().find(|t| t.name == name).unwrap()
    }

    pub fn set_row(&mut self, row: u32) {
        self.row = row;

        // Send SET_ROW message
        let mut buf = vec![3];
        buf.write_u32::<BigEndian>(row).unwrap();
        self.stream.write(&buf).unwrap();
    }

    pub fn poll_events(&mut self) {
        match self.state {
            RocketState::NewCommand => {
                let mut buf = [0;1];
                if let Ok(_) = self.stream.read_exact(&mut buf) {
                    self.cmd.extend_from_slice(&buf);
                    match self.cmd[0] {
                        0 => self.state = RocketState::IncompleteCommand(4+4+4+1), //SET_KEY
                        1 => self.state = RocketState::IncompleteCommand(4+4), //DELETE_KEY
                        3 => self.state = RocketState::IncompleteCommand(4), //SET_ROW
                        4 => self.state = RocketState::IncompleteCommand(1), //PAUSE
                        5 => self.state = RocketState::CompleteCommand, //SAVE_TRACKS
                        _ => self.state = RocketState::CompleteCommand,
                    }
                }
            },
            RocketState::IncompleteCommand(bytes) => {
                let mut buf = vec![0;bytes];
                if let Ok(bytes_read) = self.stream.read(&mut buf) {
                    self.cmd.extend_from_slice(&buf);
                    if bytes-bytes_read > 0 {
                        self.state = RocketState::IncompleteCommand(bytes-bytes_read);
                    } else {
                        self.state = RocketState::CompleteCommand;
                    }
                }
            },
            RocketState::CompleteCommand => {
                {
                    let mut cursor = Cursor::new(&self.cmd);
                    let cmd = cursor.read_u8().unwrap();
                    match cmd {
                        0 => {
                            let track = cursor.read_u32::<BigEndian>().unwrap();
                            let row = cursor.read_u32::<BigEndian>().unwrap();
                            let value = cursor.read_f32::<BigEndian>().unwrap();
                            //let interpolation = cursor.read_u8().unwrap();
                                // 0 == step
                                // 1 == linear
                                // 2 == smooth
                                // 3 == ramp
                            let interpolation = Interpolation::from(cursor.read_u8().unwrap());
                            let key = Key {
                                row: row,
                                value: value,
                                interpolation: interpolation,
                            };
                            println!("SET_KEY (track: {:?}) (key: {:?})", track, key);
                        },
                        1 => {
                            let track = cursor.read_u32::<BigEndian>().unwrap();
                            let row = cursor.read_u32::<BigEndian>().unwrap();
                            println!("DELETE_KEY (track: {:?}) (row: {:?})", track, row);
                        },
                        3 => {
                            let row = cursor.read_u32::<BigEndian>().unwrap();
                            println!("SET_ROW (row: {:?})", row);

                            self.row = row;
                        },
                        4 => {
                            let flag = cursor.read_u8().unwrap();
                                // 0 or 1
                            println!("PAUSE {:?}", flag);

                            self.paused = flag == 1;
                        },
                        5 => {
                            println!("SAVE_TRACKS");
                        },
                        _ => println!("Unknown {:?}", cmd),
                    }
                }

                self.cmd.clear();
                self.state = RocketState::NewCommand;
            },
        }
    }

    fn handshake(&mut self) -> Result<(), RocketErr> {
        let client_greeting = "hello, synctracker!";
        let server_greeting = "hello, demo!";

        self.stream.write(client_greeting.as_bytes()).expect("Failed to write client greeting");
        let mut buf = [0;12];
        self.stream.read_exact(&mut buf).expect("Failed to read server greeting");
        let read_greeting = std::str::from_utf8(&buf).expect("Failed to convert buf to utf8");
        if read_greeting == server_greeting {
            Ok(())
        } else {
            Err(RocketErr{})
        }
    }
}

fn main() {
    let mut rocket = Rocket::new().unwrap();
    rocket.get_track("test");
    rocket.get_track("test2");
    rocket.get_track("a:test2");
    rocket.set_row(5);

    loop {
        rocket.poll_events();
        std::thread::sleep_ms(1);
    }
}
<|endoftext|>