<commit_before>// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! Command-line interface of the rustbuild build system.
//!
//! This module implements the command-line parsing of the build system which
//! has various flags to configure how it's run.

use std::env;
use std::fs;
use std::path::PathBuf;
use std::process;

use getopts::{Matches, Options};

use Build;
use config::Config;
use metadata;
use step;

/// Deserialized version of all flags for this compile.
pub struct Flags {
    pub verbose: usize, // verbosity level: 0 == not verbose, 1 == verbose, 2 == very verbose
    pub on_fail: Option<String>,
    pub stage: Option<u32>,
    pub keep_stage: Option<u32>,
    pub build: String,
    pub host: Vec<String>,
    pub target: Vec<String>,
    pub config: Option<PathBuf>,
    pub src: Option<PathBuf>,
    pub jobs: Option<u32>,
    pub cmd: Subcommand,
    pub incremental: bool,
}

impl Flags {
    pub fn verbose(&self) -> bool {
        self.verbose > 0
    }

    pub fn very_verbose(&self) -> bool {
        self.verbose > 1
    }
}

pub enum Subcommand {
    Build {
        paths: Vec<PathBuf>,
    },
    Doc {
        paths: Vec<PathBuf>,
    },
    Test {
        paths: Vec<PathBuf>,
        test_args: Vec<String>,
    },
    Bench {
        paths: Vec<PathBuf>,
        test_args: Vec<String>,
    },
    Clean,
    Dist {
        paths: Vec<PathBuf>,
        install: bool,
    },
}

