cargo-drone 0.4.3

A cargo subcommand for Drone.
Documentation
//! ITM parser.

use colored::*;
use failure::{err_msg, Error};
use libc;
use std::ffi::CString;
use std::fs::{self, File};
use std::io::{self, Read, Write};
use std::os::unix::ffi::OsStringExt;
use std::path::PathBuf;
use std::thread;
use std::time::Duration;

/// ITM overflow error.
#[derive(Fail, Debug)]
#[fail(display = "ITM Overflow")]
pub struct Overflow;

/// Creates a new named pipe with given `name`.
pub fn create_pipe(name: &str) -> Result<(), Error> {
  let pipe = PathBuf::from(name);
  if pipe.exists() {
    fs::remove_file(&pipe)?;
  }
  let pipe = pipe.clone().into_os_string().into_vec();
  let result = unsafe { libc::mkfifo(CString::new(pipe)?.as_ptr(), 0o644) };
  if result != 0 {
    Err(err_msg("Failed to create a FIFO"))?;
  }
  Ok(())
}

/// Opens a pipe, and runs a read loop.
pub fn run_loop(pipe: &str, port: u8, debug: bool) -> Result<(), Error> {
  let mut stream = io::BufReader::new(File::open(pipe)?);
  let mut buffer = [0; 4];
  loop {
    match read(&mut stream, &mut buffer, port, debug) {
      Ok(Some(payload)) => {
        if debug {
          for byte in payload {
            print!("{:?} ", *byte as char);
          }
          println!();
        } else {
          io::stdout().write_all(payload)?;
          io::stdout().flush()?;
        }
      }
      Ok(None) => {
        if debug {
          println!("{}", "[IGN]".yellow());
        }
      }
      Err(err) => {
        if err.downcast_ref::<Overflow>().is_some() {
          writeln!(io::stderr(), "{}", "[OFLW]".bold().white().on_red())?;
        } else if let Some(err) = err.downcast_ref::<io::Error>() {
          match err.kind() {
            io::ErrorKind::UnexpectedEof => {
              writeln!(io::stderr(), "{}", "[EOF]".red())?;
              thread::sleep(Duration::from_millis(100));
            }
            kind => {
              let message = format!("[IO: {:?}]", kind);
              writeln!(io::stderr(), "{}", message.red())?;
            }
          }
        }
      }
    }
  }
}

/// Reads a packet from ITM stream.
fn read<'a, 'b>(
  stream: &'a mut io::BufReader<File>,
  buffer: &'b mut [u8],
  _selected_port: u8,
  debug: bool,
) -> Result<Option<&'b [u8]>, Error> {
  stream.read_exact(&mut buffer[0..1])?;
  let header = buffer[0];
  if debug {
    debug_print_byte(header)?;
  }
  if header == 0 {
    // Synchronization
    return Ok(None);
  }
  let size = header & 0b11;
  if size == 0 {
    if header == 0b0111_0000 {
      // Protocol overflow
      Err(Overflow)?
    } else {
      // Protocol other
      Ok(None)
    }
  } else if header & 0b100 == 0 {
    // Instrumentation source
    let _port = header >> 3;
    // if port != selected_port {
    //   return Ok(None);
    // }
    let payload = match size {
      0b01 => &mut buffer[0..1],
      0b10 => &mut buffer[0..2],
      0b11 => &mut buffer[0..4],
      _ => unreachable!(),
    };
    if debug {
      for byte in payload.chunks_mut(1) {
        stream.read_exact(byte)?;
        debug_print_byte(byte[0])?;
      }
    } else {
      stream.read_exact(payload)?;
    }
    Ok(Some(payload))
  } else {
    // Hardware source
    Ok(None)
  }
}

fn debug_print_byte(byte: u8) -> Result<(), Error> {
  print!("{:08b} ", byte);
  io::stdout().flush()?;
  Ok(())
}