use clap::{Args, Parser, Subcommand, ValueEnum};
use clap_num::maybe_hex;
use std::{path::PathBuf, str::FromStr};
use zencan_client::common::lss::LssIdentity;
#[derive(Debug, Parser)]
pub struct Cli {
#[command(subcommand)]
pub command: Commands,
}
#[derive(Debug, Subcommand)]
pub enum Commands {
Read(ReadArgs),
Write(WriteArgs),
Scan,
ScanPdoConfig(ScanPdoConfigArgs),
Info,
LoadConfig(LoadConfigArgs),
SaveObjects(SaveObjectsArgs),
Nmt(NmtArgs),
#[command(subcommand)]
Lss(LssCommands),
Sync(SyncArgs),
}
#[derive(Debug, Args)]
pub struct ReadArgs {
pub node_id: u8,
#[clap(value_parser=maybe_hex::<u16>)]
pub index: u16,
#[clap(value_parser=maybe_hex::<u8>)]
pub sub: u8,
pub data_type: Option<SdoDataType>,
}
#[derive(Clone, Copy, Debug, ValueEnum)]
pub enum SdoDataType {
U32,
U16,
U8,
I32,
I16,
I8,
F32,
Utf8,
}
#[derive(Debug, Args)]
pub struct WriteArgs {
pub node_id: u8,
#[clap(value_parser=maybe_hex::<u16>)]
pub index: u16,
#[clap(value_parser=maybe_hex::<u8>)]
pub sub: u8,
pub data_type: SdoDataType,
pub value: String,
}
#[derive(Debug, Args)]
pub struct ScanPdoConfigArgs {
pub node_id: u8,
}
#[derive(Debug, Args)]
pub struct LoadConfigArgs {
pub node_id: u8,
#[arg(value_hint=clap::ValueHint::FilePath)]
pub path: PathBuf,
}
#[derive(Debug, Args)]
pub struct SaveObjectsArgs {
pub node_id: u8,
}
#[derive(Debug, Args)]
pub struct SyncArgs {
pub count: Option<u8>,
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum NmtNodeArg {
All,
Specific(u8),
}
impl NmtNodeArg {
pub fn raw(&self) -> u8 {
match self {
Self::All => 0,
Self::Specific(id) => *id,
}
}
}
impl FromStr for NmtNodeArg {
type Err = &'static str;
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s.parse::<u8>() {
Ok(num) => {
if num == 0 {
Ok(Self::All)
} else if num < 128 {
Ok(Self::Specific(num))
} else {
Err("Node ID must be between 0 and 127")
}
}
Err(_) => {
if s == "all" {
Ok(Self::All)
} else {
Err("Must specify a node ID, or 'all' to broadcast")
}
}
}
}
}
#[derive(Debug, Args)]
pub struct NmtArgs {
pub action: NmtAction,
pub node: NmtNodeArg,
}
#[derive(Clone, Copy, Debug, PartialEq, ValueEnum)]
pub enum NmtAction {
ResetApp,
ResetComms,
Start,
Stop,
}
#[derive(Args, Clone, Copy, Debug)]
#[group(multiple=true, requires_all=["vendor_id", "product_code", "revision", "serial"])]
pub struct IdentityArgs {
#[clap(value_parser=maybe_hex::<u32>)]
#[arg(required = false)]
pub vendor_id: u32,
#[clap(value_parser=maybe_hex::<u32>)]
#[arg(required = false)]
pub product_code: u32,
#[clap(value_parser=maybe_hex::<u32>)]
#[arg(required = false)]
pub revision: u32,
#[clap(value_parser=maybe_hex::<u32>)]
#[arg(required = false)]
pub serial: u32,
}
impl From<IdentityArgs> for LssIdentity {
fn from(value: IdentityArgs) -> Self {
LssIdentity {
vendor_id: value.vendor_id,
product_code: value.product_code,
revision: value.revision,
serial: value.serial,
}
}
}
#[derive(Debug, Subcommand)]
pub enum LssCommands {
Activate {
#[clap(flatten)]
identity: IdentityArgs,
},
Fastscan {
#[arg(default_value = "5")]
timeout: u64,
},
SetNodeId {
node_id: u8,
#[clap(flatten)]
identity: Option<IdentityArgs>,
},
StoreConfig {
#[clap(flatten)]
identity: Option<IdentityArgs>,
},
Global {
#[clap(action=clap::ArgAction::Set)]
enable: u8,
},
}