use std::path::PathBuf;
#[derive(clap::Parser)]
pub struct Options {
#[clap(long, short)]
#[clap(global = true)]
#[clap(action = clap::ArgAction::Count)]
pub verbose: u8,
#[clap(long, short)]
#[clap(global = true)]
#[cfg_attr(target_os = "windows", clap(default_value = "COM1"))]
#[cfg_attr(not(target_os = "windows"), clap(default_value = "/dev/ttyUSB0"))]
pub serial_port: PathBuf,
#[clap(long, short)]
#[clap(global = true)]
#[clap(default_value = "57600")]
pub baud_rate: u32,
#[clap(subcommand)]
pub command: Command,
}
#[derive(clap::Parser)]
pub enum Command {
Ping {
#[clap(value_name = "MOTOR_ID|broadcast")]
motor_id: MotorId,
},
Reboot {
#[clap(value_name = "MOTOR_ID|broadcast")]
motor_id: MotorId,
},
Read8 {
#[clap(value_name = "MOTOR_ID")]
motor_id: MotorId,
#[clap(value_name = "ADDRESS")]
address: u16,
},
Read16 {
#[clap(value_name = "MOTOR_ID")]
motor_id: MotorId,
#[clap(value_name = "ADDRESS")]
address: u16,
},
Read32 {
#[clap(value_name = "MOTOR_ID")]
motor_id: MotorId,
#[clap(value_name = "ADDRESS")]
address: u16,
},
Write8 {
#[clap(value_name = "MOTOR_ID")]
motor_id: MotorId,
#[clap(value_name = "ADDRESS")]
address: u16,
#[clap(value_name = "VALUE")]
value: u8,
},
Write16 {
#[clap(value_name = "MOTOR_ID")]
motor_id: MotorId,
#[clap(value_name = "ADDRESS")]
address: u16,
#[clap(value_name = "VALUE")]
value: u16,
},
Write32 {
#[clap(value_name = "MOTOR_ID")]
motor_id: MotorId,
#[clap(value_name = "ADDRESS")]
address: u16,
#[clap(value_name = "VALUE")]
value: u32,
},
ShellCompletion {
#[clap(long)]
shell: clap_complete::Shell,
#[clap(long, short)]
output: Option<PathBuf>,
},
}
#[derive(Copy, Clone)]
pub enum MotorId {
Id(u8),
Broadcast,
}
impl MotorId {
pub fn raw(self) -> u8 {
match self {
Self::Id(raw) => raw,
Self::Broadcast => dynamixel2::instructions::packet_id::BROADCAST,
}
}
pub fn assume_unicast(self) -> Result<u8, ()> {
match self {
Self::Id(raw) => Ok(raw),
Self::Broadcast => {
log::error!("Invalid motor ID: this command can not be broadcasted.");
Err(())
},
}
}
}
impl std::str::FromStr for MotorId {
type Err = &'static str;
fn from_str(data: &str) -> Result<Self, Self::Err> {
if data.eq_ignore_ascii_case("broadcast") {
Ok(Self::Broadcast)
} else if let Ok(id) = data.parse() {
if id == dynamixel2::instructions::packet_id::BROADCAST {
Ok(Self::Broadcast)
} else {
Ok(Self::Id(id))
}
} else {
Err("invalid motor ID: expected a number in the range 0..255 or the special value \"broadcast\"")
}
}
}