Skip to content

Commit b7cb657

Browse files
committed
Split DriverStationState and DSConnection into separate modules.
1 parent b129c42 commit b7cb657

File tree

3 files changed

+228
-207
lines changed

3 files changed

+228
-207
lines changed

src/connection.rs

Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
use std::io;
2+
use std::io::Read;
3+
use std::net::{IpAddr, SocketAddr, TcpStream, UdpSocket};
4+
use std::sync::{mpsc, Arc, Mutex};
5+
use std::thread;
6+
use std::thread::JoinHandle;
7+
8+
use byteorder::{ByteOrder, NetworkEndian};
9+
10+
use ds::DriverStationState;
11+
use messages::*;
12+
13+
pub struct DSConnection {
14+
thread: JoinHandle<()>,
15+
sender: mpsc::Sender<Signal>,
16+
errors: mpsc::Receiver<io::Result<()>>,
17+
err: Option<io::Error>,
18+
}
19+
20+
impl DSConnection {
21+
pub fn release(self) {
22+
drop(self);
23+
}
24+
25+
pub fn new(addr: IpAddr, state: Arc<Mutex<DriverStationState>>) -> io::Result<Self> {
26+
let (sender_signal, receiver_signal) = mpsc::channel::<Signal>();
27+
28+
let (sender_res, receiver_res) = mpsc::channel::<io::Result<()>>();
29+
30+
let mut tcp = TcpStream::connect(SocketAddr::new(addr, 1740))?;
31+
tcp.set_nonblocking(true)?;
32+
33+
let udp = UdpSocket::bind(SocketAddr::new(addr, 1150))?;
34+
udp.set_nonblocking(true)?;
35+
36+
let t = thread::spawn(move || loop {
37+
match receiver_signal.try_recv() {
38+
Ok(Signal::Disconnect) | Err(mpsc::TryRecvError::Disconnected) => break,
39+
_ => {}
40+
}
41+
42+
let mut udp_buf = vec![0u8; 100];
43+
match udp.recv(&mut udp_buf) {
44+
Ok(n) => unimplemented!(),
45+
Err(e) => {
46+
if e.kind() != io::ErrorKind::WouldBlock {
47+
sender_res.send(Err(e)).unwrap();
48+
}
49+
}
50+
}
51+
52+
let mut size_buf = vec![0u8; 2];
53+
match tcp.read_exact(&mut size_buf) {
54+
Ok(_) => {
55+
let size = NetworkEndian::read_u16(&size_buf);
56+
let mut buf = vec![0u8; size as usize];
57+
match tcp.read_exact(&mut buf) {
58+
Ok(_) => if let Some(packet) = RioTcpPacket::from_bytes(buf) {
59+
state.lock().unwrap().update_from_tcp(packet);
60+
},
61+
Err(e) => {
62+
if e.kind() != io::ErrorKind::WouldBlock {
63+
sender_res.send(Err(e)).unwrap();
64+
}
65+
}
66+
}
67+
}
68+
Err(e) => {
69+
if e.kind() != io::ErrorKind::WouldBlock {
70+
sender_res.send(Err(e)).unwrap();
71+
}
72+
}
73+
}
74+
});
75+
76+
Ok(DSConnection {
77+
thread: t,
78+
sender: sender_signal,
79+
errors: receiver_res,
80+
err: None,
81+
})
82+
}
83+
84+
pub fn status(&self) -> io::Result<()> {
85+
match self.errors.try_recv() {
86+
Err(mpsc::TryRecvError::Empty) => Ok(()),
87+
Err(mpsc::TryRecvError::Disconnected) => Err(io::Error::new(
88+
io::ErrorKind::ConnectionAborted,
89+
"thread not connected",
90+
)),
91+
Ok(ior) => ior,
92+
}
93+
}
94+
}
95+
96+
impl Drop for DSConnection {
97+
fn drop(&mut self) {
98+
self.sender.send(Signal::Disconnect).unwrap_or(());
99+
}
100+
}
101+
102+
pub enum Signal {
103+
Udp,
104+
Tcp,
105+
Disconnect,
106+
}

