#![cfg_attr(not(feature = "std"), no_std)]
#![cfg_attr(feature = "collections", feature(collections))]
#![deny(missing_docs)]
extern crate embedded_serial;
extern crate byteorder;
#[cfg(feature = "collections")]
extern crate collections;
#[cfg(feature = "std")]
extern crate serial;
#[cfg(feature = "std")]
mod core {
pub use std::mem;
pub use std::fmt;
pub use std::result;
}
use embedded_serial::{NonBlockingTx, NonBlockingRx};
use byteorder::ByteOrder;
#[cfg(feature = "collections")]
use collections::vec::Vec;
#[cfg(feature = "std")]
mod serialwrap;
#[cfg(feature = "std")]
pub use serialwrap::SerialWrap;
#[cfg(not(feature = "std"))]
use collections::String;
use core::fmt::Display;
#[cfg(not(feature = "std"))]
use core::fmt::Debug;
#[cfg(feature = "std")]
use std::error::Error as StdError;
#[cfg(not(feature = "std"))]
pub trait StdError: Debug + Display {
fn description(&self) -> &str;
fn cause(&self) -> Option<&StdError> { None }
}
pub const SENTINEL: u8 = 0xFF;
struct HeaderState {
bytes: [u8; 2],
index: usize,
}
struct DataState {
length: usize,
}
enum RecvState {
Unknown,
Header(HeaderState),
Data(DataState),
}
enum WhatNext {
Sentinel,
Header,
Data,
}
struct SendingState{
what_next: WhatNext,
index: usize,
header_bytes: [u8; 2],
frame: Vec<u8>,
}
enum SendState {
NotSending,
Sending(SendingState),
}
pub struct TickProgress {
pub recv_is_done: bool,
pub send_is_done: bool,
}
#[derive(Debug)]
pub struct Error {
descr: String,
}
impl Error {
pub fn new(s: String) -> Error {
Error { descr: s }
}
}
impl StdError for Error {
fn description(&self) -> &str {
return &self.descr;
}
}
type Result<T> = core::result::Result<T,Error>;
impl Display for Error {
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
write!(f, "Error: {}", self.description())
}
}
pub struct FramedConnection<S>
where S : NonBlockingRx + NonBlockingTx,
{
serial: S,
recv_buf: Vec<u8>,
recv_state: RecvState,
send_state: SendState,
}
impl<S> FramedConnection<S>
where S : NonBlockingRx + NonBlockingTx,
{
pub fn new(s:S) -> FramedConnection<S> {
FramedConnection {
serial:s,
recv_buf: Vec::new(),
recv_state: FramedConnection::<S>::_start_recv_state(),
send_state: FramedConnection::<S>::_start_send_state(),
}
}
fn _start_recv_state() -> RecvState {
RecvState::Unknown
}
fn _start_send_state() -> SendState {
SendState::NotSending
}
pub fn schedule_send(&mut self, frame: Vec<u8>) -> Result<()> {
match self.send_state {
SendState::NotSending => {}
SendState::Sending(_) => {
return Err(Error::new("Previous send in progress. Hint: block_until_send_done().".into()));
}
}
if frame.len() > u16::max_value() as usize {
return Err(Error::new("frame data too long".into()));
}
let mut buf = [0; 2];
byteorder::LittleEndian::write_u16(&mut buf, frame.len() as u16);
self.send_state = SendState::Sending( {
SendingState{
what_next: WhatNext::Sentinel,
index: 0,
header_bytes: buf,
frame: frame,
}});
Ok(())
}
pub fn block_until_send_done(&mut self) -> Result<()> {
loop {
match self.send_state {
SendState::NotSending => {break;}
SendState::Sending(_) => {}
}
self.tick()?;
}
Ok(())
}
pub fn tick(&mut self) -> Result<TickProgress> {
Ok(TickProgress {
send_is_done: self._send_tick()?,
recv_is_done: self._recv_tick()?,
})
}
fn _send_tick(&mut self) -> Result<bool> {
match self.send_state {
SendState::NotSending => {
return Ok(true);
},
SendState::Sending(ref mut s) => {
loop {
let byte = match s.what_next {
WhatNext::Sentinel => SENTINEL,
WhatNext::Header => s.header_bytes[s.index],
WhatNext::Data => s.frame[s.index],
};
match self.serial.putc_try(byte) {
Ok(Some(_)) => {
s.index += 1;
let mut new_next: Option<WhatNext> = None;
match s.what_next {
WhatNext::Sentinel => {
new_next = Some(WhatNext::Header);
s.index = 0;
},
WhatNext::Header => {
if s.index == 2 {
new_next = Some(WhatNext::Data);
s.index = 0;
}
},
WhatNext::Data => {
if s.index == s.frame.len() {
break;
}
},
}
if let Some(nn) = new_next {
s.what_next = nn;
}
},
Ok(None) => {
return Ok(false);
},
Err(_) => {
return Err(Error::new("unexpected error during putc_try()".into()));
}
}
}
}
}
self.send_state = SendState::NotSending;
Ok(true)
}
fn _recv_tick(&mut self) -> Result<bool> {
loop {
if self.is_frame_complete() {
return Ok(true);
}
match self.serial.getc_try() {
Ok(Some(byte)) => {
let mut new_state: Option<RecvState> = None;
match self.recv_state {
RecvState::Unknown => {
if byte == SENTINEL {
new_state = Some(RecvState::Header(HeaderState{bytes: [0, 0], index: 0}))
}
},
RecvState::Header(ref mut hs) => {
hs.bytes[hs.index] = byte;
hs.index += 1;
if hs.index == 2 {
let ds = DataState {
length: byteorder::LittleEndian::read_u16(&hs.bytes) as usize,
};
new_state = Some(RecvState::Data(ds));
}
},
RecvState::Data(ref mut ds) => {
self.recv_buf.push(byte);
if self.recv_buf.len() == ds.length {
return Ok(true);
}
},
};
if let Some(ns) = new_state {
self.recv_state=ns;
}
},
Ok(None) => {
break;
},
Err(_) => {
return Err(Error::new("unexpected error during getc_try()".into()))
},
};
}
Ok(false)
}
fn is_frame_complete(&mut self) -> bool {
match self.recv_state {
RecvState::Unknown | RecvState::Header(_) => false,
RecvState::Data(ref ds) => ds.length == self.recv_buf.len(),
}
}
pub fn get_frame(&mut self) -> Result<Vec<u8>> {
let frame = match self.recv_state {
RecvState::Unknown | RecvState::Header(_) => {
return Err(Error::new("frame not available".into()));
},
RecvState::Data(ref ds) => {
if self.recv_buf.len() == ds.length {
let mut frame = Vec::with_capacity(0);
core::mem::swap(&mut self.recv_buf,&mut frame);
frame
} else {
return Err(Error::new("frame not available".into()));
}
},
};
self.recv_state = FramedConnection::<S>::_start_recv_state();
Ok(frame)
}
}