<commit_before>
#[macro_use]
extern crate glium;
use glium::glutin;

use std::collections::HashMap;

#[macro_use]
mod support;

pub enum Shape {
    Clear([f32; 4]),
    Rectangle(f32, f32, f32, f32, [f32; 4]),
    Triangle(f32, f32, f32, f32, f32, f32, [f32; 4]),
    Line(f32, f32, f32, f32, [f32; 4]),
}

pub struct Window {
    display: glium::Display,
    events_loop: glium::glutin::EventsLoop,
    color: [f32; 4],
    shapes: Vec<Shape>,
    keys: HashMap<glutin::VirtualKeyCode, bool>,
}

impl Window {
    pub fn new(title: &str, width: u32, height: u32) -> Self {
        let events_loop = glutin::EventsLoop::new();
        let window = glutin::WindowBuilder::new()
            .with_title(title)
            .with_dimensions(width, height);
        let context = glutin::ContextBuilder::new();
        let display = glium::Display::new(window, context, &events_loop).unwrap();

        Window {
            display: display,
            events_loop: events_loop,
            color: [1.0, 1.0, 1.0, 1.0],
            shapes: Vec::new(),
            keys: HashMap::new(),
        }
    }

    pub fn start_loop<F>(&mut self, mut callback: F)
    where
        F: FnMut(&mut Window, f32) -> support::Action,
    {
        let program = support::shaders::load_program(&self.display).unwrap();

        use glium::Surface;
        support::start_loop(|delta| {

            let mut target = self.display.draw();
            target.clear_color(0.0, 0.0, 0.0, 1.0);

            let mut rtn = callback(self, delta);
            // for shape in self.shapes.iter() {
            //     match shape {
            //         Shape::Clear(color) => {
            //             target.clear_color(color[0], color[1], color[2], color[3])
            //         }
            //         Shape::Rectangle(x1, y1, x2, y2, color) => {
            //             let vert_buff = support::buffer::rectangle_vert_buff(
            //                 &self.display,
            //                 x1,
            //                 x2,
            //                 y1,
            //                 y2,
            //                 self.color,
            //             ).unwrap();
            //             let indices =
            //                 glium::index::NoIndices(glium::index::PrimitiveType::TriangleStrip);
            //             target
            //                 .draw(
            //                     &vert_buff,
            //                     &indices,
            //                     &program,
            //                     &glium::uniforms::EmptyUniforms,
            //                     &Default::default(),
            //                 )
            //                 .unwrap();
            //         }
            //         Shape::Line(x1, y1, x2, y2, color) => {
            //             let vert_buff = support::buffer::line_vert_buff(
            //                 &self.display,
            //                 x1,
            //                 x2,
            //                 y1,
            //                 y2,
            //                 self.color,
            //             ).unwrap();
            //             let indices =
            //                 glium::index::NoIndices(glium::index::PrimitiveType::LineStrip);
            //             target
            //                 .draw(
            //                     &vert_buff,
            //                     &indices,
            //                     &program,
            //                     &glium::uniforms::EmptyUniforms,
            //                     &Default::default(),
            //                 )
            //                 .unwrap();
            //         }
            //         Shape::Triangle(x1, y1, x2, y2, x3, y3, color) => {
            //             let vert_buff = support::buffer::triangle_vert_buff(
            //                 &self.display,
            //                 x1,
            //                 x2,
            //                 y1,
            //                 y2,
            //                 x3,
            //                 y3,
            //                 self.color,
            //             ).unwrap();
            //             let indices =
            //                 glium::index::NoIndices(glium::index::PrimitiveType::TrianglesList);
            //             target
            //                 .draw(
            //                     &vert_buff,
            //                     &indices,
            //                     &program,
            //                     &glium::uniforms::EmptyUniforms,
            //                     &Default::default(),
            //                 )
            //                 .unwrap();
            //         }
            //     }
            // }
            self.shapes.clear();

            target.finish().unwrap();

            self.events_loop.poll_events(|ev| match ev {
                glium::glutin::Event::WindowEvent { event, .. } => {
                    match event {
                        glutin::WindowEvent::Closed => rtn = support::Action::Stop,
                        glutin::WindowEvent::KeyboardInput { input, .. } => {
                            match input.virtual_keycode {
                                Some(key) => {
                                    // self.keys.insert(
                                    //     key,
                                    //     match input.state {
                                    //         glutin::ElementState::Pressed => true,
                                    //         glutin::ElementState::Released => false,
                                    //     },
                                    // );
                                }
                                None => (),
                            }
                        }
                        _ => (),
                    }
                }
                _ => (),
            });

            rtn
        });
    }

    pub fn clear_color(&mut self, red: f32, green: f32, blue: f32, alpha: f32) {
        let shape = Shape::Clear([red, green, blue, alpha]);
        self.shapes.push(shape);
    }

    pub fn set_color(&mut self, red: f32, green: f32, blue: f32, alpha: f32) {
        self.color = [red, green, blue, alpha];
    }

    pub fn draw_rect(&mut self, x: f32, y: f32, width: f32, height: f32) {
        let shape = Shape::Rectangle(x, y, x + width, y + height, self.color);
        self.shapes.push(shape);
    }

    pub fn draw_triangle(
        &mut self,
        x1: f32,
        y1: f32,
        x2: f32,
        y2: f32,
        x3: f32,
        y3: f32,
        width: f32,
    ) {
        let shape = Shape::Triangle(x1, y1, x2, y2, x3, y3, self.color);
        self.shapes.push(shape);
    }

    pub fn draw_line(&mut self, x1: f32, y1: f32, x2: f32, y2: f32) {
        let shape = Shape::Line(x1, y1, x2, y2, self.color);
        self.shapes.push(shape);
    }
}

fn main() {
    let mut window = Window::new("Hello World", 640, 480);

    window.start_loop(|app, delta| {
        app.clear_color(0.0, 0.0, 0.0, 1.0);
        support::Action::Continue
    });
}
<commit_msg>Added basic render system<commit_after>#[macro_use]
extern crate glium;
use glium::glutin;

use std::collections::HashMap;

#[macro_use]
mod support;

enum Shape {
    Clear([f32; 4]),
    Rectangle(f32, f32, f32, f32, [f32; 4]),
    Triangle(f32, f32, f32, f32, f32, f32, [f32; 4]),
    Line(f32, f32, f32, f32, [f32; 4]),
}

pub struct Window {
    display: glium::Display,
    events_loop: glium::glutin::EventsLoop,
    color: [f32; 4],
    shapes: Vec<Shape>,
    keys: HashMap<glutin::VirtualKeyCode, bool>,
}

impl Window {
    pub fn new(title: &str, width: u32, height: u32) -> Self {
        let events_loop = glutin::EventsLoop::new();
        let window = glutin::WindowBuilder::new()
            .with_title(title)
            .with_dimensions(width, height);
        let context = glutin::ContextBuilder::new();
        let display = glium::Display::new(window, context, &events_loop).unwrap();

        Window {
            display: display,
            events_loop: events_loop,
            color: [1.0, 1.0, 1.0, 1.0],
            shapes: Vec::new(),
            keys: HashMap::new(),
        }
    }

    pub fn start_loop<F>(&mut self, mut callback: F)
    where
        F: FnMut(&mut Window, f32) -> support::Action,
    {
        let program = support::shaders::load_program(&self.display).unwrap();

        use glium::Surface;
        support::start_loop(|delta| {

            let mut target = self.display.draw();

            let mut rtn = callback(self, delta);
            for shape in self.shapes.iter() {
                match shape {
                    &Shape::Clear(color) => {
                        target.clear_color(color[0], color[1], color[2], color[3])
                    }
                    &Shape::Rectangle(x1, y1, x2, y2, color) => {
                        let vert_buff = support::buffer::rectangle_vert_buff(
                            &self.display,
                            x1,
                            y1,
                            x2,
                            y2,
                            color,
                        ).unwrap();
                        let indices =
                            glium::index::NoIndices(glium::index::PrimitiveType::TriangleStrip);
                        target
                            .draw(
                                &vert_buff,
                                &indices,
                                &program,
                                &glium::uniforms::EmptyUniforms,
                                &Default::default(),
                            )
                            .unwrap();
                    }
                    &Shape::Line(x1, y1, x2, y2, color) => {
                        let vert_buff =
                            support::buffer::line_vert_buff(&self.display, x1, y1, x2, y2, color)
                                .unwrap();
                        let indices =
                            glium::index::NoIndices(glium::index::PrimitiveType::LineStrip);
                        target
                            .draw(
                                &vert_buff,
                                &indices,
                                &program,
                                &glium::uniforms::EmptyUniforms,
                                &Default::default(),
                            )
                            .unwrap();
                    }
                    &Shape::Triangle(x1, y1, x2, y2, x3, y3, color) => {
                        let vert_buff = support::buffer::triangle_vert_buff(
                            &self.display,
                            x1,
                            y1,
                            x2,
                            y2,
                            x3,
                            y3,
                            color,
                        ).unwrap();
                        let indices =
                            glium::index::NoIndices(glium::index::PrimitiveType::TrianglesList);
                        target
                            .draw(
                                &vert_buff,
                                &indices,
                                &program,
                                &glium::uniforms::EmptyUniforms,
                                &Default::default(),
                            )
                            .unwrap();
                    }
                }
            }

            self.shapes.clear();

            target.finish().unwrap();

            let mut keys: HashMap<glutin::VirtualKeyCode, bool> = HashMap::new();
            self.events_loop.poll_events(|ev| match ev {
                glium::glutin::Event::WindowEvent { event, .. } => {
                    match event {
                        glutin::WindowEvent::Closed => rtn = support::Action::Stop,
                        glutin::WindowEvent::KeyboardInput { input, .. } => {
                            match input.virtual_keycode {
                                Some(key) => {
                                    keys.insert(
                                        key,
                                        match input.state {
                                            glutin::ElementState::Pressed => true,
                                            glutin::ElementState::Released => false,
                                        },
                                    );
                                }
                                None => (),
                            }
                        }
                        _ => (),
                    }
                }
                _ => (),
            });

            for (key, value) in keys {
                self.keys.insert(key, value);
            }

            rtn
        });
    }

    pub fn clear_color(&mut self, red: f32, green: f32, blue: f32, alpha: f32) {
        let shape = Shape::Clear([red, green, blue, alpha]);
        self.shapes.push(shape);
    }

    pub fn set_color(&mut self, red: f32, green: f32, blue: f32, alpha: f32) {
        self.color = [red, green, blue, alpha];
    }

