use crate::Constants;
use crate::FrameType;
use crate::checksum::{GOOD_FCS16, INIT_FCS16, fcs16_byte};
use crate::Error;
enum SlipmuxState {
Idle,
UnkownFrameType,
Diagnostic,
DiagnosticEscape,
Configuration,
ConfigurationEscape,
Ip,
IpEscape,
}
use SlipmuxState::{
Configuration, ConfigurationEscape, Diagnostic, DiagnosticEscape, Idle, Ip, IpEscape,
UnkownFrameType,
};
pub trait FrameHandler {
fn begin_frame(&mut self, frame_type: FrameType);
fn write_byte(&mut self, byte: u8);
fn end_frame(&mut self, error: Option<Error>);
}
#[derive(Debug)]
pub enum DecodeStatus {
Incomplete,
FrameCompleteDiagnostic,
FrameCompleteConfiguration,
FrameCompleteIp,
}
pub struct Decoder {
state: SlipmuxState,
fcs: u16,
}
impl Default for Decoder {
fn default() -> Self {
Self::new()
}
}
impl Decoder {
#[must_use]
pub const fn new() -> Self {
Self {
state: Idle,
fcs: 0,
}
}
#[allow(clippy::match_same_arms)]
#[allow(clippy::too_many_lines)]
pub fn decode<H: FrameHandler>(
&mut self,
byte: u8,
handler: &mut H,
) -> Result<DecodeStatus, Error> {
self.state = {
match (&self.state, byte) {
(Idle, Constants::END) => Idle,
(Idle, Constants::DIAGNOSTIC) => {
handler.begin_frame(FrameType::Diagnostic);
Diagnostic
}
(Idle, Constants::CONFIGURATION) => {
handler.begin_frame(FrameType::Configuration);
self.fcs = fcs16_byte(INIT_FCS16, Constants::CONFIGURATION);
Configuration
}
(
Idle,
Constants::IP4_FROM..Constants::IP4_TO | Constants::IP6_FROM..Constants::IP6_TO,
) => {
handler.begin_frame(FrameType::Ip);
handler.write_byte(byte);
Ip
}
(Idle, _) => {
self.state = UnkownFrameType;
handler.end_frame(Some(Error::BadFrameType(byte)));
return Err(Error::BadFrameType(byte));
}
(UnkownFrameType, Constants::END) => Idle,
(UnkownFrameType, _) => UnkownFrameType,
(Diagnostic, Constants::ESC) => DiagnosticEscape,
(Diagnostic, Constants::END) => {
handler.end_frame(None);
self.state = Idle;
return Ok(DecodeStatus::FrameCompleteDiagnostic);
}
(Diagnostic, _) => {
handler.write_byte(byte);
Diagnostic
}
(DiagnosticEscape, Constants::ESC_END) => {
handler.write_byte(Constants::END);
Diagnostic
}
(DiagnosticEscape, Constants::ESC_ESC) => {
handler.write_byte(Constants::ESC);
Diagnostic
}
(DiagnosticEscape, Constants::END) => {
self.state = Idle;
handler.end_frame(Some(Error::Abort));
return Err(Error::Abort);
}
(DiagnosticEscape, _) => {
handler.write_byte(byte);
Diagnostic
}
(Configuration, Constants::ESC) => ConfigurationEscape,
(Configuration, Constants::END) => {
self.state = Idle;
if self.fcs == GOOD_FCS16 {
handler.end_frame(None);
return Ok(DecodeStatus::FrameCompleteConfiguration);
}
handler.end_frame(Some(Error::BadFCS));
return Err(Error::BadFCS);
}
(Configuration, _) => {
handler.write_byte(byte);
self.fcs = fcs16_byte(self.fcs, byte);
Configuration
}
(ConfigurationEscape, Constants::ESC_END) => {
handler.write_byte(Constants::END);
self.fcs = fcs16_byte(self.fcs, Constants::END);
Configuration
}
(ConfigurationEscape, Constants::ESC_ESC) => {
handler.write_byte(Constants::ESC);
self.fcs = fcs16_byte(self.fcs, Constants::ESC);
Configuration
}
(ConfigurationEscape, Constants::END) => {
self.state = Idle;
handler.end_frame(Some(Error::Abort));
return Err(Error::Abort);
}
(ConfigurationEscape, _) => {
handler.write_byte(byte);
self.fcs = fcs16_byte(self.fcs, byte);
Configuration
}
(Ip, Constants::ESC) => IpEscape,
(Ip, Constants::END) => {
self.state = Idle;
handler.end_frame(None);
return Ok(DecodeStatus::FrameCompleteConfiguration);
}
(Ip, _) => {
handler.write_byte(byte);
Ip
}
(IpEscape, Constants::ESC_END) => {
handler.write_byte(Constants::END);
Ip
}
(IpEscape, Constants::ESC_ESC) => {
handler.write_byte(Constants::ESC);
Ip
}
(IpEscape, Constants::END) => {
self.state = Idle;
handler.end_frame(Some(Error::Abort));
return Err(Error::Abort);
}
(IpEscape, _) => {
handler.write_byte(byte);
Ip
}
}
};
Ok(DecodeStatus::Incomplete)
}
}