1
Fork 0

Add checksum.

This commit is contained in:
Alex Helfet 2017-12-30 17:21:25 +00:00
parent c2ea3bb1a5
commit 6d26fbeeda
6 changed files with 103 additions and 34 deletions

14
Cargo.lock generated
View file

@ -18,6 +18,11 @@ name = "bitflags"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "byteorder"
version = "1.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "case"
version = "0.1.0"
@ -43,6 +48,11 @@ name = "cobs"
version = "0.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "crc16"
version = "0.3.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "csv"
version = "1.0.0-beta.5"
@ -84,7 +94,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
name = "framed"
version = "0.2.0"
dependencies = [
"byteorder 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"cobs 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
"crc16 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
"ref_slice 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.26 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_derive 1.0.26 (registry+https://github.com/rust-lang/crates.io-index)",
@ -307,9 +319,11 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
"checksum ansi_term 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6b3568b48b7cefa6b8ce125f9bb4989e52fbcc29ebea88df04cc7c5f12f70455"
"checksum atty 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "8352656fd42c30a0c3c89d26dea01e3b77c0ab2af18230835c15e2e13cd51859"
"checksum bitflags 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b3c30d3802dfb7281680d6285f2ccdaa8c2d8fee41f93805dba5c4cf50dc23cf"
"checksum byteorder 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "652805b7e73fada9d85e9a6682a4abd490cb52d96aeecc12e33a0de34dfd0d23"
"checksum case 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e88b166b48e29667f5443df64df3c61dc07dc2b1a0b0d231800e07f09a33ecc1"
"checksum clap 2.29.0 (registry+https://github.com/rust-lang/crates.io-index)" = "110d43e343eb29f4f51c1db31beb879d546db27998577e5715270a54bcf41d3f"
"checksum cobs 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "98acedfd5fc3ef93c4c844980f30318a445c24f76863a9e51f0599b9f1d274ad"
"checksum crc16 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "11a65c4797332f3e3a5945e0377875afc79b1bdc87082a4f98ac1ef15b47e2dd"
"checksum csv 1.0.0-beta.5 (registry+https://github.com/rust-lang/crates.io-index)" = "e7a9e063dcebdb56c306f23e672bfd31df3da8ec5f6d696b35f2c29c2a9572f0"
"checksum csv-core 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ae1fbabf21d9a52d04675cc5b032d7bae24ecdcd22646f7eefcd0496a122686c"
"checksum derive-error 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "ec098440b29ea3b1ece3e641bac424c19cf996779b623c9e0f2171495425c2c8"

View file

@ -14,7 +14,9 @@ repository = "fluffysquirrels/framed-rs"
branch = "master"
[dependencies]
byteorder = { version = "^1.2.1", default-features = false }
cobs = "^0.1.3"
crc16 = "^0.3.4"
ref_slice = "^1.1.1"
serde = "^1.0"
ssmarshal = "^1.0"

View file

@ -74,7 +74,9 @@ use ::{Payload, Encoded, FRAME_END_SYMBOL};
#[cfg(feature = "use_std")]
use ::{BoxPayload, BoxEncoded};
use ::error::{Error, Result};
use byteorder::{self, ByteOrder};
use cobs;
use crc16;
#[cfg(feature = "use_std")]
use ref_slice::ref_slice_mut;
@ -84,7 +86,18 @@ use std::io::{self, Read, Write};
const HEADER_LEN: usize = 0;
const FOOTER_LEN: usize = 1;
const CHECKSUM_LEN: usize = 2;
const FOOTER_LEN: usize = CHECKSUM_LEN + 1;
const FRAMING_LEN: usize = HEADER_LEN + FOOTER_LEN;
fn checksum(p: &Payload) -> [u8; CHECKSUM_LEN] {
let u16 = crc16::State::<crc16::CDMA2000>::calculate(p);
let mut bytes = [0u8; CHECKSUM_LEN];
byteorder::NetworkEndian::write_u16(&mut bytes, u16);
bytes
}
/// Encode the supplied payload data as a frame at the beginning of
/// the supplied buffer `dest`. Available from `no_std` crates.
@ -96,17 +109,29 @@ const FOOTER_LEN: usize = 1;
/// This function will panic if `dest` is not large enough for the encoded frame.
/// Ensure `dest.len() >= max_encoded_len(p.len())`.
pub fn encode_to_slice(p: &Payload, dest: &mut Encoded) -> Result<usize> {
// Panic if code won't fit in `dest` because this is a programmer error.
// Panic if encoded frame won't fit in `dest` because this is a
// programmer error.
assert!(max_encoded_len(p.len()) <= dest.len());
let cobs_len = cobs::encode(&p, &mut dest[HEADER_LEN..]);
let footer_idx = HEADER_LEN + cobs_len;
dest[footer_idx] = FRAME_END_SYMBOL;
let checksum = checksum(p);
#[cfg(feature = "trace")] {
println!("framed: Frame code = {:?}", &dest[0..(footer_idx + 1)]);
{
let mut _header = &mut dest[0..HEADER_LEN];
}
Ok(cobs_len + HEADER_LEN + FOOTER_LEN)
{
let footer = &mut dest[
(HEADER_LEN + cobs_len)
..
(HEADER_LEN + cobs_len + FOOTER_LEN)];
footer[0..CHECKSUM_LEN].copy_from_slice(&checksum);
footer[CHECKSUM_LEN] = FRAME_END_SYMBOL;
}
let len = HEADER_LEN + cobs_len + FOOTER_LEN;
#[cfg(feature = "trace")] {
println!("framed: Encoded frame = {:?}", &dest[0..len]);
}
Ok(len)
}
/// Encode the supplied payload data as a frame and return it on the heap.
@ -167,6 +192,10 @@ pub fn decode_to_slice(e: &Encoded, dest: &mut [u8])
return Err(Error::EofBeforeFrame);
}
if e.len() < FRAMING_LEN {
return Err(Error::EofDuringFrame);
}
if e[e.len()-1] != FRAME_END_SYMBOL {
return Err(Error::EofDuringFrame)
}
@ -174,19 +203,34 @@ pub fn decode_to_slice(e: &Encoded, dest: &mut [u8])
assert!(dest.len() >= max_decoded_len(e.len()));
assert_eq!(e[e.len() - 1], FRAME_END_SYMBOL);
// Just the body (COBS-encoded payload).
let body = &e[0..(e.len()-1)];
let len = cobs::decode(body, dest)
.map_err(|_| Error::CobsDecodeFailed)?;
let _header = &e[0..HEADER_LEN];
let body = &e[HEADER_LEN..(e.len() - FOOTER_LEN)];
let footer = &e[(e.len() - FOOTER_LEN)..e.len()];
#[cfg(feature = "trace")] {
println!("framed: body = {:?}\n\
framed: decoded = {:?}",
body, &dest[0..len]);
println!("framed: header = {:?}\n\
framed: body = {:?}\n\
framed: footer = {:?}",
_header, body, footer);
}
Ok(len)
let decoded_len = cobs::decode(body, dest)
.map_err(|_| Error::CobsDecodeFailed)?;
let decoded = &dest[0..decoded_len];
let calc_checksum = checksum(decoded);
let received_checksum = &footer[0..CHECKSUM_LEN];
if calc_checksum != received_checksum {
return Err(Error::ChecksumError);
}
#[cfg(feature = "trace")] {
println!("framed: decoded = {:?}",
decoded);
}
Ok(decoded_len)
}
/// Decode the supplied encoded frame, returning the payload on the heap.
@ -372,11 +416,11 @@ mod tests {
#[test]
fn max_encoded_len_ok() {
assert_eq!(max_encoded_len(0) , 2);
assert_eq!(max_encoded_len(1) , 3);
assert_eq!(max_encoded_len(2) , 4);
assert_eq!(max_encoded_len(254), 257);
assert_eq!(max_encoded_len(255), 258);
assert_eq!(max_encoded_len(0) , 4);
assert_eq!(max_encoded_len(1) , 5);
assert_eq!(max_encoded_len(2) , 6);
assert_eq!(max_encoded_len(254), 259);
assert_eq!(max_encoded_len(255), 260);
}
#[test]
@ -501,7 +545,7 @@ mod rw_tests {
fn one_frame() {
let (mut tx, mut rx) = pair();
let p = [0x00, 0x01, 0x02];
assert_eq!(tx.send(&p).unwrap(), 5);
tx.send(&p).unwrap();
let recvd = rx.recv().unwrap();
assert_eq!(*recvd, p);
}
@ -511,14 +555,14 @@ mod rw_tests {
let (mut tx, mut rx) = pair();
{
let sent = [0x00, 0x01, 0x02];
assert_eq!(tx.send(&sent).unwrap(), 5);
tx.send(&sent).unwrap();
let recvd = rx.recv().unwrap();
assert_eq!(*recvd, sent);
}
{
let sent = [0x10, 0x11, 0x12];
assert_eq!(tx.send(&sent).unwrap(), 5);
tx.send(&sent).unwrap();
let recvd = rx.recv().unwrap();
assert_eq!(*recvd, sent);
}

View file

@ -19,6 +19,9 @@ pub enum Error {
/// COBS decode failed
CobsDecodeFailed,
/// Checksum error: the received frame was corrupted.
ChecksumError,
/// End of data while reading a frame; we received some of a frame
/// but it was incomplete.
EofDuringFrame,

View file

@ -22,8 +22,13 @@
//!
//! Currently the encoding is:
//!
//! * The "body": payload [COBS]-encoded to remove bytes equal to zero
//! * A terminating zero byte.
//! * Header:
//! * Nothing here yet.
//! * Body: payload [COBS]-encoded to remove bytes equal to zero
//! * Footer:
//! * A 2 byte checksum.
//! * A terminating zero byte.
//!
//! [COBS]: https://en.wikipedia.org/wiki/Consistent_Overhead_Byte_Stuffing
//!
//! The encoding is not stable at the moment, i.e. it can and will
@ -171,13 +176,14 @@ macro_rules! const_fn {
}
// ## extern crate statements
extern crate byteorder;
extern crate cobs;
#[cfg(feature = "use_std")]
extern crate core;
extern crate crc16;
extern crate ref_slice;
extern crate serde;
#[macro_use]

View file

@ -386,17 +386,17 @@ mod tests {
#[test]
fn serialize_buf_len() {
assert_eq!(max_serialize_buf_len::<Test>(), 42);
assert_eq!(max_serialize_buf_len::<u8>(), 3);
assert_eq!(max_serialize_buf_len::<u16>(), 4);
assert_eq!(max_serialize_buf_len::<u32>(), 6);
assert_eq!(max_serialize_buf_len::<u64>(), 10);
assert_eq!(max_serialize_buf_len::<Test>(), 44);
assert_eq!(max_serialize_buf_len::<u8>(), 5);
assert_eq!(max_serialize_buf_len::<u16>(), 6);
assert_eq!(max_serialize_buf_len::<u32>(), 8);
assert_eq!(max_serialize_buf_len::<u64>(), 12);
}
#[test]
fn encoded_len() {
assert_eq!(max_encoded_len::<Test>(), 44);
assert_eq!(max_encoded_len::<u8>(), 5);
assert_eq!(max_encoded_len::<Test>(), 48);
assert_eq!(max_encoded_len::<u8>(), 9);
}
}