Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Better error handling in backend and migrate to async #9

Merged
merged 1 commit into from
Sep 2, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions src-tauri/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions src-tauri/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ tauri = { version = "1", features = ["shell-open"] }
serde = { version = "1", features = ["derive"] }
ds = { git = "https://github.com/spacey-sooty/ds-rs.git", branch = "updatedeps" }
gilrs = { version = "0.10.9", features = ["serde", "serde-serialize"] }
tokio = "1.40.0"
once_cell = "1.19.0"

[features]
# This feature is used for production builds or when a dev server is not specified, DO NOT REMOVE!!
Expand Down
135 changes: 80 additions & 55 deletions src-tauri/src/main.rs
Original file line number Diff line number Diff line change
@@ -1,21 +1,19 @@
// Prevents additional console window on Windows in release, DO NOT REMOVE!!
#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")]

use std::{
fmt,
fs::File,
io::Write,
sync::{Mutex, MutexGuard},
thread,
time::Duration,
};
use std::{fmt, fs::File, io::Write, thread, time::Duration};

use once_cell::sync::Lazy;
use tauri::async_runtime::Mutex;
use tokio::sync::MutexGuard;

use ds::{DriverStation, JoystickValue, Mode};
use gilrs::{Axis, Button, Gilrs};
use serde::{
de::{self, Visitor},
Deserialize, Serialize,
};

use tauri::{api::path::app_config_dir, Manager, State};

