use crate::models::*;
use clyde_3g_eps_api::{Checksum, Clyde3gEps, Eps};
use eps_api::EpsResult;
use failure::Error;
use rust_i2c::*;
use std::sync::{Arc, Mutex, RwLock};
use std::thread;
use std::time::Duration;
#[derive(Copy, Clone, Debug, Eq, Hash, GraphQLEnum, PartialEq)]
pub enum Mutations {
None,
Noop,
ManualReset,
RawCommand,
ResetWatchdog,
SetWatchdogPeriod,
TestHardware,
}
fn watchdog_thread(eps: Arc<Mutex<Box<Clyde3gEps + Send>>>) {
loop {
thread::sleep(Duration::from_secs(60));
let _res_ = eps.lock().unwrap().reset_comms_watchdog();
}
}
#[derive(Clone)]
pub struct Subsystem {
pub eps: Arc<Mutex<Box<Clyde3gEps + Send>>>,
pub last_mutation: Arc<RwLock<Mutations>>,
pub errors: Arc<RwLock<Vec<String>>>,
pub watchdog_handle: Arc<Mutex<thread::JoinHandle<()>>>,
pub checksum: Arc<Mutex<Checksum>>,
}
impl Subsystem {
pub fn new(eps: Box<Clyde3gEps + Send>) -> EpsResult<Self> {
let eps = Arc::new(Mutex::new(eps));
let thread_eps = eps.clone();
let watchdog = thread::spawn(move || watchdog_thread(thread_eps));
Ok(Self {
eps,
last_mutation: Arc::new(RwLock::new(Mutations::None)),
errors: Arc::new(RwLock::new(vec![])),
watchdog_handle: Arc::new(Mutex::new(watchdog)),
checksum: Arc::new(Mutex::new(Checksum::default())),
})
}
pub fn from_path(bus: &str) -> EpsResult<Self> {
let clyde_eps: Box<Clyde3gEps + Send> =
Box::new(Eps::new(Connection::from_path(bus, 0x2B)));
Subsystem::new(clyde_eps)
}
pub fn get_motherboard_telemetry(
&self,
telem_type: motherboard_telemetry::Type,
) -> Result<f64, String> {
let result = run!(
self.eps
.lock()
.unwrap()
.get_motherboard_telemetry(telem_type.into()),
self.errors
)?;
Ok(result)
}
pub fn get_daughterboard_telemetry(
&self,
telem_type: daughterboard_telemetry::Type,
) -> Result<f64, String> {
let eps = self.eps.lock().unwrap();
Ok(run!(
eps.get_daughterboard_telemetry(telem_type.into()),
self.errors
)?)
}
pub fn get_reset_telemetry(
&self,
telem_type: reset_telemetry::Type,
) -> Result<reset_telemetry::Data, String> {
let eps = self.eps.lock().unwrap();
Ok(run!(eps.get_reset_telemetry(telem_type.into()), self.errors)?.into())
}
pub fn get_comms_watchdog_period(&self) -> Result<u8, String> {
let eps = self.eps.lock().unwrap();
Ok(run!(eps.get_comms_watchdog_period(), self.errors)?)
}
pub fn get_version(&self) -> Result<version::VersionData, String> {
let eps = self.eps.lock().unwrap();
Ok(run!(eps.get_version_info(), self.errors)?.into())
}
pub fn get_board_status(&self) -> Result<board_status::BoardData, String> {
let eps = self.eps.lock().unwrap();
Ok(run!(eps.get_board_status(), self.errors)?.into())
}
pub fn get_last_eps_error(&self) -> Result<last_error::ErrorData, String> {
let eps = self.eps.lock().unwrap();
Ok(run!(eps.get_last_error(), self.errors)?.into())
}
pub fn get_power(&self) -> Result<GetPowerResponse, String> {
let eps = self.eps.lock().unwrap();
if let Ok(data) = eps.get_version_info() {
let daughterboard = if data.daughterboard.is_some() {
PowerState::On
} else {
PowerState::Off
};
Ok(GetPowerResponse {
motherboard: PowerState::On,
daughterboard,
})
} else {
Ok(GetPowerResponse {
motherboard: PowerState::Off,
daughterboard: PowerState::Off,
})
}
}
pub fn manual_reset(&self) -> Result<MutationResponse, String> {
let eps = self.eps.lock().unwrap();
match run!(eps.manual_reset(), self.errors) {
Ok(_v) => Ok(MutationResponse {
success: true,
errors: "".to_string(),
}),
Err(e) => Ok(MutationResponse {
success: false,
errors: e,
}),
}
}
pub fn reset_watchdog(&self) -> Result<MutationResponse, String> {
let eps = self.eps.lock().unwrap();
match run!(eps.reset_comms_watchdog(), self.errors) {
Ok(_v) => Ok(MutationResponse {
success: true,
errors: "".to_string(),
}),
Err(e) => Ok(MutationResponse {
success: false,
errors: e,
}),
}
}
pub fn set_watchdog_period(&self, period: u8) -> Result<MutationResponse, String> {
let eps = self.eps.lock().unwrap();
match run!(eps.set_comms_watchdog_period(period), self.errors) {
Ok(_v) => Ok(MutationResponse {
success: true,
errors: "".to_string(),
}),
Err(e) => Ok(MutationResponse {
success: false,
errors: e,
}),
}
}
pub fn raw_command(&self, command: u8, data: Vec<u8>) -> Result<MutationResponse, String> {
let eps = self.eps.lock().unwrap();
match run!(eps.raw_command(command, data), self.errors) {
Ok(_v) => Ok(MutationResponse {
success: true,
errors: "".to_string(),
}),
Err(e) => Ok(MutationResponse {
success: false,
errors: e,
}),
}
}
pub fn test_hardware(&self) -> Result<MutationResponse, String> {
let eps = self.eps.lock().unwrap();
match run!(eps.get_checksum(), self.errors) {
Ok(new_data) => {
let mut errors = vec![];
let mut success = true;
let mut old_data = self.checksum.lock().unwrap();
if old_data.motherboard != 0 {
if old_data.motherboard != new_data.motherboard {
success = false;
errors.push(format!(
"Motherboard checksum changed: {} -> {}",
old_data.motherboard, new_data.motherboard
));
}
if old_data.daughterboard != new_data.daughterboard {
success = false;
errors.push(format!(
"Daughterboard checksum changed: {:?} -> {:?}",
old_data.daughterboard, new_data.daughterboard
));
}
}
old_data.motherboard = new_data.motherboard;
old_data.daughterboard = new_data.daughterboard;
eprintln!(
"EPS checksums: {}, {:?}",
old_data.motherboard, old_data.daughterboard
);
Ok(MutationResponse {
success,
errors: errors.join(". "),
})
}
Err(e) => Ok(MutationResponse {
success: false,
errors: e,
}),
}
}
pub fn set_last_mutation(&self, mutation: Mutations) {
if let Ok(mut last_cmd) = self.last_mutation.write() {
*last_cmd = mutation;
}
}
pub fn get_errors(&self) -> EpsResult<Vec<String>> {
match self.errors.write() {
Ok(mut master_vec) => {
let current = master_vec.clone();
master_vec.clear();
master_vec.shrink_to_fit();
Ok(current)
}
_ => Ok(vec![
"Error: Failed to borrow master errors vector".to_string()
]),
}
}
}