Skip to content

Commit da3eeb9

Browse files
committed
ravedude: add newline_after and newline_on
newline_after adds a newline after the n’th byte newline_on adds a newline after the given byte
1 parent b82a0d7 commit da3eeb9

File tree

2 files changed

+101
-27
lines changed

2 files changed

+101
-27
lines changed

ravedude/src/console.rs

Lines changed: 30 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
use anyhow::Context as _;
21
use std::io::Read as _;
32
use std::io::Write as _;
43

@@ -32,6 +31,7 @@ pub fn open(args: Args) -> anyhow::Result<()> {
3231
task_message!("", "{}", "CTRL+C to exit.".dimmed());
3332
// Empty line for visual consistency
3433
eprintln!();
34+
3535
let mut rx = serialport::new(port.to_string_lossy(), baudrate)
3636
.timeout(std::time::Duration::from_secs(2))
3737
.open_native()
@@ -43,13 +43,29 @@ pub fn open(args: Args) -> anyhow::Result<()> {
4343

4444
// Set a CTRL+C handler to terminate cleanly instead of with an error.
4545
ctrlc::set_handler(move || {
46-
eprintln!("");
46+
eprintln!();
4747
eprintln!("Exiting.");
4848
std::process::exit(0);
4949
})
5050
.context("failed setting a CTRL+C handler")?;
5151

52+
let newline_after = match args.newline_after {
53+
Some(n) => n,
54+
None => match args.output_mode {
55+
Some(Hex) | Some(Dec) => 16,
56+
Some(Bin) => 8,
57+
_ => 0,
58+
},
59+
};
60+
61+
let (spaces, space_after) = if args.newline_on.is_none() && newline_after % 4 == 0 {
62+
(true, 4)
63+
} else {
64+
(false, 0)
65+
};
66+
5267
let mut byte_count = 0;
68+
5369
// Spawn a thread for the receiving end because stdio is not portably non-blocking...
5470
std::thread::spawn(move || loop {
5571
#[cfg(not(target_os = "windows"))]
@@ -82,32 +98,26 @@ pub fn open(args: Args) -> anyhow::Result<()> {
8298
Some(Ascii) | None => unreachable!(),
8399
Some(Hex) => {
84100
write!(stdout, "{:02x} ", byte).unwrap();
85-
if byte_count % 4 == 0 {
86-
write!(stdout, " ").unwrap();
87-
}
88-
if byte_count % 16 == 0 {
89-
writeln!(stdout).unwrap();
90-
}
91101
}
92102
Some(Dec) => {
93103
write!(stdout, "{:03} ", byte).unwrap();
94-
if byte_count % 4 == 0 {
95-
write!(stdout, " ").unwrap();
96-
}
97-
if byte_count % 16 == 0 {
98-
writeln!(stdout).unwrap();
99-
}
100104
}
101105
Some(Bin) => {
102106
write!(stdout, "{:08b} ", byte).unwrap();
103-
if byte_count % 4 == 0 {
104-
write!(stdout, " ").unwrap();
105-
}
106-
if byte_count % 8 == 0 {
107-
writeln!(stdout).unwrap();
108-
}
109107
}
110108
}
109+
// don’t execute in ascii mode, ascii is unreachable here
110+
if spaces && byte_count % space_after == 0 {
111+
write!(stdout, " ").unwrap();
112+
}
113+
if args.newline_on.is_none() && byte_count % newline_after == 0 {
114+
writeln!(stdout).unwrap();
115+
}
116+
if args.newline_on.is_some()
117+
&& *byte as char == args.newline_on.unwrap()
118+
{
119+
writeln!(stdout).unwrap();
120+
}
111121
}
112122
}
113123
}

ravedude/src/main.rs

Lines changed: 71 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use anyhow::Context as _;
1+
use anyhow::{bail, Context as _};
22
use colored::Colorize as _;
33
use structopt::clap::AppSettings;
44

@@ -35,6 +35,51 @@ impl FromStr for OutputMode {
3535
}
3636
}
3737