    pub fn draw_rect(&mut self, x: f32, y: f32, width: f32, height: f32) {
        let shape = Shape::Rectangle(x, y, x + width, y + height, self.color);
        self.shapes.push(shape);
    }

    pub fn draw_triangle(&mut self, x1: f32, y1: f32, x2: f32, y2: f32, x3: f32, y3: f32) {
        let shape = Shape::Triangle(x1, y1, x2, y2, x3, y3, self.color);
        self.shapes.push(shape);
    }

    pub fn draw_line(&mut self, x1: f32, y1: f32, x2: f32, y2: f32) {
        let shape = Shape::Line(x1, y1, x2, y2, self.color);
        self.shapes.push(shape);
    }
}

fn main() {
    let mut window = Window::new("Hello World", 640, 480);

    window.start_loop(|app, delta| {
        app.clear_color(0.1, 0.3, 0.2, 1.0);

        app.set_color(0.3, 0.1, 0.2, 1.0);
        app.draw_rect(0.0, 0.0, 10.0, 10.0);

        app.set_color(1.0, 0.0, 0.0, 1.0);
        app.draw_line(0.0, 0.0, 1.0, 1.0);

        app.set_color(0.0, 0.0, 1.0, 0.1);
        app.draw_triangle(0.0, 0.0, 1.0, 1.0, 1.0, 0.0);

        support::Action::Continue
    });
}
<|endoftext|>


<commit_before>//! # Hexdino
//!
//! A hex editor with vim like keybindings written in Rust.

#![doc(html_logo_url = "https://raw.githubusercontent.com/Luz/hexdino/master/logo.png")]

use std::io::prelude::*;
use std::fs::OpenOptions;
use std::io::SeekFrom;
use std::path::Path;
use std::error::Error;
use std::env;

mod draw;
mod find;
use draw::draw;
use find::FindSubset;

extern crate ncurses;
use ncurses::*;

// extern crate getopts;
// use getopts::Options;

#[derive(PartialEq, Copy, Clone)]
pub enum Mode {
    Command,
    Replace,
    TypeCommand,
    Insert,
    TypeSearch,
    SearchIt,
    SearchItHex,
}

fn main() {
    let mut buf = vec![];
    let mut cursorpos: usize = 0;
    // 0 is left nibble, 1 is right nibble, 2 is ascii
    let mut cursorstate: usize = 0;
    // 0 = display data from first line of file
    let mut screenoffset: usize = 0;
    const SPALTEN: usize = 16;
    let mut command = String::new();

    // start ncursesw
    initscr();
    let screenheight: usize = getmaxy(stdscr) as usize;
    // ctrl+z and fg works with this
    cbreak();
    noecho();
    start_color();
    init_pair(1, COLOR_GREEN, COLOR_BLACK);

    printw("Welcome to Hexdino.\nPlease find the any-key on your keyboard and press it.\n");

    let args: Vec<_> = env::args().collect();
    // let program = args[0].clone();
    // let mut opts = Options::new();
    // opts.optopt("f", "", "set file name", "NAME");
    // opts.optflag("h", "help", "print this help menu");
    //
    // let matches = match opts.parse(&args[1..]) {
    // Ok(m) => { m }
    // Err(f) => { panic!(f.to_string()) }
    // };
    // if matches.opt_present("h") {
    // let brief = format!("Usage: {} FILE [options]", program);
    // print!("{}", opts.usage(&brief));
    // return;
    // }
    // let path = if !matches.free.is_empty() {
    // matches.free[0].clone()
    // } else {
    // let brief = format!("Usage: {} FILE [options]", program);
    // print!("{}", opts.usage(&brief));
    // return;
    // };

    let path = if args.len() > 1 {
        printw(&format!("Opening file {}", args[1]));
        args[1].clone()
    } else {
        printw(&format!("No file specified. Trying to open foo.txt"));
        "foo.txt".into()
    };

    let path = Path::new(&path);
    let display = path.display();

    getch();
    clear();

    if !has_colors() {
        endwin();
        println!("Your terminal does not support color!\n");
        return;
    }

    // TODO in this order: 1)disp files 2) hjkl movement 3) edit file by 'r' 4) save file 5) edit file by 'x, i' 6) search by '/'

    let mut file = match OpenOptions::new().read(true).write(true).create(true).open(&path) {
        Err(why) => panic!("couldn't open {}: {}", display, Error::description(&why)),
        Ok(file) => file,
    };

    file.read_to_end(&mut buf).ok().expect("File could not be read.");

    let mut mode = Mode::Command;

    draw(&buf,
         cursorpos,
         SPALTEN,
         mode,
         &command,
         cursorstate,
         screenoffset);

    let mut key;
    //    key = getch() as u8;
    //    printw(&format!("{:?}", key));

    let mut quitnow = 0;
    while quitnow == 0 {
        key = getch() as u8;
        if mode == Mode::Command {
            match key as char {
                'h' => {
                    if cursorstate == 2 {
                        // ascii mode
                        if cursorpos > 0 {
                            // not at start
                            cursorpos -= 1; // go left
                        }
                    } else if cursorstate == 1 {
                        // hex mode, right nibble
                        cursorstate = 0; // left nibble
                    } else if cursorstate == 0 {
                        // hex mode, left nibble
                        if cursorpos > 0 {
                            // not at start
                            cursorstate = 1; // right nibble
                            cursorpos -= 1; // go left
                        }
                    }
                }
                'j' => {
                    if cursorpos + SPALTEN < buf.len() {
                        // not at end
                        cursorpos += SPALTEN; // go down
                    } else {
                        // when at end
                        if buf.len() != 0 {
                            // Suppress underflow
                            cursorpos = buf.len() - 1; // go to end
                        }
                    }
                }
                'k' => {
                    if cursorpos >= SPALTEN {
                        cursorpos -= SPALTEN;
                    }
                }
                'l' => {
                    if cursorstate == 2 {
                        // ascii mode
                        if cursorpos + 1 < buf.len() {
                            // not at end
                            cursorpos += 1; // go right
                        }
                    } else if cursorstate == 0 {
                        // hex mode, left nibble
                        cursorstate = 1; // right nibble
                    } else if cursorstate == 1 {
                        // hex mode, right nibble
                        if cursorpos + 1 < buf.len() {
                            // not at end
                            cursorstate = 0; // left nibble
                            cursorpos += 1; // go right
                        }
                    }
                }
                '0' => {
                    cursorpos -= cursorpos % SPALTEN; // jump to start of line
                    if cursorstate == 1 {
                        // hex mode, right nibble
                        cursorstate = 0; // left nibble
                    }
                }
                '$' => {
                    if cursorpos - (cursorpos % SPALTEN) + (SPALTEN - 1) < buf.len() {
                        // check if no overflow
                        cursorpos = cursorpos - (cursorpos % SPALTEN) + (SPALTEN - 1); // jump to end of line
                    } else {
                        cursorpos = buf.len() - 1 // jump to end of line
                    }
                    if cursorstate == 0 {
                        // hex mode, left nibble
                        cursorstate = 1; // right nibble
                    }
                }
                'r' => {
                    mode = Mode::Replace;
                }
                'x' => {
                    if buf.len() > 0 {
                        // remove the current char
                        buf.remove(cursorpos);
                        if cursorpos >= buf.len() && cursorpos > 0 {
                            cursorpos -= 1;
                        }
                    }
                }
                'i' => {
                    mode = Mode::Insert;
                }
                ':' => {
                    command.clear(); // delete old command
                    mode = Mode::TypeCommand;
                }
                'J' => {
                    if cursorstate == 2 {
                        // ascii mode
                        cursorstate = 0; // hex mode, left nibble
                    } else {
                        cursorstate = 2; // jump to ascii
                    }
                }
                '?' => {
                    // TODO
                    command.push_str("No helpfile yet");
                }
                '/' => {
                    // TODO
                    command.clear();
                    mode = Mode::TypeSearch;
                }
                _ => (),
            }

            // Always move screen when cursor leaves screen
            if cursorpos > (screenheight + screenoffset - 1) * SPALTEN - 1 {
                screenoffset += 1; // move screen
            }
            if cursorpos < screenoffset * SPALTEN {
                screenoffset -= 1; // move screen
            }

        } else if mode == Mode::Replace && cursorstate == 2 {
            // r was pressed so replace next char in ascii mode
            if cursorpos >= buf.len() {
                buf.insert(cursorpos, 0 );
            }
            match key {
                c @ 32...126 => buf[cursorpos] = c,
                _ => (),
            }
            mode = Mode::Command;
        } else if mode == Mode::Replace {
            let mask = if cursorstate == 0 { 0x0F } else { 0xF0 };
            let shift = if cursorstate == 0 { 4 } else { 0 };
            if cursorpos >= buf.len() {
                buf.insert(cursorpos, 0 );
            }
            // Change the selected nibble
            if let Some(c) = (key as char).to_digit(16) {
                buf[cursorpos] = buf[cursorpos] & mask | (c as u8) << shift;
            }
            mode = Mode::Command;
        } else if mode == Mode::TypeCommand {
            match key {
                c @ 32...126 => {
                    command.push(c as char);
                }
                27 => {
                    command.clear();
                    mode = Mode::Command;
                }
                10 => {
                    // Enter pressed, compute command!
                    if (command == "w".to_string()) || (command == "wq".to_string()) {
                        file.seek(SeekFrom::Start(0))
                            .ok()
                            .expect("Filepointer could not be set to 0");
                        file.write_all(&mut buf).ok().expect("File could not be written.");
												file.set_len(buf.len() as u64).ok().expect("File could not be set to correct lenght.");
                        if command == "wq".to_string() {
                            quitnow = 1;
                        }
                        command.clear();
                        mode = Mode::Command;
                    } else if command == "q".to_string() {
                        quitnow = 1;
                    } else {
                        command.clear();
                        command.push_str("Bad_command!");
                        mode = Mode::Command;
                    }
                }
                _ => (),
            }
        } else if mode == Mode::Insert {
            if cursorstate == 0 {
                // Left nibble
                if let Some(c) = (key as char).to_digit(16) {
                    buf.insert(cursorpos, (c as u8) << 4); cursorstate = 1;
                }
                if key == 27 {mode = Mode::Command;};
            } else if cursorstate == 1 {
                // Right nibble
                if cursorpos == buf.len() {
                    buf.insert(cursorpos, 0 );
                }
                if let Some(c) = (key as char).to_digit(16) {
                    buf[cursorpos] = buf[cursorpos]&0xF0 | c as u8; cursorstate = 0; cursorpos+=1;
                }
                if key == 27 {mode = Mode::Command;};
            } else if cursorstate == 2 {
                // Ascii
                match key {
                    c @ 32...126 => {
                        buf.insert(cursorpos, c);
                        cursorpos += 1;
                    }
                    27 => {
                        mode = Mode::Command;
                    }
                    _ => (),
                }
            }
        } else if mode == Mode::TypeSearch {
            //            if cursorstate == 2 { // Ascii search
            match key {
                c @ 32...126 => {
                    command.push(c as char);
                }
                27 => {
                    command.clear();
                    mode = Mode::Command;
                }
                10 => {
                    // Enter pressed, compute command!
                    if cursorstate == 2 {
                        mode = Mode::SearchIt;
                    } else {
                        mode = Mode::SearchItHex;
                    }
                }
                _ => (),
            }
            //            }

            if mode == Mode::SearchIt {
                let search = command.as_bytes();
                cursorpos = buf.find_subset(&search).unwrap_or(cursorpos);
                mode = Mode::Command;
                // command.push_str("Bad_command!");
            }
            if mode == Mode::SearchItHex {
                // TODO
                mode = Mode::Command;
                command.push_str("Hex search not yet implemented!");
            }
        }
        draw(&buf,
             cursorpos,
             SPALTEN,
             mode,
             &command,
             cursorstate,
             screenoffset);
    }

    refresh();
    endwin();
}
<commit_msg>Remove welcome message to increase working speed<commit_after>//! # Hexdino
//!
//! A hex editor with vim like keybindings written in Rust.