#[derive(Debug, Serialize, Deserialize, PartialEq, Clone)]
Expand Down Expand Up @@ -101,7 +99,10 @@ fn send_packet_no_last(
let change_team_num = connection.team_num != packet.team_num;
let change_position = connection.position != packet.position;
let change_colour = connection.colour != packet.colour;
let ds = &mut connection.ds.as_mut().unwrap();
let ds = &mut match connection.ds.as_mut() {
Some(ds) => ds,
None => return,
};

if change_team_num {
ds.set_team_number(packet.team_num);
Expand Down Expand Up @@ -131,34 +132,53 @@ fn send_packet_no_last(
}

#[tauri::command]
fn send_packet(last_packet: State<Mutex<Packet>>, packet: Packet) {
*last_packet.lock().unwrap() = packet;
async fn send_packet(
last_packet: State<'_, Lazy<Mutex<Packet>>>,
packet: Packet,
) -> Result<(), ()> {
*last_packet.lock().await = packet;

Ok(())
}

#[tauri::command]
fn restart_code(state: State<Mutex<DriverStationState>>) {
state.lock().unwrap().ds.as_mut().unwrap().restart_code();
async fn restart_code(state: State<'_, Lazy<Mutex<DriverStationState>>>) -> Result<(), ()> {
match state.lock().await.ds.as_mut() {
Some(ds) => ds.restart_code(),
None => {
println!("Can't restart code, DriverStationState doesn't exist yet.");
return Ok(());
}
}

Ok(())
}

#[tauri::command]
fn estop(last_packet: State<Mutex<Packet>>) {
let mut packet = last_packet.lock().unwrap().clone();
async fn estop(last_packet: State<'_, Lazy<Mutex<Packet>>>) -> Result<(), ()> {
let mut packet = last_packet.lock().await.clone();
packet.state = RobotState::Enabled;
send_packet(last_packet, packet);
send_packet(last_packet, packet).await.unwrap();

Ok(())
}

#[tauri::command]
fn disable(last_packet: State<Mutex<Packet>>) {
let mut packet = last_packet.lock().unwrap().clone();
async fn disable(last_packet: State<'_, Lazy<Mutex<Packet>>>) -> Result<(), ()> {
let mut packet = last_packet.lock().await.clone();
packet.state = RobotState::Disabled;
send_packet(last_packet, packet);
send_packet(last_packet, packet).await.unwrap();

Ok(())
}

#[tauri::command]
fn enable(last_packet: State<Mutex<Packet>>) {
let mut packet = last_packet.lock().unwrap().clone();
async fn enable(last_packet: State<'_, Lazy<Mutex<Packet>>>) -> Result<(), ()> {
let mut packet = last_packet.lock().await.clone();
packet.state = RobotState::Enabled;
send_packet(last_packet, packet);
send_packet(last_packet, packet).await.unwrap();

Ok(())
}

// Learn more about Tauri commands at https://tauri.app/v1/guides/features/command
Expand All @@ -167,19 +187,23 @@ fn greet(name: &str) -> String {
format!("Hello, {}! You've been greeted from Rust!", name)
}

static LAST_PACKET: Mutex<Packet> = Mutex::new(Packet {
colour: AllianceColour::Red,
mode: RobotMode(Mode::Teleoperated),
position: 1,
state: RobotState::Disabled,
team_num: 4788,
static LAST_PACKET: Lazy<Mutex<Packet>> = Lazy::new(|| {
Mutex::new(Packet {
colour: AllianceColour::Red,
mode: RobotMode(Mode::Teleoperated),
position: 1,
state: RobotState::Disabled,
team_num: 4788,
})
});

static DRIVERSTATION_STATE: Mutex<DriverStationState> = Mutex::new(DriverStationState {
ds: None,
colour: AllianceColour::Red,
position: 1,
team_num: 4788,
static DRIVERSTATION_STATE: Lazy<Mutex<DriverStationState>> = Lazy::new(|| {
Mutex::new(DriverStationState {
ds: None,
colour: AllianceColour::Red,
position: 1,
team_num: 4788,
})
});

const AXIS: [Axis; 4] = [
Expand Down Expand Up @@ -216,30 +240,37 @@ fn main() {

tauri::Builder::default()
.setup(|app| {
let config_dir = app_config_dir(&app.config()).unwrap();
let config_dir =
app_config_dir(&app.config()).expect("Should be able to get config dir.");
let _ = std::fs::create_dir_all(&config_dir);
let location = config_dir.to_str().unwrap().to_string() + "/team_num";
let location = config_dir
.to_str()
.expect("Config directory should be valid string.")
.to_string()
+ "/team_num";
let team_num_string = std::fs::read_to_string(&location);
let team_num: u32 = match team_num_string {
Ok(string) => string.parse().unwrap(),
Ok(string) => string
.parse()
.expect("Saved team number should be a number."),
Err(_) => {
File::create_new(&location)
.unwrap()
.expect("Team number file doesn't exist, so should be creatable.")
.write_all(b"4788")
.unwrap();
.expect("Should be able to write to team number file.");
4788
}
};

{
LAST_PACKET.lock().unwrap().team_num = team_num;
let mut ds = DRIVERSTATION_STATE.lock().unwrap();
tauri::async_runtime::spawn(async move {
LAST_PACKET.lock().await.team_num = team_num;
let mut ds = DRIVERSTATION_STATE.lock().await;
ds.ds = Some(DriverStation::new_team(team_num, ds::Alliance::new_red(1)));
ds.team_num = team_num;
let driverstation = ds.ds.as_mut().unwrap();
let driverstation = ds.ds.as_mut().expect("Driverstation should exist.");
driverstation.set_use_usb(false);
driverstation.set_joystick_supplier(|| {
let gilrs = Gilrs::new().unwrap();
let gilrs = Gilrs::new().expect("Should be able to load Gilrs.");
let mut out: Vec<Vec<JoystickValue>> = vec![];
for (_id, gamepad) in gilrs.gamepads() {
let mut values: Vec<JoystickValue> = vec![];
Expand All @@ -261,23 +292,17 @@ fn main() {
}
out
});
}
});

app.manage(&DRIVERSTATION_STATE);
app.manage(&LAST_PACKET);

thread::Builder::new()
.name("background sender".to_string())
.spawn(move || loop {
{
send_packet_no_last(
LAST_PACKET.lock().unwrap(),
DRIVERSTATION_STATE.lock().unwrap(),
);
}
tauri::async_runtime::spawn(async move {
loop {
send_packet_no_last(LAST_PACKET.lock().await, DRIVERSTATION_STATE.lock().await);
thread::sleep(Duration::from_millis(15));
})
.unwrap();
}
});

Ok(())
})
Expand Down