4 stable releases
1.1.1 | Nov 12, 2021 |
---|---|
1.1.0 | Mar 18, 2021 |
1.0.1 | Mar 10, 2021 |
#619 in Embedded development
24KB
204 lines
crc8-rs
NOTE: I strongly suggest you use the crc crate instead of this crate
A minimal heapless no_std implementation of 8-bit cyclic redundancy checks in Rust. This allows us to check for the integrity of data, and thus is mostly used when transferring data over unstable or noisy connections. For example, this is connections with embedded systems and network connections.
Take a look at the documentation.
Features
This crate provides the minimal functions needed to properly handle CRC's in an 8-bit
system. The provided functions are
fetch_crc8
,
has_valid_crc8
and insert_crc8
.
This
should make handling most of the common CRC situations simple. Because of the minimalist
approach this crate takes, binary size should remain small. This especially fits well on
embedded hardware.
Usage
Add this to your projects Cargo.toml with:
[dependencies]
crc8-rs = "1.1"
There are generally two ways to use this crate. We can use plain buffers or we wrap CRCs with
struct
methods. Let us go over both
ways.
Using plain buffers
On the transferring end, we would similar code to the following.
use crc8_rs::{ has_valid_crc8, insert_crc8 };
// We are given a data buffer we would like to transfer
// It is important to leave a unused byte at the end for the CRC byte
let data: [u8; 256] = [
// ...snip
];
// We can insert a CRC byte to the data buffer, this will be the last byte
// This time we use the generator polynomial of `0xD5`
let crc_data: [u8; 256] = insert_crc8(data, 0xD5);
// Now we are able to verify that the CRC is valid
assert!(has_valid_crc8(crc_data, 0xD5));
// Transfer the data...
Then on the receiving end, we would have code such as the following.
use crc8_rs::has_valid_crc8;
// We receive the CRCed data from some source
// This buffer has the CRC byte as the last byte
let crc_data: [u8; 256] = // ...snip
// Now we can conditionally unpack it and use the data
if has_valid_crc8(crc_data, 0xD5) {
// The data is contained in the crc_data
let data = crc_data;
// ...snip
} else {
panic!("CRC is invalid!")
}
Wrapping the CRC
If we want to form packets from some given data, we may want to append a CRC byte when transferring the data to verify the data's integrity.
use crc8_rs::insert_crc8;
// Define a example packet structure
struct Packet {
header: [u8; 4],
content: [u8; 247],
footer: [u8; 4],
}
impl Packet {
fn to_data_buffer(&self) -> [u8; 256] {
let mut data = [0; 256];
// First we insert the packet data into the buffer
for i in 0..4 { data[i] = self.header[i] }
for i in 0..247 { data[i + 4] = self.content[i] }
for i in 0..4 { data[i + 251] = self.footer[i] }
// We use the generator polynomial `0xD5` here.
insert_crc8(data, 0xD5)
}
}
Receiving the given buffer is now quite simple.
use crc8_rs::has_valid_crc8;
struct ReceivedPacket {
header: [u8; 4],
content: [u8; 247],
footer: [u8; 4],
}
impl ReceivedPacket {
fn receive(data: [u8; 256]) -> Option<ReceivedPacket> {
// Before we construct the instance, we first check the CRC
if has_valid_crc8(data, 0xD6) {
Some(ReceivedPacket {
// ...snip
})
} else {
None
}
}
}
License
Licensed with a MIT license.