#crc #checksum #data-integrity #networking

no-std crc8-rs

A heapless no-std library for doing 8-bit cyclic redundancy checks

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

MIT license

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.

No runtime deps