framed_serial/
lib.rs

1//! Add frames to serial connections. Useful for embedded devices. Can be built with `no_std`.
2//!
3//! The main type of interest is [`FramedConnection`](struct.FramedConnection.html), which takes ownership
4//! of a serial connection and allows sending and receiving complete frames.
5//!
6//! To use with the standard library, put this in your `Cargo.toml`:
7//!
8//! ```toml
9//! [dependencies]
10//! framed-serial = "0.1"
11//! ```
12//!
13//! To use in an embedded device with `no_std`, put this in your `Cargo.toml`:
14//!
15//! ```toml
16//! [dependencies]
17//! framed-serial = {version = "0.1", default-features = false, features = ["collections"]}
18//! ```
19//!
20//! Example usage:
21//!
22//! ```
23//! #[cfg(feature = "std")]
24//! extern crate serial;
25//! extern crate framed_serial;
26//! #[cfg(feature = "std")]
27//! use serial::SerialPort;
28//!
29//! #[cfg(feature = "std")]
30//! fn wait_for_frame() -> Result<(),framed_serial::Error> {
31//!
32//!     let device = match std::env::var("DEVICE") {
33//!         Ok(val) => val,
34//!         Err(_) => "/dev/ttyACM0".to_string(),
35//!     };
36//!     println!("opening device {}", device);
37//!     let mut raw = serial::open(&device).expect("open serial port");
38//!
39//!     // Async processing depends on this being short.
40//!     raw.set_timeout(std::time::Duration::from_millis(100)).expect("set_timeout");
41//!
42//!     let my_ser = framed_serial::SerialWrap::new(raw);
43//!     let mut conn = framed_serial::FramedConnection::new(my_ser);
44//!
45//!     // Loop until we get a frame. This requires a connected device
46//!     // sending with FramedConnection.
47//!     loop {
48//!         let tick_state = conn.tick()?;
49//!         if tick_state.recv_is_done {
50//!             let data = conn.get_frame()?;
51//!             println!("{:?}", data);
52//!             break;
53//!         }
54//!     }
55//!     Ok(())
56//! }
57//!
58//! // This example requires std to compile. To run successfully, it further requires a connected
59//! // serial device on /dev/ttyACM0 implementing `FramedConnection`. Use conditional compilation
60//! // to run only if the `device_connected` feature was specified at compile time.
61//!
62//! #[cfg(feature = "device_connected")]
63//! fn main() {
64//!     wait_for_frame().unwrap();
65//! }
66//! #[cfg(not(feature = "device_connected"))]
67//! fn main() {
68//!     // Do nothing if device is not connected.
69//! }
70//! ```
71#![cfg_attr(not(feature = "std"), no_std)]
72#![cfg_attr(feature = "collections", feature(collections))]
73#![deny(missing_docs)]
74extern crate embedded_serial;
75extern crate byteorder;
76
77#[cfg(feature = "collections")]
78extern crate collections;
79
80#[cfg(feature = "std")]
81extern crate serial;
82
83#[cfg(feature = "std")]
84mod core {
85    pub use std::mem;
86    pub use std::fmt;
87    pub use std::result;
88}
89
90use embedded_serial::{NonBlockingTx, NonBlockingRx};
91use byteorder::ByteOrder;
92
93#[cfg(feature = "collections")]
94use collections::vec::Vec;
95
96#[cfg(feature = "std")]
97mod serialwrap;
98
99#[cfg(feature = "std")]
100pub use serialwrap::SerialWrap;
101
102#[cfg(not(feature = "std"))]
103use collections::String;
104
105use core::fmt::Display;
106
107#[cfg(not(feature = "std"))]
108use core::fmt::Debug;
109
110#[cfg(feature = "std")]
111use std::error::Error as StdError;
112
113/// A replacement for std::error::Error
114#[cfg(not(feature = "std"))]
115pub trait StdError: Debug + Display {
116    /// A short description of the error.
117    ///
118    /// The description should not contain newlines or sentence-ending
119    /// punctuation, to facilitate embedding in larger user-facing
120    /// strings.
121    fn description(&self) -> &str;
122
123    /// The lower-level cause of this error, if any.
124    fn cause(&self) -> Option<&StdError> { None }
125}
126
127/// A marker which appears only rarely in stream, used to catch frame start.
128pub const SENTINEL: u8 = 0xFF;
129
130struct HeaderState {
131    bytes: [u8; 2],
132    index: usize,
133}
134
135struct DataState {
136    length: usize,
137}
138
139enum RecvState {
140    Unknown,
141    Header(HeaderState),
142    Data(DataState),
143}
144
145enum WhatNext {
146    Sentinel,
147    Header,
148    Data,
149}
150
151struct SendingState{
152    what_next: WhatNext,
153    index: usize,
154    header_bytes: [u8; 2],
155    frame: Vec<u8>,
156}
157
158enum SendState {
159    NotSending,
160    Sending(SendingState),
161}
162
163/// The result of a `tick()`. Check for progress indication.
164pub struct TickProgress {
165    /// State of ongoing receive.
166    pub recv_is_done: bool,
167    /// State of ongoing send.
168    pub send_is_done: bool,
169}
170
171/// Error type.
172#[derive(Debug)]
173pub struct Error {
174    descr: String,
175}
176
177impl Error {
178    /// create a new Error
179    pub fn new(s: String) -> Error {
180        Error { descr: s }
181    }
182}
183
184impl StdError for Error {
185    fn description(&self) -> &str {
186        return &self.descr;
187    }
188}
189
190type Result<T> = core::result::Result<T,Error>;
191
192impl Display for Error {
193    fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
194        write!(f, "Error: {}", self.description())
195    }
196}
197
198/// Wrapper around a serial port to provide framed connections.
199///
200/// See the module level documentation for more information.
201pub struct FramedConnection<S>
202    where S : NonBlockingRx + NonBlockingTx,
203{
204    serial: S,
205    recv_buf: Vec<u8>,
206    recv_state: RecvState,
207    send_state: SendState,
208}
209
210impl<S> FramedConnection<S>
211    where S : NonBlockingRx + NonBlockingTx,
212{
213    /// Create a new `FramedConnection`. Takes ownership of the serial device.
214    pub fn new(s:S) -> FramedConnection<S> {
215        FramedConnection {
216            serial:s,
217            recv_buf: Vec::new(),
218            recv_state: FramedConnection::<S>::_start_recv_state(),
219            send_state: FramedConnection::<S>::_start_send_state(),
220            }
221    }
222
223    fn _start_recv_state() -> RecvState {
224        RecvState::Unknown
225    }
226
227    fn _start_send_state() -> SendState {
228        SendState::NotSending
229    }
230
231    /// Schedule a frame to be sent. Returns `Err(Error)` if the frame is too long,
232    /// otherwise returns immediately with `Ok(())`.
233    pub fn schedule_send(&mut self, frame: Vec<u8>) -> Result<()> {
234        match self.send_state {
235            SendState::NotSending => {}
236            SendState::Sending(_) => {
237                return Err(Error::new("Previous send in progress. Hint: block_until_send_done().".into()));
238            }
239        }
240
241        if frame.len() > u16::max_value() as usize {
242            return Err(Error::new("frame data too long".into()));
243        }
244        let mut buf = [0; 2];
245        byteorder::LittleEndian::write_u16(&mut buf, frame.len() as u16);
246        self.send_state = SendState::Sending( {
247            SendingState{
248                what_next: WhatNext::Sentinel,
249                index: 0,
250                header_bytes: buf,
251                frame: frame,
252            }});
253        Ok(())
254    }
255
256    /// Wait until previous send is done.
257    pub fn block_until_send_done(&mut self) -> Result<()> {
258        loop {
259            match self.send_state {
260                SendState::NotSending => {break;}
261                SendState::Sending(_) => {}
262            }
263            self.tick()?;
264        }
265        Ok(())
266    }
267
268    /// Service the connection.
269    pub fn tick(&mut self) -> Result<TickProgress> {
270        Ok(TickProgress {
271            send_is_done: self._send_tick()?,
272            recv_is_done: self._recv_tick()?,
273        })
274    }
275
276    /// return bool to describe whether send is done.
277    fn _send_tick(&mut self) -> Result<bool> {
278        match self.send_state {
279            SendState::NotSending => {
280                return Ok(true);
281            },
282            SendState::Sending(ref mut s) => {
283                loop {
284                    // while we are not blocked on send, keep sending.
285                    let byte = match s.what_next {
286                        WhatNext::Sentinel => SENTINEL,
287                        WhatNext::Header => s.header_bytes[s.index],
288                        WhatNext::Data => s.frame[s.index],
289                    };
290                    match self.serial.putc_try(byte) {
291                        Ok(Some(_)) => {
292                            s.index += 1;
293                            let mut new_next: Option<WhatNext> = None;
294                            match s.what_next {
295                                WhatNext::Sentinel => {
296                                    new_next = Some(WhatNext::Header);
297                                    s.index = 0;
298                                },
299                                WhatNext::Header => {
300                                    if s.index == 2 {
301                                        new_next = Some(WhatNext::Data);
302                                        s.index = 0;
303                                    }
304                                },
305                                WhatNext::Data => {
306                                    if s.index == s.frame.len() {
307                                        // don't send more
308                                        break;
309                                    }
310                                },
311                            }
312                            if let Some(nn) = new_next {
313                                s.what_next = nn;
314                            }
315                        },
316                        Ok(None) => {
317                            return Ok(false);
318                        },
319                        Err(_) => {
320                            return Err(Error::new("unexpected error during putc_try()".into()));
321                        }
322                    }
323                }
324            }
325        }
326        // we have completed sending a frame
327        self.send_state = SendState::NotSending;
328        Ok(true)
329    }
330
331    /// return bool to describe whether recv is done.
332    fn _recv_tick(&mut self) -> Result<bool> {
333
334        loop {
335            // While we get characters, keep looping.
336
337            if self.is_frame_complete() {
338                return Ok(true);
339            }
340
341            match self.serial.getc_try() {
342                Ok(Some(byte)) => {
343                    let mut new_state: Option<RecvState> = None;
344                    match self.recv_state {
345                        RecvState::Unknown => {
346                            if byte == SENTINEL {
347                                new_state = Some(RecvState::Header(HeaderState{bytes: [0, 0], index: 0}))
348                            }
349                        },
350                        RecvState::Header(ref mut hs) => {
351                            hs.bytes[hs.index] = byte;
352                            hs.index += 1;
353                            if hs.index == 2 {
354                                let ds = DataState {
355                                    length: byteorder::LittleEndian::read_u16(&hs.bytes) as usize,
356                                };
357                                new_state = Some(RecvState::Data(ds));
358                            }
359                        },
360                        RecvState::Data(ref mut ds) => {
361                            self.recv_buf.push(byte);
362                            if self.recv_buf.len() == ds.length {
363                                // this frame is complete, stop polling for new data
364                                return Ok(true);
365                            }
366                        },
367                    };
368                    if let Some(ns) = new_state {
369                        self.recv_state=ns;
370                    }
371                },
372                Ok(None) => {
373                    // no more data available
374                    break;
375                },
376                Err(_) => {
377                    return Err(Error::new("unexpected error during getc_try()".into()))
378                },
379            };
380
381        }
382        Ok(false)
383    }
384
385    /// Check if frame is complete.
386    fn is_frame_complete(&mut self) -> bool {
387        match self.recv_state {
388            RecvState::Unknown | RecvState::Header(_) => false,
389            RecvState::Data(ref ds) => ds.length == self.recv_buf.len(),
390        }
391    }
392
393    /// Get completed frame.
394    pub fn get_frame(&mut self) -> Result<Vec<u8>> {
395        let frame = match self.recv_state {
396            RecvState::Unknown | RecvState::Header(_) => {
397                return Err(Error::new("frame not available".into()));
398            },
399            RecvState::Data(ref ds) => {
400                if self.recv_buf.len() == ds.length {
401                    let mut frame = Vec::with_capacity(0);
402                    core::mem::swap(&mut self.recv_buf,&mut frame);
403                    frame
404                } else {
405                    return Err(Error::new("frame not available".into()));
406                }
407            },
408        };
409        self.recv_state = FramedConnection::<S>::_start_recv_state();
410        Ok(frame)
411    }
412
413}