use failure::bail;
use std::thread;
mod conn;
pub(crate) mod state;
use self::conn::*;
use self::state::*;
use futures::executor::block_on;
use std::sync::Arc;
use futures_channel::mpsc::{unbounded, UnboundedSender};
use crate::proto::tcp::outbound::{GameData, TcpTag};
use crate::proto::udp::inbound::types::Trace;
use crate::proto::udp::outbound::types::tags::UdpTag;
use crate::proto::udp::outbound::types::*;
use crate::util::ip_from_team_number;
use crate::{Result, TcpPacket};
pub struct DriverStation {
thread_tx: UnboundedSender<Signal>,
team_number: u32,
state: Arc<DsState>,
}
impl DriverStation {
pub fn new_team(team_number: u32, alliance: Alliance) -> DriverStation {
Self::new(&ip_from_team_number(team_number), alliance, team_number)
}
pub fn new(ip: &str, alliance: Alliance, team_number: u32) -> DriverStation {
let (tx, rx) = unbounded::<Signal>();
let state = Arc::new(DsState::new(alliance));
let udp_state = state.clone();
let udp_ip = ip.to_owned();
let sim_tx = tx.clone();
thread::spawn(move || {
use tokio::runtime::Runtime;
let mut rt = Runtime::new().unwrap();
rt.spawn(sim_conn(sim_tx));
rt.block_on(udp_conn(udp_state, udp_ip, rx))
.expect("Error with udp connection");
});
DriverStation {
thread_tx: tx,
state,
team_number,
}
}
pub fn set_joystick_supplier(
&mut self,
supplier: impl Fn() -> Vec<Vec<JoystickValue>> + Send + Sync + 'static,
) {
block_on(self.state.send().lock()).set_joystick_supplier(supplier);
}
pub fn set_tcp_consumer(&mut self, consumer: impl FnMut(TcpPacket) + Send + Sync + 'static) {
block_on(self.state.tcp().lock()).set_tcp_consumer(consumer);
}
pub fn set_alliance(&mut self, alliance: Alliance) {
block_on(self.state.send().lock()).set_alliance(alliance);
}
pub fn set_mode(&mut self, mode: Mode) {
block_on(self.state.send().lock()).set_mode(mode);
}
pub fn ds_mode(&self) -> DsMode {
*block_on(self.state.send().lock()).ds_mode()
}
pub fn set_team_number(&mut self, team_number: u32) {
self.team_number = team_number;
self.thread_tx
.unbounded_send(Signal::NewTarget(ip_from_team_number(team_number)))
.unwrap();
}
pub fn set_use_usb(&mut self, use_usb: bool) {
if use_usb {
self.thread_tx
.unbounded_send(Signal::NewTarget("172.22.11.2".to_string()))
.unwrap();
} else {
self.thread_tx
.unbounded_send(Signal::NewTarget(ip_from_team_number(self.team_number)))
.unwrap();
}
}
pub fn team_number(&self) -> u32 {
self.team_number
}
pub fn set_game_specific_message(&mut self, message: &str) -> Result<()> {
if message.len() != 3 {
bail!("Message should be 3 characters long");
}
let _ = block_on(self.state.tcp().lock()).queue_tcp(TcpTag::GameData(GameData {
gsm: message.to_string(),
}));
Ok(())
}
pub fn mode(&self) -> Mode {
*block_on(self.state.send().lock()).mode()
}
pub fn enable(&mut self) {
block_on(self.state.send().lock()).enable();
}
pub fn restart_code(&mut self) {
block_on(self.state.send().lock()).request(Request::RESTART_CODE);
}
pub fn restart_roborio(&mut self) {
block_on(self.state.send().lock()).request(Request::REBOOT_ROBORIO);
}
pub fn enabled(&self) -> bool {
block_on(self.state.send().lock()).enabled()
}
pub fn trace(&self) -> Trace {
*block_on(self.state.recv().lock()).trace()
}
pub fn battery_voltage(&self) -> f32 {
block_on(self.state.recv().lock()).battery_voltage()
}
pub fn queue_udp(&mut self, udp_tag: UdpTag) {
block_on(self.state.send().lock()).queue_udp(udp_tag);
}
pub fn udp_queue(&self) -> Vec<UdpTag> {
block_on(self.state.send().lock()).pending_udp().clone()
}
pub fn queue_tcp(&mut self, tcp_tag: TcpTag) {
let _ = block_on(self.state.tcp().lock()).queue_tcp(tcp_tag);
}
pub fn estop(&mut self) {
block_on(self.state.send().lock()).estop();
}
pub fn estopped(&self) -> bool {
block_on(self.state.send().lock()).estopped()
}
pub fn disable(&mut self) {
block_on(self.state.send().lock()).disable();
}
}
#[derive(Debug, Copy, Clone, PartialEq)]
pub enum JoystickValue {
Axis { id: u8, value: f32 },
Button { id: u8, pressed: bool },
POV { id: u8, angle: i16 },
}
impl Drop for DriverStation {
fn drop(&mut self) {
let _ = self.thread_tx.unbounded_send(Signal::Disconnect);
}
}
#[derive(Debug)]
pub(crate) enum Signal {
Disconnect,
NewTarget(String),
NewMode(DsMode),
}