Skip to content
This repository has been archived by the owner on Oct 12, 2022. It is now read-only.

Commit

Permalink
Merge pull request #23 from msoermc/DriveTrain
Browse files Browse the repository at this point in the history
Drive train
  • Loading branch information
Noah-Kennedy authored Dec 30, 2018
2 parents 8896a5f + e179ec4 commit 48373d7
Show file tree
Hide file tree
Showing 18 changed files with 513 additions and 451 deletions.
44 changes: 24 additions & 20 deletions src/comms/driver_station/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,30 +8,33 @@ use crate::comms::driver_station::parsing::*;
use crate::comms::SendableMessage;
use crate::drive_train::DriveTrainCommand;
use crate::logging::log_data::LogData;
use crate::logging::log_sender::LogSender;
use crate::logging::LogAccepter;

mod parsing;
pub mod sender;

const ADDRESS: &str = "127.0.0.1";
const PORT: u16 = 2401;


pub struct DriverStationComms {
message_queue: Receiver<Box<SendableMessage>>,
logging_channel: Sender<LogData>,
log_sender: LogSender,
communicator: Communicator,
drive_train_channel: Sender<DriveTrainCommand>,
}

impl DriverStationComms {
/// Instantiates the comms.
/// This constructor will bind the listener.
pub fn new(logging_channel: Sender<LogData>, message_queue: Receiver<Box<SendableMessage>>,
pub fn new(logging_channel: LogSender, message_queue: Receiver<Box<SendableMessage>>,
drive_train_channel: Sender<DriveTrainCommand>) -> DriverStationComms {
let communicator = Communicator::from(ADDRESS, PORT);

DriverStationComms {
message_queue,
logging_channel,
log_sender: logging_channel,
communicator,
drive_train_channel,
}
Expand All @@ -54,7 +57,7 @@ impl DriverStationComms {

fn check_connections(&mut self) {
if let Err(error) = self.communicator.check_connections() {
self.logging_channel.send(error).unwrap();
self.log_sender.accept_log(error);
}
}

Expand All @@ -73,7 +76,7 @@ impl DriverStationComms {
for result in self.communicator.receive_next_lines() {
match result {
Ok(message) => self.handle_message(message.as_str()),
Err(error) => self.logging_channel.send(error).unwrap()
Err(error) => self.log_sender.accept_log(error)
}
}
}
Expand All @@ -82,21 +85,24 @@ impl DriverStationComms {
let parsed_result = parse_message(message);
match parsed_result {
Ok(parsed_message) => self.handle_valid_command(parsed_message),
Err(log) => self.logging_channel.send(log).unwrap(),
Err(log) => self.log_sender.accept_log(log)
}
}

fn send_message(&mut self, message: &SendableMessage) {
let sending_string = message.encode();

self.communicator.send_line(sending_string).expect("Error in sending a line!");
let sending_logs = self.communicator.send_line(sending_string);

for log in sending_logs {
self.log_sender.accept_log(log)
}
}

fn handle_sending_channel_disconnect(&mut self) {
let log = LogData::fatal("Sending channel disconnected in external comms!");
self.logging_channel.send(log)
.expect("Sending channel and logging channel disconnected in Driver Station Comms!");
panic!("{}", "Sending channel disconnected in external comms!");
self.log_sender.accept_log(log);
panic!("Sending channel disconnected in external comms!");
}

fn handle_valid_command(&mut self, message: ReceivableMessage) {
Expand All @@ -118,20 +124,18 @@ impl DriverStationComms {
self.drive_train_channel.send(DriveTrainCommand::Revive).unwrap();
}

fn handle_enable_command(&mut self, subsystem: ProtocolSubsystem) {
fn handle_enable_command(&mut self, subsystem: Subsystem) {
match subsystem {
ProtocolSubsystem::DriveTrain => self.drive_train_channel
.send(DriveTrainCommand::Enable)
.unwrap(),
}
Subsystem::DriveTrain => self.drive_train_channel
.send(DriveTrainCommand::Enable).unwrap(),
};
}

fn handle_disable_command(&mut self, subsystem: ProtocolSubsystem) {
fn handle_disable_command(&mut self, subsystem: Subsystem) {
match subsystem {
ProtocolSubsystem::DriveTrain => self.drive_train_channel
.send(DriveTrainCommand::Disable)
.unwrap(),
}
Subsystem::DriveTrain => self.drive_train_channel
.send(DriveTrainCommand::Disable).unwrap(),
};
}

fn handle_drive_command(&mut self, left_speed: f32, right_speed: f32) {
Expand Down
54 changes: 38 additions & 16 deletions src/comms/driver_station/parsing.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,22 +2,24 @@ use crate::comms::get_wrong_arg_count_log;
use crate::logging::log_data::LogData;

#[derive(Copy, Clone, Eq, PartialEq, Debug)]
pub enum ProtocolSubsystem {
pub enum Subsystem {
DriveTrain,
}

#[derive(Copy, Clone, PartialEq, Debug)]
pub enum ReceivableMessage {
Kill,
Revive,
Enable(ProtocolSubsystem),
Disable(ProtocolSubsystem),
Enable(Subsystem),
Disable(Subsystem),
Drive(f32, f32),
Brake,
}


pub fn parse_message(message: &str) -> Result<ReceivableMessage, LogData> {
// Trim newline from end
let message = message.trim_end();
let elements: Vec<&str> = message.split_whitespace().collect();
let command = match elements.first() {
Some(com) => *com,
Expand Down Expand Up @@ -52,27 +54,30 @@ fn parse_drive_command(original_message: &str, args: &[&str]) -> Result<Receivab
let log = get_wrong_arg_count_log(original_message, 2, args.len() as u64);
Err(log)
} else {
// It should not be possible here for us to have too few arguments since we already
// checked our that, so it should be safe to unwrap
let left_speed_string = args[1];
let right_speed_string = args[2];

let left_speed: f32 = match left_speed_string.parse() {
Ok(speed) => speed,
Err(_) => {
let log = LogData::warning("Left speed not parsable!");
let log = LogData::warning("Received unparseable speed in drive message");
return Err(log);
}
};

let right_speed: f32 = match right_speed_string.parse() {
Ok(speed) => speed,
Err(_) => {
let log = LogData::warning("Right speed not parsable!");
let log = LogData::warning("Received unparseable speed in drive message");
return Err(log);
}
};

if left_speed > 1.0 || right_speed > 1.0 {
let log = LogData::warning("Received speed > 1 in drive train message");
return Err(log);
}

Ok(ReceivableMessage::Drive(left_speed, right_speed))
}
}
Expand All @@ -97,9 +102,9 @@ fn parse_disable_command(original_message: &str, args: &[&str]) -> Result<Receiv
}
}

fn parse_subsystem(field: &str) -> Result<ProtocolSubsystem, LogData> {
fn parse_subsystem(field: &str) -> Result<Subsystem, LogData> {
match field {
"drive_train" => Ok(ProtocolSubsystem::DriveTrain),
"drive_train" => Ok(Subsystem::DriveTrain),
_ => Err(LogData::warning("Unrecognized subsystem in message!"))
}
}
Expand Down Expand Up @@ -137,17 +142,21 @@ mod tests {

#[test]
fn test_drive_parsing() {
let valid_f_f = parse_message("drive 2.0 1.0").unwrap();
let valid_i_i = parse_message("drive 2 1").unwrap();
let valid_i_f = parse_message("drive 2 1.0").unwrap();
let valid_f_i = parse_message("drive 2.0 1").unwrap();
let valid_f_f = parse_message("drive 1.0 -1.0").unwrap();
let valid_i_i = parse_message("drive 1 -1").unwrap();
let valid_i_f = parse_message("drive 1 -1.0").unwrap();
let valid_f_i = parse_message("drive 1.0 -1").unwrap();

let invalid = parse_message("drive 2 3 4");
let invalid_bad_left = parse_message("drive hi 4");
let invalid_bad_right = parse_message("drive 5 hi");
let invalid_bad_args = parse_message("drive hi bye");
let invalid_right_too_high = parse_message("drive train 1 2");
let invalid_left_too_high = parse_message("drive train 2 1");
let invalid_both_too_high = parse_message("drive train 2 2");


let expected = ReceivableMessage::Drive(2.0, 1.0);
let expected = ReceivableMessage::Drive(1.0, -1.0);

assert_eq!(valid_f_f, expected);
assert_eq!(valid_i_i, expected);
Expand All @@ -157,6 +166,9 @@ mod tests {
assert!(invalid_bad_left.is_err());
assert!(invalid_bad_right.is_err());
assert!(invalid_bad_args.is_err());
assert!(invalid_left_too_high.is_err());
assert!(invalid_right_too_high.is_err());
assert!(invalid_both_too_high.is_err());
}

#[test]
Expand Down Expand Up @@ -195,7 +207,7 @@ mod tests {
let invalid_no_args = parse_message("enable");
let invalid_too_many_args = parse_message("enable drive_train hi");
let invalid_bad_subsystem = parse_message("enable fail");
let expected_valid = ReceivableMessage::Enable(ProtocolSubsystem::DriveTrain);
let expected_valid = ReceivableMessage::Enable(Subsystem::DriveTrain);

assert_eq!(valid, expected_valid);
assert!(invalid_no_args.is_err());
Expand All @@ -209,7 +221,7 @@ mod tests {
let invalid_no_args = parse_message("disable");
let invalid_too_many_args = parse_message("disable drive_train hi");
let invalid_bad_subsystem = parse_message("disable fail");
let expected_valid = ReceivableMessage::Disable(ProtocolSubsystem::DriveTrain);
let expected_valid = ReceivableMessage::Disable(Subsystem::DriveTrain);

assert_eq!(valid, expected_valid);
assert!(invalid_no_args.is_err());
Expand All @@ -230,6 +242,7 @@ mod tests {
fn test_nonexistent_command() {
let actual_1 = parse_message("annihilate").unwrap_err();
let actual_2 = parse_message("annihilate Noah").unwrap_err();

let expected_1 = LogData::warning("Received nonexistent command, message is 'annihilate'");
let expected_2 = LogData::warning("Received nonexistent command, message is 'annihilate Noah'");

Expand All @@ -239,4 +252,13 @@ mod tests {
assert_eq!(actual_2.get_severity(), expected_2.get_severity());
assert_eq!(actual_2.get_description(), expected_2.get_description());
}

#[test]
fn test_removed_newline() {
let actual = parse_message("annihilate Noah\n").unwrap_err();
let expected = LogData::warning("Received nonexistent command, message is 'annihilate Noah'");

assert_eq!(actual.get_severity(), expected.get_severity());
assert_eq!(actual.get_description(), expected.get_description());
}
}
27 changes: 27 additions & 0 deletions src/comms/driver_station/sender.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
use crate::comms::SendableMessage;
use std::sync::mpsc::Sender;
use crate::logging::LogAccepter;
use crate::logging::log_data::LogData;

#[derive(Clone, Debug)]
pub struct DSMessageSender {
channel: Sender<Box<SendableMessage>>
}

impl LogAccepter for DSMessageSender {
fn accept_log(&mut self, log: LogData) {
self.send(Box::new(log));
}
}

impl DSMessageSender {
pub fn new(channel: Sender<Box<SendableMessage>>) -> Self {
DSMessageSender {
channel
}
}

pub fn send(&mut self, message: Box<SendableMessage>) {
self.channel.send(message).expect("DSMessageSender hangup");
}
}
23 changes: 16 additions & 7 deletions src/comms/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -60,17 +60,26 @@ impl Communicator {
}
}

fn send(&mut self, message: &str) -> Result<(), Vec<LogData>> {
// TODO add error handling
for client in &mut self.clients {
write!(client, "{}", message).expect("Could not write line");
client.flush().expect("Failed to flush");
fn send(&mut self, message: &str) -> Vec<LogData> {
let mut errors = Vec::new();
for client_index in 0..self.clients.len() {
if write!(self.clients[client_index], "{}", message).is_err() {
let log = LogData::warning("Failed to write to client!");
errors.push(log);
self.clients.remove(client_index);
continue;
};
if self.clients[client_index].flush().is_err() {
let log = LogData::warning("Failed to flush data to client!");
errors.push(log);
self.clients.remove(client_index);
};
}

Ok(())
errors
}

fn send_line(&mut self, message: String) -> Result<(), Vec<LogData>> {
fn send_line(&mut self, message: String) -> Vec<LogData> {
self.send(&(message + "\n"))
}

Expand Down
Loading

0 comments on commit 48373d7

Please sign in to comment.