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:
parent
ddfdc7894f
commit
2fc7f142db
6 changed files with 73 additions and 30 deletions
38
src/device.rs
Normal file → Executable file
38
src/device.rs
Normal file → Executable 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
0
src/gpio_facade.rs
Normal file → Executable file
0
src/lib.rs
Normal file → Executable file
0
src/lib.rs
Normal file → Executable file
2
src/log_facade.rs
Normal file → Executable file
2
src/log_facade.rs
Normal file → Executable 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
26
src/main.rs
Normal file → Executable 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
37
src/tty.rs
Normal file → Executable 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);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue