use std::{str, time::Duration};
use thiserror::Error;
#[derive(Error, Debug)]
pub enum LssDriverError {
#[error("Failed to parse data")]
PacketParsingError(String),
#[error("Operation timed out")]
TimeoutError,
#[error("Failed to open serial port")]
FailedOpeningSerialPort,
#[error("Failed to open serial port")]
SendingError,
}
#[derive(Copy, Clone, Debug, PartialEq)]
pub enum LedColor {
Off = 0,
Red = 1,
Green = 2,
Blue = 3,
Yellow = 4,
Cyan = 5,
Magenta = 6,
White = 7,
}
impl LedColor {
pub(crate) fn from_i32(number: i32) -> Result<LedColor, LssDriverError> {
match number {
0 => Ok(LedColor::Off),
1 => Ok(LedColor::Red),
2 => Ok(LedColor::Green),
3 => Ok(LedColor::Blue),
4 => Ok(LedColor::Yellow),
5 => Ok(LedColor::Cyan),
6 => Ok(LedColor::Magenta),
7 => Ok(LedColor::White),
value => Err(LssDriverError::PacketParsingError(format!(
"Failed parsing LedColor from {}",
value
))),
}
}
}
#[derive(Copy, Clone, Debug, PartialEq)]
pub enum MotorStatus {
Unknown = 0,
Limp = 1,
FreeMoving = 2,
Accelerating = 3,
Traveling = 4,
Decelerating = 5,
Holding = 6,
OutsideLimits = 7,
Stuck = 8,
Blocked = 9,
SafeMode = 10,
}
impl MotorStatus {
pub(crate) fn from_i32(number: i32) -> Result<MotorStatus, LssDriverError> {
match number {
0 => Ok(MotorStatus::Unknown),
1 => Ok(MotorStatus::Limp),
2 => Ok(MotorStatus::FreeMoving),
3 => Ok(MotorStatus::Accelerating),
4 => Ok(MotorStatus::Traveling),
5 => Ok(MotorStatus::Decelerating),
6 => Ok(MotorStatus::Holding),
7 => Ok(MotorStatus::OutsideLimits),
8 => Ok(MotorStatus::Stuck),
9 => Ok(MotorStatus::Blocked),
10 => Ok(MotorStatus::SafeMode),
value => Err(LssDriverError::PacketParsingError(format!(
"Failed parsing MotorStatus from {}",
value
))),
}
}
}
#[derive(Copy, Clone, Debug, PartialEq)]
pub enum SafeModeStatus {
NoLimits = 0,
CurrentLimit = 1,
InputVoltageOutOfRange = 2,
TemperatureLimit = 3,
}
impl SafeModeStatus {
pub(crate) fn from_i32(number: i32) -> Result<SafeModeStatus, LssDriverError> {
match number {
0 => Ok(SafeModeStatus::NoLimits),
1 => Ok(SafeModeStatus::CurrentLimit),
2 => Ok(SafeModeStatus::InputVoltageOutOfRange),
3 => Ok(SafeModeStatus::TemperatureLimit),
value => Err(LssDriverError::PacketParsingError(format!(
"Failed parsing SafeModeStatus from {}",
value
))),
}
}
}
#[derive(Clone, Debug, PartialEq)]
pub enum Model {
ST1,
HS1,
HT1,
Other(String),
}
impl Model {
pub(crate) fn from_str(model: &str) -> Model {
match model {
"LSS-ST1" => Model::ST1,
"LSS-HS1" => Model::HS1,
"LSS-HT1" => Model::HT1,
other => Model::Other(other.to_owned()),
}
}
}
#[derive(Copy, Clone, Debug, PartialEq)]
pub enum LedBlinking {
NoBlinking = 0,
Limp = 1,
Holding = 2,
Accelerating = 4,
Decelerating = 8,
Free = 16,
Travelling = 32,
AlwaysBlink = 63,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum CommandModifier {
Speed(u32),
SpeedDegrees(u32),
Timed(u32),
TimedDuration(Duration),
CurrentHold(u32),
CurrentLimp(u32),
None,
Custom(&'static str, i32),
}
impl CommandModifier {
pub fn to_msg(&self) -> String {
use CommandModifier::*;
match self {
Speed(speed) => format!("S{}", speed),
SpeedDegrees(speed) => format!("SD{}", speed),
Timed(time) => format!("T{}", time),
TimedDuration(time) => format!("T{}", time.as_millis()),
CurrentHold(current) => format!("CH{}", current),
CurrentLimp(current) => format!("CL{}", current),
CommandModifier::None => String::from(""),
Custom(text, value) => format!("{}{}", text, value),
}
}
pub fn vec_to_msg(modifiers: &[CommandModifier]) -> String {
let mut buffer = String::new();
for modifier in modifiers {
buffer.push_str(&modifier.to_msg());
}
buffer
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn model_parses_other() {
let model = Model::from_str("something");
assert_eq!(model, Model::Other("something".to_owned()));
}
#[test]
fn color_parse_fails() {
let color = LedColor::from_i32(42);
assert!(color.is_err());
}
#[test]
fn colors_parse() {
let params = vec![
(LedColor::Off, 0),
(LedColor::Red, 1),
(LedColor::Green, 2),
(LedColor::Blue, 3),
(LedColor::Yellow, 4),
(LedColor::Cyan, 5),
(LedColor::Magenta, 6),
(LedColor::White, 7),
];
for (expected_color, int) in params {
let color = LedColor::from_i32(int).unwrap();
assert_eq!(expected_color, color);
}
}
#[test]
fn motor_status_parse_fails() {
let status = MotorStatus::from_i32(42);
assert!(status.is_err());
}
#[test]
fn motor_status_parse() {
let params = vec![
(MotorStatus::Unknown, 0),
(MotorStatus::Limp, 1),
(MotorStatus::FreeMoving, 2),
(MotorStatus::Accelerating, 3),
(MotorStatus::Traveling, 4),
(MotorStatus::Decelerating, 5),
(MotorStatus::Holding, 6),
(MotorStatus::OutsideLimits, 7),
(MotorStatus::Stuck, 8),
(MotorStatus::Blocked, 9),
(MotorStatus::SafeMode, 10),
];
for (expected_status, int) in params {
let status = MotorStatus::from_i32(int).unwrap();
assert_eq!(expected_status, status);
}
}
}