src/ds.rs

Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
use joystick::Joystick;
2+
use messages::*;
3+
use packet::PacketWriter;
4+
use states::{Alliance, RobotMode};
5+
6+
use chrono::prelude::*;
7+
8+
const TIMEZONE: &'static str = "UTC";
9+
10+
pub struct DriverStationState {
11+
joysticks: Vec<Option<Joystick>>,
12+
estop: bool,
13+
enabled: bool,
14+
mode: RobotMode,
15+
alliance: Alliance,
16+
game_data: String,
17+
competition: String,
18+
sequence_num: u16,
19+
request_time: bool,
20+
}
21+
22+
impl DriverStationState {
23+
pub fn new() -> Self {
24+
Default::default()
25+
}
26+
27+
pub fn udp_packet(&mut self) -> Vec<u8> {
28+
let mut packet = PacketWriter::new();
29+
30+
// Packet number in case they arrive out of order
31+
packet.write_u16(self.sequence_num);
32+
self.sequence_num += 1;
33+
34+
packet.write_u8(0x01); // comm version
35+
packet.write_u8(self.control_byte()); // control byte
36+
packet.write_u8(0); // TODO: actually restart code or rio with this byte.
37+
packet.write_u8(self.alliance.to_position_u8()); // alliance
38+
39+
// joystick tags
40+
for stick in &self.joysticks {
41+
if let Some(stick) = stick {
42+
let mut tag = stick.udp_tag();
43+
packet.write_u8(tag.len() as u8 + 1); // size
44+
packet.write_u8(0x0c); // id
45+
packet.write_vec(tag); // joystick tag info
46+
} else {
47+
// Empty joystick tag
48+
packet.write_u8(0x01); // size
49+
packet.write_u8(0x0c); // id
50+
}
51+
}
52+
53+
// datetime and timezone
54+
if self.request_time {
55+
// timezone
56+
packet.write_u8(TIMEZONE.len() as u8 + 1); // size
57+
packet.write_u8(0x10); // id
58+
packet.write_slice(TIMEZONE.as_bytes());
59+
60+
// date and time
61+
packet.write_vec(date_packet());
62+
}
63+
64+
packet.into_vec()
65+
}
66+
67+
fn control_byte(&self) -> u8 {
68+
let mut byte: u8 = 0;
69+
if self.estop {
70+
byte |= 0b1000_0000;
71+
}
72+
// fms is never connected, but if it were that would go here
73+
if self.enabled {
74+
byte |= 0b0000_0100;
75+
}
76+
77+
byte |= self.mode as u8;
78+
79+
byte
80+
}
81+
82+
pub fn update_from_tcp(&mut self, packet: RioTcpPacket) {
83+
unimplemented!();
84+
}
85+
}
86+
87+
fn date_packet() -> Vec<u8> {
88+
let mut packet = PacketWriter::new();
89+
let now = Utc::now();
90+
packet.write_u8(11); // size
91+
packet.write_u8(0x0f); // id
92+
let nanos = now.nanosecond();
93+
let micros = nanos / 1000;
94+
packet.write_u32(micros);
95+
packet.write_u8(now.second() as u8);
96+
packet.write_u8(now.minute() as u8);
97+
packet.write_u8(now.hour() as u8);
98+
packet.write_u8(now.day() as u8); // should this be day0?
99+
packet.write_u8(now.month0() as u8);
100+
packet.write_u8((now.year() - 1900) as u8);
101+
packet.into_vec()
102+
}
103+
104+
impl Default for DriverStationState {
105+
fn default() -> Self {
106+
DriverStationState {
107+
joysticks: vec![None; 6],
108+
estop: false,
109+
enabled: false,
110+
mode: RobotMode::Teleop,
111+
alliance: Alliance::Red(1),
112+
game_data: String::new(),
113+
competition: String::from("unknown"),
114+
sequence_num: 0,
115+
request_time: false,
116+
}
117+
}
118+
}

0 commit comments

Comments
 (0)