#![doc(html_logo_url = "https://raw.githubusercontent.com/Luz/hexdino/master/logo.png")]

use std::io::prelude::*;
use std::fs::OpenOptions;
use std::io::SeekFrom;
use std::path::Path;
use std::error::Error;
use std::env;

mod draw;
mod find;
use draw::draw;
use find::FindSubset;

extern crate ncurses;
use ncurses::*;

// extern crate getopts;
// use getopts::Options;

#[derive(PartialEq, Copy, Clone)]
pub enum Mode {
    Command,
    Replace,
    TypeCommand,
    Insert,
    TypeSearch,
    SearchIt,
    SearchItHex,
}

fn main() {
    let mut buf = vec![];
    let mut cursorpos: usize = 0;
    // 0 is left nibble, 1 is right nibble, 2 is ascii
    let mut cursorstate: usize = 0;
    // 0 = display data from first line of file
    let mut screenoffset: usize = 0;
    const SPALTEN: usize = 16;
    let mut command = String::new();

    // start ncursesw
    initscr();
    let screenheight: usize = getmaxy(stdscr) as usize;
    // ctrl+z and fg works with this
    cbreak();
    noecho();
    start_color();
    init_pair(1, COLOR_GREEN, COLOR_BLACK);

    let args: Vec<_> = env::args().collect();
    // let program = args[0].clone();
    // let mut opts = Options::new();
    // opts.optopt("f", "", "set file name", "NAME");
    // opts.optflag("h", "help", "print this help menu");
    //
    // let matches = match opts.parse(&args[1..]) {
    // Ok(m) => { m }
    // Err(f) => { panic!(f.to_string()) }
    // };
    // if matches.opt_present("h") {
    // let brief = format!("Usage: {} FILE [options]", program);
    // print!("{}", opts.usage(&brief));
    // return;
    // }
    // let path = if !matches.free.is_empty() {
    // matches.free[0].clone()
    // } else {
    // let brief = format!("Usage: {} FILE [options]", program);
    // print!("{}", opts.usage(&brief));
    // return;
    // };

    let path = if args.len() > 1 {
        command.push_str(&format!("\"{}\"", args[1]));
        args[1].clone()
    } else {
        command.push_str(&format!("No file specified. Trying to open foo.txt"));
        "foo.txt".into()
    };

    let path = Path::new(&path);
    let display = path.display();

    if !has_colors() {
        endwin();
        println!("Your terminal does not support color!\n");
        return;
    }

    // TODO in this order: 1)disp files 2) hjkl movement 3) edit file by 'r' 4) save file 5) edit file by 'x, i' 6) search by '/'

    let mut file = match OpenOptions::new().read(true).write(true).create(true).open(&path) {
        Err(why) => panic!("couldn't open {}: {}", display, Error::description(&why)),
        Ok(file) => file,
    };

    file.read_to_end(&mut buf).ok().expect("File could not be read.");

    let mut mode = Mode::Command;

    draw(&buf,
         cursorpos,
         SPALTEN,
         mode,
         &command,
         cursorstate,
         screenoffset);

    let mut key;
    //    key = getch() as u8;
    //    printw(&format!("{:?}", key));

    let mut quitnow = 0;
    while quitnow == 0 {
        key = getch() as u8;
        if mode == Mode::Command {
            match key as char {
                'h' => {
                    if cursorstate == 2 {
                        // ascii mode
                        if cursorpos > 0 {
                            // not at start
                            cursorpos -= 1; // go left
                        }
                    } else if cursorstate == 1 {
                        // hex mode, right nibble
                        cursorstate = 0; // left nibble
                    } else if cursorstate == 0 {
                        // hex mode, left nibble
                        if cursorpos > 0 {
                            // not at start
                            cursorstate = 1; // right nibble
                            cursorpos -= 1; // go left
                        }
                    }
                }
                'j' => {
                    if cursorpos + SPALTEN < buf.len() {
                        // not at end
                        cursorpos += SPALTEN; // go down
                    } else {
                        // when at end
                        if buf.len() != 0 {
                            // Suppress underflow
                            cursorpos = buf.len() - 1; // go to end
                        }
                    }
                }
                'k' => {
                    if cursorpos >= SPALTEN {
                        cursorpos -= SPALTEN;
                    }
                }
                'l' => {
                    if cursorstate == 2 {
                        // ascii mode
                        if cursorpos + 1 < buf.len() {
                            // not at end
                            cursorpos += 1; // go right
                        }
                    } else if cursorstate == 0 {
                        // hex mode, left nibble
                        cursorstate = 1; // right nibble
                    } else if cursorstate == 1 {
                        // hex mode, right nibble
                        if cursorpos + 1 < buf.len() {
                            // not at end
                            cursorstate = 0; // left nibble
                            cursorpos += 1; // go right
                        }
                    }
                }
                '0' => {
                    cursorpos -= cursorpos % SPALTEN; // jump to start of line
                    if cursorstate == 1 {
                        // hex mode, right nibble
                        cursorstate = 0; // left nibble
                    }
                }
                '$' => {
                    if cursorpos - (cursorpos % SPALTEN) + (SPALTEN - 1) < buf.len() {
                        // check if no overflow
                        cursorpos = cursorpos - (cursorpos % SPALTEN) + (SPALTEN - 1); // jump to end of line
                    } else {
                        cursorpos = buf.len() - 1 // jump to end of line
                    }
                    if cursorstate == 0 {
                        // hex mode, left nibble
                        cursorstate = 1; // right nibble
                    }
                }
                'r' => {
                    mode = Mode::Replace;
                }
                'x' => {
                    if buf.len() > 0 {
                        // remove the current char
                        buf.remove(cursorpos);
                        if cursorpos >= buf.len() && cursorpos > 0 {
                            cursorpos -= 1;
                        }
                    }
                }
                'i' => {
                    mode = Mode::Insert;
                }
                ':' => {
                    command.clear(); // delete old command
                    mode = Mode::TypeCommand;
                }
                'J' => {
                    if cursorstate == 2 {
                        // ascii mode
                        cursorstate = 0; // hex mode, left nibble
                    } else {
                        cursorstate = 2; // jump to ascii
                    }
                }
                '?' => {
                    // TODO
                    command.push_str("No helpfile yet");
                }
                '/' => {
                    // TODO
                    command.clear();
                    mode = Mode::TypeSearch;
                }
                _ => (),
            }

            // Always move screen when cursor leaves screen
            if cursorpos > (screenheight + screenoffset - 1) * SPALTEN - 1 {
                screenoffset += 1; // move screen
            }
            if cursorpos < screenoffset * SPALTEN {
                screenoffset -= 1; // move screen
            }

        } else if mode == Mode::Replace && cursorstate == 2 {
            // r was pressed so replace next char in ascii mode
            if cursorpos >= buf.len() {
                buf.insert(cursorpos, 0 );
            }
            match key {
                c @ 32...126 => buf[cursorpos] = c,
                _ => (),
            }
            mode = Mode::Command;
        } else if mode == Mode::Replace {
            let mask = if cursorstate == 0 { 0x0F } else { 0xF0 };
            let shift = if cursorstate == 0 { 4 } else { 0 };
            if cursorpos >= buf.len() {
                buf.insert(cursorpos, 0 );
            }
            // Change the selected nibble
            if let Some(c) = (key as char).to_digit(16) {
                buf[cursorpos] = buf[cursorpos] & mask | (c as u8) << shift;
            }
            mode = Mode::Command;
        } else if mode == Mode::TypeCommand {
            match key {
                c @ 32...126 => {
                    command.push(c as char);
                }
                27 => {
                    command.clear();
                    mode = Mode::Command;
                }
                10 => {
                    // Enter pressed, compute command!
                    if (command == "w".to_string()) || (command == "wq".to_string()) {
                        file.seek(SeekFrom::Start(0))
                            .ok()
                            .expect("Filepointer could not be set to 0");
                        file.write_all(&mut buf).ok().expect("File could not be written.");
                        file.set_len(buf.len() as u64).ok().expect("File could not be set to correct lenght.");
                        if command == "wq".to_string() {
                            quitnow = 1;
                        }
                        command.clear();
                        mode = Mode::Command;
                    } else if command == "q".to_string() {
                        quitnow = 1;
                    } else {
                        command.clear();
                        command.push_str("Bad_command!");
                        mode = Mode::Command;
                    }
                }
                _ => (),
            }
        } else if mode == Mode::Insert {
            if cursorstate == 0 {
                // Left nibble
                if let Some(c) = (key as char).to_digit(16) {
                    buf.insert(cursorpos, (c as u8) << 4); cursorstate = 1;
                }
                if key == 27 {mode = Mode::Command;};
            } else if cursorstate == 1 {
                // Right nibble
                if cursorpos == buf.len() {
                    buf.insert(cursorpos, 0 );
                }
                if let Some(c) = (key as char).to_digit(16) {
                    buf[cursorpos] = buf[cursorpos]&0xF0 | c as u8; cursorstate = 0; cursorpos+=1;
                }
                if key == 27 {mode = Mode::Command;};
            } else if cursorstate == 2 {
                // Ascii
                match key {
                    c @ 32...126 => {
                        buf.insert(cursorpos, c);
                        cursorpos += 1;
                    }
                    27 => {
                        mode = Mode::Command;
                    }
                    _ => (),
                }
            }
        } else if mode == Mode::TypeSearch {
            //            if cursorstate == 2 { // Ascii search
            match key {
                c @ 32...126 => {
                    command.push(c as char);
                }
                27 => {
                    command.clear();
                    mode = Mode::Command;
                }
                10 => {
                    // Enter pressed, compute command!
                    if cursorstate == 2 {
                        mode = Mode::SearchIt;
                    } else {
                        mode = Mode::SearchItHex;
                    }
                }
                _ => (),
            }
            //            }

            if mode == Mode::SearchIt {
                let search = command.as_bytes();
                cursorpos = buf.find_subset(&search).unwrap_or(cursorpos);
                mode = Mode::Command;
                // command.push_str("Bad_command!");
            }
            if mode == Mode::SearchItHex {
                // TODO
                mode = Mode::Command;
                command.push_str("Hex search not yet implemented!");
            }
        }
        draw(&buf,
             cursorpos,
             SPALTEN,
             mode,
             &command,
             cursorstate,
             screenoffset);
    }

    refresh();
    endwin();
}
<|endoftext|>


