use std::collections::HashMap;
use clap::Parser;
use strum::{Display, EnumString, EnumVariantNames};
mod drivers;
pub use drivers::*;
mod handle;
pub use handle::*;
#[derive(Copy, Clone, PartialEq, Debug, EnumVariantNames, Display, EnumString)]
#[strum(serialize_all = "lowercase")]
pub enum Model {
NanoS,
#[strum(serialize = "nanosplus", to_string = "nanosp")]
NanoSP,
NanoX,
}
impl Model {
pub fn target(&self) -> &'static str {
match self {
Model::NanoS => "nanos",
Model::NanoSP => "nanosplus",
Model::NanoX => "nanox",
}
}
}
#[derive(Copy, Clone, PartialEq, Debug, EnumVariantNames, Display, EnumString, clap::ValueEnum)]
#[strum(serialize_all = "lowercase")]
pub enum Display {
Headless,
Qt,
Text,
}
#[derive(Clone, PartialEq, Debug, Parser)]
pub struct Options {
#[clap(long, default_value_t = Options::default().model)]
pub model: Model,
#[clap(long, value_enum, default_value_t = Options::default().display)]
pub display: Display,
#[clap(long)]
pub sdk: Option<String>,
#[clap(long)]
pub api_level: Option<String>,
#[clap(long, env)]
pub seed: Option<String>,
#[clap(long, default_value_t = Options::default().http_port)]
pub http_port: u16,
#[clap(long, env)]
pub apdu_port: Option<u16>,
#[clap(long)]
pub debug: bool,
#[clap(long, env = "SPECULOS_ROOT")]
pub root: Option<String>,
#[clap(long)]
pub trace: bool,
}
impl Default for Options {
fn default() -> Self {
Self {
model: Model::NanoSP,
display: Display::Headless,
sdk: None,
api_level: None,
seed: None,
http_port: 5000,
apdu_port: None,
debug: false,
root: None,
trace: false,
}
}
}
impl Options {
pub fn args(&self) -> Vec<String> {
let mut args = vec![
format!("--model={}", self.model),
format!("--display={}", self.display),
format!("--api-port={}", self.http_port),
];
if let Some(seed) = &self.seed {
args.push(format!("--seed={seed}"));
}
if let Some(apdu_port) = &self.apdu_port {
args.push(format!("--apdu-port={apdu_port}"));
}
if let Some(sdk) = &self.sdk {
args.push(format!("--sdk={sdk}"));
}
if let Some(api_level) = &self.api_level {
args.push(format!("--apiLevel={api_level}"));
}
if self.debug {
args.push("--debug".to_string());
}
if self.trace {
args.push("-t".to_string());
}
args
}
pub fn env(&self) -> HashMap<String, String> {
let mut env = HashMap::new();
if let Some(seed) = &self.seed {
env.insert("SPECULOS_SEED".to_string(), seed.clone());
}
env
}
}
#[cfg(test)]
mod tests {
use std::str::FromStr;
use crate::Model;
#[test]
fn model_name_encoding() {
let t = &[
(Model::NanoS, "nanos", "nanos"),
(Model::NanoSP, "nanosp", "nanosp"),
(Model::NanoSP, "nanosp", "nanosplus"),
(Model::NanoX, "nanox", "nanox"),
];
for (model, enc, dec) in t {
assert_eq!(&model.to_string(), enc);
assert_eq!(Ok(*model), Model::from_str(dec));
}
}
}