End of major bugfixes. Starting medium-scale testing

This commit is contained in:
Blizzard Finnegan 2023-05-11 16:31:03 -04:00
parent 2fc7f142db
commit 2f93f493c4
Signed by: blizzardfinnegan
GPG key ID: 61C1E13067E0018E
5 changed files with 143 additions and 95 deletions

View file

@ -1,9 +1,8 @@
use std::{fs::{self, File}, path::Path, io::{BufReader, BufRead, BufWriter, Write}, thread, time::Duration};
use crate::tty;
use std::{fs::{self, File}, path::Path, io::Write, thread, time::Duration};
use crate::tty::{TTY, Response,Command};
use rppal::gpio::{Gpio,OutputPin};
const BOOT_TIME:Duration = Duration::new(60, 0);
const BP_START:Duration = Duration::new(3, 0);
const BP_RUN:Duration = Duration::new(75, 0);
const REBOOTS_SECTION: &str = "Reboots: ";
const BP_SECTION: &str = "Successful BP tests: ";
@ -20,7 +19,7 @@ pub enum State{
#[derive(Debug)]
pub struct Device{
usb_tty: tty::TTY,
usb_tty:TTY,
output_file: Option<File>,
gpio: rppal::gpio::Gpio,
address: Option<u8>,
@ -37,18 +36,23 @@ impl Device{
if ! Path::new(&OUTPUT_FOLDER).is_dir(){
_ = fs::create_dir(&OUTPUT_FOLDER);
};
let output_path = OUTPUT_FOLDER.to_owned() + &self.serial.to_string();
log::debug!("{:?}",&self.serial);
let output_path = OUTPUT_FOLDER.to_owned() + &self.serial + ".txt";
if ! Path::new(&output_path).exists(){
log::debug!("Creating file {}",output_path);
self.output_file = Some(fs::File::create(&output_path).unwrap());
self.save_values();
}
else {
if let Some(file) = &self.output_file{
let reader = BufReader::new(file);
for line in reader.lines(){
let unwrapped_line = line.unwrap().to_string();
let mut split_sections = unwrapped_line.split(": ");
let section: &str = &*split_sections.next().unwrap().to_lowercase();
let value = split_sections.next().unwrap().parse::<u64>().unwrap();
let file_contents = std::fs::read_to_string(output_path).unwrap();
let file_lines = file_contents.split("\n");
log::trace!("{:?}",file_contents);
for line in file_lines {
if line.len() > 0{
log::trace!("{:?}",line);
let section_and_data:Vec<&str> = line.split(": ").collect();
let section = section_and_data[0];
let value:u64 = section_and_data[1].parse().unwrap();
match section {
REBOOTS_SECTION => {
self.reboots = value;
@ -62,11 +66,32 @@ impl Device{
_ => ()
};
};
}
};
};
return self;
}
pub fn new(usb_port:tty::TTY) -> Self{
pub fn new(mut usb_port:TTY,response:Option<Response>) -> Self{
let initial_state:State;
match response{
Some(response_value)=> {
match response_value{
Response::PasswordPrompt=>{
usb_port.write_to_device(Command::Newline);
_ = usb_port.read_from_device(None);
initial_state = State::LoginPrompt;
},
Response::Other | Response::Empty | Response::ShellPrompt
| Response::LoginPrompt | Response::Rebooting =>
initial_state = State::LoginPrompt,
Response::BPOn | Response::BPOff | Response::TempFailed
| Response::TempSuccess =>
initial_state = State::LifecycleMenu,
Response::DebugMenuReady | Response::DebugMenuWithContinuedMessage=>
initial_state = State::DebugMenu,
}
},
None => initial_state = State::LoginPrompt
};
let mut output = Self{
usb_tty: usb_port,
gpio: Gpio::new().unwrap(),
@ -74,7 +99,7 @@ impl Device{
pin: None,
output_file: None,
serial: UNINITIALISED_SERIAL.to_string(),
current_state: State::LoginPrompt,
current_state: initial_state,
reboots: 0,
temps: 0,
bps: 0
@ -88,7 +113,7 @@ impl Device{
match self.current_state {
State::LoginPrompt => return self,
State::DebugMenu | State::LifecycleMenu | State::BrightnessMenu => {
self.usb_tty.write_to_device(tty::Command::Quit);
self.usb_tty.write_to_device(Command::Quit);
_ = self.usb_tty.read_from_device(None);
self.current_state = State::LoginPrompt;
self.reboots+=1;
@ -104,20 +129,20 @@ impl Device{
match self.current_state {
State::BrightnessMenu => return self,
State::DebugMenu => {
self.usb_tty.write_to_device(tty::Command::LifecycleMenu);
self.usb_tty.write_to_device(Command::LifecycleMenu);
_ = self.usb_tty.read_from_device(None);
self.current_state = State::LifecycleMenu;
},
State::LifecycleMenu =>{
self.usb_tty.write_to_device(tty::Command::BrightnessMenu);
self.usb_tty.write_to_device(Command::BrightnessMenu);
_ = self.usb_tty.read_from_device(None);
self.current_state = State::BrightnessMenu;
return self;
},
State::LoginPrompt => {
self.usb_tty.write_to_device(tty::Command::Login);
self.usb_tty.write_to_device(Command::Login);
_ = self.usb_tty.read_from_device(None);
self.usb_tty.write_to_device(tty::Command::DebugMenu);
self.usb_tty.write_to_device(Command::DebugMenu);
_ = self.usb_tty.read_from_device(None);
self.current_state = State::DebugMenu;
},
@ -131,19 +156,19 @@ impl Device{
match self.current_state {
State::DebugMenu => return self,
State::BrightnessMenu => {
self.usb_tty.write_to_device(tty::Command::UpMenuLevel);
self.usb_tty.write_to_device(Command::UpMenuLevel);
_ = self.usb_tty.read_from_device(None);
self.current_state = State::LifecycleMenu;
},
State::LifecycleMenu =>{
self.usb_tty.write_to_device(tty::Command::UpMenuLevel);
self.usb_tty.write_to_device(Command::UpMenuLevel);
_ = self.usb_tty.read_from_device(None);
self.current_state = State::BrightnessMenu;
},
State::LoginPrompt => {
self.usb_tty.write_to_device(tty::Command::Login);
self.usb_tty.write_to_device(Command::Login);
_ = self.usb_tty.read_from_device(None);
self.usb_tty.write_to_device(tty::Command::DebugMenu);
self.usb_tty.write_to_device(Command::DebugMenu);
_ = self.usb_tty.read_from_device(None);
self.current_state = State::DebugMenu;
return self;
@ -157,21 +182,21 @@ impl Device{
match self.current_state {
State::LifecycleMenu => return self,
State::DebugMenu => {
self.usb_tty.write_to_device(tty::Command::LifecycleMenu);
self.usb_tty.write_to_device(Command::LifecycleMenu);
_ = self.usb_tty.read_from_device(None);
self.current_state = State::LifecycleMenu;
return self;
},
State::BrightnessMenu =>{
self.usb_tty.write_to_device(tty::Command::UpMenuLevel);
self.usb_tty.write_to_device(Command::UpMenuLevel);
_ = self.usb_tty.read_from_device(None);
self.current_state = State::LifecycleMenu;
return self;
},
State::LoginPrompt => {
self.usb_tty.write_to_device(tty::Command::Login);
self.usb_tty.write_to_device(Command::Login);
_ = self.usb_tty.read_from_device(None);
self.usb_tty.write_to_device(tty::Command::DebugMenu);
self.usb_tty.write_to_device(Command::DebugMenu);
_ = self.usb_tty.read_from_device(None);
self.current_state = State::DebugMenu;
},
@ -180,8 +205,11 @@ impl Device{
return self;
}
fn save_values(&mut self) -> &mut Self{
if let Some(file_name) = &self.output_file{
let mut file_writer = BufWriter::new(file_name);
let output_path = OUTPUT_FOLDER.to_owned() + &self.serial + ".txt";
self.output_file = Some(std::fs::OpenOptions::new().write(true).truncate(true).open(output_path).unwrap());
log::trace!("{:?}",self.output_file);
if let Some(ref mut file_name) = self.output_file{
log::debug!("Writing to file!");
let mut output_data = REBOOTS_SECTION.to_string();
output_data.push_str(&self.reboots.to_string());
output_data.push_str("\n");
@ -190,14 +218,18 @@ impl Device{
output_data.push_str("\n");
output_data.push_str(TEMP_SECTION);
output_data.push_str(&self.temps.to_string());
file_writer.write_all(output_data.as_bytes()).expect("Unable to write to bufwriter");
file_writer.flush().expect("Unable to write to file");
output_data.push_str("\n");
file_name.write_all(output_data.as_bytes()).expect("Unable to write to bufwriter");
}
else {
log::warn!("Cannot write to log!");
}
return self;
}
pub fn set_serial(&mut self, serial:&str) -> &mut Self{
self.serial = serial.to_string();
self.load_values();
self.save_values();
return self;
}
pub fn get_serial(&mut self) -> &str{
@ -222,40 +254,43 @@ impl Device{
}
pub fn start_bp(&mut self) -> &mut Self {
self.go_to_lifecycle_menu();
self.usb_tty.write_to_device(tty::Command::StartBP);
self.usb_tty.write_to_device(Command::StartBP);
_ = self.usb_tty.read_from_device(None);
return self;
}
pub fn darken_screen(&mut self) -> &mut Self {
self.go_to_brightness_menu();
self.usb_tty.write_to_device(tty::Command::BrightnessLow);
_ = self.usb_tty.read_from_device(None);
self.usb_tty.write_to_device(tty::Command::RedrawMenu);
self.usb_tty.write_to_device(Command::BrightnessLow);
_ = self.usb_tty.read_from_device(None);
return self;
}
pub fn brighten_screen(&mut self) -> &mut Self {
self.go_to_brightness_menu();
self.usb_tty.write_to_device(tty::Command::BrightnessHigh);
_ = self.usb_tty.read_from_device(None);
self.usb_tty.write_to_device(tty::Command::RedrawMenu);
self.usb_tty.write_to_device(Command::BrightnessHigh);
_ = self.usb_tty.read_from_device(None);
return self;
}
pub fn is_temp_running(&mut self) -> bool {
self.go_to_lifecycle_menu();
self.usb_tty.write_to_device(tty::Command::ReadTemp);
match self.usb_tty.read_from_device(None){
tty::Response::TempSuccess => return true,
_ => return false
self.usb_tty.write_to_device(Command::ReadTemp);
loop {
match self.usb_tty.read_from_device(None){
Response::TempSuccess => return true,
Response::TempFailed => return false,
_ => {},
}
}
}
pub fn is_bp_running(&mut self) -> bool {
self.go_to_lifecycle_menu();
self.usb_tty.write_to_device(tty::Command::CheckBPState);
match self.usb_tty.read_from_device(None){
tty::Response::BPOn => return true,
_ => return false
self.usb_tty.write_to_device(Command::CheckBPState);
loop {
match self.usb_tty.read_from_device(None){
Response::BPOn => return true,
Response::BPOff => return false,
Response::DebugMenuWithContinuedMessage =>{},
_ => return false,
}
}
}
pub fn reboot(&mut self) -> () {
@ -283,22 +318,25 @@ impl Device{
_ = self.usb_tty.read_from_device(Some("["));
for bp_count in 1..=local_bp_cycles{
log::info!("Running bp {} on device {} ...",bp_count,self.serial);
_ = self.start_bp().usb_tty.read_from_device(None);
thread::sleep(BP_START);
let _bp_start = self.is_bp_running();
self.start_bp();
let bp_start = self.is_bp_running();
log::trace!("{:?}",bp_start);
thread::sleep(BP_RUN);
let _bp_end = self.is_bp_running();
if _bp_start != _bp_end {
let bp_end = self.is_bp_running();
log::trace!("{:?}",bp_end);
if bp_start != bp_end {
self.bps +=1;
log::debug!("Increasing bp count to {}",self.bps);
self.save_values();
}
}
for temp_count in 1..=local_temp_cycles{
log::info!("Running temp {} on device {} ...",temp_count,self.serial);
let _temp_start = self.start_temp().is_temp_running();
let _temp_end = self.stop_temp().is_temp_running();
if _temp_start != _temp_end {
let temp_start = self.start_temp().is_temp_running();
let temp_end = self.stop_temp().is_temp_running();
if temp_start != temp_end {
self.temps +=1;
log::debug!("Increasing temp count to {}",self.temps);
self.save_values();
}
}

View file

@ -14,7 +14,7 @@ impl GpioPins{
}
pub fn remove_address(&mut self, address:u8) -> () {
self.unassigned_addresses.retain(|&x| x != address);
self.unassigned_addresses.retain(|x| *x != address);
}
pub fn get_unassigned_addresses(&mut self) -> &mut Vec<u8>{

View file

@ -1,7 +1,12 @@
use chrono::prelude::*;
use std::path::Path;
use std::fs;
pub fn setup_logs() -> Result<(), fern::InitError>{
let chrono_now: DateTime<Local> = Local::now();
if ! Path::new("logs").is_dir(){
_ = fs::create_dir("logs");
};
fern::Dispatch::new()
.format(|out,message,record|{
out.finish(format_args!(
@ -16,13 +21,13 @@ pub fn setup_logs() -> Result<(), fern::InitError>{
fern::Dispatch::new()
.level(log::LevelFilter::Trace)
.chain(fern::log_file(
format!("logs/output-{0}.log",
format!("logs/{0}.log",
chrono_now.format("%Y-%m-%d_%H.%M.%S").to_string()
))?),
)
.chain(
fern::Dispatch::new()
.level(log::LevelFilter::Warn)
.level(log::LevelFilter::Info)
.chain(std::io::stdout())
)
.apply()?;

View file

@ -45,30 +45,33 @@ fn main(){
for possible_tty in available_ttys.to_vec(){
tty_test_threads.push(thread::spawn(move ||{
let mut possible_port = TTY::new(possible_tty.port_name.to_string());
println!("Testing port {}. This may take a moment...",possible_tty.port_name);
log::info!("Testing port {}. This may take a moment...",possible_tty.port_name);
possible_port.write_to_device(tty::Command::Newline);
let response = possible_port.read_from_device(Some(":"));
if response != tty::Response::Other{
println!("{} is valid port!",possible_tty.port_name);
Some(device::Device::new(possible_port))
if response != tty::Response::Empty{
log::debug!("{} is valid port!",possible_tty.port_name);
Some(device::Device::new(possible_port,Some(response)))
}
else{
None
}
}));//.join().unwrap());
}));
}
for thread in tty_test_threads{
possible_devices.push(thread.join().unwrap());
let output = thread.join().unwrap_or_else(|x|{log::trace!("{:?}",x); None});
possible_devices.push(output);
}
let mut devices:Vec<device::Device> = Vec::new();
for possible_device in possible_devices.into_iter(){
if let Some(device) = possible_device{
devices.push(device);
}
}
println!("Number of devices detected: {}",devices.len());
println!("Dimming all screens...");
log::info!("Number of devices detected: {}",devices.len());
log::info!("Dimming all screens...");
for device in devices.iter_mut(){
device.darken_screen();
}
@ -77,11 +80,14 @@ fn main(){
device.brighten_screen()
.set_serial(&input_filtering(Some("Enter the serial of the device with the bright screen: ")).to_string())
.darken_screen();
let mut unassigned_addresses:Vec<u8> = gpio.get_unassigned_addresses().to_vec();
for address in unassigned_addresses.iter_mut(){
device.set_pin_address(*address).start_temp();
let unassigned_addresses:Vec<u8> = gpio.get_unassigned_addresses().to_vec();
log::debug!("Number of unassigned addresses: {}",unassigned_addresses.len());
for address in unassigned_addresses{
device.set_pin_address(address).start_temp();
thread::sleep(std::time::Duration::new(3,0));
if device.is_temp_running(){
device.stop_temp();
gpio.remove_address(address);
break;
}
else{
@ -99,7 +105,7 @@ fn main(){
while let Some(mut device) = devices.pop(){
iteration_threads.push(thread::spawn(move||{
for i in 1..=iteration_count{
println!("Starting iteration {} of {} for device {}...",
log::info!("Starting iteration {} of {} for device {}...",
i,iteration_count,device.get_serial());
device.test_cycle(None, None);
}

View file

@ -1,4 +1,4 @@
use std::{collections::HashMap, io::{BufReader, BufRead, Write}, time::Duration};
use std::{collections::HashMap, io::{BufReader, Write, Read}, time::Duration};
use once_cell::sync::Lazy;
use serialport::{SerialPortInfo,SerialPort};
use derivative::Derivative;
@ -35,16 +35,18 @@ pub enum Response{
TempFailed,
TempSuccess,
LoginPrompt,
DebugMenu,
DebugMenuReady,
DebugMenuWithContinuedMessage,
Rebooting,
Other,
Empty,
}
const COMMAND_MAP:Lazy<HashMap<Command,&str>> = Lazy::new(||HashMap::from([
(Command::Quit, "q\n"),
(Command::StartBP, "c"),
(Command::CheckBPState, "C"),
(Command::StartBP, "N"),
(Command::CheckBPState, "n"),
(Command::LifecycleMenu, "L"),
(Command::BrightnessMenu, "B"),
(Command::BrightnessHigh, "0"),
@ -53,21 +55,22 @@ const COMMAND_MAP:Lazy<HashMap<Command,&str>> = Lazy::new(||HashMap::from([
(Command::UpMenuLevel, "\\"),
(Command::Login,"root\n"),
(Command::RedrawMenu,"?"),
(Command::DebugMenu,"python3 -m debugmenu; shutdown -r now\n"),
(Command::DebugMenu," python3 -m debugmenu; shutdown -r now\n"),
(Command::Newline,"\n"),
]));
const RESPONSE_MAP:Lazy<HashMap<&str,Response>> = Lazy::new(||HashMap::from([
const RESPONSES:[(&str,Response);10] = [
("login:",Response::LoginPrompt),
("Password:",Response::PasswordPrompt),
("root@",Response::ShellPrompt),
("Check NIBP In Progress: True",Response::BPOn),
("Check NIBP In Progress: False",Response::BPOff),
("Temp: 0",Response::TempFailed),
("Temp:",Response::TempSuccess),
(">",Response::DebugMenu),
("> ",Response::DebugMenuWithContinuedMessage),
(">",Response::DebugMenuReady),
("[",Response::Rebooting),
("login:",Response::LoginPrompt),
]));
];
pub struct TTY{
tty: Box<dyn SerialPort>
@ -87,39 +90,35 @@ impl TTY{
}
else {
return TTY {
tty: serialport::new(serial_location,BAUD_RATE).timeout(Duration::new(3, 0)).open().unwrap()
tty: serialport::new(serial_location,BAUD_RATE).timeout(Duration::new(1, 0)).open().unwrap()
};
}
}
pub fn write_to_device(&mut self,command:Command) -> bool {
println!("writing {:?} to tty {}...", command, self.tty.name().unwrap_or("unknown".to_string()));
log::debug!("writing {:?} to tty {}...", command, self.tty.name().unwrap_or("unknown".to_string()));
let output = self.tty.write_all(COMMAND_MAP.get(&command).unwrap().as_bytes()).is_ok();
_ = self.tty.flush();
return output;
}
pub fn read_from_device(&mut self,break_char:Option<&str>) -> Response {
let mut internal_break_char = break_char.unwrap_or(">").as_bytes();
if internal_break_char.len() == 0{
internal_break_char = ">".as_bytes();
}
pub fn read_from_device(&mut self,_break_char:Option<&str>) -> Response {
let mut reader = BufReader::new(&mut self.tty);
let mut read_buffer: Vec<u8> = Vec::new();
let read_result = reader.read_until(internal_break_char[0], &mut read_buffer).unwrap_or(0);
println!("Successfully read {:?} from tty {}",String::from_utf8_lossy(read_buffer.as_slice()),self.tty.name().unwrap_or("unknown".to_string()));
if read_result > 0 {
let read_string:String = String::from_utf8_lossy(read_buffer.as_slice()).to_string();
for possible_response in RESPONSE_MAP.keys(){
if read_string.contains(possible_response){
println!("{:?} matches pattern {:?}",read_string,RESPONSE_MAP.get(*possible_response).unwrap());
return *RESPONSE_MAP.get(*possible_response).unwrap_or(&Response::Other);
_ = reader.read_to_end(&mut read_buffer);
if read_buffer.len() > 0 {
let read_line:String = String::from_utf8_lossy(read_buffer.as_slice()).to_string();
for (string,enum_value) in RESPONSES{
if read_line.contains(string){
log::debug!("Successful read of {:?} from tty {}, which matches pattern {:?}",read_line,self.tty.name().unwrap_or("unknown shell".to_string()),enum_value);
return enum_value;
}
}
return Response::Other;
}
else {
return Response::Other;
log::debug!("Read an empty string. Possible read error.");
return Response::Empty;
};
}
}