<commit_before>#[macro_use]
extern crate log;
extern crate pretty_env_logger;
extern crate clap;
extern crate libmodbus_rs;
extern crate iron;
extern crate router;
extern crate staticfile;
extern crate serde;
#[macro_use]
extern crate serde_derive;
extern crate serde_json;
extern crate ctrlc;
extern crate retry;
extern crate hex_slice;
#[macro_use]
extern crate enum_primitive;
#[macro_use]
extern crate bitflags;

use std::fs;
use std::path::Path;
use std::os::unix::fs::FileTypeExt;
use std::sync::{Arc, Mutex};
use std::convert::From;
use std::sync::atomic::{AtomicBool, Ordering};

use clap::{App, Arg};

use iron::Iron;
use iron::prelude::*;
use iron::status;
use iron::middleware::Handler;
use iron::headers::{AccessControlAllowMethods, AccessControlAllowOrigin};
use iron::method::Method;
use iron::mime::Mime;
use router::Router;
use staticfile::Static;

mod sunsaver_connection;
use sunsaver_connection::{SunSaverConnection, FileSunSaverConnection, ModbusSunSaverConnection};
mod sunsaver;
use sunsaver::{SunSaverResponse, ChargeState, ArrayFault, LoggedResponse, LoggedResponseDay};

#[derive(Debug, Clone, Serialize)]
struct ApiStatusResponse {
    generation: ApiStatusResponseGeneration,
    storage: ApiStatusResponseStorage,
    load: ApiStatusResponseLoad,
    temperature: ApiStatusResponseTemperature,
    faults: ApiStatusResponseFaults,
}

#[derive(Debug, Clone, Serialize)]
struct ApiStatusResponseGeneration {
    solar_input_voltage_filtered: f32,
    calculated_generation_power: f32,
}

#[derive(Debug, Clone, Serialize)]
struct ApiStatusResponseStorage {
    battery_voltage_filtered: f32,
    battery_charge_current_filtered: f32,
    battery_charge_power_calculated: f32,
    charge_state: ChargeState,
}

#[derive(Debug, Clone, Serialize)]
struct ApiStatusResponseLoad {
    load_voltage_filtered: f32,
    load_current_filtered: f32,
    load_power_calculated: f32,
}

#[derive(Debug, Clone, Serialize)]
struct ApiStatusResponseTemperature {
    heatsink_temperature: i8,
    battery_temperature: i8,
    ambient_temperature: i8,
    remote_temperature: i8,
}

#[derive(Debug, Clone, Serialize)]
struct ApiStatusResponseFaults {
    array_fault: ArrayFault,
}

impl From<SunSaverResponse> for ApiStatusResponse {
    fn from(response: SunSaverResponse) -> Self {
        let battery_voltage_filtered = response.battery_voltage_filtered();
        let battery_charge_current_filtered = response.battery_charge_current_filtered();
        let load_voltage_filtered = response.load_voltage_filtered();
        let load_current_filtered = response.load_current_filtered();
        let solar_input_voltage_filtered = response.solar_input_voltage_filtered();

        let generation = ApiStatusResponseGeneration {
            solar_input_voltage_filtered: solar_input_voltage_filtered,
            calculated_generation_power: (load_current_filtered + battery_charge_current_filtered) * solar_input_voltage_filtered,
        };
        let storage = ApiStatusResponseStorage {
            battery_voltage_filtered: battery_voltage_filtered,
            battery_charge_current_filtered: battery_charge_current_filtered,
            battery_charge_power_calculated: battery_voltage_filtered * battery_charge_current_filtered,
            charge_state: response.charge_state(),
        };
        let load = ApiStatusResponseLoad {
            load_voltage_filtered: load_voltage_filtered,
            load_current_filtered: load_current_filtered,
            load_power_calculated: load_voltage_filtered * load_current_filtered,
        };
        let temperature = ApiStatusResponseTemperature {
            heatsink_temperature: response.heatsink_temperature(),
            battery_temperature: response.battery_temperature(),
            ambient_temperature: response.ambient_temperature(),
            remote_temperature: response.remote_temperature(),
        };
        let faults = ApiStatusResponseFaults {
            array_fault: response.array_fault(),
        };
        ApiStatusResponse {
            generation: generation,
            storage: storage,
            load: load,
            temperature: temperature,
            faults: faults,
        }
    }
}

#[derive(Debug, Clone, Serialize)]
struct ApiLoggedResponse {
    days: Vec<ApiLoggedDayResponse>,
}

#[derive(Debug, Clone, Serialize)]
struct ApiLoggedDayResponse {
    hourmeter: u32,
    battery_voltage_min: f32,
    battery_voltage_max: f32,
    battery_charge_daily: f32,
    load_charge_daily: f32,
    array_voltage_max: f32,
}

impl From<LoggedResponse> for ApiLoggedResponse {
    fn from(response: LoggedResponse) -> Self {
        let days = response.days.into_iter().map(ApiLoggedDayResponse::from).collect();
        ApiLoggedResponse {
            days: days,
        }
    }
}

impl From<LoggedResponseDay> for ApiLoggedDayResponse {
    fn from(response: LoggedResponseDay) -> Self {
        ApiLoggedDayResponse {
            hourmeter: response.hourmeter,
            battery_voltage_min: response.battery_voltage_min(),
            battery_voltage_max: response.battery_voltage_max(),
            battery_charge_daily: response.battery_charge_daily(),
            load_charge_daily: response.load_charge_daily(),
            array_voltage_max: response.array_voltage_max(),
        }
    }
}

#[derive(Clone)]
struct ApiHandler {
    connection: Arc<Mutex<Box<SunSaverConnection>>>,
}

impl ApiHandler {
    fn new(connection: Box<SunSaverConnection>) -> ApiHandler {
        ApiHandler {
            connection: Arc::new(Mutex::new(connection)),
        }
    }
}

unsafe impl Send for ApiHandler {}
unsafe impl Sync for ApiHandler {}

impl Handler for ApiHandler {
    fn handle(&self, req: &mut Request) -> IronResult<Response> {
        debug!("{:?}", req.url);

        let mut response = Response::new();
        response.headers.set(AccessControlAllowMethods(vec![Method::Get]));
        response.headers.set(AccessControlAllowOrigin::Any);
        let mime: Mime = "application/json".parse().unwrap();
        response = response.set((mime));

        let path = req.url.path();
        let last_path = path.clone().pop().unwrap();
        match last_path {
            "status" => {
                let connection = self.connection.clone();
                let mut unlocked_connection = connection.lock().unwrap();
                let a = ApiStatusResponse::from(unlocked_connection.read_status());
                let b = serde_json::to_string_pretty(&a).unwrap();
                response = response.set((status::Ok, b));
            },
            "logged" => {
                let connection = self.connection.clone();
                let mut unlocked_connection = connection.lock().unwrap();
                let a = ApiLoggedResponse::from(unlocked_connection.read_logged());
                let b = serde_json::to_string_pretty(&a).unwrap();
                response = response.set((status::Ok, b));
            },
            _ => {
                response = response.set((status::NotFound, String::new()));
            },
        };

        Ok(response)
    }
}

fn is_socket(path: &str) -> bool {
    let metadata = fs::metadata(path).unwrap();
    let file_type = metadata.file_type();
    debug!("is_socket for {} had metadata {:?}", path, metadata);
    debug!("is_socket for {} is_block_device: {}, is_char_device: {}, is_fifo: {}, is_socket: {}", path, file_type.is_block_device(), file_type.is_char_device(), file_type.is_fifo(), file_type.is_socket());
    metadata.file_type().is_char_device()
}

fn main() {
    assert!(pretty_env_logger::init().is_ok());

    let matches = App::new("simple-client")
        .version(env!("CARGO_PKG_VERSION"))
        .about("HTTP RESTful server for SunSaver MPPT ModBus data")
        .author("Guy Taylor <thebiggerguy.co.uk@gmail.com>")
        .arg(Arg::with_name("device")
            .help("Serial device e.g. /dev/ttyUSB0")
            .long("device")
            .short("d")
            .takes_value(true)
            .required(true))
        .get_matches();

    let serial_interface = matches.value_of("device").unwrap();

    let connection: Box<SunSaverConnection> = if is_socket(serial_interface) {
        info!("Device is a socket. Using Modbus");
        Box::new(ModbusSunSaverConnection::open(serial_interface))
    } else {
        info!("Device is not a socket. Using File");
        Box::new(FileSunSaverConnection::open(serial_interface))
    };

    let api_handler = ApiHandler::new(connection);
    let static_handler = Static::new(Path::new("web"));

    let mut router = Router::new();
    router.get("/", static_handler.clone(), "index");
    router.get("/:filepath(*)", static_handler.clone(), "static");
    router.get("/api/v1/status", api_handler.clone(), "api_v1_status");
    router.get("/api/v1/logged", api_handler.clone(), "api_v2_logger");

    let running = Arc::new(AtomicBool::new(true));
    let r = running.clone();
    ctrlc::set_handler(move || {
        r.store(false, Ordering::SeqCst);
        info!("Cought Ctrl-C");
    }).expect("Error setting Ctrl-C handler");

    info!("Starting server ...");
    let bind_address = format!("0.0.0.0:{}", option_env!("PORT").unwrap_or("8080"));
    let mut listening = Iron::new(router).http(&bind_address).unwrap();
    info!("Started server {}", bind_address);

    info!("Use Ctrl-C to stop");
    while running.load(Ordering::SeqCst) {}
    listening.close().unwrap();
}
<commit_msg>Get port number from CLI not ENV<commit_after>#[macro_use]
extern crate log;
extern crate pretty_env_logger;
extern crate clap;
extern crate libmodbus_rs;
extern crate iron;
extern crate router;
extern crate staticfile;
extern crate serde;
#[macro_use]
extern crate serde_derive;
extern crate serde_json;
extern crate ctrlc;
extern crate retry;
extern crate hex_slice;
#[macro_use]
extern crate enum_primitive;
#[macro_use]
extern crate bitflags;

