use anyhow::{ Context, Result, }; use clap::{ Parser, Subcommand, }; use env_logger; use improv_setup::improv::{ RawPacket, ImprovPacket, SendWiFiSettingsPacket, RequestCurrentStatePacket, RequestDeviceInformationPacket, RequestScannedWiFiNetworksPacket, }; use improv_setup::serial; use tokio_serial; #[derive(Subcommand, Clone)] #[command(arg_required_else_help = true)] enum DeviceCommands { /// Request current state State, /// Connect to wifi network Connect { /// SSID of the network ssid: String, /// Password for the SSID password: String, }, /// Request device info Info, /// WiFi networks visible to device Scan, } impl Default for DeviceCommands { fn default() -> Self { return Self::State; } } #[derive(Subcommand, Clone)] #[command(arg_required_else_help = true)] enum Commands { /// List available serial devices ListDevices, /// Device Device { /// Path to the serial device path: String, /// Baud rate used for connecting to the serial device #[arg(long, default_value_t = 115200)] baud_rate: u32, #[command(subcommand)] device_command: Option<DeviceCommands>, }, } #[derive(Parser)] #[command(version, about, long_about = None, arg_required_else_help = true)] struct Cli { #[command(subcommand)] command: Option<Commands>, } #[tokio::main] async fn main() -> Result<()>{ env_logger::init(); let cli = Cli::parse(); let command = &cli.command.context("No command provided")?.clone(); match &command { Commands::ListDevices => { println!("{}", tokio_serial::available_ports() .context("Failed to list available ports")? .iter() .map(|serialport| serialport.port_name.clone()) .fold(String::new(), |a, b| a + &b + &String::from("\n"))); }, Commands::Device {path, baud_rate, device_command} => { match &device_command.clone().unwrap_or_default() { DeviceCommands::State => { let request_current_state_packet = RequestCurrentStatePacket {}; let mut serial_interface = serial::SerialInterface::new(path, *baud_rate).context("Couldn't init serial interface")?; serial_interface.send(&request_current_state_packet).context("Failed to send improv packet")?; let result_bytes = serial_interface.recv_bytes().context("Couldn't receive any improv packet")?; let raw_packet = RawPacket::try_from_bytes(&result_bytes).context("Failed to deserialize packet")?; if let ImprovPacket::CurrentState(current_state_response) = ImprovPacket::try_from_raw_packet(&raw_packet).context("Failed to read packet")? { println!("Current state: {}", ¤t_state_response.current_state); } if let ImprovPacket::ErrorState(error_state) = ImprovPacket::try_from_raw_packet(&raw_packet).context("Failed to read packet")? { println!("Error state: {}", &error_state.error_state); } }, DeviceCommands::Connect{ssid, password} => { let send_wifi_settings_packet = SendWiFiSettingsPacket { ssid: ssid.clone(), password: password.clone(), }; let mut serial_interface = serial::SerialInterface::new(path, *baud_rate).context("Couldn't init serial interface")?; serial_interface.send(&send_wifi_settings_packet).context("Failed to send improv packet")?; let result_bytes = serial_interface.recv_bytes().context("Couldn't receive any improv packet")?; let raw_packet = RawPacket::try_from_bytes(&result_bytes).context("Failed to deserialize packet")?; if let ImprovPacket::RPCResult(rpc_result) = ImprovPacket::try_from_raw_packet(&raw_packet).context("Failed to read packet")? { for r in rpc_result.results { println!("{}", &r); } } }, DeviceCommands::Info => { let request_device_information_packet = RequestDeviceInformationPacket {}; let mut serial_interface = serial::SerialInterface::new(path, *baud_rate).context("Couldn't init serial interface")?; serial_interface.send(&request_device_information_packet).context("Failed to send improv packet")?; let result_bytes = serial_interface.recv_bytes().context("Couldn't receive any improv packet")?; let raw_packet = RawPacket::try_from_bytes(&result_bytes).context("Failed to deserialize packet")?; if let ImprovPacket::RPCResult(rpc_result) = ImprovPacket::try_from_raw_packet(&raw_packet).context("Failed to read packet")? { for r in rpc_result.results { println!("{}", &r); } } }, DeviceCommands::Scan => { let request_scanned_wifi_networks_packet = RequestScannedWiFiNetworksPacket {}; let mut serial_interface = serial::SerialInterface::new(path, *baud_rate).context("Couldn't init serial interface")?; serial_interface.send(&request_scanned_wifi_networks_packet).context("Failed to send improv packet")?; loop { let result_bytes = serial_interface.recv_bytes().context("Couldn't receive any improv packet")?; let raw_packet = RawPacket::try_from_bytes(&result_bytes).context("Failed to deserialize packet")?; if let ImprovPacket::RPCResult(rpc_result) = ImprovPacket::try_from_raw_packet(&raw_packet).context("Failed to read packet")? { if rpc_result.results.len() <= 0 { break; } println!("{:<25} {:>3} {}", &rpc_result.results[0], &rpc_result.results[1], match rpc_result.results[2].as_str() { "YES" => "secure", "NO" => "open", _ => "", }); } } }, }; }, }; Ok(()) }