171 lines
6.5 KiB
Rust
171 lines
6.5 KiB
Rust
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(())
|
|
}
|