use std::fs;
use std::path::Path;
use std::os::unix::fs::FileTypeExt;
use std::sync::{Arc, Mutex};
use std::convert::From;
use std::sync::atomic::{AtomicBool, Ordering};

use clap::{App, Arg};

use iron::Iron;
use iron::prelude::*;
use iron::status;
use iron::middleware::Handler;
use iron::headers::{AccessControlAllowMethods, AccessControlAllowOrigin};
use iron::method::Method;
use iron::mime::Mime;
use router::Router;
use staticfile::Static;

mod sunsaver_connection;
use sunsaver_connection::{SunSaverConnection, FileSunSaverConnection, ModbusSunSaverConnection};
mod sunsaver;
use sunsaver::{SunSaverResponse, ChargeState, ArrayFault, LoggedResponse, LoggedResponseDay};

#[derive(Debug, Clone, Serialize)]
struct ApiStatusResponse {
    generation: ApiStatusResponseGeneration,
    storage: ApiStatusResponseStorage,
    load: ApiStatusResponseLoad,
    temperature: ApiStatusResponseTemperature,
    faults: ApiStatusResponseFaults,
}

#[derive(Debug, Clone, Serialize)]
struct ApiStatusResponseGeneration {
    solar_input_voltage_filtered: f32,
    calculated_generation_power: f32,
}

#[derive(Debug, Clone, Serialize)]
struct ApiStatusResponseStorage {
    battery_voltage_filtered: f32,
    battery_charge_current_filtered: f32,
    battery_charge_power_calculated: f32,
    charge_state: ChargeState,
}

#[derive(Debug, Clone, Serialize)]
struct ApiStatusResponseLoad {
    load_voltage_filtered: f32,
    load_current_filtered: f32,
    load_power_calculated: f32,
}

#[derive(Debug, Clone, Serialize)]
struct ApiStatusResponseTemperature {
    heatsink_temperature: i8,
    battery_temperature: i8,
    ambient_temperature: i8,
    remote_temperature: i8,
}

#[derive(Debug, Clone, Serialize)]
struct ApiStatusResponseFaults {
    array_fault: ArrayFault,
}

impl From<SunSaverResponse> for ApiStatusResponse {
    fn from(response: SunSaverResponse) -> Self {
        let battery_voltage_filtered = response.battery_voltage_filtered();
        let battery_charge_current_filtered = response.battery_charge_current_filtered();
        let load_voltage_filtered = response.load_voltage_filtered();
        let load_current_filtered = response.load_current_filtered();
        let solar_input_voltage_filtered = response.solar_input_voltage_filtered();

        let generation = ApiStatusResponseGeneration {
            solar_input_voltage_filtered: solar_input_voltage_filtered,
            calculated_generation_power: (load_current_filtered + battery_charge_current_filtered) * solar_input_voltage_filtered,
        };
        let storage = ApiStatusResponseStorage {
            battery_voltage_filtered: battery_voltage_filtered,
            battery_charge_current_filtered: battery_charge_current_filtered,
            battery_charge_power_calculated: battery_voltage_filtered * battery_charge_current_filtered,
            charge_state: response.charge_state(),
        };
        let load = ApiStatusResponseLoad {
            load_voltage_filtered: load_voltage_filtered,
            load_current_filtered: load_current_filtered,
            load_power_calculated: load_voltage_filtered * load_current_filtered,
        };
        let temperature = ApiStatusResponseTemperature {
            heatsink_temperature: response.heatsink_temperature(),
            battery_temperature: response.battery_temperature(),
            ambient_temperature: response.ambient_temperature(),
            remote_temperature: response.remote_temperature(),
        };
        let faults = ApiStatusResponseFaults {
            array_fault: response.array_fault(),
        };
        ApiStatusResponse {
            generation: generation,
            storage: storage,
            load: load,
            temperature: temperature,
            faults: faults,
        }
    }
}

#[derive(Debug, Clone, Serialize)]
struct ApiLoggedResponse {
    days: Vec<ApiLoggedDayResponse>,
}

#[derive(Debug, Clone, Serialize)]
struct ApiLoggedDayResponse {
    hourmeter: u32,
    battery_voltage_min: f32,
    battery_voltage_max: f32,
    battery_charge_daily: f32,
    load_charge_daily: f32,
    array_voltage_max: f32,
}

impl From<LoggedResponse> for ApiLoggedResponse {
    fn from(response: LoggedResponse) -> Self {
        let days = response.days.into_iter().map(ApiLoggedDayResponse::from).collect();
        ApiLoggedResponse {
            days: days,
        }
    }
}

impl From<LoggedResponseDay> for ApiLoggedDayResponse {
    fn from(response: LoggedResponseDay) -> Self {
        ApiLoggedDayResponse {
            hourmeter: response.hourmeter,
            battery_voltage_min: response.battery_voltage_min(),
            battery_voltage_max: response.battery_voltage_max(),
            battery_charge_daily: response.battery_charge_daily(),
            load_charge_daily: response.load_charge_daily(),
            array_voltage_max: response.array_voltage_max(),
        }
    }
}

#[derive(Clone)]
struct ApiHandler {
    connection: Arc<Mutex<Box<SunSaverConnection>>>,
}

impl ApiHandler {
    fn new(connection: Box<SunSaverConnection>) -> ApiHandler {
        ApiHandler {
            connection: Arc::new(Mutex::new(connection)),
        }
    }
}

unsafe impl Send for ApiHandler {}
unsafe impl Sync for ApiHandler {}

impl Handler for ApiHandler {
    fn handle(&self, req: &mut Request) -> IronResult<Response> {
        debug!("{:?}", req.url);

        let mut response = Response::new();
        response.headers.set(AccessControlAllowMethods(vec![Method::Get]));
        response.headers.set(AccessControlAllowOrigin::Any);
        let mime: Mime = "application/json".parse().unwrap();
        response = response.set((mime));

        let path = req.url.path();
        let last_path = path.clone().pop().unwrap();
        match last_path {
            "status" => {
                let connection = self.connection.clone();
                let mut unlocked_connection = connection.lock().unwrap();
                let a = ApiStatusResponse::from(unlocked_connection.read_status());
                let b = serde_json::to_string_pretty(&a).unwrap();
                response = response.set((status::Ok, b));
            },
            "logged" => {
                let connection = self.connection.clone();
                let mut unlocked_connection = connection.lock().unwrap();
                let a = ApiLoggedResponse::from(unlocked_connection.read_logged());
                let b = serde_json::to_string_pretty(&a).unwrap();
                response = response.set((status::Ok, b));
            },
            _ => {
                response = response.set((status::NotFound, String::new()));
            },
        };

        Ok(response)
    }
}

fn is_socket(path: &str) -> bool {
    let metadata = fs::metadata(path).unwrap();
    let file_type = metadata.file_type();
    debug!("is_socket for {} had metadata {:?}", path, metadata);
    debug!("is_socket for {} is_block_device: {}, is_char_device: {}, is_fifo: {}, is_socket: {}", path, file_type.is_block_device(), file_type.is_char_device(), file_type.is_fifo(), file_type.is_socket());
    metadata.file_type().is_char_device()
}

static CLI_ARG_DEVICE: &'static str = "DEVICE";
static CLI_ARG_PORT: &'static str = "PORT";

fn is_port_number(v: String) -> Result<(), String> {
    v.parse::<u16>().map(|_| ()).map_err(|_| format!("Invalid port number: {}", v))
}

fn main() {
    assert!(pretty_env_logger::init().is_ok());

    let matches = App::new("simple-client")
        .version(env!("CARGO_PKG_VERSION"))
        .about("HTTP RESTful server for SunSaver MPPT ModBus data")
        .author("Guy Taylor <thebiggerguy.co.uk@gmail.com>")
        .arg(Arg::with_name(CLI_ARG_DEVICE)
            .help("Serial device e.g. /dev/ttyUSB0")
            .long("device")
            .short("d")
            .takes_value(true)
            .empty_values(false)
            .required(true)
            )
        .arg(Arg::with_name(CLI_ARG_PORT)
            .help("HTTP server port")
            .long("port")
            .short("p")
            .takes_value(true)
            .empty_values(false)
            .required(false)
            .default_value("8080")
            .validator(is_port_number)
            )
        .get_matches();

    let serial_interface = matches.value_of(CLI_ARG_DEVICE).unwrap();
    let port_number = matches.value_of(CLI_ARG_PORT).unwrap().parse::<u16>().unwrap();

    let connection: Box<SunSaverConnection> = if is_socket(serial_interface) {
        info!("Device is a socket. Using Modbus");
        Box::new(ModbusSunSaverConnection::open(serial_interface))
    } else {
        info!("Device is not a socket. Using File");
        Box::new(FileSunSaverConnection::open(serial_interface))
    };

    let api_handler = ApiHandler::new(connection);
    let static_handler = Static::new(Path::new("web"));

    let mut router = Router::new();
    router.get("/", static_handler.clone(), "index");
    router.get("/:filepath(*)", static_handler.clone(), "static");
    router.get("/api/v1/status", api_handler.clone(), "api_v1_status");
    router.get("/api/v1/logged", api_handler.clone(), "api_v2_logger");

    let running = Arc::new(AtomicBool::new(true));
    let r = running.clone();
    ctrlc::set_handler(move || {
        r.store(false, Ordering::SeqCst);
        info!("Cought Ctrl-C");
    }).expect("Error setting Ctrl-C handler");

    info!("Starting server ...");
    let bind_address = format!("0.0.0.0:{}", port_number);
    let mut listening = Iron::new(router).http(&bind_address).unwrap();
    info!("Started server {}", bind_address);

    info!("Use Ctrl-C to stop");
    while running.load(Ordering::SeqCst) {}
    listening.close().unwrap();
}
<|endoftext|>


<commit_before>extern crate mmap;
extern crate time;
extern crate timely;
extern crate columnar;
extern crate docopt;

use docopt::Docopt;

use std::thread;

use timely::progress::timestamp::RootTimestamp;
use timely::progress::scope::Scope;
use timely::progress::nested::Summary::Local;
use timely::example_shared::*;
use timely::example_shared::operators::*;
use timely::communication::*;
use timely::communication::pact::Exchange;

