Add checksum.
This commit is contained in:
parent
c2ea3bb1a5
commit
6d26fbeeda
6 changed files with 103 additions and 34 deletions
14
Cargo.lock
generated
14
Cargo.lock
generated
|
@ -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"
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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]
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue