Started testing on hardware

In no particular order:
- GPIO works now (finally)
- Threading works properly
- Direct serial communication seems to be working properly. Parsing of
  serial responses is going to take some adjustments...
This commit is contained in:
Blizzard Finnegan 2023-05-10 16:09:53 -04:00
parent ddfdc7894f
commit 2fc7f142db
Signed by: blizzardfinnegan
GPG key ID: 61C1E13067E0018E
6 changed files with 73 additions and 30 deletions

38
src/device.rs Normal file → Executable file
View file

@ -1,6 +1,6 @@
use std::{fs::{self, File}, path::Path, io::{BufReader, BufRead, BufWriter, Write}, thread, time::Duration};
use crate::tty;
use rppal::gpio::Gpio;
use rppal::gpio::{Gpio,OutputPin};
const BOOT_TIME:Duration = Duration::new(60, 0);
const BP_START:Duration = Duration::new(3, 0);
@ -10,7 +10,7 @@ const BP_SECTION: &str = "Successful BP tests: ";
const TEMP_SECTION: &str = "Successful temp tests: ";
const OUTPUT_FOLDER: &str = "output/";
const UNINITIALISED_SERIAL: &str = "uninitialised";
#[derive(PartialEq)]
#[derive(PartialEq,Debug)]
pub enum State{
LoginPrompt,
DebugMenu,
@ -18,11 +18,13 @@ pub enum State{
BrightnessMenu
}
#[derive(Debug)]
pub struct Device{
usb_tty: tty::TTY,
output_file: Option<File>,
gpio: rppal::gpio::Gpio,
pin: Option<u8>,
address: Option<u8>,
pin: Option<OutputPin>,
serial: String,
current_state: State,
reboots: u64,
@ -68,6 +70,7 @@ impl Device{
let mut output = Self{
usb_tty: usb_port,
gpio: Gpio::new().unwrap(),
address: None,
pin: None,
output_file: None,
serial: UNINITIALISED_SERIAL.to_string(),
@ -86,6 +89,7 @@ impl Device{
State::LoginPrompt => return self,
State::DebugMenu | State::LifecycleMenu | State::BrightnessMenu => {
self.usb_tty.write_to_device(tty::Command::Quit);
_ = self.usb_tty.read_from_device(None);
self.current_state = State::LoginPrompt;
self.reboots+=1;
return self;
@ -101,16 +105,20 @@ impl Device{
State::BrightnessMenu => return self,
State::DebugMenu => {
self.usb_tty.write_to_device(tty::Command::LifecycleMenu);
_ = self.usb_tty.read_from_device(None);
self.current_state = State::LifecycleMenu;
return self;
},
State::LifecycleMenu =>{
self.usb_tty.write_to_device(tty::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.read_from_device(None);
self.usb_tty.write_to_device(tty::Command::DebugMenu);
_ = self.usb_tty.read_from_device(None);
self.current_state = State::DebugMenu;
},
};
@ -124,15 +132,19 @@ impl Device{
State::DebugMenu => return self,
State::BrightnessMenu => {
self.usb_tty.write_to_device(tty::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.read_from_device(None);
self.current_state = State::BrightnessMenu;
},
State::LoginPrompt => {
self.usb_tty.write_to_device(tty::Command::Login);
_ = self.usb_tty.read_from_device(None);
self.usb_tty.write_to_device(tty::Command::DebugMenu);
_ = self.usb_tty.read_from_device(None);
self.current_state = State::DebugMenu;
return self;
},
@ -146,16 +158,21 @@ impl Device{
State::LifecycleMenu => return self,
State::DebugMenu => {
self.usb_tty.write_to_device(tty::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.current_state = State::BrightnessMenu;
_ = 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.read_from_device(None);
self.usb_tty.write_to_device(tty::Command::DebugMenu);
_ = self.usb_tty.read_from_device(None);
self.current_state = State::DebugMenu;
},
};
@ -187,18 +204,19 @@ impl Device{
&self.serial
}
pub fn set_pin_address(&mut self, address:u8) -> &mut Self{
self.pin = Some(address);
self.address = Some(address);
self.pin = Some(self.gpio.get(self.address.unwrap()).unwrap().into_output());
return self;
}
pub fn start_temp(&mut self) -> &mut Self {
if let Some(_) = self.pin {
self.gpio.get(self.pin.unwrap()).unwrap().into_output().set_high();
if let Some(ref mut pin) = self.pin {
pin.set_high();
}
return self;
}
pub fn stop_temp(&mut self) -> &mut Self {
if let Some(_) = self.pin {
self.gpio.get(self.pin.unwrap()).unwrap().into_output().set_low();
if let Some(ref mut pin) = self.pin {
pin.set_low();
}
return self;
}

0
src/gpio_facade.rs Normal file → Executable file
View file

0
src/lib.rs Normal file → Executable file
View file

2
src/log_facade.rs Normal file → Executable file
View file

@ -16,7 +16,7 @@ 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/output-{0}.log",
chrono_now.format("%Y-%m-%d_%H.%M.%S").to_string()
))?),
)

26
src/main.rs Normal file → Executable file
View file

@ -4,9 +4,7 @@ use serialport;
use crate::serialport::SerialPortInfo;
use seymour_poc_rust::{device, tty,log_facade,gpio_facade::GpioPins, tty::TTY};
use std::io::{stdin,stdout,Write};
#[allow(unused_imports)]
use std::{thread, time::Duration};
use std::thread::{self, JoinHandle};
fn int_input_filtering(prompt:Option<&str>) -> u64{
let internal_prompt = prompt.unwrap_or(">>>");
@ -28,7 +26,7 @@ fn input_filtering(prompt:Option<&str>) -> String{
let mut user_input:String = String::new();
print!("{}",internal_prompt);
_ = stdout().flush();
stdin().read_line(&mut user_input).expect("Did not enter a correct string");
stdin().read_line(&mut user_input).ok().expect("Did not enter a correct string");
if let Some('\n')=user_input.chars().next_back() {
user_input.pop();
}
@ -43,19 +41,24 @@ fn main(){
let gpio = &mut GpioPins::new();
let available_ttys:Vec<SerialPortInfo> = tty::AVAILABLE_TTYS.clone();
let mut possible_devices:Vec<Option<device::Device>> = Vec::new();
let mut tty_test_threads:Vec<JoinHandle<Option<device::Device>>> = Vec::new();
for possible_tty in available_ttys.to_vec(){
possible_devices.push(thread::spawn(move ||{
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);
possible_port.write_to_device(tty::Command::Newline);
let response = possible_port.read_from_device(Some(""));
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))
}
else{
None
}
}).join().unwrap());
}));//.join().unwrap());
}
for thread in tty_test_threads{
possible_devices.push(thread.join().unwrap());
}
let mut devices:Vec<device::Device> = Vec::new();
for possible_device in possible_devices.into_iter(){
@ -63,6 +66,7 @@ fn main(){
devices.push(device);
}
}
println!("Number of devices detected: {}",devices.len());
println!("Dimming all screens...");
for device in devices.iter_mut(){
@ -91,13 +95,17 @@ fn main(){
iteration_count = int_input_filtering(Some("Enter the number of iterations to complete: "));
}
let mut iteration_threads = Vec::new();
while let Some(mut device) = devices.pop(){
thread::spawn(move||{
iteration_threads.push(thread::spawn(move||{
for i in 1..=iteration_count{
println!("Starting iteration {} of {} for device {}...",
i,iteration_count,device.get_serial());
device.test_cycle(None, None);
}
}).join().unwrap();
}));
}
for thread in iteration_threads{
thread.join().unwrap();
}
}

37
src/tty.rs Normal file → Executable file
View file

@ -1,13 +1,13 @@
use std::{collections::HashMap, io::{BufReader, BufRead, Write}};
use std::{collections::HashMap, io::{BufReader, BufRead, Write}, time::Duration};
use once_cell::sync::Lazy;
use serialport::{SerialPortInfo, TTYPort};
use serialport::{SerialPortInfo,SerialPort};
use derivative::Derivative;
pub const BAUD_RATE:u32 = 115200;
pub const AVAILABLE_TTYS: Lazy<Vec<SerialPortInfo>> = Lazy::new(||serialport::available_ports().unwrap());
#[derive(Eq,Derivative)]
#[derive(Eq,Derivative,Debug)]
#[derivative(PartialEq, Hash)]
pub enum Command{
Quit,
@ -25,7 +25,7 @@ pub enum Command{
Newline,
}
#[derive(Clone,Eq,Derivative)]
#[derive(Clone,Eq,Derivative,Debug)]
#[derivative(Copy,PartialEq, Hash)]
pub enum Response{
PasswordPrompt,
@ -51,7 +51,8 @@ const COMMAND_MAP:Lazy<HashMap<Command,&str>> = Lazy::new(||HashMap::from([
(Command::BrightnessLow, "1"),
(Command::ReadTemp, "h"),
(Command::UpMenuLevel, "\\"),
(Command::Login,"root"),
(Command::Login,"root\n"),
(Command::RedrawMenu,"?"),
(Command::DebugMenu,"python3 -m debugmenu; shutdown -r now\n"),
(Command::Newline,"\n"),
]));
@ -65,10 +66,18 @@ const RESPONSE_MAP:Lazy<HashMap<&str,Response>> = Lazy::new(||HashMap::from([
("Temp:",Response::TempSuccess),
(">",Response::DebugMenu),
("[",Response::Rebooting),
("login:",Response::LoginPrompt),
]));
pub struct TTY{
tty: Box<TTYPort>
tty: Box<dyn SerialPort>
}
impl std::fmt::Debug for TTY{
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result{
f.debug_struct("TTY")
.field("Serial port name",&self.tty.name().unwrap_or("Unknown".to_string()))
.finish()
}
}
impl TTY{
@ -78,24 +87,32 @@ impl TTY{
}
else {
return TTY {
tty: Box::new(TTYPort::open(&serialport::new(serial_location, BAUD_RATE)).unwrap())
tty: serialport::new(serial_location,BAUD_RATE).timeout(Duration::new(3, 0)).open().unwrap()
};
}
}
pub fn write_to_device(&mut self,command:Command) -> bool {
return self.tty.write_all(COMMAND_MAP.get(&command).unwrap().as_bytes()).is_ok();
println!("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 internal_break_char = break_char.unwrap_or(">").as_bytes()[0];
let mut internal_break_char = break_char.unwrap_or(">").as_bytes();
if internal_break_char.len() == 0{
internal_break_char = ">".as_bytes();
}
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, &mut read_buffer).unwrap_or(0);
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);
}
}