use timely::networking::initialize_networking;
use timely::networking::initialize_networking_from_file;

use timely::drain::DrainExt;

use columnar::Columnar;

mod typedrw;
mod graphmap;
use graphmap::GraphMMap;

mod sorting;
use sorting::{SegmentList, radix_sort_32};

static USAGE: &'static str = "
Usage: pagerank <source> [options] [<arguments>...]

Options:
    -w <arg>, --workers <arg>    number of workers per process [default: 1]
    -p <arg>, --processid <arg>  identity of this process      [default: 0]
    -n <arg>, --processes <arg>  number of processes involved  [default: 1]
    -h <arg>, --hosts <arg>      file containing list of host:port for workers
";

#[derive(Copy, Clone, Debug)]
struct NodeRank { node: u32, rank: f32, }
impl Columnar for NodeRank { type Stack = Vec<NodeRank>; }

fn main () {
    let args = Docopt::new(USAGE).and_then(|dopt| dopt.parse()).unwrap_or_else(|e| e.exit());

    let source = args.get_str("<source>").to_owned();

    let workers: u64 = if let Ok(threads) = args.get_str("-w").parse() { threads }
                       else { panic!("invalid setting for --workers: {}", args.get_str("-t")) };
    let process_id: u64 = if let Ok(proc_id) = args.get_str("-p").parse() { proc_id }
                          else { panic!("invalid setting for --processid: {}", args.get_str("-p")) };
    let processes: u64 = if let Ok(processes) = args.get_str("-n").parse() { processes }
                         else { panic!("invalid setting for --processes: {}", args.get_str("-n")) };

    println!("Starting pagerank dataflow with");
    println!("\tworkers:\t{}", workers);
    println!("\tprocesses:\t{}", processes);
    println!("\tprocessid:\t{}", process_id);

    // vector holding communicators to use; one per local worker.
    if processes > 1 {
        println!("Initializing BinaryCommunicator");

        let hosts = args.get_str("-h");
        let communicators = if hosts != "" {
            initialize_networking_from_file(hosts, process_id, workers).ok().expect("error initializing networking")
        }
        else {
            let addresses = (0..processes).map(|index| format!("localhost:{}", 2101 + index).to_string()).collect();
            initialize_networking(addresses, process_id, workers).ok().expect("error initializing networking")
        };

        pagerank_spawn(communicators, source);
    }
    else if workers > 1 { pagerank_spawn(ProcessCommunicator::new_vector(workers), source); }
    else { pagerank_spawn(vec![ThreadCommunicator], source); };
}

fn pagerank_spawn<C>(communicators: Vec<C>, filename: String)
where C: Communicator+Send {
    let mut guards = Vec::new();
    let workers = communicators.len();
    for communicator in communicators.into_iter() {
        let filename = filename.clone();
        guards.push(thread::Builder::new().name(format!("timely worker {}", communicator.index()))
                                          .spawn(move || pagerank_thread(communicator, filename, workers))
                                          .unwrap());
    }

    for guard in guards { guard.join().unwrap(); }
}

// returns [src/peers] degrees, (dst, deg) pairs, and a list of [src/peers] endpoints
fn transpose(mut edges: Vec<Vec<(u32, u32)>>, peers: usize, nodes: usize) -> (Vec<u32>, Vec<(u32, u32)>, Vec<u32>)  {

    let mut deg = vec![0; (nodes as usize / peers) + 1];
    for list in &edges {
        for &(s, _) in list {
            deg[s as usize / peers] += 1;
        }
    }

    // let start = time::precise_time_s();
    radix_sort_32(&mut edges, &mut Vec::new(), &|&(_,d)| d);
    // println!("sorted in {}s", time::precise_time_s() - start);

    let mut rev = Vec::<(u32,u32)>::with_capacity(deg.len());
    let mut trn = Vec::with_capacity(edges.len() * 1024);
    for list in edges {
        for (s,d) in list {
            let len = rev.len();
            if (len == 0) || (rev[len-1].0 < d) {
                rev.push((d, 0u32));
            }

            let len = rev.len();
            rev[len-1].1 += 1;
            trn.push(s / peers as u32);
        }
    }

    return (deg, rev, trn);
}

// pagerank dataflow graph has a set of edges as input, and a binary vertex that for each epoch of
// received edges initiates an iterative subcomputation to compute the pagerank.

fn pagerank_thread<C>(communicator: C, filename: String, _workers: usize)
where C: Communicator {
    let index = communicator.index() as usize;
    let peers = communicator.peers() as usize;

    let mut root = GraphRoot::new(communicator);

    let start = time::precise_time_s();
    let mut going = start;

    let nodes = GraphMMap::new(&filename).nodes();

    let mut segments = SegmentList::new(1024); // list of edge segments

    let mut src = vec![];   // holds ranks
    let mut deg = vec![];   // holds source degrees
    let mut rev = vec![];   // holds (dst, deg) pairs
    let mut trn = vec![];   // holds transposed sources

    let mut input = root.subcomputation(|builder| {

        let (input, edges) = builder.new_input::<(u32, u32)>();
        let (cycle, ranks) = builder.loop_variable::<NodeRank>(RootTimestamp::new(20), Local(1));

        edges.binary_notify(&ranks,
                            Exchange::new(|x: &(u32,u32)| x.0 as u64),
                            Exchange::new(|x: &NodeRank| x.node as u64),
                            format!("pagerank"),
                            vec![RootTimestamp::new(0)],
                            move |input1, input2, output, notificator| {

            // receive incoming edges
            while let Some((_index, data)) = input1.pull() {
                segments.push(data.drain_temp());
            }

            while let Some((iter, _)) = notificator.next() {
                // if the very first iteration, prepare some stuff
                if iter.inner == 0 {
                    // println!("received edges in {}s", time::precise_time_s() - start);
                    // (deg, rev, trn) = transpose(srcs, dsts, peers);
                    let (a, b, c) = transpose(segments.finalize(), peers, nodes);
                    deg = a;
                    rev = b;
                    trn = c;
                    src = vec![0.0f32; deg.len()];
                    if index == 0 { println!("transformed; {} x {} shape", deg.len(), rev.len()); }
                }

                if iter.inner == 10 { going = time::precise_time_s(); }
                if iter.inner == 20 && index == 0 { println!("avg: {}", (time::precise_time_s() - going) / 10.0); }

                let iter_start = time::precise_time_s();

                for s in 0..src.len() { src[s] = 0.15 + 0.85 * src[s] / deg[s] as f32; }

                let mut trn_slice = &trn[..];
                let mut rev_slice = &rev[..];
                while rev_slice.len() > 0 {
                    // TODO: session should just flush...
                    let mut session = output.session(&iter);
                    let next = std::cmp::min(100_000, rev_slice.len());
                    for &(dst, deg) in &rev_slice[..next] {
                        let mut accum = 0.0;
                        for &s in &trn_slice[..deg as usize] {
                            accum += src[s as usize];
                        }
                        trn_slice = &trn_slice[deg as usize..];
                        session.give(NodeRank { node: dst, rank: accum });
                    }
                    rev_slice = &rev_slice[next..];
                }

                for s in &mut src { *s = 0.0; }

                if index == 0 { println!("iter: {} took {}s", iter.inner, time::precise_time_s() - iter_start); }
            }

            while let Some((iter, data)) = input2.pull() {
                notificator.notify_at(&iter);
                for x in data.drain_temp() {
                    src[x.node as usize / peers] += x.rank;
                }
            }
        })
        .connect_loop(cycle);

        input
    });

    {
        let graph = GraphMMap::new(&filename);

        let mut edges = Vec::new();
        for node in 0..graph.nodes() {
            if node % peers == index {
                for dst in graph.edges(node) {
                    edges.push((node as u32, *dst as u32));
                }
                if edges.len() > 1024 {
                    input.send_at(0, edges.drain_temp());
                    root.step();
                }
            }
        }

        input.send_at(0, edges.drain_temp());
    }
    input.close();
    while root.step() { }

    if index == 0 { println!("elapsed: {}", time::precise_time_s() - start); }
}

    // .unary_notify(
    //     Exchange::new(move |x: &(u32, f32)| (workers * (index / workers)) as u64 + (x.0 as u64 % workers as u64)),
    //     format!("Aggregation"),
    //     vec![],
    //     move |input, output, iterator| {
    //         while let Some((iter, data)) = input.pull() {
    //             iterator.notify_at(&iter);
    //             for (node, rank) in data.drain_temp() {
    //                 acc[node as usize / workers] += rank;
    //             }
    //         }
    //
    //         while let Some((item, _)) = iterator.next() {
    //
    //             output.give_at(&item, acc.drain_temp().enumerate().filter(|x| x.1 != 0.0)
    //                                      .map(|(u,f)| (((u * workers + local_index) as u32), f)));
    //
    //             for _ in 0..(1 + (nodes/workers)) { acc.push(0.0); }
    //             assert!(acc.len() == (1 + (nodes/workers)));
    //         }
    //     }
    // )
<commit_msg>added recv time accounting<commit_after>extern crate mmap;
extern crate time;
extern crate timely;
extern crate columnar;
extern crate docopt;

use docopt::Docopt;

use std::thread;

use timely::progress::timestamp::RootTimestamp;
use timely::progress::scope::Scope;
use timely::progress::nested::Summary::Local;
use timely::example_shared::*;
use timely::example_shared::operators::*;
use timely::communication::*;
use timely::communication::pact::Exchange;

use timely::networking::initialize_networking;
use timely::networking::initialize_networking_from_file;

use timely::drain::DrainExt;

use columnar::Columnar;

mod typedrw;
mod graphmap;
use graphmap::GraphMMap;

mod sorting;
use sorting::{SegmentList, radix_sort_32};

static USAGE: &'static str = "
Usage: pagerank <source> [options] [<arguments>...]

Options:
    -w <arg>, --workers <arg>    number of workers per process [default: 1]
    -p <arg>, --processid <arg>  identity of this process      [default: 0]
    -n <arg>, --processes <arg>  number of processes involved  [default: 1]
    -h <arg>, --hosts <arg>      file containing list of host:port for workers
";

#[derive(Copy, Clone, Debug)]
struct NodeRank { node: u32, rank: f32, }
impl Columnar for NodeRank { type Stack = Vec<NodeRank>; }