impl Flags {
    pub fn parse(args: &[String]) -> Flags {
        let mut opts = Options::new();
        opts.optflagmulti("v", "verbose", "use verbose output (-vv for very verbose)");
        opts.optflag("i", "incremental", "use incremental compilation");
        opts.optopt("", "config", "TOML configuration file for build", "FILE");
        opts.optopt("", "build", "build target of the stage0 compiler", "BUILD");
        opts.optmulti("", "host", "host targets to build", "HOST");
        opts.optmulti("", "target", "target targets to build", "TARGET");
        opts.optopt("", "on-fail", "command to run on failure", "CMD");
        opts.optopt("", "stage", "stage to build", "N");
        opts.optopt("", "keep-stage", "stage to keep without recompiling", "N");
        opts.optopt("", "src", "path to the root of the rust checkout", "DIR");
        opts.optopt("j", "jobs", "number of jobs to run in parallel", "JOBS");
        opts.optflag("h", "help", "print this help message");

        let usage = |n, opts: &Options| -> ! {
            let subcommand = args.get(0).map(|s| &**s);
            let brief = format!("Usage: x.py <subcommand> [options] [<args>...]");

            println!("{}", opts.usage(&brief));
            match subcommand {
                Some("build") => {
                    println!("\
Arguments:
    This subcommand accepts a number of positional arguments of directories to
    the crates and/or artifacts to compile. For example:

        ./x.py build src/libcore
        ./x.py build src/libproc_macro
        ./x.py build src/libstd --stage 1

    If no arguments are passed then the complete artifacts for that stage are
    also compiled.

        ./x.py build
        ./x.py build --stage 1

    For a quick build with a usable compile, you can pass:

        ./x.py build --stage 1 src/libtest
");
                }

                Some("test") => {
                    println!("\
Arguments:
    This subcommand accepts a number of positional arguments of directories to
    tests that should be compiled and run. For example:

        ./x.py test src/test/run-pass
        ./x.py test src/libstd --test-args hash_map
        ./x.py test src/libstd --stage 0

    If no arguments are passed then the complete artifacts for that stage are
    compiled and tested.

        ./x.py test
        ./x.py test --stage 1
");
                }

                Some("doc") => {
                    println!("\
Arguments:
    This subcommand accepts a number of positional arguments of directories of
    documentation to build. For example:

        ./x.py doc src/doc/book
        ./x.py doc src/doc/nomicon
        ./x.py doc src/libstd

    If no arguments are passed then everything is documented:

        ./x.py doc
        ./x.py doc --stage 1
");
                }

                _ => {}
            }

            if let Some(subcommand) = subcommand {
                if subcommand == "build" ||
                   subcommand == "dist" ||
                   subcommand == "doc" ||
                   subcommand == "test" ||
                   subcommand == "bench" ||
                   subcommand == "clean"  {
                    println!("Available invocations:");
                    if args.iter().any(|a| a == "-v") {
                        let flags = Flags::parse(&["build".to_string()]);
                        let mut config = Config::default();
                        config.build = flags.build.clone();
                        let mut build = Build::new(flags, config);
                        metadata::build(&mut build);
                        step::build_rules(&build).print_help(subcommand);
                    } else {
                        println!("    ... elided, run `./x.py {} -h -v` to see",
                                 subcommand);
                    }

                    println!("");
                }
            }

println!("\
Subcommands:
    build       Compile either the compiler or libraries
    test        Build and run some test suites
    bench       Build and run some benchmarks
    doc         Build documentation
    clean       Clean out build directories
    dist        Build and/or install distribution artifacts

To learn more about a subcommand, run `./x.py <subcommand> -h`
");

            process::exit(n);
        };
        if args.len() == 0 {
            println!("a subcommand must be passed");
            usage(1, &opts);
        }
        let parse = |opts: &Options| {
            let m = opts.parse(&args[1..]).unwrap_or_else(|e| {
                println!("failed to parse options: {}", e);
                usage(1, opts);
            });
            if m.opt_present("h") {
                usage(0, opts);
            }
            return m
        };

        let cwd = t!(env::current_dir());
        let remaining_as_path = |m: &Matches| {
            m.free.iter().map(|p| cwd.join(p)).collect::<Vec<_>>()
        };

        let m: Matches;
        let cmd = match &args[0][..] {
            "build" => {
                m = parse(&opts);
                Subcommand::Build { paths: remaining_as_path(&m) }
            }
            "doc" => {
                m = parse(&opts);
                Subcommand::Doc { paths: remaining_as_path(&m) }
            }
            "test" => {
                opts.optmulti("", "test-args", "extra arguments", "ARGS");
                m = parse(&opts);
                Subcommand::Test {
                    paths: remaining_as_path(&m),
                    test_args: m.opt_strs("test-args"),
                }
            }
            "bench" => {
                opts.optmulti("", "test-args", "extra arguments", "ARGS");
                m = parse(&opts);
                Subcommand::Bench {
                    paths: remaining_as_path(&m),
                    test_args: m.opt_strs("test-args"),
                }
            }
            "clean" => {
                m = parse(&opts);
                if m.free.len() > 0 {
                    println!("clean takes no arguments");
                    usage(1, &opts);
                }
                Subcommand::Clean
            }
            "dist" => {
                opts.optflag("", "install", "run installer as well");
                m = parse(&opts);
                Subcommand::Dist {
                    paths: remaining_as_path(&m),
                    install: m.opt_present("install"),
                }
            }
            "--help" => usage(0, &opts),
            cmd => {
                println!("unknown subcommand: {}", cmd);
                usage(1, &opts);
            }
        };

        let cfg_file = m.opt_str("config").map(PathBuf::from).or_else(|| {
            if fs::metadata("config.toml").is_ok() {
                Some(PathBuf::from("config.toml"))
            } else {
                None
            }
        });

        let mut stage = m.opt_str("stage").map(|j| j.parse().unwrap());

        let incremental = m.opt_present("i");

        if incremental {
            if stage.is_none() {
                stage = Some(1);
            }
        }

        Flags {
            verbose: m.opt_count("v"),
            stage: stage,
            on_fail: m.opt_str("on-fail"),
            keep_stage: m.opt_str("keep-stage").map(|j| j.parse().unwrap()),
            build: m.opt_str("build").unwrap_or_else(|| {
                env::var("BUILD").unwrap()
            }),
            host: split(m.opt_strs("host")),
            target: split(m.opt_strs("target")),
            config: cfg_file,
            src: m.opt_str("src").map(PathBuf::from),
            jobs: m.opt_str("jobs").map(|j| j.parse().unwrap()),
            cmd: cmd,
            incremental: incremental,
        }
    }
}

impl Subcommand {
    pub fn test_args(&self) -> Vec<&str> {
        match *self {
            Subcommand::Test { ref test_args, .. } |
            Subcommand::Bench { ref test_args, .. } => {
                test_args.iter().flat_map(|s| s.split_whitespace()).collect()
            }
            _ => Vec::new(),
        }
    }
}

fn split(s: Vec<String>) -> Vec<String> {
    s.iter().flat_map(|s| s.split(',')).map(|s| s.to_string()).collect()
}
<commit_msg>When dealing with the list of all possible subcommands, deal with them in the same order to ease comparing the sections of code in order.  I chose the order that appears in the help text, because that is most likely to have been ordered with specific reasoning.<commit_after>// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! Command-line interface of the rustbuild build system.
//!
//! This module implements the command-line parsing of the build system which
//! has various flags to configure how it's run.

use std::env;
use std::fs;
use std::path::PathBuf;
use std::process;

use getopts::{Matches, Options};

use Build;
use config::Config;
use metadata;
use step;

/// Deserialized version of all flags for this compile.
pub struct Flags {
    pub verbose: usize, // verbosity level: 0 == not verbose, 1 == verbose, 2 == very verbose
    pub on_fail: Option<String>,
    pub stage: Option<u32>,
    pub keep_stage: Option<u32>,
    pub build: String,
    pub host: Vec<String>,
    pub target: Vec<String>,
    pub config: Option<PathBuf>,
    pub src: Option<PathBuf>,
    pub jobs: Option<u32>,
    pub cmd: Subcommand,
    pub incremental: bool,
}

impl Flags {
    pub fn verbose(&self) -> bool {
        self.verbose > 0
    }

    pub fn very_verbose(&self) -> bool {
        self.verbose > 1
    }
}

pub enum Subcommand {
    Build {
        paths: Vec<PathBuf>,
    },
    Doc {
        paths: Vec<PathBuf>,
    },
    Test {
        paths: Vec<PathBuf>,
        test_args: Vec<String>,
    },
    Bench {
        paths: Vec<PathBuf>,
        test_args: Vec<String>,
    },
    Clean,
    Dist {
        paths: Vec<PathBuf>,
        install: bool,
    },
}

impl Flags {
    pub fn parse(args: &[String]) -> Flags {
        let mut opts = Options::new();
        opts.optflagmulti("v", "verbose", "use verbose output (-vv for very verbose)");
        opts.optflag("i", "incremental", "use incremental compilation");
        opts.optopt("", "config", "TOML configuration file for build", "FILE");
        opts.optopt("", "build", "build target of the stage0 compiler", "BUILD");
        opts.optmulti("", "host", "host targets to build", "HOST");
        opts.optmulti("", "target", "target targets to build", "TARGET");
        opts.optopt("", "on-fail", "command to run on failure", "CMD");
        opts.optopt("", "stage", "stage to build", "N");
        opts.optopt("", "keep-stage", "stage to keep without recompiling", "N");
        opts.optopt("", "src", "path to the root of the rust checkout", "DIR");
        opts.optopt("j", "jobs", "number of jobs to run in parallel", "JOBS");
        opts.optflag("h", "help", "print this help message");

        let usage = |n, opts: &Options| -> ! {
            let subcommand = args.get(0).map(|s| &**s);
            let brief = format!("Usage: x.py <subcommand> [options] [<args>...]");

            println!("{}", opts.usage(&brief));
            match subcommand {
                Some("build") => {
                    println!("\
Arguments:
    This subcommand accepts a number of positional arguments of directories to
    the crates and/or artifacts to compile. For example:

        ./x.py build src/libcore
        ./x.py build src/libproc_macro
        ./x.py build src/libstd --stage 1

    If no arguments are passed then the complete artifacts for that stage are
    also compiled.

        ./x.py build
        ./x.py build --stage 1

    For a quick build with a usable compile, you can pass:

        ./x.py build --stage 1 src/libtest
");
                }

                Some("test") => {
                    println!("\
Arguments:
    This subcommand accepts a number of positional arguments of directories to
    tests that should be compiled and run. For example:

        ./x.py test src/test/run-pass
        ./x.py test src/libstd --test-args hash_map
        ./x.py test src/libstd --stage 0

    If no arguments are passed then the complete artifacts for that stage are
    compiled and tested.

        ./x.py test
        ./x.py test --stage 1
");
                }

                Some("doc") => {
                    println!("\
Arguments:
    This subcommand accepts a number of positional arguments of directories of
    documentation to build. For example:

        ./x.py doc src/doc/book
        ./x.py doc src/doc/nomicon
        ./x.py doc src/libstd

    If no arguments are passed then everything is documented:

        ./x.py doc
        ./x.py doc --stage 1
");
                }

                _ => {}
            }

            if let Some(subcommand) = subcommand {
                if subcommand == "build" ||
                   subcommand == "test" ||
                   subcommand == "bench" ||
                   subcommand == "doc" ||
                   subcommand == "clean" ||
                   subcommand == "dist"  {
                    println!("Available invocations:");
                    if args.iter().any(|a| a == "-v") {
                        let flags = Flags::parse(&["build".to_string()]);
                        let mut config = Config::default();
                        config.build = flags.build.clone();
                        let mut build = Build::new(flags, config);
                        metadata::build(&mut build);
                        step::build_rules(&build).print_help(subcommand);
                    } else {
                        println!("    ... elided, run `./x.py {} -h -v` to see",
                                 subcommand);
                    }

                    println!("");
                }
            }

println!("\
Subcommands:
    build       Compile either the compiler or libraries
    test        Build and run some test suites
    bench       Build and run some benchmarks
    doc         Build documentation
    clean       Clean out build directories
    dist        Build and/or install distribution artifacts

To learn more about a subcommand, run `./x.py <subcommand> -h`
");

            process::exit(n);
        };
        if args.len() == 0 {
            println!("a subcommand must be passed");
            usage(1, &opts);
        }
        let parse = |opts: &Options| {
            let m = opts.parse(&args[1..]).unwrap_or_else(|e| {
                println!("failed to parse options: {}", e);
                usage(1, opts);
            });
            if m.opt_present("h") {
                usage(0, opts);
            }
            return m
        };

        let cwd = t!(env::current_dir());
        let remaining_as_path = |m: &Matches| {
            m.free.iter().map(|p| cwd.join(p)).collect::<Vec<_>>()
        };

        let m: Matches;
        let cmd = match &args[0][..] {
            "build" => {
                m = parse(&opts);
                Subcommand::Build { paths: remaining_as_path(&m) }
            }
            "test" => {
                opts.optmulti("", "test-args", "extra arguments", "ARGS");
                m = parse(&opts);
                Subcommand::Test {
                    paths: remaining_as_path(&m),
                    test_args: m.opt_strs("test-args"),
                }
            }
            "bench" => {
                opts.optmulti("", "test-args", "extra arguments", "ARGS");
                m = parse(&opts);
                Subcommand::Bench {
                    paths: remaining_as_path(&m),
                    test_args: m.opt_strs("test-args"),
                }
            }
            "doc" => {
                m = parse(&opts);
                Subcommand::Doc { paths: remaining_as_path(&m) }
            }
            "clean" => {
                m = parse(&opts);
                if m.free.len() > 0 {
                    println!("clean takes no arguments");
                    usage(1, &opts);
                }
                Subcommand::Clean
            }
            "dist" => {
                opts.optflag("", "install", "run installer as well");
                m = parse(&opts);
                Subcommand::Dist {
                    paths: remaining_as_path(&m),
                    install: m.opt_present("install"),
                }
            }
            "--help" => usage(0, &opts),
            cmd => {
                println!("unknown subcommand: {}", cmd);
                usage(1, &opts);
            }
        };

        let cfg_file = m.opt_str("config").map(PathBuf::from).or_else(|| {
            if fs::metadata("config.toml").is_ok() {
                Some(PathBuf::from("config.toml"))
            } else {
                None
            }
        });

        let mut stage = m.opt_str("stage").map(|j| j.parse().unwrap());

        let incremental = m.opt_present("i");

        if incremental {
            if stage.is_none() {
                stage = Some(1);
            }
        }

        Flags {
            verbose: m.opt_count("v"),
            stage: stage,
            on_fail: m.opt_str("on-fail"),
            keep_stage: m.opt_str("keep-stage").map(|j| j.parse().unwrap()),
            build: m.opt_str("build").unwrap_or_else(|| {
                env::var("BUILD").unwrap()
            }),
            host: split(m.opt_strs("host")),
            target: split(m.opt_strs("target")),
            config: cfg_file,
            src: m.opt_str("src").map(PathBuf::from),
            jobs: m.opt_str("jobs").map(|j| j.parse().unwrap()),
            cmd: cmd,
            incremental: incremental,
        }
    }
}

impl Subcommand {
    pub fn test_args(&self) -> Vec<&str> {
        match *self {
            Subcommand::Test { ref test_args, .. } |
            Subcommand::Bench { ref test_args, .. } => {
                test_args.iter().flat_map(|s| s.split_whitespace()).collect()
            }
            _ => Vec::new(),
        }
    }
}

fn split(s: Vec<String>) -> Vec<String> {
    s.iter().flat_map(|s| s.split(',')).map(|s| s.to_string()).collect()
}
<|endoftext|>


<commit_before>use std::ops::{Mul, Add, Div, Sub, Index};
use math::linalg::vector::Vector;
use math::utils;

struct Matrix {
	cols: usize,
	rows: usize,
	data: Vec<f32>
}

impl Matrix {
    fn new(cols: usize, rows: usize, data: Vec<f32>) -> Matrix {
        Matrix {
            cols: cols,
            rows: rows,
            data: data
        }
    }

    fn zeros(cols: usize, rows: usize) -> Matrix {
    	Matrix {
            cols: cols,
            rows: rows,
            data: vec![0.0; cols*rows]
        }
    }

    fn identity(size: usize) -> Matrix {
    	let mut data = vec![0.0; size * size];

    	for i in 0..size
    	{
    		data[(i*(size+1)) as usize] = 1.0;
    	}

    	Matrix {
            cols: size,
            rows: size,
            data: data
        }
    }

    fn from_diag(diag: &Vec<f32>) -> Matrix {
    	let size = diag.len();
    	let mut data = vec![0.0; size * size];

    	for i in 0..size
    	{
    		data[(i*(size+1)) as usize] = diag[i];
    	}

    	Matrix {
            cols: size,
            rows: size,
            data: data
        }
    }

    fn transpose(&self) -> Matrix {
        let mut new_data = vec![0.0; self.cols * self.rows];
        for i in 0..self.cols
        {
            for j in 0..self.rows
            {
                new_data[j*self.cols+i] = self.data[i*self.rows + j];
            }
        }

        Matrix {
            cols: self.rows,
            rows: self.cols,
            data: new_data
        }
    }
}

impl Mul<f32> for Matrix {
    type Output = Matrix;

    fn mul(self, f: f32) -> Matrix {
        let new_data = self.data.into_iter().map(|v| v * f).collect();

        Matrix {
            cols: self.cols,
            rows: self.rows,
            data: new_data
        }
    }
}

impl Mul<Matrix> for Matrix {
	type Output = Matrix;

	fn mul(self, m: Matrix) -> Matrix {
		// Will use Strassen algorithm if large, traditional otherwise
		self
	}
}

impl Mul<Vector> for Matrix {
    type Output = Vector;

    fn mul(self, v: Vector) -> Vector {
        assert!(v.size == self.cols);

        let mut new_data = vec![0.0; v.size];

        for i in 0..v.size
        {
            new_data[i] = utils::dot(&self.data[i*self.cols..(i+1)*self.cols], &v.data);
        }

        return Vector {
            size: v.size,
            data: new_data
        }
    }
}

impl Add<f32> for Matrix {
	type Output = Matrix;

	fn add(self, f: f32) -> Matrix {
		let new_data = self.data.into_iter().map(|v| v + f).collect();

        Matrix {
            cols: self.cols,
            rows: self.rows,
            data: new_data
        }
    }
}

impl Sub<f32> for Matrix {
	type Output = Matrix;

	fn sub(self, f: f32) -> Matrix {
		let new_data = self.data.into_iter().map(|v| v - f).collect();

        Matrix {
            cols: self.cols,
            rows: self.rows,
            data: new_data
        }
    }
}

impl Add<Matrix> for Matrix {
	type Output = Matrix;

	fn add(self, m: Matrix) -> Matrix {
		assert!(self.cols == m.cols);
		assert!(self.rows == m.rows);

		let new_data = self.data.into_iter().enumerate().map(|(i,v)| v + m.data[i]).collect();

        Matrix {
            cols: self.cols,
            rows: self.rows,
            data: new_data
        }
	}
}

impl Sub<Matrix> for Matrix {
	type Output = Matrix;

	fn sub(self, m: Matrix) -> Matrix {
		assert!(self.cols == m.cols);
		assert!(self.rows == m.rows);

		let new_data = self.data.into_iter().enumerate().map(|(i,v)| v - m.data[i]).collect();

        Matrix {
            cols: self.cols,
            rows: self.rows,
            data: new_data
        }
	}
}

impl Div<f32> for Matrix {
	type Output = Matrix;

	fn div(self, f: f32) -> Matrix {
		assert!(f != 0.0);

		let new_data = self.data.into_iter().map(|v| v / f).collect();

        Matrix {
            cols: self.cols,
            rows: self.rows,
            data: new_data
        }
	}
}

impl Index<[usize; 2]> for Matrix {
	type Output = f32;

	fn index(&self, idx : [usize; 2]) -> &f32 {
		assert!(idx[0] < self.cols);
		assert!(idx[1] < self.rows);

		&self.data[idx[0] * self.cols + idx[1]]
	}
}<commit_msg>Implementing vectorized matrix * vector.<commit_after>use std::ops::{Mul, Add, Div, Sub, Index};
use math::linalg::vector::Vector;
use math::utils;

struct Matrix {
	cols: usize,
	rows: usize,
	data: Vec<f32>
}

impl Matrix {
    fn new(cols: usize, rows: usize, data: Vec<f32>) -> Matrix {
        Matrix {
            cols: cols,
            rows: rows,
            data: data
        }
    }

    fn zeros(cols: usize, rows: usize) -> Matrix {
    	Matrix {
            cols: cols,
            rows: rows,
            data: vec![0.0; cols*rows]
        }
    }

    fn identity(size: usize) -> Matrix {
    	let mut data = vec![0.0; size * size];

    	for i in 0..size
    	{
    		data[(i*(size+1)) as usize] = 1.0;
    	}

    	Matrix {
            cols: size,
            rows: size,
            data: data
        }
    }

    fn from_diag(diag: &Vec<f32>) -> Matrix {
    	let size = diag.len();
    	let mut data = vec![0.0; size * size];

    	for i in 0..size
    	{
    		data[(i*(size+1)) as usize] = diag[i];
    	}

    	Matrix {
            cols: size,
            rows: size,
            data: data
        }
    }

    fn transpose(&self) -> Matrix {
        let mut new_data = vec![0.0; self.cols * self.rows];
        for i in 0..self.cols
        {
            for j in 0..self.rows
            {
                new_data[j*self.cols+i] = self.data[i*self.rows + j];
            }
        }

        Matrix {
            cols: self.rows,
            rows: self.cols,
            data: new_data
        }
    }
}

impl Mul<f32> for Matrix {
    type Output = Matrix;

    fn mul(self, f: f32) -> Matrix {
        let new_data = self.data.into_iter().map(|v| v * f).collect();

        Matrix {
            cols: self.cols,
            rows: self.rows,
            data: new_data
        }
    }
}

impl Mul<Matrix> for Matrix {
	type Output = Matrix;

	fn mul(self, m: Matrix) -> Matrix {
		// Will use Strassen algorithm if large, traditional otherwise
		self
	}
}

impl Mul<Vector> for Matrix {
    type Output = Vector;

    fn mul(self, v: Vector) -> Vector {
        assert!(v.size == self.cols);

        let mut new_data = vec![0.0; self.rows];

        for i in 0..self.rows
        {
            new_data[i] = utils::dot(&self.data[i*self.cols..(i+1)*self.cols], &v.data);
        }

        return Vector {
            size: v.size,
            data: new_data
        }
    }
}

impl Add<f32> for Matrix {
	type Output = Matrix;

	fn add(self, f: f32) -> Matrix {
		let new_data = self.data.into_iter().map(|v| v + f).collect();

        Matrix {
            cols: self.cols,
            rows: self.rows,
            data: new_data
        }
    }
}

impl Sub<f32> for Matrix {
	type Output = Matrix;

	fn sub(self, f: f32) -> Matrix {
		let new_data = self.data.into_iter().map(|v| v - f).collect();

        Matrix {
            cols: self.cols,
            rows: self.rows,
            data: new_data
        }
    }
}

impl Add<Matrix> for Matrix {
	type Output = Matrix;

	fn add(self, m: Matrix) -> Matrix {
		assert!(self.cols == m.cols);
		assert!(self.rows == m.rows);

		let new_data = self.data.into_iter().enumerate().map(|(i,v)| v + m.data[i]).collect();

        Matrix {
            cols: self.cols,
            rows: self.rows,
            data: new_data
        }
	}
}

impl Sub<Matrix> for Matrix {
	type Output = Matrix;

	fn sub(self, m: Matrix) -> Matrix {
		assert!(self.cols == m.cols);
		assert!(self.rows == m.rows);

		let new_data = self.data.into_iter().enumerate().map(|(i,v)| v - m.data[i]).collect();

        Matrix {
            cols: self.cols,
            rows: self.rows,
            data: new_data
        }
	}
}

impl Div<f32> for Matrix {
	type Output = Matrix;

	fn div(self, f: f32) -> Matrix {
		assert!(f != 0.0);

		let new_data = self.data.into_iter().map(|v| v / f).collect();

        Matrix {
            cols: self.cols,
            rows: self.rows,
            data: new_data
        }
	}
}

impl Index<[usize; 2]> for Matrix {
	type Output = f32;

	fn index(&self, idx : [usize; 2]) -> &f32 {
		assert!(idx[0] < self.cols);
		assert!(idx[1] < self.rows);

		&self.data[idx[0] * self.cols + idx[1]]
	}
}<|endoftext|>


<commit_before>/*
 * Cymbalum, Molecular Simulation in Rust
 * Copyright (C) 2015 Guillaume Fraux
 *
 * 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/
*/

//! Saving properties of the simulation to some stream (file or stdout mainly)

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

use ::units;
use ::universe::Universe;

/// The `Output` trait define the interface for all the quantities outputed by
/// the simulation during the run. An Output can be a text or a binary data
/// file, an image, a text log, …
pub trait Output {
    /// Function called once at the beggining of the simulation, which allow
    /// for some setup of the output if needed.
    fn setup(&mut self, _: &Universe) {}

    /// Write the output from the universe.
    fn write(&mut self, universe: &Universe);

    /// Function called once at the end of the simulation.
    fn finish(&mut self, _: &Universe) {}
}

/******************************************************************************/
/// The `TrajectoryOutput` allow to write the trajectory of the system to a
/// file, using the XYZ format.
pub struct TrajectoryOutput {
    file: File,
}

impl TrajectoryOutput {
    /// Create a new `TrajectoryOutput`, using the file ate `filename` for
    /// as the trajectory file. The file is replaced if it already exists.
    pub fn new<'a, S>(filename: S) -> TrajectoryOutput where S: Into<&'a str> {
        TrajectoryOutput{
            file: File::create(filename.into()).unwrap()
        }
    }
}

impl Output for TrajectoryOutput {
    fn write(&mut self, universe: &Universe) {
        writeln!(&mut self.file, "{}", universe.size()).unwrap();
        writeln!(&mut self.file, "Generated by cymbalum \\o/").unwrap();
        for n in 0..universe.size() {
            let part = &universe[n];
            let pos = part.position();
            writeln!(&mut self.file, "{} {} {} {}", part.name(), pos.x, pos.y, pos.z).unwrap();
        }
    }
}

/******************************************************************************/
/// The `EnergyOutput` write the energy of the system to a text file, organized
/// as: `PotentialEnergy     KineticEnergy     TotalEnergy`.
pub struct EnergyOutput {
    file: File,
}

impl EnergyOutput {
    /// Create a new `TrajectoryOutput`, using the file ate `filename` for
    /// output.
    pub fn new<'a, S>(filename: S) -> EnergyOutput where S: Into<&'a str> {
        EnergyOutput{
            file: File::create(filename.into()).unwrap()
        }
    }
}

impl Output for EnergyOutput {
    fn setup(&mut self, _: &Universe) {
        writeln!(&mut self.file, "# Energy of the simulation (kJ/mol)").unwrap();
        writeln!(&mut self.file, "# Potential     Kinetic     Total").unwrap();
    }

    fn write(&mut self, universe: &Universe) {
        let potential = units::to(universe.potential_energy(), "kJ/mol").unwrap();
        let kinetic = units::to(universe.kinetic_energy(), "kJ/mol").unwrap();
        let total = units::to(universe.total_energy(), "kJ/mol").unwrap();
        writeln!(&mut self.file, "{}   {}   {}", potential, kinetic, total).unwrap();
    }
}
<commit_msg>Add tests for outputs algorithms<commit_after>/*
 * Cymbalum, Molecular Simulation in Rust
 * Copyright (C) 2015 Guillaume Fraux
 *
 * 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/
*/

//! Saving properties of the simulation to some stream (file or stdout mainly)

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

use ::units;
use ::universe::Universe;

/// The `Output` trait define the interface for all the quantities outputed by
/// the simulation during the run. An Output can be a text or a binary data
/// file, an image, a text log, …
pub trait Output {
    /// Function called once at the beggining of the simulation, which allow
    /// for some setup of the output if needed.
    fn setup(&mut self, _: &Universe) {}

    /// Write the output from the universe.
    fn write(&mut self, universe: &Universe);

    /// Function called once at the end of the simulation.
    fn finish(&mut self, _: &Universe) {}
}

/******************************************************************************/
/// The `TrajectoryOutput` allow to write the trajectory of the system to a
/// file, using the XYZ format.
pub struct TrajectoryOutput {
    file: File,
}

impl TrajectoryOutput {
    /// Create a new `TrajectoryOutput`, using the file ate `filename` for
    /// as the trajectory file. The file is replaced if it already exists.
    pub fn new<'a, S>(filename: S) -> TrajectoryOutput where S: Into<&'a str> {
        TrajectoryOutput{
            file: File::create(filename.into()).unwrap()
        }
    }
}

impl Output for TrajectoryOutput {
    fn write(&mut self, universe: &Universe) {
        writeln!(&mut self.file, "{}", universe.size()).unwrap();
        writeln!(&mut self.file, "Generated by cymbalum \\o/").unwrap();
        for n in 0..universe.size() {
            let part = &universe[n];
            let pos = part.position();
            writeln!(&mut self.file, "{} {} {} {}", part.name(), pos.x, pos.y, pos.z).unwrap();
        }
    }
}

/******************************************************************************/
/// The `EnergyOutput` write the energy of the system to a text file, organized
/// as: `PotentialEnergy     KineticEnergy     TotalEnergy`.
pub struct EnergyOutput {
    file: File,
}

impl EnergyOutput {
    /// Create a new `TrajectoryOutput`, using the file ate `filename` for
    /// output.
    pub fn new<'a, S>(filename: S) -> EnergyOutput where S: Into<&'a str> {
        EnergyOutput{
            file: File::create(filename.into()).unwrap()
        }
    }
}

impl Output for EnergyOutput {
    fn setup(&mut self, _: &Universe) {
        writeln!(&mut self.file, "# Energy of the simulation (kJ/mol)").unwrap();
        writeln!(&mut self.file, "# Potential     Kinetic     Total").unwrap();
    }

    fn write(&mut self, universe: &Universe) {
        let potential = units::to(universe.potential_energy(), "kJ/mol").unwrap();
        let kinetic = units::to(universe.kinetic_energy(), "kJ/mol").unwrap();
        let total = units::to(universe.total_energy(), "kJ/mol").unwrap();
        writeln!(&mut self.file, "{}   {}   {}", potential, kinetic, total).unwrap();
    }
}

#[cfg(test)]
mod tests {
    use std::io::prelude::*;
    use std::fs;

    use super::*;
    use ::universe::*;
    use ::types::*;
    use ::potentials::*;
    use ::units;

    fn testing_universe() -> Universe {
        let mut universe = Universe::from_cell(UnitCell::cubic(10.0));;

        universe.add_particle(Particle::new("F"));
        universe[0].set_position(Vector3D::new(0.0, 0.0, 0.0));

        universe.add_particle(Particle::new("F"));
        universe[1].set_position(Vector3D::new(1.3, 0.0, 0.0));

        universe.add_pair_interaction("F", "F",
            Harmonic{k: units::from(300.0, "kJ/mol/A^2").unwrap(), x0: units::from(1.2, "A").unwrap()});
        return universe;
    }

    fn check_file_content(filename: &str, content: &str) {
        let mut file = fs::File::open(filename).unwrap();
        let mut buffer = String::new();
        file.read_to_string(&mut buffer).unwrap();

        assert_eq!(buffer, content);
    }

    #[test]
    fn trajectory() {
        let filename = "testing-trajectory-output.xyz";
        let universe = testing_universe();
        {
            let mut out = TrajectoryOutput::new(filename).unwrap();
            out.setup(&universe);
            out.write(&universe);
            out.finish(&universe);
        }

        check_file_content(filename, "2\nWritten by Chemharp\nF 0 0 0\nF 1.3 0 0\n");
        fs::remove_file(filename).unwrap();
    }

    #[test]
    fn energy() {
        let filename = "testing-energy-output.dat";
        let universe = testing_universe();
        {
            let mut out = EnergyOutput::new(filename);
            out.setup(&universe);
            out.write(&universe);
            out.finish(&universe);
        }

        check_file_content(filename, "# Energy of the simulation (kJ/mol)\n# Potential     Kinetic     Total\n1.5000000000000027   0   1.5000000000000027\n");
        fs::remove_file(filename).unwrap();
    }
}
<|endoftext|>


<commit_before>use system::*;
use gpu::gpu_registers::{GPU_Registers, ShadeProfile};
use image::ImageBuffer;
use image::{RgbaImage, Rgba};

pub struct TileMap
{
    pub tiles: Vec<TileData>,
    pub map: Vec<u8>,
}

impl TileMap {
     pub fn new() -> TileMap
     {
         return TileMap
         {
             tiles: vec![TileData::new();256],
             map: vec![0, 1024],
         }
     }

     pub fn populate_tile_map(&mut self, system_data_original: &mut SystemData, lcdc_data_select: bool, lcdc_display_select: bool)
     {
        let mut system_data = system_data_original;
        for tile_index in 0..self.tiles.len()
        {
            self.tiles[tile_index] = get_tile_data(tile_index as u8, &mut system_data, lcdc_data_select);
        }

        self.map = self.vectorize_map(&mut system_data, lcdc_display_select);
     }

     fn vectorize_map(&mut self, system_data: &mut SystemData, lcdc_display_select: bool) -> Vec<u8>
     {
        let mut map: Vec<u8> = vec![0;1024];
        let mut map_offset: u16 = 0;
        if lcdc_display_select
        {
            map_offset = 0x9C00;
        }
        else {
            map_offset = 0x9800;
        }

        for i in 0..map.len()
        {
            map[i] = system_data.mmu.mem_map[map_offset as usize + i];
        }

        return map
     }
}

#[derive(Clone)]
pub struct TileData
{
    pub data: Vec<u8>,
}

impl TileData
{
    pub fn new() -> TileData
    {
        return TileData
        {
            data: vec![0; 64],
        }
    }
}

pub fn get_tile_data(tile_index: u8, system_data: &mut SystemData, lcdc_data_select: bool) -> TileData
{
    let mut tile_data = TileData::new();
    let mut vram_offset: u16 = 0;

    if lcdc_data_select
    {
        vram_offset = 0x8000;
    }
    else {
        vram_offset = 0x8800
    }

    let mem_loc: u16 = vram_offset + (tile_index as u16 * 16);
    for byte_pair in 0..8
    {
        for bit in 0..8
        {
            let upper_bit: u8 = (system_data.mmu.mem_map[(mem_loc + (2 * byte_pair as u16)) as usize + 1] >> (7 - bit)) & 0x01;
            let lower_bit: u8 = (system_data.mmu.mem_map[(mem_loc + (2 * byte_pair as u16)) as usize] >> (7 - bit)) & 0x01;
            tile_data.data[(byte_pair as usize * 8) + bit as usize] = (upper_bit << 1) | lower_bit;
        }
    }
    return tile_data;
}

pub fn update_gpu(system_data_original: &mut SystemData, registers_original: &mut Registers, gpu_registers_original: &mut GPU_Registers)
{
    let mut system_data = system_data_original;
    let mut registers = registers_original;
    let mut gpu_registers = gpu_registers_original;
    LCD_Y_Coordinate_Update(&mut system_data, &mut gpu_registers);
    gpu_registers.lcdc_register.update_lcdc_register(&system_data);
    gpu_registers.lcdc_status.update_lcdc_status(&system_data);
    gpu_registers.lcd_position.update(&mut system_data, gpu_registers.lcdc_status.lyc_ly_coincidence_interrupt);
}

pub fn LCD_Y_Coordinate_Update(system_data_original: &mut SystemData, gpu_registers: &mut GPU_Registers)
{
    let mut system_data = system_data_original;
    gpu_registers.lcd_position.ly_register.add_cycles(&system_data);
    let tick_flag = gpu_registers.lcd_position.ly_register.add_sub_cycles(&system_data);
    if tick_flag
    {
        let reset_flag = gpu_registers.lcd_position.ly_register.tick(&mut system_data);
        let ly_value = gpu_registers.lcd_position.ly_register.value;
        if ly_value == 144
        {
            gpu_registers.v_blank = true;
            system_data.mmu.mem_map[0xFF0F] |= 0x01;
            gpu_registers.v_blank_draw_flag = true;
        }
        else if ly_value < 144
        {
            gpu_registers.lcd_position.scroll_x_buffer[ly_value as usize] = gpu_registers.lcd_position.scroll_x;
            gpu_registers.lcd_position.scroll_y_buffer[ly_value as usize] = gpu_registers.lcd_position.scroll_y;
        }
        if reset_flag
        {
            gpu_registers.v_blank = false;
            system_data.mmu.mem_map[0xFF0F] &= 0xFE;
        }
    }
}

pub fn create_background_img(background_tile_map: &TileMap, gpu_registers: &GPU_Registers, system_data: &SystemData) -> RgbaImage
{
    //Technically switchable by the row, will implement later
    let palette_data = system_data.mmu.mem_map[0xFF47];
    let mut image_buffer = ImageBuffer::new(160, 144);
    let background_buffer = build_background_bitmap(background_tile_map, gpu_registers.lcdc_register.tile_data);
    for row_y in 0..144
    {
        for row_x in 0..160
        {
           let mut row_x_scrolled = (row_x + gpu_registers.lcd_position.scroll_x_buffer[row_y] as usize) % 256;
           let mut row_y_scrolled = (row_y + gpu_registers.lcd_position.scroll_y_buffer[row_y] as usize) % 256;
           let pixel_data = background_buffer[(row_y_scrolled * 256) + row_x_scrolled];
           let pixel = pixel_color_map(pixel_data, palette_data, &gpu_registers.shade_profile);
           image_buffer.put_pixel(row_x as u32, row_y as u32, pixel);
        }
    }
   return image_buffer;
}

fn build_background_bitmap(background_tile_map: &TileMap, tile_data_select: bool) -> Vec<u8>
{

    let mut buffer = vec![0; 0x10000];
    for tile_y in 0..32
    {
        for tile_x in 0..32
        {
            for pixel_y in 0..8
            {
                for pixel_x in 0..8
                {
                    let mut tile = background_tile_map.map[(tile_y * 32) + tile_x];
                    if !tile_data_select
                    {
                        let tile_temp = tile as i8 as i16;
                        tile = (tile_temp + 0x80) as u8;
                    }
                    let pixel_data = background_tile_map.tiles[tile as usize].data[(pixel_y * 8) + pixel_x];
                    buffer[(256 * ((tile_y * 8) + pixel_y)) + ((tile_x * 8) + pixel_x)] = pixel_data;
                }
            }
        }
    }
    return buffer;
}

fn pixel_color_map(pixel_data: u8, palette_data: u8, shade_profile: &ShadeProfile) -> Rgba<u8>
{
    let mut pixel_shade = 0;
    match pixel_data
    {
        0 => pixel_shade = palette_data & 0x03,
        1 => pixel_shade = (palette_data & 0x0C) >> 2,
        2 => pixel_shade = (palette_data & 0x30) >> 4,
        3 => pixel_shade = (palette_data & 0xC0) >> 6,
        _ => (),
    }

    match pixel_shade
    {
        0 => return shade_profile.shade_0,
        1 => return shade_profile.shade_1,
        2 => return shade_profile.shade_2,
        3 => return shade_profile.shade_3,
        _ => return shade_profile.default,
    }
}

#[cfg(test)]
mod gpu_tests
{
    use system::get_system_data;
    use gpu::gpu::*;

    #[test]
    fn get_tile_data_test() {
        let mut system_data : SystemData = get_system_data(&String::from("CLASSIC"));

        let temp_memory_values : Vec<u8> = vec![0b00110011, 0b00001111, 0b11001100, 0b11110000];

        for vram_offset in vec![0x8000, 0x8800].iter()
        {
            for i in 0..temp_memory_values.len()
            {
                system_data.mmu.mem_map[*vram_offset + i] = temp_memory_values[i];
            }
        }
        let tiles = vec![get_tile_data(0, &mut system_data, false), get_tile_data(0, &mut system_data, true)];
        for tile in tiles.iter()
        {
            for i in 0..4
            {
                assert_eq!(tile.data[i as usize * 2], i);
                assert_eq!(tile.data[(i as usize * 2) + 1 ], i);
                assert_eq!(tile.data[8 + (i as usize * 2)], 3 - i);
                assert_eq!(tile.data[(8 + (i as usize * 2)) + 1], 3 - i);
            }
        }
    }

    #[test]
    fn get_tile_map_test() {
        let mut system_data : SystemData = get_system_data(&String::from("CLASSIC"));
        let mut TileMap = TileMap::new();

        let memory_values: Vec<u8> = vec![0x00, 0xFF];
        let test_values: Vec<u8> = vec![0, 3];
        let tiles_offset: Vec<usize> = vec![0x8800, 0x8000];
        let bools: Vec<bool> = vec![false, true];

        for offset_index in 0..tiles_offset.len()
        {
            for index in 0..test_values.len()
            {
                for i in 0..0x1000
                {
                    system_data.mmu.mem_map[tiles_offset[offset_index] + i] = memory_values[index];
                }

                TileMap.populate_tile_map(&mut system_data, bools[offset_index], true);

                for i in 0..TileMap.tiles.len()
                {
                    for j in 0..64
                    {
                        assert_eq!(TileMap.tiles[i].data[j], test_values[index]);
                    }
                }
            }
        }

        let display_offset: Vec<usize> = vec![0x9800, 0x9C00];

        for offset_index in 0..display_offset.len()
        {
            for value_index in 0..memory_values.len()
            {
                for i in 0..TileMap.map.len()
                {
                    system_data.mmu.mem_map[display_offset[offset_index] + i] = memory_values[value_index];
                }

                TileMap.populate_tile_map(&mut system_data, false, bools[offset_index]);

                for i in 0..TileMap.map.len()
                {
                    assert_eq!(TileMap.map[i], memory_values[value_index]);
                }
            }
        }

    }

}
<commit_msg>Created sprite attribute table<commit_after>use system::*;
use gpu::gpu_registers::{GPU_Registers, ShadeProfile};
use image::ImageBuffer;
use image::{RgbaImage, Rgba};

pub struct TileMap
{
    pub tiles: Vec<TileData>,
    pub map: Vec<u8>,
}

impl TileMap {
     pub fn new() -> TileMap
     {
         return TileMap
         {
             tiles: vec![TileData::new();256],
             map: vec![0, 1024],
         }
     }

     pub fn populate_tile_map(&mut self, system_data_original: &mut SystemData, lcdc_data_select: bool, lcdc_display_select: bool)
     {
        let mut system_data = system_data_original;
        for tile_index in 0..self.tiles.len()
        {
            self.tiles[tile_index] = get_tile_data(tile_index as u8, &mut system_data, lcdc_data_select);
        }

        self.map = self.vectorize_map(&mut system_data, lcdc_display_select);
     }

     fn vectorize_map(&mut self, system_data: &mut SystemData, lcdc_display_select: bool) -> Vec<u8>
     {
        let mut map: Vec<u8> = vec![0;1024];
        let mut map_offset: u16 = 0;
        if lcdc_display_select
        {
            map_offset = 0x9C00;
        }
        else {
            map_offset = 0x9800;
        }

        for i in 0..map.len()
        {
            map[i] = system_data.mmu.mem_map[map_offset as usize + i];
        }

        return map
     }
}

#[derive(Clone)]
pub struct SpriteAttribute
{
    pub y_position: u8,
    pub x_position: u8,
    pub tile_number: u8,
    pub flags: u8,
}

impl SpriteAttribute {
    pub fn new() -> SpriteAttribute
    {
        return SpriteAttribute
        {
            y_position: 0,
            x_position: 0,
            tile_number: 0,
            flags: 0,
        }
    }

    pub fn update_sprite(&mut self, y_position: u8, x_position: u8, tile_number: u8, flags: u8)
    {
        self.y_position = y_position;
        self.x_position = x_position;
        self.tile_number = tile_number;
        self.flags = flags;
    }
}

pub struct OAM_Table
{
    pub table: Vec<SpriteAttribute>,
}

impl OAM_Table {
    pub fn new() -> OAM_Table
    {
        return OAM_Table
        {
            table: vec![SpriteAttribute::new();40],
        }
    }

    pub fn populate_oam_table(&mut self, system_data: &SystemData)
    {
        for i in 0..40
        {
            let mut sprite_attribute = SpriteAttribute::new();
            let y_position = system_data.mmu.mem_map[0xFE00 + (i * 4)];
            let x_position = system_data.mmu.mem_map[0xFE01 + (i * 4)];
            let tile_number = system_data.mmu.mem_map[0xFE02 + (i * 4)];
            let flags = system_data.mmu.mem_map[0xFE03 + (i * 4)];
            sprite_attribute.update_sprite(y_position, x_position, tile_number, flags);
            self.table[i] = sprite_attribute;
        }
    }
}

#[derive(Clone)]
pub struct TileData
{
    pub data: Vec<u8>,
}

impl TileData
{
    pub fn new() -> TileData
    {
        return TileData
        {
            data: vec![0; 64],
        }
    }
}

pub fn get_tile_data(tile_index: u8, system_data: &mut SystemData, lcdc_data_select: bool) -> TileData
{
    let mut tile_data = TileData::new();
    let mut vram_offset: u16 = 0;

    if lcdc_data_select
    {
        vram_offset = 0x8000;
    }
    else {
        vram_offset = 0x8800
    }

    let mem_loc: u16 = vram_offset + (tile_index as u16 * 16);
    for byte_pair in 0..8
    {
        for bit in 0..8
        {
            let upper_bit: u8 = (system_data.mmu.mem_map[(mem_loc + (2 * byte_pair as u16)) as usize + 1] >> (7 - bit)) & 0x01;
            let lower_bit: u8 = (system_data.mmu.mem_map[(mem_loc + (2 * byte_pair as u16)) as usize] >> (7 - bit)) & 0x01;
            tile_data.data[(byte_pair as usize * 8) + bit as usize] = (upper_bit << 1) | lower_bit;
        }
    }
    return tile_data;
}

pub fn update_gpu(system_data_original: &mut SystemData, registers_original: &mut Registers, gpu_registers_original: &mut GPU_Registers)
{
    let mut system_data = system_data_original;
    let mut registers = registers_original;
    let mut gpu_registers = gpu_registers_original;
    LCD_Y_Coordinate_Update(&mut system_data, &mut gpu_registers);
    gpu_registers.lcdc_register.update_lcdc_register(&system_data);
    gpu_registers.lcdc_status.update_lcdc_status(&system_data);
    gpu_registers.lcd_position.update(&mut system_data, gpu_registers.lcdc_status.lyc_ly_coincidence_interrupt);
}

pub fn LCD_Y_Coordinate_Update(system_data_original: &mut SystemData, gpu_registers: &mut GPU_Registers)
{
    let mut system_data = system_data_original;
    gpu_registers.lcd_position.ly_register.add_cycles(&system_data);
    let tick_flag = gpu_registers.lcd_position.ly_register.add_sub_cycles(&system_data);
    if tick_flag
    {
        let reset_flag = gpu_registers.lcd_position.ly_register.tick(&mut system_data);
        let ly_value = gpu_registers.lcd_position.ly_register.value;
        if ly_value == 144
        {
            gpu_registers.v_blank = true;
            system_data.mmu.mem_map[0xFF0F] |= 0x01;
            gpu_registers.v_blank_draw_flag = true;
        }
        else if ly_value < 144
        {
            gpu_registers.lcd_position.scroll_x_buffer[ly_value as usize] = gpu_registers.lcd_position.scroll_x;
            gpu_registers.lcd_position.scroll_y_buffer[ly_value as usize] = gpu_registers.lcd_position.scroll_y;
        }
        if reset_flag
        {
            gpu_registers.v_blank = false;
            system_data.mmu.mem_map[0xFF0F] &= 0xFE;
        }
    }
}

pub fn create_background_img(background_tile_map: &TileMap, gpu_registers: &GPU_Registers, system_data: &SystemData) -> RgbaImage
{
    //Technically switchable by the row, will implement later
    let palette_data = system_data.mmu.mem_map[0xFF47];
    let mut image_buffer = ImageBuffer::new(160, 144);
    let background_buffer = build_background_bitmap(background_tile_map, gpu_registers.lcdc_register.tile_data);
    for row_y in 0..144
    {
        for row_x in 0..160
        {
           let mut row_x_scrolled = (row_x + gpu_registers.lcd_position.scroll_x_buffer[row_y] as usize) % 256;
           let mut row_y_scrolled = (row_y + gpu_registers.lcd_position.scroll_y_buffer[row_y] as usize) % 256;
           let pixel_data = background_buffer[(row_y_scrolled * 256) + row_x_scrolled];
           let pixel = pixel_color_map(pixel_data, palette_data, &gpu_registers.shade_profile);
           image_buffer.put_pixel(row_x as u32, row_y as u32, pixel);
        }
    }
   return image_buffer;
}

fn build_background_bitmap(background_tile_map: &TileMap, tile_data_select: bool) -> Vec<u8>
{

    let mut buffer = vec![0; 0x10000];
    for tile_y in 0..32
    {
        for tile_x in 0..32
        {
            for pixel_y in 0..8
            {
                for pixel_x in 0..8
                {
                    let mut tile = background_tile_map.map[(tile_y * 32) + tile_x];
                    if !tile_data_select
                    {
                        let tile_temp = tile as i8 as i16;
                        tile = (tile_temp + 0x80) as u8;
                    }
                    let pixel_data = background_tile_map.tiles[tile as usize].data[(pixel_y * 8) + pixel_x];
                    buffer[(256 * ((tile_y * 8) + pixel_y)) + ((tile_x * 8) + pixel_x)] = pixel_data;
                }
            }
        }
    }
    return buffer;
}

fn pixel_color_map(pixel_data: u8, palette_data: u8, shade_profile: &ShadeProfile) -> Rgba<u8>
{
    let mut pixel_shade = 0;
    match pixel_data
    {
        0 => pixel_shade = palette_data & 0x03,
        1 => pixel_shade = (palette_data & 0x0C) >> 2,
        2 => pixel_shade = (palette_data & 0x30) >> 4,
        3 => pixel_shade = (palette_data & 0xC0) >> 6,
        _ => (),
    }

    match pixel_shade
    {
        0 => return shade_profile.shade_0,
        1 => return shade_profile.shade_1,
        2 => return shade_profile.shade_2,
        3 => return shade_profile.shade_3,
        _ => return shade_profile.default,
    }
}

#[cfg(test)]
mod gpu_tests
{
    use system::get_system_data;
    use gpu::gpu::*;

    #[test]
    fn get_tile_data_test() {
        let mut system_data : SystemData = get_system_data(&String::from("CLASSIC"));

        let temp_memory_values : Vec<u8> = vec![0b00110011, 0b00001111, 0b11001100, 0b11110000];

        for vram_offset in vec![0x8000, 0x8800].iter()
        {
            for i in 0..temp_memory_values.len()
            {
                system_data.mmu.mem_map[*vram_offset + i] = temp_memory_values[i];
            }
        }
        let tiles = vec![get_tile_data(0, &mut system_data, false), get_tile_data(0, &mut system_data, true)];
        for tile in tiles.iter()
        {
            for i in 0..4
            {
                assert_eq!(tile.data[i as usize * 2], i);
                assert_eq!(tile.data[(i as usize * 2) + 1 ], i);
                assert_eq!(tile.data[8 + (i as usize * 2)], 3 - i);
                assert_eq!(tile.data[(8 + (i as usize * 2)) + 1], 3 - i);
            }
        }
    }

    #[test]
    fn get_tile_map_test() {
        let mut system_data : SystemData = get_system_data(&String::from("CLASSIC"));
        let mut TileMap = TileMap::new();

        let memory_values: Vec<u8> = vec![0x00, 0xFF];
        let test_values: Vec<u8> = vec![0, 3];
        let tiles_offset: Vec<usize> = vec![0x8800, 0x8000];
        let bools: Vec<bool> = vec![false, true];

        for offset_index in 0..tiles_offset.len()
        {
            for index in 0..test_values.len()
            {
                for i in 0..0x1000
                {
                    system_data.mmu.mem_map[tiles_offset[offset_index] + i] = memory_values[index];
                }

                TileMap.populate_tile_map(&mut system_data, bools[offset_index], true);

                for i in 0..TileMap.tiles.len()
                {
                    for j in 0..64
                    {
                        assert_eq!(TileMap.tiles[i].data[j], test_values[index]);
                    }
                }
            }
        }

        let display_offset: Vec<usize> = vec![0x9800, 0x9C00];

        for offset_index in 0..display_offset.len()
        {
            for value_index in 0..memory_values.len()
            {
                for i in 0..TileMap.map.len()
                {
                    system_data.mmu.mem_map[display_offset[offset_index] + i] = memory_values[value_index];
                }

                TileMap.populate_tile_map(&mut system_data, false, bools[offset_index]);

                for i in 0..TileMap.map.len()
                {
                    assert_eq!(TileMap.map[i], memory_values[value_index]);
                }
            }
        }

    }

}
<|endoftext|>


<commit_before>extern crate proc_macro;

#[macro_use]
extern crate syn;

#[macro_use]
extern crate quote;

use proc_macro::TokenStream;
use syn::{DeriveInput, Data, Fields, Generics, GenericParam};
use quote::Tokens;

#[proc_macro_derive(HeapSize)]
pub fn derive_heap_size(input: TokenStream) -> TokenStream {
    // Parse the input tokens into a syntax tree.
    let input: DeriveInput = syn::parse(input).unwrap();

    // Used in the quasi-quotation below as `#name`.
    let name = input.ident;

    // Add a bound `T: HeapSize` to every type parameter T.
    let generics = add_trait_bounds(input.generics);
    let (impl_generics, ty_generics, where_clause) = generics.split_for_impl();

    // Generate an expression to sum up the heap size of each field.
    let sum = heap_size_sum(&input.data);

    let expanded = quote! {
        mod scope {
            extern crate heapsize;
            use self::heapsize::HeapSize;

            // The generated impl. Okay to use `HeapSize` unqualified here, it
            // is guaranteed to resolve to the import on the previous line. This
            // works even in edge cases like the user's struct having the name
            // `HeapSize` as demonstrated in main.rs, in which case the
            // generated code looks like `impl HeapSize for HeapSize`.
            impl #impl_generics HeapSize for #name #ty_generics #where_clause {
                fn heap_size_of_children(&self) -> usize {
                    #sum
                }
            }
        }
    };

    // Hand the output tokens back to the compiler.
    expanded.into()
}

// Add a bound `T: HeapSize` to every type parameter T.
fn add_trait_bounds(mut generics: Generics) -> Generics {
    for param in &mut generics.params {
        if let GenericParam::Type(ref mut type_param) = *param {
            type_param.bounds.push(parse_quote!(HeapSize));
        }
    }
    generics
}

// Generate an expression to sum up the heap size of each field.
fn heap_size_sum(data: &Data) -> Tokens {
    match *data {
        Data::Struct(ref data) => {
            match data.fields {
                Fields::Named(ref fields) => {
                    // Expands to an expression like
                    //
                    //     0 + self.x.heap_size() + self.y.heap_size() + self.z.heap_size()
                    //
                    // Does not need to use fully qualified function call syntax
                    // like `::heapsize::HeapSize::heap_size_of_children(&...)`.
                    // Our procedural macro places the `HeapSize` trait in scope
                    // within the generated code so this is guaranteed to
                    // resolve to the right trait method, even if one of these
                    // fields has an inherent method with a conflicting name as
                    // demonstrated in main.rs.
                    let fnames = fields.named.iter().map(|f| f.ident);
                    quote! {
                        0 #(
                            + self.#fnames.heap_size_of_children()
                        )*
                    }
                }
                Fields::Unnamed(ref fields) => {
                    // Expands to an expression like
                    //
                    //     0 + self.0.heap_size() + self.1.heap_size() + self.2.heap_size()
                    let indices = 0..fields.unnamed.len();
                    quote! {
                        0 #(
                            + self.#indices.heap_size_of_children()
                        )*
                    }
                }
                Fields::Unit => {
                    // Unit structs cannot own more than 0 bytes of heap memory.
                    quote!(0)
                }
            }
        }
        Data::Enum(_) | Data::Union(_) => unimplemented!(),
    }
}
<commit_msg>Good errors from heapsize2<commit_after>extern crate proc_macro;

#[macro_use]
extern crate syn;

#[macro_use]
extern crate quote;

use proc_macro::TokenStream;
use syn::{DeriveInput, Data, Fields, Generics, GenericParam, Ident};
use syn::spanned::Spanned;
use quote::Tokens;

#[proc_macro_derive(HeapSize)]
pub fn derive_heap_size(input: TokenStream) -> TokenStream {
    // Parse the input tokens into a syntax tree.
    let input: DeriveInput = syn::parse(input).unwrap();

    // Used in the quasi-quotation below as `#name`.
    let name = input.ident;

    // Add a bound `T: HeapSize` to every type parameter T.
    let generics = add_trait_bounds(input.generics);
    let (impl_generics, ty_generics, where_clause) = generics.split_for_impl();

    // Generate an expression to sum up the heap size of each field.
    let sum = heap_size_sum(&input.data);

    let expanded = quote! {
        mod scope {
            extern crate heapsize;
            use self::heapsize::HeapSize;

            // The generated impl. Okay to use `HeapSize` unqualified here, it
            // is guaranteed to resolve to the import on the previous line. This
            // works even in edge cases like the user's struct having the name
            // `HeapSize` as demonstrated in main.rs, in which case the
            // generated code looks like `impl HeapSize for HeapSize`.
            impl #impl_generics HeapSize for #name #ty_generics #where_clause {
                fn heap_size_of_children(&self) -> usize {
                    #sum
                }
            }
        }
    };

    // Hand the output tokens back to the compiler.
    expanded.into()
}

// Add a bound `T: HeapSize` to every type parameter T.
fn add_trait_bounds(mut generics: Generics) -> Generics {
    for param in &mut generics.params {
        if let GenericParam::Type(ref mut type_param) = *param {
            type_param.bounds.push(parse_quote!(HeapSize));
        }
    }
    generics
}

// Generate an expression to sum up the heap size of each field.
fn heap_size_sum(data: &Data) -> Tokens {
    match *data {
        Data::Struct(ref data) => {
            match data.fields {
                Fields::Named(ref fields) => {
                    // Expands to an expression like
                    //
                    //     0 + self.x.heap_size() + self.y.heap_size() + self.z.heap_size()
                    //
                    // Does not need to use fully qualified function call syntax
                    // like `::heapsize::HeapSize::heap_size_of_children(&...)`.
                    // Our procedural macro places the `HeapSize` trait in scope
                    // within the generated code so this is guaranteed to
                    // resolve to the right trait method, even if one of these
                    // fields has an inherent method with a conflicting name as
                    // demonstrated in main.rs.
                    //
                    // We take some care to use the span of each `syn::Field` as
                    // the span of the corresponding `heap_size_of_children`
                    // call. This way if one of the field types does not
                    // implement `HeapSize` then the compiler's error message
                    // underlines which field it is. An example is shown in the
                    // readme of the parent directory.
                    let children = fields.named.iter().map(|f| {
                        let name = f.ident;
                        let method = Ident::new("heap_size_of_children", f.span());
                        quote! {
                            self.#name.#method()
                        }
                    });
                    quote! {
                        0 #(+ #children)*
                    }
                }
                Fields::Unnamed(ref fields) => {
                    // We can also expand in the straightforward way without
                    // worrying about spans. This works but the error message
                    // may not be as good in the case that one of the field
                    // types does not implement HeapSize.
                    //
                    // This expands to an expression like
                    //
                    //     0 + self.0.heap_size() + self.1.heap_size() + self.2.heap_size()
                    let indices = 0..fields.unnamed.len();
                    quote! {
                        0 #(+ self.#indices.heap_size_of_children())*
                    }
                }
                Fields::Unit => {
                    // Unit structs cannot own more than 0 bytes of heap memory.
                    quote!(0)
                }
            }
        }
        Data::Enum(_) | Data::Union(_) => unimplemented!(),
    }
}
<|endoftext|>


<commit_before>use core::cell::Cell;
use common::take_cell::TakeCell;
use common::math::{sqrtf32, get_errno};
use hil::{Driver,Callback};
use hil::i2c;
use hil::gpio::{GPIOPin, InputMode, InterruptMode, Client};

pub static mut BUFFER : [u8; 3] = [0; 3];

// error codes for this driver
const ERR_BAD_VALUE: isize = -2;

const MAX_SAMPLING_RATE: u8 = 0x0;
const DEFAULT_SAMPLING_RATE: u8 = 0x02;

// temperature calculation constants
//  From TMP006 User's Guide section 5.1
//  S_0 should be determined from calibration and ranges from 5E-14 to 7E-14
//  We have selected 5E-14 experimentally
const S_0: f32 = 5E-14;
const A_1: f32 = 1.75E-3;
const A_2: f32 = -1.678E-5;
const T_REF: f32 = 298.15;
const B_0: f32 = -2.94E-5;
const B_1: f32 = -5.7E-7;
const B_2: f32 = 4.63E-9;
const C_2: f32 = 13.4;
const K_TO_C: f32 = -273.15;
const C_TO_K: f32 = 273.15;
const NV_TO_V: f32 = 1E9;
const T_DIE_CONVERT: f32 = 0.03125;
const V_OBJ_CONVERT: f32 = 156.25;

#[allow(dead_code)]
enum Registers {
    SensorVoltage = 0x00,
    DieTemperature = 0x01,
    Configuration = 0x02,
    ManufacturerID = 0xFE,
    DeviceID = 0xFF,
}

type SensorVoltage = u16;

/// States of the I2C protocol with the TMP006. There are three sequences:
///
/// ### Enable sensor
///
/// Configure -> ()
///
/// ### Disable sensor
///
/// Disconfigure -> ()
///
/// ### Read temperature
///
/// SetRegSensorVoltage -->
///     ReadingSensorVoltage --(voltage)->
///         SetRegDieTemperature(voltage) --(voltage)->
///             ReadingDieTemperature -> ()
#[derive(Clone,Copy)]
enum ProtocolState {
    /// Enable sensor by setting the configuration register.
    Configure,

    /// Disable sensor by setting the configuration register.
    Deconfigure,

    /// Set the active register to sensor voltage.
    SetRegSensorVoltage,

    /// Read the sensor voltage register.
    ReadingSensorVoltage,

    /// Set the active register to die temperature, carrying over the sensor
    /// voltage reading.
    SetRegDieTemperature(SensorVoltage),

    /// Read the die temperature register, carrying over the sensor voltage
    /// reading.
    ReadingDieTemperature(usize),
}

pub struct TMP006<'a, I: i2c::I2C + 'a, G: GPIOPin + 'a> {
    i2c: &'a I,
    i2c_address: Cell<u8>,
    interrupt_pin: &'a G,
    sampling_period: Cell<u8>,
    repeated_mode: Cell<bool>,
    callback: Cell<Option<Callback>>,
    protocol_state: Cell<ProtocolState>,
    buffer: TakeCell<&'static mut [u8]>
}

impl<'a, I: i2c::I2C, G: GPIOPin> TMP006<'a, I, G> {
    pub fn new(i2c: &'a I, i2c_address: u8, interrupt_pin: &'a G,
               buffer: &'static mut [u8]) -> TMP006<'a, I, G> {
        // setup and return struct
        TMP006{
            i2c: i2c,
            i2c_address: Cell::new(i2c_address),
            interrupt_pin: interrupt_pin,
            sampling_period: Cell::new(DEFAULT_SAMPLING_RATE),
            repeated_mode: Cell::new(false),
            callback: Cell::new(None),
            protocol_state: Cell::new(ProtocolState::Configure),
            buffer: TakeCell::new(buffer)
        }
    }

    fn enable_sensor(&self, sampling_period: u8) {
        // enable and configure TMP006
        self.buffer.take().map(|buf| {
            // turn on i2c to send commands
            self.i2c.enable();

            let config = 0x7100 | (((sampling_period & 0x7) as u16) << 9);
            buf[0] = Registers::Configuration as u8;
            buf[1] = ((config & 0xFF00) >> 8) as u8;
            buf[2] = (config & 0x00FF) as u8;
            self.i2c.write(self.i2c_address.get(), buf, 3);
        });
    }

    fn disable_sensor(&self) {
        // turn on i2c to send commands
        self.i2c.enable();

        // disable the TMP006
        let mut buf: [u8; 3] = [0; 3];
        let config = 0x0000;
        buf[0] = Registers::Configuration as u8;
        buf[1] = ((config & 0xFF00) >> 8) as u8;
        buf[2] = (config & 0x00FF) as u8;
        self.i2c.write_sync(self.i2c_address.get(), &buf);

        // disable the i2c
        self.i2c.disable();
    }

    fn enable_interrupts(&self) {
        // setup interrupts from the sensor
        self.interrupt_pin.enable_input(InputMode::PullUp);
        self.interrupt_pin.enable_interrupt(0, InterruptMode::FallingEdge);
    }

    fn disable_interrupts(&self) {
        // disable interrupts from the sensor
        self.interrupt_pin.disable_interrupt();
        self.interrupt_pin.disable();
    }

    fn read_temperature(&self) -> f32 {
        // turn on i2c to send commands
        self.i2c.enable();

        let mut buf: [u8; 3] = [0; 3];

        // select sensor voltage register and read it
        buf[0] = Registers::SensorVoltage as u8;
        self.i2c.write_sync(self.i2c_address.get(), &buf[0..1]);
        self.i2c.read_sync(self.i2c_address.get(), &mut buf[0..2]);
        let sensor_voltage = (((buf[0] as u16) << 8) | buf[1] as u16) as i16;

        // select die temperature register and read it
        buf[0] = Registers::DieTemperature as u8;
        self.i2c.write_sync(self.i2c_address.get(), &buf[0..1]);
        self.i2c.read_sync(self.i2c_address.get(), &mut buf[0..2]);
        let die_temperature = (((buf[0] as u16) << 8) | buf[1] as u16) as i16;

        // disable the i2c
        self.i2c.disable();

        // do calculation of actual temperature
        //  Calculations based on TMP006 User's Guide section 5.1
        let t_die = ((die_temperature >> 2) as f32)*T_DIE_CONVERT + C_TO_K;
        let t_adj = t_die-T_REF;
        let s = S_0 * (1.0 + A_1*t_adj + A_2*t_adj*t_adj);

        let v_obj = (sensor_voltage as f32)*V_OBJ_CONVERT/NV_TO_V;
        let v_os = B_0 + B_1*t_adj + B_2*t_adj*t_adj;

        let v_adj = v_obj-v_os;
        let f_v_obj = v_adj + C_2*v_adj*v_adj;

        let t_kelvin =
            sqrtf32(sqrtf32(t_die * t_die * t_die * t_die + (f_v_obj / s)));
        let t_celsius = t_kelvin + K_TO_C;

        // return data value
        t_celsius
    }
}

impl<'a, I: i2c::I2C, G: GPIOPin> i2c::I2CClient for TMP006<'a, I, G> {
    fn command_complete(&self, buffer: &'static mut [u8], error: i2c::Error) {
        match self.protocol_state.get() {
            ProtocolState::Configure => {
                self.buffer.replace(buffer);
                self.enable_interrupts();
                self.i2c.disable()
            },
            _ => {}
        }
    }

}

impl<'a, I: i2c::I2C, G: GPIOPin> Client for TMP006<'a, I, G> {
    fn fired(&self, _: usize) {
        // read value from temperature sensor
        let temp_val = self.read_temperature();

        // send value to callback
        if self.callback.get().is_some() {
            self.callback.get().unwrap().schedule(temp_val as usize, get_errno() as usize, 0);
        }

        // disable callback and sensing if in single-shot mode
        if self.repeated_mode.get() == false {
            // clear callback
            self.callback.set(None);

            // disable temperature sensor
            self.disable_sensor();
            self.disable_interrupts();
        }
    }
}

impl<'a, I: i2c::I2C, G: GPIOPin> Driver for TMP006<'a, I, G> {
    fn subscribe(&self, subscribe_num: usize, callback: Callback) -> isize {
        match subscribe_num {
            // single temperature reading with callback
            0 => {
                // single sample mode
                self.repeated_mode.set(false);

                // set callback function
                self.callback.set(Some(callback));

                // enable sensor
                //  turn up the sampling rate so we get the sample faster
                self.enable_sensor(MAX_SAMPLING_RATE);

                0
            },

            // periodic temperature reading subscription
            1 => {
                // periodic sampling mode
                self.repeated_mode.set(true);

                // set callback function
                self.callback.set(Some(callback));

                // enable temperature sensor
                self.enable_sensor(self.sampling_period.get());

                0
            },

            // default
            _ => -1
        }
    }

    fn command(&self, command_num: usize, data: usize) -> isize {
        match command_num {
            // set period for sensing
            0 => {
                // bounds check on the period
                if (data & 0xFFFFFFF8) != 0 {
                    return ERR_BAD_VALUE;
                }

                // set period value
                self.sampling_period.set((data & 0x7) as u8);

                0
            },

            // unsubscribe callback
            1 => {
                // clear callback function
                self.callback.set(None);

                // disable temperature sensor
                self.disable_sensor();
                self.disable_interrupts();

                0
            },

            // default
            _ => -1
        }
    }
}

<commit_msg>TMP006: Complete transition to DMA based I2C<commit_after>use core::cell::Cell;
use common::take_cell::TakeCell;
use common::math::{sqrtf32, get_errno};
use hil::{Driver,Callback};
use hil::i2c;
use hil::gpio::{GPIOPin, InputMode, InterruptMode, Client};

pub static mut BUFFER : [u8; 3] = [0; 3];

// error codes for this driver
const ERR_BAD_VALUE: isize = -2;

const MAX_SAMPLING_RATE: u8 = 0x0;
const DEFAULT_SAMPLING_RATE: u8 = 0x02;

// temperature calculation constants
//  From TMP006 User's Guide section 5.1
//  S_0 should be determined from calibration and ranges from 5E-14 to 7E-14
//  We have selected 5E-14 experimentally
const S_0: f32 = 5E-14;
const A_1: f32 = 1.75E-3;
const A_2: f32 = -1.678E-5;
const T_REF: f32 = 298.15;
const B_0: f32 = -2.94E-5;
const B_1: f32 = -5.7E-7;
const B_2: f32 = 4.63E-9;
const C_2: f32 = 13.4;
const K_TO_C: f32 = -273.15;
const C_TO_K: f32 = 273.15;
const NV_TO_V: f32 = 1E9;
const T_DIE_CONVERT: f32 = 0.03125;
const V_OBJ_CONVERT: f32 = 156.25;

#[allow(dead_code)]
enum Registers {
    SensorVoltage = 0x00,
    DieTemperature = 0x01,
    Configuration = 0x02,
    ManufacturerID = 0xFE,
    DeviceID = 0xFF,
}

type SensorVoltage = i16;

/// States of the I2C protocol with the TMP006. There are three sequences:
///
/// ### Enable sensor
///
/// Configure -> ()
///
/// ### Disable sensor
///
/// Disconfigure -> ()
///
/// ### Read temperature
///
/// SetRegSensorVoltage -->
///     ReadingSensorVoltage --(voltage)->
///         SetRegDieTemperature(voltage) --(voltage)->
///             ReadingDieTemperature --(unless repeated_mode)->
///                 Disconfigure
#[derive(Clone,Copy,PartialEq)]
enum ProtocolState {
    Idle,

    /// Enable sensor by setting the configuration register.
    Configure,

    /// Disable sensor by setting the configuration register. Optionally contains the most recent
    /// temperature to give back to callbacks.
    Deconfigure(Option<f32>),

    /// Set the active register to sensor voltage.
    SetRegSensorVoltage,

    /// Read the sensor voltage register.
    ReadingSensorVoltage,

    /// Set the active register to die temperature, carrying over the sensor
    /// voltage reading.
    SetRegDieTemperature(SensorVoltage),

    /// Read the die temperature register, carrying over the sensor voltage
    /// reading.
    ReadingDieTemperature(SensorVoltage),
}

pub struct TMP006<'a, I: i2c::I2C + 'a, G: GPIOPin + 'a> {
    i2c: &'a I,
    i2c_address: Cell<u8>,
    interrupt_pin: &'a G,
    sampling_period: Cell<u8>,
    repeated_mode: Cell<bool>,
    callback: Cell<Option<Callback>>,
    protocol_state: Cell<ProtocolState>,
    buffer: TakeCell<&'static mut [u8]>
}

impl<'a, I: i2c::I2C, G: GPIOPin> TMP006<'a, I, G> {
    pub fn new(i2c: &'a I, i2c_address: u8, interrupt_pin: &'a G,
               buffer: &'static mut [u8]) -> TMP006<'a, I, G> {
        // setup and return struct
        TMP006{
            i2c: i2c,
            i2c_address: Cell::new(i2c_address),
            interrupt_pin: interrupt_pin,
            sampling_period: Cell::new(DEFAULT_SAMPLING_RATE),
            repeated_mode: Cell::new(false),
            callback: Cell::new(None),
            protocol_state: Cell::new(ProtocolState::Idle),
            buffer: TakeCell::new(buffer)
        }
    }

    fn enable_sensor(&self, sampling_period: u8) {
        // enable and configure TMP006
        self.buffer.take().map(|buf| {
            // turn on i2c to send commands
            self.i2c.enable();

            let config = 0x7100 | (((sampling_period & 0x7) as u16) << 9);
            buf[0] = Registers::Configuration as u8;
            buf[1] = ((config & 0xFF00) >> 8) as u8;
            buf[2] = (config & 0x00FF) as u8;
            self.i2c.write(self.i2c_address.get(), buf, 3);
            self.protocol_state.set(ProtocolState::Configure);
        });
    }

    fn disable_sensor(&self, temperature: Option<f32>) {
        // disable the TMP006
        self.buffer.take().map(|buf| {
            // turn on i2c to send commands
            self.i2c.enable();

            let config = 0x0000;
            buf[0] = Registers::Configuration as u8;
            buf[1] = ((config & 0xFF00) >> 8) as u8;
            buf[2] = (config & 0x00FF) as u8;
            self.i2c.write(self.i2c_address.get(), buf, 3);
            self.protocol_state.set(ProtocolState::Deconfigure(temperature));
        });
    }

    fn enable_interrupts(&self) {
        // setup interrupts from the sensor
        self.interrupt_pin.enable_input(InputMode::PullUp);
        self.interrupt_pin.enable_interrupt(0, InterruptMode::FallingEdge);
    }

    fn disable_interrupts(&self) {
        // disable interrupts from the sensor
        self.interrupt_pin.disable_interrupt();
        self.interrupt_pin.disable();
    }
}

fn calculate_temperature(sensor_voltage: i16, die_temperature: i16) -> f32 {
    // do calculation of actual temperature
    //  Calculations based on TMP006 User's Guide section 5.1
    let t_die = ((die_temperature >> 2) as f32)*T_DIE_CONVERT + C_TO_K;
    let t_adj = t_die-T_REF;
    let s = S_0 * (1.0 + A_1*t_adj + A_2*t_adj*t_adj);

    let v_obj = (sensor_voltage as f32)*V_OBJ_CONVERT/NV_TO_V;
    let v_os = B_0 + B_1*t_adj + B_2*t_adj*t_adj;

    let v_adj = v_obj-v_os;
    let f_v_obj = v_adj + C_2*v_adj*v_adj;

    let t_kelvin =
        sqrtf32(sqrtf32(t_die * t_die * t_die * t_die + (f_v_obj / s)));
    let t_celsius = t_kelvin + K_TO_C;

    // return data value
    t_celsius
}

impl<'a, I: i2c::I2C, G: GPIOPin> i2c::I2CClient for TMP006<'a, I, G> {
    fn command_complete(&self, buffer: &'static mut [u8], _error: i2c::Error) {
        //TODO(alevy): handle protocol errors
        match self.protocol_state.get() {
            ProtocolState::Configure => {
                self.buffer.replace(buffer);
                self.enable_interrupts();
                self.i2c.disable();
                self.protocol_state.set(ProtocolState::Idle);
            },
            ProtocolState::Deconfigure(temperature) => {
                self.buffer.replace(buffer);
                self.disable_interrupts();
                self.i2c.disable();
                self.protocol_state.set(ProtocolState::Idle);
                temperature.map(|temp_val| {
                    self.callback.get().map(|mut cb|
                        cb.schedule(temp_val as usize, get_errno() as usize, 0));
                    self.callback.set(None);
                });
            },
            ProtocolState::SetRegSensorVoltage => {
                // Read sensor voltage register
                self.i2c.read(self.i2c_address.get(), buffer, 2);
                self.protocol_state.set(ProtocolState::ReadingSensorVoltage);
            },
            ProtocolState::ReadingSensorVoltage => {
                let sensor_voltage =
                    (((buffer[0] as u16) << 8) | buffer[1] as u16) as i16;

                // Select die temperature register
                buffer[0] = Registers::DieTemperature as u8;
                self.i2c.write(self.i2c_address.get(), buffer, 1);

                self.protocol_state.set(
                    ProtocolState::SetRegDieTemperature(sensor_voltage));
            },
            ProtocolState::SetRegDieTemperature(sensor_voltage) => {
                // Read die temperature register
                self.i2c.read(self.i2c_address.get(), buffer, 2);
                self.protocol_state.set(
                    ProtocolState::ReadingDieTemperature(sensor_voltage));
            },
            ProtocolState::ReadingDieTemperature(sensor_voltage) => {
                let die_temperature =
                    (((buffer[0] as u16) << 8) | buffer[1] as u16) as i16;
                self.buffer.replace(buffer);

                let temp_val = calculate_temperature(sensor_voltage, die_temperature);

                // disable callback and sensing if in single-shot mode
                if self.repeated_mode.get() == false {
                    // disable temperature sensor. When disabling is finished, we will give the
                    // temperature to the callback.
                    self.disable_sensor(Some(temp_val));
                } else {
                    // send value to callback
                    self.callback.get().map(|mut cb|
                        cb.schedule(temp_val as usize, get_errno() as usize, 0)
                    );

                    self.i2c.disable();
                }
            },
            _ => {}
        }
    }
}

impl<'a, I: i2c::I2C, G: GPIOPin> Client for TMP006<'a, I, G> {
    fn fired(&self, _: usize) {
        self.buffer.take().map(|buf| {
            // turn on i2c to send commands
            self.i2c.enable();

            // select sensor voltage register and read it
            buf[0] = Registers::SensorVoltage as u8;
            self.i2c.write(self.i2c_address.get(), buf, 1);
            self.protocol_state.set(ProtocolState::SetRegSensorVoltage);
        });
    }
}

impl<'a, I: i2c::I2C, G: GPIOPin> Driver for TMP006<'a, I, G> {
    fn subscribe(&self, subscribe_num: usize, callback: Callback) -> isize {
        match subscribe_num {
            // single temperature reading with callback
            0 => {
                // single sample mode
                self.repeated_mode.set(false);

                // set callback function
                self.callback.set(Some(callback));

                // enable sensor
                //  turn up the sampling rate so we get the sample faster
                self.enable_sensor(MAX_SAMPLING_RATE);

                0
            },

            // periodic temperature reading subscription
            1 => {
                // periodic sampling mode
                self.repeated_mode.set(true);

                // set callback function
                self.callback.set(Some(callback));

                // enable temperature sensor
                self.enable_sensor(self.sampling_period.get());

                0
            },

            // default
            _ => -1
        }
    }

    fn command(&self, command_num: usize, data: usize) -> isize {
        match command_num {
            // set period for sensing
            0 => {
                // bounds check on the period
                if (data & 0xFFFFFFF8) != 0 {
                    return ERR_BAD_VALUE;
                }

                // set period value
                self.sampling_period.set((data & 0x7) as u8);

                0
            },

            // unsubscribe callback
            1 => {
                // clear callback function
                self.callback.set(None);

                // disable temperature sensor
                self.disable_sensor(None);

                0
            },

            // default
            _ => -1
        }
    }
}

<|endoftext|>


<commit_before>//! An "easy" multiplexing module
//!
//! This module is the same as the top-level `multiplex` module in this crate
//! except that it has no support for streaming bodies. This in turn simplifies
//! a number of generics and allows for protocols to easily get off the ground
//! running.
//!
//! The API surface area of this module is the same as the top-level one, so no
//! new functionality is introduced here. In fact all APIs here are built on top
//! of the `multiplex` module itself, they just simplify the generics in play and
//! such.

use std::io;
use std::marker;

use futures::stream::Receiver;
use futures::{Future, Async, Poll};
use tokio_core::io::FramedIo;
use tokio_core::reactor::Handle;
use tokio_service::Service;

use easy::EasyClient;
use multiplex::{self, RequestId};
use {Message, Body};

/// The "easy" form of connecting a multiplexed client.
///
/// This function takes an instance of the `tokio_core::io::FrameIo` trait as
/// the `frames` argument, a `handle` to the event loop to connect on, and then
/// returns the connected client.
///
/// The client returned implements the `Service` trait. This trait
/// implementation allows sending requests to the transport provided and returns
/// futures to the responses. All requests are automatically multiplexed and
/// managed internally.
pub fn connect<F, T>(frames: F, handle: &Handle)
    -> EasyClient<F::In, T>
    where F: FramedIo<Out = Option<(RequestId, T)>> + 'static,
          F::In: 'static,
          T: 'static,
{
    EasyClient {
        inner: multiplex::connect(MyTransport::new(frames), handle),
    }
}

struct MyTransport<F, T> {
    inner: F,
    _marker: marker::PhantomData<fn() -> T>,
}

impl<F, T> MyTransport<F, T> {
    fn new(f: F) -> MyTransport<F, T> {
        MyTransport {
            inner: f,
            _marker: marker::PhantomData,
        }
    }
}

impl<F, T> multiplex::Transport for MyTransport<F, T>
    where F: FramedIo<Out = Option<(RequestId, T)>> + 'static,
          F::In: 'static,
          T: 'static,
{
    type In = F::In;
    type BodyIn = ();
    type Out = T;
    type BodyOut = ();
    type Error = io::Error;

    fn poll_read(&mut self) -> Async<()> {
        self.inner.poll_read()
    }

    fn read(&mut self) -> Poll<multiplex::Frame<T, (), io::Error>, io::Error> {
        let (id, msg) = match try_ready!(self.inner.read()) {
            Some(msg) => msg,
            None => return Ok(multiplex::Frame::Done.into()),
        };
        Ok(multiplex::Frame::Message {
            message: msg,
            body: false,
            solo: false,
            id: id,
        }.into())
    }

    fn poll_write(&mut self) -> Async<()> {
        self.inner.poll_write()
    }

    fn write(&mut self, req: multiplex::Frame<F::In, (), io::Error>) -> Poll<(), io::Error> {
        match req {
            multiplex::Frame::Message { message, .. } => self.inner.write(message),
            _ => panic!("not a message frame"),
        }
    }

    fn flush(&mut self) -> Poll<(), io::Error> {
        self.inner.flush()
    }
}

/// An "easy" multiplexed server.
///
/// This struct is an implementation of a server which takes a `FramedIo` (`T`)
/// and dispatches all requests to a service (`S`) to be handled. Internally
/// requests are multiplexed and dispatched/written appropriately over time.
///
/// Note that no streaming request/response bodies are supported with this
/// server to help simplify generics and get off the ground running. If
/// streaming bodies are desired then the top level `multiplex::Server` type can
/// be used (which this is built on).
pub struct EasyServer<S, T, I>
    where S: Service<Request = I, Response = T::In, Error = io::Error> + 'static,
          T: FramedIo<Out = Option<(RequestId, I)>> + 'static,
          T::In: 'static,
          I: 'static,
{
    inner: multiplex::Server<MyService<S>,
                             MyTransport<T, I>,
                             Receiver<(), io::Error>>,
}

impl<S, T, I> EasyServer<S, T, I>
    where S: Service<Request = I, Response = T::In, Error = io::Error> + 'static,
          T: FramedIo<Out = Option<(RequestId, I)>> + 'static,
          T::In: 'static,
          I: 'static,
{
    /// Instantiates a new multiplexed server.
    ///
    /// The returned server implements the `Future` trait and is used to
    /// internally drive forward all requests for this given transport. The
    /// `transport` provided is an instance of `FramedIo` where the requests are
    /// dispatched to the `service` provided to get a response to write.
    pub fn new(service: S, transport: T) -> EasyServer<S, T, I> {
        EasyServer {
            inner: multiplex::Server::new(MyService(service),
                                          MyTransport::new(transport)),
        }
    }
}

impl<S, T, I> Future for EasyServer<S, T, I>
    where S: Service<Request = I, Response = T::In, Error = io::Error> + 'static,
          T: FramedIo<Out = Option<(RequestId, I)>> + 'static,
          T::In: 'static,
          I: 'static,
{
    type Item = ();
    type Error = ();

    fn poll(&mut self) -> Poll<(), ()> {
        self.inner.poll()
    }
}

struct MyService<S>(S);

impl<S: Service> Service for MyService<S> {
    type Request = Message<S::Request, Body<(), io::Error>>;
    type Response = Message<S::Response, Receiver<(), S::Error>>;
    type Error = S::Error;
    type Future = MyFuture<S::Future, Receiver<(), S::Error>>;

    fn call(&self, req: Self::Request) -> Self::Future {
        match req {
            Message::WithoutBody(msg) => {
                MyFuture(self.0.call(msg), marker::PhantomData)
            }
            Message::WithBody(..) => panic!("bodies not supported"),
        }
    }

    fn poll_ready(&self) -> Async<()> {
        self.0.poll_ready()
    }
}

struct MyFuture<F, T>(F, marker::PhantomData<fn() -> T>);

impl<F: Future, T> Future for MyFuture<F, T> {
    type Item = Message<F::Item, T>;
    type Error = F::Error;

    fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
        let item = try_ready!(self.0.poll());
        Ok(Message::WithoutBody(item).into())
    }
}
<commit_msg>Write request ids to the framing layer in easy<commit_after>//! An "easy" multiplexing module
//!
//! This module is the same as the top-level `multiplex` module in this crate
//! except that it has no support for streaming bodies. This in turn simplifies
//! a number of generics and allows for protocols to easily get off the ground
//! running.
//!
//! The API surface area of this module is the same as the top-level one, so no
//! new functionality is introduced here. In fact all APIs here are built on top
//! of the `multiplex` module itself, they just simplify the generics in play and
//! such.

use std::io;
use std::marker;

use futures::stream::Receiver;
use futures::{Future, Async, Poll};
use tokio_core::io::FramedIo;
use tokio_core::reactor::Handle;
use tokio_service::Service;

use easy::EasyClient;
use multiplex::{self, RequestId};
use {Message, Body};

/// The "easy" form of connecting a multiplexed client.
///
/// This function takes an instance of the `tokio_core::io::FrameIo` trait as
/// the `frames` argument, a `handle` to the event loop to connect on, and then
/// returns the connected client.
///
/// The client returned implements the `Service` trait. This trait
/// implementation allows sending requests to the transport provided and returns
/// futures to the responses. All requests are automatically multiplexed and
/// managed internally.
pub fn connect<F, T, U>(frames: F, handle: &Handle)
    -> EasyClient<U, T>
    where F: FramedIo<In = (RequestId, U),
                      Out = Option<(RequestId, T)>> + 'static,
          T: 'static,
          U: 'static,
{
    EasyClient {
        inner: multiplex::connect(MyTransport::new(frames), handle),
    }
}

struct MyTransport<F, T, U> {
    inner: F,
    _marker: marker::PhantomData<fn() -> (T, U)>,
}

impl<F, T, U> MyTransport<F, T, U> {
    fn new(f: F) -> MyTransport<F, T, U> {
        MyTransport {
            inner: f,
            _marker: marker::PhantomData,
        }
    }
}

impl<F, T, U> multiplex::Transport for MyTransport<F, T, U>
    where F: FramedIo<In = (RequestId, U),
                      Out = Option<(RequestId, T)>> + 'static,
          T: 'static,
          U: 'static,
{
    type In = U;
    type BodyIn = ();
    type Out = T;
    type BodyOut = ();
    type Error = io::Error;

    fn poll_read(&mut self) -> Async<()> {
        self.inner.poll_read()
    }

    fn read(&mut self) -> Poll<multiplex::Frame<T, (), io::Error>, io::Error> {
        let (id, msg) = match try_ready!(self.inner.read()) {
            Some(msg) => msg,
            None => return Ok(multiplex::Frame::Done.into()),
        };
        Ok(multiplex::Frame::Message {
            message: msg,
            body: false,
            solo: false,
            id: id,
        }.into())
    }

    fn poll_write(&mut self) -> Async<()> {
        self.inner.poll_write()
    }

    fn write(&mut self, req: multiplex::Frame<U, (), io::Error>) -> Poll<(), io::Error> {
        match req {
            multiplex::Frame::Message {
                message,
                id,
                body,
                solo,
            } => {
                assert!(!body, "no bodies allowed");
                assert!(!solo, "solo not supported in easy mode");
                self.inner.write((id, message))
            }
            _ => panic!("not a message frame"),
        }
    }

    fn flush(&mut self) -> Poll<(), io::Error> {
        self.inner.flush()
    }
}

/// An "easy" multiplexed server.
///
/// This struct is an implementation of a server which takes a `FramedIo` (`T`)
/// and dispatches all requests to a service (`S`) to be handled. Internally
/// requests are multiplexed and dispatched/written appropriately over time.
///
/// Note that no streaming request/response bodies are supported with this
/// server to help simplify generics and get off the ground running. If
/// streaming bodies are desired then the top level `multiplex::Server` type can
/// be used (which this is built on).
pub struct EasyServer<S, T, Out, In>
    where S: Service<Request = Out, Response = In, Error = io::Error> + 'static,
          T: FramedIo<In = (RequestId, In),
                      Out = Option<(RequestId, Out)>> + 'static,
          In: 'static,
          Out: 'static,
{
    inner: multiplex::Server<MyService<S>,
                             MyTransport<T, Out, In>,
                             Receiver<(), io::Error>>,
}

impl<S, T, Out, In> EasyServer<S, T, Out, In>
    where S: Service<Request = Out, Response = In, Error = io::Error> + 'static,
          T: FramedIo<In = (RequestId, In),
                      Out = Option<(RequestId, Out)>> + 'static,
          In: 'static,
          Out: 'static,
{
    /// Instantiates a new multiplexed server.
    ///
    /// The returned server implements the `Future` trait and is used to
    /// internally drive forward all requests for this given transport. The
    /// `transport` provided is an instance of `FramedIo` where the requests are
    /// dispatched to the `service` provided to get a response to write.
    pub fn new(service: S, transport: T) -> EasyServer<S, T, Out, In> {
        EasyServer {
            inner: multiplex::Server::new(MyService(service),
                                          MyTransport::new(transport)),
        }
    }
}

impl<S, T, Out, In> Future for EasyServer<S, T, Out, In>
    where S: Service<Request = Out, Response = In, Error = io::Error> + 'static,
          T: FramedIo<In = (RequestId, In),
                      Out = Option<(RequestId, Out)>> + 'static,
          In: 'static,
          Out: 'static,
{
    type Item = ();
    type Error = ();

    fn poll(&mut self) -> Poll<(), ()> {
        self.inner.poll()
    }
}

struct MyService<S>(S);

impl<S: Service> Service for MyService<S> {
    type Request = Message<S::Request, Body<(), io::Error>>;
    type Response = Message<S::Response, Receiver<(), S::Error>>;
    type Error = S::Error;
    type Future = MyFuture<S::Future, Receiver<(), S::Error>>;

    fn call(&self, req: Self::Request) -> Self::Future {
        match req {
            Message::WithoutBody(msg) => {
                MyFuture(self.0.call(msg), marker::PhantomData)
            }
            Message::WithBody(..) => panic!("bodies not supported"),
        }
    }

    fn poll_ready(&self) -> Async<()> {
        self.0.poll_ready()
    }
}

struct MyFuture<F, T>(F, marker::PhantomData<fn() -> T>);

impl<F: Future, T> Future for MyFuture<F, T> {
    type Item = Message<F::Item, T>;
    type Error = F::Error;

    fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
        let item = try_ready!(self.0.poll());
        Ok(Message::WithoutBody(item).into())
    }
}
<|endoftext|>