Some cleanup, improvements to CLI options/docs
This commit is contained in:
parent
a3a5d61838
commit
b09fdfe6b7
89
src/main.rs
89
src/main.rs
@ -1,12 +1,5 @@
|
|||||||
use core::fmt;
|
use core::fmt;
|
||||||
use std::{
|
use std::{ffi::CString, fs::File, io::BufWriter, os::unix::prelude::OsStrExt, path::PathBuf};
|
||||||
ffi::CString,
|
|
||||||
fs::File,
|
|
||||||
fs::{self, OpenOptions},
|
|
||||||
io::BufWriter,
|
|
||||||
os::unix::prelude::OsStrExt,
|
|
||||||
path::PathBuf,
|
|
||||||
};
|
|
||||||
|
|
||||||
use anyhow::{anyhow, Context, Error};
|
use anyhow::{anyhow, Context, Error};
|
||||||
use clap_num::maybe_hex;
|
use clap_num::maybe_hex;
|
||||||
@ -15,7 +8,6 @@ use file::ObjectFileReader;
|
|||||||
use log::{debug, error, info, log_enabled, warn, Level};
|
use log::{debug, error, info, log_enabled, warn, Level};
|
||||||
|
|
||||||
use hidapi::{DeviceInfo, HidApi};
|
use hidapi::{DeviceInfo, HidApi};
|
||||||
use object::Object;
|
|
||||||
|
|
||||||
use crate::file::{MemoryFileType, MemoryWriter};
|
use crate::file::{MemoryFileType, MemoryWriter};
|
||||||
use clap::{
|
use clap::{
|
||||||
@ -48,6 +40,18 @@ struct VidPid {
|
|||||||
vid: u16,
|
vid: u16,
|
||||||
pid: u16,
|
pid: u16,
|
||||||
}
|
}
|
||||||
|
impl fmt::Display for VidPid {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
f.write_fmt(format_args!("{:04x}:{:04x}", self.vid, self.pid))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ValueParserFactory for VidPid {
|
||||||
|
type Parser = VidPidParser;
|
||||||
|
fn value_parser() -> Self::Parser {
|
||||||
|
VidPidParser
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
struct VidPidParser;
|
struct VidPidParser;
|
||||||
@ -75,13 +79,6 @@ impl TypedValueParser for VidPidParser {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ValueParserFactory for VidPid {
|
|
||||||
type Parser = VidPidParser;
|
|
||||||
fn value_parser() -> Self::Parser {
|
|
||||||
VidPidParser
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Parser, Debug)]
|
#[derive(Parser, Debug)]
|
||||||
#[command(author, version, about)]
|
#[command(author, version, about)]
|
||||||
struct Cli {
|
struct Cli {
|
||||||
@ -92,7 +89,7 @@ struct Cli {
|
|||||||
#[derive(Args, Debug)]
|
#[derive(Args, Debug)]
|
||||||
struct UsbDeviceSpecifier {
|
struct UsbDeviceSpecifier {
|
||||||
/// USB VID:PID as colon-separated pair
|
/// USB VID:PID as colon-separated pair
|
||||||
#[arg(short = 'i', long, default_value = "1fc9:0021", group = "device")]
|
#[arg(short = 'i', long, default_value_t = VidPid{vid:0x1fc9,pid:0x0021}, group = "device")]
|
||||||
usb_id: VidPid,
|
usb_id: VidPid,
|
||||||
|
|
||||||
/// hidraw device node path
|
/// hidraw device node path
|
||||||
@ -105,9 +102,20 @@ enum ObjectFileType {
|
|||||||
Elf,
|
Elf,
|
||||||
Ihex,
|
Ihex,
|
||||||
Bin,
|
Bin,
|
||||||
|
/// Derive file type from file name
|
||||||
Auto,
|
Auto,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(ValueEnum, Debug, Clone)]
|
||||||
|
enum WriteEraseMethod {
|
||||||
|
/// Erase the entire flash
|
||||||
|
All,
|
||||||
|
/// Erase only the area to be written
|
||||||
|
Region,
|
||||||
|
/// Don't do an erase. Memory to be written must be erased already if it's flash.
|
||||||
|
None,
|
||||||
|
}
|
||||||
|
|
||||||
impl ObjectFileType {
|
impl ObjectFileType {
|
||||||
fn mem_writer(&self, filename: &PathBuf) -> Box<dyn MemoryWriter> {
|
fn mem_writer(&self, filename: &PathBuf) -> Box<dyn MemoryWriter> {
|
||||||
match self {
|
match self {
|
||||||
@ -152,21 +160,18 @@ struct WriteArgs {
|
|||||||
/// USB device to act on
|
/// USB device to act on
|
||||||
#[command(flatten)]
|
#[command(flatten)]
|
||||||
devspec: UsbDeviceSpecifier,
|
devspec: UsbDeviceSpecifier,
|
||||||
/// Base memory address on microcontroller (defaults to start of flash)
|
/// Base memory address on microcontroller to write to (defaults to start of flash)
|
||||||
#[arg(short = 'a', long = "write-address", value_parser=maybe_hex::<u32>)]
|
#[arg(short = 'a', long = "write-address", value_parser=maybe_hex::<u32>)]
|
||||||
addr: Option<u32>,
|
addr: Option<u32>,
|
||||||
/// Base memory address in <FILE> (defaults to the start of the first TEXT block in the file)
|
|
||||||
#[arg(long="read-address", value_parser=maybe_hex::<u32>)]
|
|
||||||
read_addr: Option<u32>,
|
|
||||||
/// Size to write in bytes (defaults to size of flash)
|
/// Size to write in bytes (defaults to size of flash)
|
||||||
#[arg(short, long, value_parser=maybe_hex::<u32>)]
|
#[arg(short, long, value_parser=maybe_hex::<u32>)]
|
||||||
size: Option<u32>,
|
size: Option<u32>,
|
||||||
/// Don't reset the microcontroller after writing
|
/// Don't reset the microcontroller after writing
|
||||||
#[arg(short, long, action=ArgAction::SetFalse)]
|
#[arg(short, long, action=ArgAction::SetFalse)]
|
||||||
no_reset: bool,
|
no_reset: bool,
|
||||||
#[arg(short, long)]
|
#[arg(short, long, default_value = "region")]
|
||||||
/// Erase all flash before writing
|
/// Erase method to use before writing
|
||||||
erase: bool,
|
erase: WriteEraseMethod,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Args, Debug)]
|
#[derive(Args, Debug)]
|
||||||
@ -182,10 +187,15 @@ struct EraseArgs {
|
|||||||
#[command(flatten)]
|
#[command(flatten)]
|
||||||
devspec: UsbDeviceSpecifier,
|
devspec: UsbDeviceSpecifier,
|
||||||
|
|
||||||
|
#[arg(long = "all", default_value_t = true)]
|
||||||
|
/// Erase the entire chip
|
||||||
|
erase_all: bool,
|
||||||
|
|
||||||
/// Address to start erasing at
|
/// Address to start erasing at
|
||||||
#[arg(short = 'a', long="base-address", value_parser=maybe_hex::<u32>, requires="size")]
|
#[arg(short = 'a', long="base-address", value_parser=maybe_hex::<u32>, conflicts_with="erase_all")]
|
||||||
addr: Option<u32>,
|
addr: Option<u32>,
|
||||||
#[arg(short, long, value_parser=maybe_hex::<u32>)]
|
/// Number of bytes to erase
|
||||||
|
#[arg(short, long, value_parser=maybe_hex::<u32>, conflicts_with="erase_all")]
|
||||||
size: Option<u32>,
|
size: Option<u32>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -221,16 +231,33 @@ fn write_file_to_flash(args: &WriteArgs) -> Result<(), Error> {
|
|||||||
let api = HidApi::new()?;
|
let api = HidApi::new()?;
|
||||||
let isp = connect_device(&api, &args.devspec)?;
|
let isp = connect_device(&api, &args.devspec)?;
|
||||||
|
|
||||||
let infile = args.filetype.file_reader(&args.file)
|
let mut infile = args
|
||||||
|
.filetype
|
||||||
|
.file_reader(&args.file)
|
||||||
.with_context(|| format!("Opening {} for reading", args.file.display()))?;
|
.with_context(|| format!("Opening {} for reading", args.file.display()))?;
|
||||||
|
|
||||||
|
let contents = infile
|
||||||
|
.read_all(None)
|
||||||
|
.or_else(|e| Err(anyhow!("Unable to read file contents: {}", e)))?;
|
||||||
|
|
||||||
|
println!("Input file first section contents:");
|
||||||
|
for (i, line) in contents.chunks(16).enumerate() {
|
||||||
|
print!("{:08x} ", i * 16);
|
||||||
|
for block in line.chunks(8) {
|
||||||
|
for s in block.iter().map(|x| format!("{:02x} ", x)) {
|
||||||
|
print!("{}", s);
|
||||||
|
}
|
||||||
|
print!(" ");
|
||||||
|
}
|
||||||
|
println!();
|
||||||
|
}
|
||||||
|
|
||||||
let flash_start = args.addr.unwrap_or(isp.GetFlashStartAddress()?);
|
let flash_start = args.addr.unwrap_or(isp.GetFlashStartAddress()?);
|
||||||
let flash_size = args.size.unwrap_or(isp.GetFlashSizeInBytes()?);
|
let flash_size = args.size.unwrap_or(isp.GetFlashSizeInBytes()?);
|
||||||
|
|
||||||
if !args.no_reset {
|
// if !args.no_reset {
|
||||||
isp.reset()?;
|
// isp.reset()?;
|
||||||
}
|
// }
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@ -298,7 +325,7 @@ fn erase_flash(args: &EraseArgs) -> Result<(), Error> {
|
|||||||
let erase_pb = ProgressBar::new(1)
|
let erase_pb = ProgressBar::new(1)
|
||||||
.with_style(read_write_style())
|
.with_style(read_write_style())
|
||||||
.with_prefix("Erasing flash");
|
.with_prefix("Erasing flash");
|
||||||
if args.addr.is_none() && args.size.is_none() {
|
if args.erase_all {
|
||||||
isp.flash_erase_all(None)?;
|
isp.flash_erase_all(None)?;
|
||||||
erase_pb.finish();
|
erase_pb.finish();
|
||||||
} else {
|
} else {
|
||||||
|
@ -1,19 +1,19 @@
|
|||||||
|
// Allow non snake case to match with NXP documentation
|
||||||
#![allow(non_snake_case)]
|
#![allow(non_snake_case)]
|
||||||
|
|
||||||
use anyhow::{anyhow, Error};
|
use anyhow::{anyhow, Error};
|
||||||
use byteorder::{ByteOrder, LittleEndian, NativeEndian};
|
use hidapi::HidDevice;
|
||||||
use hidapi::{HidApi, HidDevice};
|
|
||||||
use log::debug;
|
use log::debug;
|
||||||
use num_enum::{FromPrimitive, IntoPrimitive, TryFromPrimitive};
|
use num_enum::{FromPrimitive, IntoPrimitive};
|
||||||
use std::fmt::{Debug, Display};
|
use std::fmt::{Debug, Display};
|
||||||
use std::io::{Cursor, Write};
|
use std::io::Write;
|
||||||
use strum::IntoEnumIterator;
|
use strum::IntoEnumIterator;
|
||||||
use strum_macros::EnumIter;
|
use strum_macros::EnumIter;
|
||||||
use uuid::Uuid;
|
use uuid::Uuid;
|
||||||
|
|
||||||
use crate::packet::{
|
use crate::packet::{
|
||||||
self, GenericResponseParams, GetPropertyResponseParams, Packet, ResponsePacket,
|
self, GetPropertyResponseParams, Packet, ResponsePacket, ResponseParameters, StatusCode,
|
||||||
ResponseParameters, StatusCode, UsbPacket,
|
UsbPacket,
|
||||||
};
|
};
|
||||||
use crate::packet::{CommandFlags, CommandPacket, CommandTag};
|
use crate::packet::{CommandFlags, CommandPacket, CommandTag};
|
||||||
|
|
||||||
@ -329,7 +329,7 @@ impl UsbIsp {
|
|||||||
usb_packet.write(&mut buf)?;
|
usb_packet.write(&mut buf)?;
|
||||||
|
|
||||||
//FIXME: don't expect a response on data packets
|
//FIXME: don't expect a response on data packets
|
||||||
let rsize = self.device.write(&buf)?;
|
let _ = self.device.write(&buf)?;
|
||||||
let mut rbuf = [0u8; 64];
|
let mut rbuf = [0u8; 64];
|
||||||
let res_size = self.device.read(&mut rbuf[..])?;
|
let res_size = self.device.read(&mut rbuf[..])?;
|
||||||
let parsed = packet::usb_packet(&rbuf[..res_size]).unwrap(); //TODO: handle more gracefully, but requires ownership of I
|
let parsed = packet::usb_packet(&rbuf[..res_size]).unwrap(); //TODO: handle more gracefully, but requires ownership of I
|
||||||
|
Loading…
x
Reference in New Issue
Block a user