fn main () {
    let args = Docopt::new(USAGE).and_then(|dopt| dopt.parse()).unwrap_or_else(|e| e.exit());

    let source = args.get_str("<source>").to_owned();

    let workers: u64 = if let Ok(threads) = args.get_str("-w").parse() { threads }
                       else { panic!("invalid setting for --workers: {}", args.get_str("-t")) };
    let process_id: u64 = if let Ok(proc_id) = args.get_str("-p").parse() { proc_id }
                          else { panic!("invalid setting for --processid: {}", args.get_str("-p")) };
    let processes: u64 = if let Ok(processes) = args.get_str("-n").parse() { processes }
                         else { panic!("invalid setting for --processes: {}", args.get_str("-n")) };

    println!("Starting pagerank dataflow with");
    println!("\tworkers:\t{}", workers);
    println!("\tprocesses:\t{}", processes);
    println!("\tprocessid:\t{}", process_id);

    // vector holding communicators to use; one per local worker.
    if processes > 1 {
        println!("Initializing BinaryCommunicator");

        let hosts = args.get_str("-h");
        let communicators = if hosts != "" {
            initialize_networking_from_file(hosts, process_id, workers).ok().expect("error initializing networking")
        }
        else {
            let addresses = (0..processes).map(|index| format!("localhost:{}", 2101 + index).to_string()).collect();
            initialize_networking(addresses, process_id, workers).ok().expect("error initializing networking")
        };

        pagerank_spawn(communicators, source);
    }
    else if workers > 1 { pagerank_spawn(ProcessCommunicator::new_vector(workers), source); }
    else { pagerank_spawn(vec![ThreadCommunicator], source); };
}

fn pagerank_spawn<C>(communicators: Vec<C>, filename: String)
where C: Communicator+Send {
    let mut guards = Vec::new();
    let workers = communicators.len();
    for communicator in communicators.into_iter() {
        let filename = filename.clone();
        guards.push(thread::Builder::new().name(format!("timely worker {}", communicator.index()))
                                          .spawn(move || pagerank_thread(communicator, filename, workers))
                                          .unwrap());
    }

    for guard in guards { guard.join().unwrap(); }
}

// returns [src/peers] degrees, (dst, deg) pairs, and a list of [src/peers] endpoints
fn transpose(mut edges: Vec<Vec<(u32, u32)>>, peers: usize, nodes: usize) -> (Vec<u32>, Vec<(u32, u32)>, Vec<u32>)  {

    let mut deg = vec![0; (nodes as usize / peers) + 1];
    for list in &edges {
        for &(s, _) in list {
            deg[s as usize / peers] += 1;
        }
    }

    // let start = time::precise_time_s();
    radix_sort_32(&mut edges, &mut Vec::new(), &|&(_,d)| d);
    // println!("sorted in {}s", time::precise_time_s() - start);

    let mut rev = Vec::<(u32,u32)>::with_capacity(deg.len());
    let mut trn = Vec::with_capacity(edges.len() * 1024);
    for list in edges {
        for (s,d) in list {
            let len = rev.len();
            if (len == 0) || (rev[len-1].0 < d) {
                rev.push((d, 0u32));
            }

            let len = rev.len();
            rev[len-1].1 += 1;
            trn.push(s / peers as u32);
        }
    }

    return (deg, rev, trn);
}

// pagerank dataflow graph has a set of edges as input, and a binary vertex that for each epoch of
// received edges initiates an iterative subcomputation to compute the pagerank.

fn pagerank_thread<C>(communicator: C, filename: String, _workers: usize)
where C: Communicator {
    let index = communicator.index() as usize;
    let peers = communicator.peers() as usize;

    let mut root = GraphRoot::new(communicator);

    let start = time::precise_time_s();
    let mut going = start;

    let nodes = GraphMMap::new(&filename).nodes();

    let mut segments = SegmentList::new(1024); // list of edge segments

    let mut src = vec![];   // holds ranks
    let mut deg = vec![];   // holds source degrees
    let mut rev = vec![];   // holds (dst, deg) pairs
    let mut trn = vec![];   // holds transposed sources

    let mut accounted = 0.0;

    let mut input = root.subcomputation(|builder| {

        let (input, edges) = builder.new_input::<(u32, u32)>();
        let (cycle, ranks) = builder.loop_variable::<NodeRank>(RootTimestamp::new(20), Local(1));

        edges.binary_notify(&ranks,
                            Exchange::new(|x: &(u32,u32)| x.0 as u64),
                            Exchange::new(|x: &NodeRank| x.node as u64),
                            format!("pagerank"),
                            vec![RootTimestamp::new(0)],
                            move |input1, input2, output, notificator| {

            // receive incoming edges
            while let Some((_index, data)) = input1.pull() {
                segments.push(data.drain_temp());
            }

            while let Some((iter, _)) = notificator.next() {
                // if the very first iteration, prepare some stuff
                if iter.inner == 0 {
                    // println!("received edges in {}s", time::precise_time_s() - start);
                    // (deg, rev, trn) = transpose(srcs, dsts, peers);
                    let (a, b, c) = transpose(segments.finalize(), peers, nodes);
                    deg = a;
                    rev = b;
                    trn = c;
                    src = vec![0.0f32; deg.len()];
                    if index == 0 { println!("transformed; {} x {} shape", deg.len(), rev.len()); }
                }

                if iter.inner == 10 { going = time::precise_time_s(); }
                if iter.inner == 20 && index == 0 { println!("avg: {}", (time::precise_time_s() - going) / 10.0); println!("rcv: {}", accounted / 20.0); }

                let iter_start = time::precise_time_s();

                for s in 0..src.len() { src[s] = 0.15 + 0.85 * src[s] / deg[s] as f32; }

                let mut trn_slice = &trn[..];
                let mut rev_slice = &rev[..];
                while rev_slice.len() > 0 {
                    // TODO: session should just flush...
                    let mut session = output.session(&iter);
                    let next = std::cmp::min(100_000, rev_slice.len());
                    for &(dst, deg) in &rev_slice[..next] {
                        let mut accum = 0.0;
                        for &s in &trn_slice[..deg as usize] {
                            accum += src[s as usize];
                        }
                        trn_slice = &trn_slice[deg as usize..];
                        session.give(NodeRank { node: dst, rank: accum });
                    }
                    rev_slice = &rev_slice[next..];
                }

                for s in &mut src { *s = 0.0; }

                if index == 0 { println!("iter: {} took {}s", iter.inner, time::precise_time_s() - iter_start); }
            }

            while let Some((iter, data)) = input2.pull() {
                let start = time::precise_time_s();
                notificator.notify_at(&iter);
                for x in data.drain_temp() {
                    src[x.node as usize / peers] += x.rank;
                }
                accounted += time::precise_time_s() - start;
            }
        })
        .connect_loop(cycle);

        input
    });

    {
        let graph = GraphMMap::new(&filename);

        let mut edges = Vec::new();
        for node in 0..graph.nodes() {
            if node % peers == index {
                for dst in graph.edges(node) {
                    edges.push((node as u32, *dst as u32));
                }
                if edges.len() > 1024 {
                    input.send_at(0, edges.drain_temp());
                    root.step();
                }
            }
        }

        input.send_at(0, edges.drain_temp());
    }
    input.close();
    while root.step() { }

    if index == 0 { println!("elapsed: {}", time::precise_time_s() - start); }
}

    // .unary_notify(
    //     Exchange::new(move |x: &(u32, f32)| (workers * (index / workers)) as u64 + (x.0 as u64 % workers as u64)),
    //     format!("Aggregation"),
    //     vec![],
    //     move |input, output, iterator| {
    //         while let Some((iter, data)) = input.pull() {
    //             iterator.notify_at(&iter);
    //             for (node, rank) in data.drain_temp() {
    //                 acc[node as usize / workers] += rank;
    //             }
    //         }
    //
    //         while let Some((item, _)) = iterator.next() {
    //
    //             output.give_at(&item, acc.drain_temp().enumerate().filter(|x| x.1 != 0.0)
    //                                      .map(|(u,f)| (((u * workers + local_index) as u32), f)));
    //
    //             for _ in 0..(1 + (nodes/workers)) { acc.push(0.0); }
    //             assert!(acc.len() == (1 + (nodes/workers)));
    //         }
    //     }
    // )
<|endoftext|>


<commit_before>extern crate x86;
extern crate perfcnt;
extern crate rustc_serialize;
extern crate docopt;
extern crate rand;
extern crate libc;
extern crate time;
extern crate ansi_term;
extern crate mio;
extern crate thread_id;
#[macro_use]
extern crate lazy_static;
// extern crate influent;

use ansi_term::Colour::Yellow;

mod PerfCounters;
mod Parameters;
mod SimulatedAnnealing;
mod EnergyEval;
mod MeterProxy;
// mod InfluxProxy;

#[derive(Debug, Clone,RustcDecodable)]
pub enum CoolingSchedule {
    linear,
    exponential,
    adaptive,
}

#[derive(Debug, Clone,RustcDecodable)]
pub enum EnergyType {
    throughput,
    latency,
}

#[derive(Debug, Clone)]
pub enum TerminationCriteria {
    Max_Steps(u64),
    Max_Time_Seconds(u64),
}

use std::sync::{Arc, Mutex, Condvar};
use std::sync::RwLock;

use docopt::Docopt;
use std::process::Command;
use PerfCounters::PerfMetrics;
use std::thread;

//The Docopt usage string.
const USAGE: &'static str = "
Usage:   sgxmusl-tuner [-t] --targ=<targetPath> [--args2targ=<args>] [-b] --bench=<benchmarkPath> [--args2bench=<args>] [-ms] --maxSteps=<maxSteps> [-t] --maxTemp=<maxTemperature> [-mt] --minTemp=<minTemperature> [-at] --maxAtt=<maxAttempts> [-ac] --maxAcc=<maxAccepts> [-rj] --maxRej=<maxRejects> --energy=<energy> --cooling=<cooling>
Options:
    -t,    --targ=<args>     	Target Path.
    --args2targ=<args>          Arguments for Target.
    -b,    --bench=<args>     	Benchmark Path.
    --args2bench=<args>         Arguments for Benchmark.
    -ms,   --maxSteps=<args>    Max Steps.
    -tp,   --maxTemp=<args>     Max Temperature.
    -mt,   --minTemp=<args>     Min Temperature.
    -at,   --maxAtt=<args>     	Max Attemtps.
    -ac,   --maxAcc=<args>     	Max Accepts.
    -rj,   --maxRej=<args>     	Max Rejects.
    -e,	   --energy=<args>      Energy to eval (latency or throughput)
    -c,    --cooling=<args>     Cooling Schedule (linear, exponential, adaptive)
";

#[derive(Debug, RustcDecodable)]
struct Args {
    flag_targ: String,
    flag_bench: String,
    flag_maxSteps: u64,
    flag_maxTemp: f64,
    flag_minTemp: f64,
    flag_maxAtt: u64,
    flag_maxAcc: u64,
    flag_maxRej: u64,
    flag_energy: EnergyType,
    flag_cooling: CoolingSchedule,
    flag_args2targ: String,
    flag_args2bench: String,
}