38+
// this could have fewer nested if’s, but this produces better error messages
39+
fn parse_newline_on(s: &str) -> Result<char, anyhow::Error> {
40+
if let Ok(c) = s.parse::<char>() {
41+
Ok(c)
42+
43+
// if it starts with 0x then parse the hex byte
44+
} else if &s[0..2] == "0x" {
45+
if s.len() == 4 {
46+
if let Ok(n) = u8::from_str_radix(&s[2..4], 16) {
47+
Ok(n as char)
48+
} else {
49+
bail!("invalid hex byte")
50+
}
51+
} else {
52+
bail!("hex byte must have 2 characters")
53+
}
54+
// if it starts with 0b then parse the binary byte
55+
} else if &s[0..2] == "0b" {
56+
if s.len() == 10 {
57+
if let Ok(n) = u8::from_str_radix(&s[2..10], 2) {
58+
Ok(n as char)
59+
} else {
60+
bail!("invalid binary byte")
61+
}
62+
} else {
63+
bail!("binary byte must have 8 characters")
64+
}
65+
} else {
66+
bail!("must be a single character or a byte in hex or binary notation")
67+
}
68+
}
69+
70+
#[test]
71+
fn test_parse_newline_on() {
72+
assert_eq!(parse_newline_on("a").unwrap(), 'a');
73+
assert_eq!(parse_newline_on("\n").unwrap(), '\n');
74+
assert_eq!(parse_newline_on("0x41").unwrap(), 'A');
75+
assert_eq!(parse_newline_on("0b01000001").unwrap(), 'A');
76+
assert!(parse_newline_on("not a char").is_err());
77+
assert!(parse_newline_on("0x").is_err());
78+
assert!(parse_newline_on("0xzz").is_err());
79+
assert!(parse_newline_on("0b").is_err());
80+
assert!(parse_newline_on("0b0a0a0a0a").is_err());
81+
}
82+
3883
/// ravedude is a rust wrapper around avrdude for providing the smoothest possible development
3984
/// experience with rust on AVR microcontrollers.
4085
///
@@ -74,6 +119,27 @@ struct Args {
74119
#[structopt(long = "debug-avrdude")]
75120
debug_avrdude: bool,
76121

122+
/// Output mode.
123+
///
124+
/// Can be ascii, hex, dec or bin
125+
#[structopt(short = "o")]
126+
output_mode: Option<OutputMode>,
127+
128+
/// Print a newline after this byte
129+
/// not used with output_mode ascii
130+
/// hex (0x) and bin (0b) notations are supported.
131+
/// matching chars/bytes are NOT removed
132+
/// to add newlines after \n (in non-ascii mode), use \n, 0x0a or 0b00001010
133+
#[structopt(long = "newline-on", parse(try_from_str = parse_newline_on))]
134+
newline_on: Option<char>,
135+
136+
/// Print a newline after n bytes
137+
/// not used with output_mode ascii
138+
/// defaults to 16 for hex and dec and 8 for bin
139+
/// if dividable by 4, bytes will be grouped to 4
140+
#[structopt(long = "newline-after")]
141+
newline_after: Option<u8>,
142+
77143
/// Which board to interact with.
78144
///
79145
/// Must be one of the known board identifiers:
@@ -101,12 +167,6 @@ struct Args {
101167
/// If no binary is given, flashing will be skipped.
102168
#[structopt(name = "BINARY", parse(from_os_str))]
103169
bin: Option<std::path::PathBuf>,
104-
105-
/// Output mode.
106-
///
107-
/// Can be ascii, hex, dec or bin
108-
#[structopt(short = "o")]
109-
output_mode: Option<OutputMode>,
110170
}
111171

112172
fn main() {
@@ -125,6 +185,10 @@ fn ravedude() -> anyhow::Result<()> {
125185

126186
let board = board::get_board(&args.board).expect("board not found");
127187

188+
if args.newline_on.is_some() && args.newline_after.is_some() {
189+
bail!("newline_on and newline_after cannot be used at the same time");
190+
}
191+
128192
task_message!("Board", "{}", board.display_name());
129193

130194
if let Some(wait_time) = args.reset_delay {

0 commit comments

Comments
 (0)