use bytes::{Bytes, BytesMut};
use eds_core::crc::get_crc;
use eds_core::frame::*;
const MAX_LEN: usize = 4096;
enum Status {
Lead(u8),
Start,
Length1,
Length2,
Load,
Crc1,
Crc2,
End,
Finish,
}
pub struct Reader {
lead_len: u8,
load: BytesMut,
load_len: u16,
load_crc: u16,
status: Status,
}
impl Reader {
pub fn new(lead_len: u8) -> Self {
Reader {
lead_len,
load: BytesMut::new(),
load_len: 0,
load_crc: 0,
status: Status::Lead(0),
}
}
pub fn is_empty(&self) -> bool {
self.load.is_empty()
}
fn clean(&mut self) {
self.load.clear();
self.status = Status::Lead(0);
}
fn recv_one(&mut self, res: u8) -> bool {
match self.status {
Status::Lead(mut count) => {
if res == CHAR_LEAD {
count += 1;
if count >= self.lead_len {
self.status = Status::Start;
} else {
self.status = Status::Lead(count);
}
} else {
self.clean();
}
}
Status::Start => {
if res == CHAR_LEAD {
} else if res == CHAR_START {
self.status = Status::Length1;
} else {
self.clean();
}
}
Status::Length1 => {
self.load_len = (res as u16) << 8;
self.status = Status::Length2;
}
Status::Length2 => {
self.load_len |= res as u16;
if self.load_len as usize > MAX_LEN {
self.clean();
self.recv_one(res);
} else {
self.status = Status::Load;
}
}
Status::Load => {
let _ = self.load.extend([res]);
if self.load.len() >= self.load_len as usize {
self.load_crc = get_crc(&self.load);
self.status = Status::Crc1;
}
}
Status::Crc1 => {
if res == (self.load_crc >> 8) as u8 {
self.status = Status::Crc2;
} else {
self.clean();
self.recv_one(res);
}
}
Status::Crc2 => {
if res == self.load_crc as u8 {
self.status = Status::End;
} else {
self.clean();
self.recv_one(res);
}
}
Status::End => {
if res == CHAR_END {
self.status = Status::Finish;
return true;
} else {
self.clean();
self.recv_one(res);
}
}
Status::Finish => {
self.clean();
self.recv_one(res);
}
}
return false;
}
pub fn recv(&mut self, buf: &[u8]) -> usize {
for i in 0..buf.len() {
let res = buf[i];
let finish = self.recv_one(res);
if finish {
return i + 1;
}
}
return buf.len();
}
pub fn is_ready(&self) -> bool {
if let Status::Finish = self.status {
true
} else {
false
}
}
pub fn get_load(&mut self) -> Option<Bytes> {
if let Status::Finish = self.status {
let load = core::mem::replace(&mut self.load, BytesMut::new());
self.status = Status::Lead(0);
Some(load.freeze())
} else {
None
}
}
}