/**
The Sgx-Musl Auto Tuner is a tool able to needs in input:

	- The target app
	- The benchmark app
	- An initial default parameter configuration
	- The possible categorical levels that each parameter can assume
	- The cutoff time k after which terminate the target algorithm execution
	- The iteration number r for random selection of initial parameter configuration
	- Probability p_restart with which re-initialize the search at random
	- Fixed number s of random moves for perturbation
**/
/**
Sgx-Musl Auto Tuner Entry Point
**/
fn main() {

    /// Collect command line arguments
    ///
    let args: Args = Docopt::new(USAGE)
        .and_then(|d| d.decode())
        .unwrap_or_else(|e| e.exit());
    println!("{:?}", args);

    /// Create ParamsConfigurator useful to manage the parameters (or states)
    /// that the simulated annealing algorithm will explore. ParamsConfigurator set initial default parameters
    /// defined in the initial-params.txt input file
    ///
    let params_config = Parameters::ParamsConfigurator {
        param_file_path: "initial-params.conf".to_string(),
        ..Parameters::ParamsConfigurator::default()
    };

    /// Instantiate the EnergyEval struct needed for start/stop the Target and the Benchmark applications
    /// and then evaluate the energy selected by the user
    ///
    let energy_eval = EnergyEval::EnergyEval {
        target_path: args.flag_targ,
        bench_path: args.flag_bench,
        target_args: args.flag_args2targ,
        bench_args: args.flag_args2bench.split_whitespace().map(String::from).collect(),
    };

    /// Configure the Simulated Annealing problem with the ParamsConfigurator and EnergyEval instances.
    /// Finally,the solver is started
    ///
    let mut problem = SimulatedAnnealing::Problem::ProblemInputs {
        params_configurator: params_config,
        energy_evaluator: energy_eval,
    };

    /// Based on the user choice define what type of energy evaluate. Based on this, the Solver will perform
    /// either a maximization problem or a minimization problem
    ///
    let energy_type = match args.flag_energy {
        EnergyType::latency => EnergyType::latency,
        EnergyType::throughput => EnergyType::throughput,
    };

    /// An important aspect of the simulated anneling is how the temperature decrease.
    /// Therefore, the user can choice three types of decreasing function (exp, lin, adapt)
    ///
    let cooling_schedule = match args.flag_cooling {
        CoolingSchedule::exponential => CoolingSchedule::exponential,
        CoolingSchedule::linear => CoolingSchedule::linear,
        CoolingSchedule::adaptive => CoolingSchedule::adaptive,
    };

    let annealing_solver = SimulatedAnnealing::Solver::Solver {
        termination_criteria: TerminationCriteria::Max_Steps(args.flag_maxSteps),
        min_temperature: args.flag_minTemp,
        max_temperature: args.flag_maxTemp,
        max_attempts: args.flag_maxAtt,
        max_accepts: args.flag_maxAcc,
        max_rejects: args.flag_maxRej,
        energy_type: energy_type,
        cooling_schedule: cooling_schedule,
    };

    /// Start the solver
    let best_state = annealing_solver.solve(&mut problem);
    println!("{}",Yellow.paint("\n-------------------------------------------------------------------------------------------------------------------"));
    println!("{} {:?}",
             Yellow.paint("The Best State found is: "),
             best_state);
    println!("{}",Yellow.paint("-------------------------------------------------------------------------------------------------------------------"));

}
<commit_msg>renamed params.conf<commit_after>extern crate x86;
extern crate perfcnt;
extern crate rustc_serialize;
extern crate docopt;
extern crate rand;
extern crate libc;
extern crate time;
extern crate ansi_term;
extern crate mio;
extern crate thread_id;
#[macro_use]
extern crate lazy_static;
// extern crate influent;

use ansi_term::Colour::Yellow;

mod PerfCounters;
mod Parameters;
mod SimulatedAnnealing;
mod EnergyEval;
mod MeterProxy;
// mod InfluxProxy;

#[derive(Debug, Clone,RustcDecodable)]
pub enum CoolingSchedule {
    linear,
    exponential,
    adaptive,
}

#[derive(Debug, Clone,RustcDecodable)]
pub enum EnergyType {
    throughput,
    latency,
}

#[derive(Debug, Clone)]
pub enum TerminationCriteria {
    Max_Steps(u64),
    Max_Time_Seconds(u64),
}

use std::sync::{Arc, Mutex, Condvar};
use std::sync::RwLock;

use docopt::Docopt;
use std::process::Command;
use PerfCounters::PerfMetrics;
use std::thread;

//The Docopt usage string.
const USAGE: &'static str = "
Usage:   sgxmusl-tuner [-t] --targ=<targetPath> [--args2targ=<args>] [-b] --bench=<benchmarkPath> [--args2bench=<args>] [-ms] --maxSteps=<maxSteps> [-t] --maxTemp=<maxTemperature> [-mt] --minTemp=<minTemperature> [-at] --maxAtt=<maxAttempts> [-ac] --maxAcc=<maxAccepts> [-rj] --maxRej=<maxRejects> --energy=<energy> --cooling=<cooling>
Options:
    -t,    --targ=<args>     	Target Path.
    --args2targ=<args>          Arguments for Target.
    -b,    --bench=<args>     	Benchmark Path.
    --args2bench=<args>         Arguments for Benchmark.
    -ms,   --maxSteps=<args>    Max Steps of Annealing.
    -tp,   --maxTemp=<args>     Max Temperature.
    -mt,   --minTemp=<args>     Min Temperature.
    -at,   --maxAtt=<args>     	Max Attemtps.
    -ac,   --maxAcc=<args>     	Max Accepts.
    -rj,   --maxRej=<args>     	Max Rejects.
    -e,	   --energy=<args>      Energy to eval (latency or throughput)
    -c,    --cooling=<args>     Cooling Schedule (linear, exponential, adaptive)
";

#[derive(Debug, RustcDecodable)]
struct Args {
    flag_targ: String,
    flag_bench: String,
    flag_maxSteps: u64,
    flag_maxTemp: f64,
    flag_minTemp: f64,
    flag_maxAtt: u64,
    flag_maxAcc: u64,
    flag_maxRej: u64,
    flag_energy: EnergyType,
    flag_cooling: CoolingSchedule,
    flag_args2targ: String,
    flag_args2bench: String,
}

/**
The Sgx-Musl Auto Tuner is a tool able to needs in input:

	- The target app
	- The benchmark app
	- An initial default parameter configuration
	- The possible categorical levels that each parameter can assume
	- The cutoff time k after which terminate the target algorithm execution
	- The iteration number r for random selection of initial parameter configuration
	- Probability p_restart with which re-initialize the search at random
	- Fixed number s of random moves for perturbation
**/
/**
Sgx-Musl Auto Tuner Entry Point
**/
fn main() {

    /// Collect command line arguments
    ///
    let args: Args = Docopt::new(USAGE)
        .and_then(|d| d.decode())
        .unwrap_or_else(|e| e.exit());
    println!("{:?}", args);

    /// Create ParamsConfigurator useful to manage the parameters (or states)
    /// that the simulated annealing algorithm will explore. ParamsConfigurator set initial default parameters
    /// defined in the initial-params.txt input file
    ///
    let params_config = Parameters::ParamsConfigurator {
        param_file_path: "params.conf".to_string(),
        ..Parameters::ParamsConfigurator::default()
    };

    /// Instantiate the EnergyEval struct needed for start/stop the Target and the Benchmark applications
    /// and then evaluate the energy selected by the user
    ///
    let energy_eval = EnergyEval::EnergyEval {
        target_path: args.flag_targ,
        bench_path: args.flag_bench,
        target_args: args.flag_args2targ,
        bench_args: args.flag_args2bench.split_whitespace().map(String::from).collect(),
    };

    /// Configure the Simulated Annealing problem with the ParamsConfigurator and EnergyEval instances.
    /// Finally,the solver is started
    ///
    let mut problem = SimulatedAnnealing::Problem::ProblemInputs {
        params_configurator: params_config,
        energy_evaluator: energy_eval,
    };

    /// Based on the user choice define what type of energy evaluate. Based on this, the Solver will perform
    /// either a maximization problem or a minimization problem
    ///
    let energy_type = match args.flag_energy {
        EnergyType::latency => EnergyType::latency,
        EnergyType::throughput => EnergyType::throughput,
    };

    /// An important aspect of the simulated anneling is how the temperature decrease.
    /// Therefore, the user can choice three types of decreasing function (exp, lin, adapt)
    ///
    let cooling_schedule = match args.flag_cooling {
        CoolingSchedule::exponential => CoolingSchedule::exponential,
        CoolingSchedule::linear => CoolingSchedule::linear,
        CoolingSchedule::adaptive => CoolingSchedule::adaptive,
    };

    let annealing_solver = SimulatedAnnealing::Solver::Solver {
        termination_criteria: TerminationCriteria::Max_Steps(args.flag_maxSteps),
        min_temperature: args.flag_minTemp,
        max_temperature: args.flag_maxTemp,
        max_attempts: args.flag_maxAtt,
        max_accepts: args.flag_maxAcc,
        max_rejects: args.flag_maxRej,
        energy_type: energy_type,
        cooling_schedule: cooling_schedule,
    };

    /// Start the solver
    let best_state = annealing_solver.solve(&mut problem);
    println!("{}",Yellow.paint("\n-------------------------------------------------------------------------------------------------------------------"));
    println!("{} {:?}",
             Yellow.paint("The Best State found is: "),
             best_state);
    println!("{}",Yellow.paint("-------------------------------------------------------------------------------------------------------------------"));

}
<|endoftext|>


<commit_before>#![no_std]
#![no_main]

use core::panic::PanicInfo;
use daedalos::println;

#[cfg(not(test))]
#[panic_handler]
fn panic(info: &PanicInfo) -> ! {
    println!("{}", info);
    loop {}
}

#[no_mangle]
pub extern "C" fn _start() -> ! {
    println!("Hello, world!");
    loop {}
}
<commit_msg>Reorganized main<commit_after>#![no_std]
#![no_main]

use daedalos::println;

#[no_mangle]
pub extern "C" fn _start() -> ! {
    println!("Hello, world!");
    loop {}
}

#[cfg(not(test))]
use core::panic::PanicInfo;
#[cfg(not(test))]
#[panic_handler]
fn panic(info: &PanicInfo) -> ! {
    println!("{}", info);
    loop {}
}
<|endoftext|>