bin_file 0.1.4

Mangling of various file formats that conveys binary information (Motorola S-Record, Intel HEX, TI-TXT and binary files).
Documentation
//
// Copyright 2016 ihex Developers (ihex)
// Copyright 2023 Robert Ernst
//
// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
// http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
// http://opensource.org/licenses/MIT>, at your option. This file may not be
// copied, modified, or distributed except according to those terms.
//
//
use std::num::Wrapping;

/// Computes the Intel HEX checksum of `data`. This is done by summing all the bytes of `data`
/// and taking the two's complement of the least significant byte of the sum.
///
/// # Parameters
///
/// - `data`: datas, over which checksum should be calculated
pub fn crc_ihex<T>(data: T) -> u8
where
    T: AsRef<[u8]>,
{
    (0_u8).wrapping_sub(
        data.as_ref()
            .iter()
            .fold(0, |acc, &value| acc.wrapping_add(value)),
    )
}

pub fn crc_srec<T>(data: T) -> u8
where
    T: AsRef<[u8]>,
{
    !data
        .as_ref()
        .iter()
        .map(|b| Wrapping(*b))
        .sum::<Wrapping<u8>>()
        .0
}

pub fn crc_ext_tek_hex<T>(data: T) -> u8
where
    T: AsRef<[char]>,
{
    let mut sum: u8 = 0;
    for char in data.as_ref() {
        let value = match char {
            x if (&'0'..=&'9').contains(&x) => *x as u8 - b'0',
            x if (&'A'..=&'Z').contains(&x) => *x as u8 - b'A' + 10,
            '$' => 36,
            '%' => 37,
            '.' => 38,
            '_' => 39,
            x if (&'a'..=&'z').contains(&x) => *x as u8 - b'a' + 40,
            _ => 0,
        };
        sum = sum.wrapping_add(value);
    }
    sum
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_checksum_empty() {
        assert_eq!(crc_ihex([]), 0x00);
    }

    #[test]
    fn test_checksum_eof_record() {
        assert_eq!(crc_ihex([0x00, 0x00, 0x00, 0x01]), 0xFF);
    }

    #[test]
    fn test_checksum_ela_record() {
        assert_eq!(crc_ihex([0x02, 0x00, 0x00, 0x04, 0xFF, 0xFF]), 0xFC);
    }

    #[test]
    fn test_ihex_crc() {
        assert_eq!(crc_ihex([0x03, 0x00, 0x30, 0x00, 0x02, 0x33, 0x7a]), 0x1e);
        assert_eq!(crc_ihex([0x00; 4]), 0x00);
    }

    #[test]
    fn test_checksum_sla_record() {
        assert_eq!(
            crc_ihex([0x04, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0xCD]),
            0x2A
        );
    }

    #[test]
    fn checksum_of_returns_correct_value() {
        // All sourced from the Wikipedia SREC article
        // https://en.wikipedia.org/wiki/SREC_(file_format)
        assert_eq!(
            crc_srec([
                0x13, 0x7a, 0xf0, 0x0a, 0x0a, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
                0x00, 0x00, 0x00, 0x00, 0x00
            ]),
            0x61
        );

        assert_eq!(
            crc_srec([
                0x0f, 0x00, 0x00, 0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x20, 0x20, 0x20, 0x20, 0x20, 0x00,
                0x00
            ]),
            0x3c
        );

        assert_eq!(
            crc_srec([
                0x1f, 0x00, 0x00, 0x7c, 0x08, 0x02, 0xa6, 0x90, 0x01, 0x00, 0x04, 0x94, 0x21, 0xff,
                0xf0, 0x7c, 0x6c, 0x1b, 0x78, 0x7c, 0x8c, 0x23, 0x78, 0x3c, 0x60, 0x00, 0x00, 0x38,
                0x63, 0x00, 0x00
            ]),
            0x26
        );

        assert_eq!(
            crc_srec([
                0x1f, 0x00, 0x1c, 0x4b, 0xff, 0xff, 0xe5, 0x39, 0x80, 0x00, 0x00, 0x7d, 0x83, 0x63,
                0x78, 0x80, 0x01, 0x00, 0x14, 0x38, 0x21, 0x00, 0x10, 0x7c, 0x08, 0x03, 0xa6, 0x4e,
                0x80, 0x00, 0x20
            ]),
            0xe9
        );

        assert_eq!(
            crc_srec([
                0x11, 0x00, 0x38, 0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x20, 0x77, 0x6f, 0x72, 0x6c, 0x64,
                0x2e, 0x0a, 0x00
            ]),
            0x42
        );

        assert_eq!(crc_srec([0x03, 0x00, 0x03]), 0xf9);

        assert_eq!(crc_srec([0x03, 0x00, 0x00]), 0xfc);
    }
}