2024-10-15 23:48:06 +02:00
|
|
|
use anyhow::{
|
|
|
|
Context,
|
|
|
|
Result,
|
|
|
|
};
|
|
|
|
use clap::{
|
|
|
|
Parser,
|
|
|
|
Subcommand,
|
|
|
|
};
|
|
|
|
use env_logger;
|
|
|
|
use hex;
|
|
|
|
use improv_setup::improv::{
|
|
|
|
IMPROV_HEADER,
|
|
|
|
IMPROV_VERSION,
|
|
|
|
RPCCommand,
|
|
|
|
CurrentState,
|
|
|
|
calculate_checksum,
|
2024-10-30 22:03:13 +01:00
|
|
|
ImprovDataToPacket,
|
2024-12-18 20:00:26 +01:00
|
|
|
ImprovDataFromPacket,
|
2024-12-18 20:14:25 +01:00
|
|
|
RawPacket,
|
2024-12-18 21:00:09 +01:00
|
|
|
ImprovPacket,
|
2024-10-30 22:03:13 +01:00
|
|
|
RequestCurrentStateCommand,
|
2024-10-15 23:48:06 +02:00
|
|
|
};
|
|
|
|
use log::{
|
|
|
|
debug,
|
|
|
|
log_enabled,
|
|
|
|
info,
|
|
|
|
Level,
|
|
|
|
};
|
|
|
|
use tokio_serial;
|
|
|
|
|
|
|
|
#[derive(Subcommand, Clone)]
|
|
|
|
enum DeviceCommands {
|
|
|
|
/// Set wifi credentials
|
|
|
|
SetWifi {
|
|
|
|
/// SSID of the network
|
|
|
|
ssid: String,
|
|
|
|
/// Password for the SSID
|
|
|
|
password: String,
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Subcommand, Clone)]
|
|
|
|
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)]
|
|
|
|
struct Cli {
|
|
|
|
#[command(subcommand)]
|
|
|
|
command: Option<Commands>,
|
|
|
|
}
|
|
|
|
|
|
|
|
fn to_ascii_debug(bytes: &Vec<u8>) -> String {
|
|
|
|
let mut out = String::new();
|
|
|
|
|
|
|
|
for b in bytes {
|
|
|
|
if b.is_ascii_graphic() {
|
|
|
|
out += &b.escape_ascii().to_string();
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
out.push_str(".");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return out;
|
|
|
|
}
|
|
|
|
|
|
|
|
fn find_begin_of_improv_packet(buffer: &Vec<u8>) -> Result<usize, String> {
|
|
|
|
|
|
|
|
let mut improv_header_char: usize = 0;
|
|
|
|
|
|
|
|
for (i, b) in buffer.iter().enumerate() {
|
|
|
|
if b == &IMPROV_HEADER[improv_header_char] {
|
|
|
|
improv_header_char += 1;
|
|
|
|
|
|
|
|
if improv_header_char >= IMPROV_HEADER.len() {
|
|
|
|
return Ok(i - (IMPROV_HEADER.len() - 1));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
improv_header_char = 0;
|
|
|
|
if b == &IMPROV_HEADER[improv_header_char] {
|
|
|
|
improv_header_char += 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return Err(String::from("Improv header not found"));
|
|
|
|
}
|
|
|
|
|
|
|
|
#[tokio::main]
|
|
|
|
async fn main() -> Result<()>{
|
|
|
|
env_logger::init();
|
|
|
|
|
|
|
|
let cli = Cli::parse();
|
|
|
|
|
|
|
|
let command: Commands = match &cli.command {
|
|
|
|
Some(command) => command.clone(),
|
|
|
|
None => Commands::ListDevices,
|
|
|
|
};
|
|
|
|
|
|
|
|
match &command {
|
|
|
|
Commands::ListDevices => {
|
|
|
|
println!("{}", tokio_serial::available_ports()
|
|
|
|
.unwrap()
|
|
|
|
.iter()
|
|
|
|
.map(|serialport| serialport.port_name.clone())
|
|
|
|
.fold(String::new(), |a, b| a + &b + &String::from("\n")));
|
|
|
|
},
|
|
|
|
Commands::Device {path, baud_rate, device_command} => {
|
2024-12-18 20:14:25 +01:00
|
|
|
let request_current_state_packet = (RequestCurrentStateCommand {}).to_raw_packet();
|
2024-10-15 23:48:06 +02:00
|
|
|
|
2024-10-30 20:35:31 +01:00
|
|
|
println!("{}", hex::encode(&request_current_state_packet.to_bytes()));
|
|
|
|
println!("{}", to_ascii_debug(&request_current_state_packet.to_bytes()));
|
2024-10-15 23:48:06 +02:00
|
|
|
|
|
|
|
let mut serial_interface = tokio_serial::new(path, *baud_rate).open().unwrap();
|
|
|
|
|
2024-10-30 20:35:31 +01:00
|
|
|
serial_interface.write(&request_current_state_packet.to_bytes()).unwrap();
|
2024-10-15 23:48:06 +02:00
|
|
|
|
|
|
|
let mut buffer: Vec<u8> = Vec::new();
|
|
|
|
serial_interface.read_to_end(&mut buffer);
|
|
|
|
|
|
|
|
println!("{}", hex::encode(&buffer));
|
|
|
|
println!("{}", to_ascii_debug(&buffer));
|
|
|
|
println!("{}", std::str::from_utf8(&buffer).unwrap_or(""));
|
|
|
|
|
|
|
|
let improv_packet_offset = find_begin_of_improv_packet(&buffer).unwrap();
|
|
|
|
println!("{}", improv_packet_offset);
|
|
|
|
|
2024-10-27 12:46:42 +01:00
|
|
|
let improv_packet_end = improv_packet_offset + 10 + <u8 as Into<usize>>::into(buffer[improv_packet_offset+8]);
|
2024-12-18 20:14:25 +01:00
|
|
|
let raw_packet = RawPacket::try_from_bytes(&buffer[improv_packet_offset..improv_packet_end].to_vec()).unwrap();
|
2024-10-15 23:48:06 +02:00
|
|
|
|
|
|
|
// version
|
2024-12-18 20:14:25 +01:00
|
|
|
println!("Version: {}", &raw_packet.version);
|
2024-10-15 23:48:06 +02:00
|
|
|
|
|
|
|
// type
|
2024-12-18 20:14:25 +01:00
|
|
|
println!("Type: {}", &raw_packet.r#type);
|
2024-10-15 23:48:06 +02:00
|
|
|
|
2024-12-18 21:00:09 +01:00
|
|
|
if let ImprovPacket::CurrentStateResponse(current_state_response) = ImprovPacket::try_from_raw_packet(&raw_packet).unwrap() {
|
2024-12-18 20:00:26 +01:00
|
|
|
println!("Current state: {}", ¤t_state_response.current_state);
|
2024-10-15 23:48:06 +02:00
|
|
|
}
|
|
|
|
|
2024-12-18 21:20:00 +01:00
|
|
|
if let ImprovPacket::ErrorState(error_state) = ImprovPacket::try_from_raw_packet(&raw_packet).unwrap() {
|
|
|
|
println!("Error state: {}", &error_state.error_state);
|
|
|
|
}
|
|
|
|
|
2024-10-15 23:48:06 +02:00
|
|
|
},
|
|
|
|
};
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
}
|