SML: CRC for binary SML (#23205)

* SML: CRC for binary SML parsing

* switch algos

* improve errormessage on buffer overflow

* move crc variable to their own struct

* Use Flag bit to disable CRC, auto-detect algorithm,
data in own struct
debug log

* configure and enable/disable via special option "=soC,bufsz,mode", mode 16 autodetect.

* fix 15 vs 0xF

* remove benchmark code

* fix typo in comment

* Byteflip for CRC
This commit is contained in:
Thomas Büngener 2025-04-05 11:22:22 +02:00 committed by GitHub
parent c121dbcd4a
commit 4ed48feaa2
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
10 changed files with 3286 additions and 6 deletions

View File

@ -0,0 +1,21 @@
The MIT License (MIT)
Copyright (c) 2016 Frank
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@ -0,0 +1,56 @@
FastCRC
=======
Fast CRC Arduino library
Up to 30 times faster than crc16.h (_avr_libc)
- uses the on-chip hardware for Teensy 3.0 / 3.1 / 3.2 / 3.5 / 3.6
- uses fast table-algorithms for other chips
List of supported CRC calculations:
-
7 BIT:
CRC7
(poly=0x09 init=0x00 refin=false refout=false xorout=0x00 check=0x75)
MultiMediaCard interface
8 BIT:
SMBUS
(poly=0x07 init=0x00 refin=false refout=false xorout=0x00 check=0xf4)
MAXIM
(poly=0x31 init=0x00 refin=true refout=true xorout=0x00 check=0xa1)
16 BIT:
KERMIT (Alias CRC-16/CCITT, CRC-16/CCITT-TRUE, CRC-CCITT)
(poly=0x1021 init=0x0000 refin=true refout=true xorout=0x0000 check=0x2189
Attention: sometimes you'll find byteswapped presentation of result in other implementations)
CCITT-FALSE
(poly=0x1021 init=0xffff refin=false refout=false xorout=0x0000 check=0x29b1)
MCRF4XX
(poly=0x1021 init=0xffff refin=true refout=true xorout=0x0000 check=0x6f91)
MODBUS
(poly=0x8005 init=0xffff refin=true refout=true xorout=0x0000 check=0x4b37)
XMODEM (Alias ZMODEM, CRC-16/ACORN)
(poly=0x1021 init=0x0000 refin=false refout=false xorout=0x0000 check=0x31c3)
X25 (Alias CRC-16/IBM-SDLC, CRC-16/ISO-HDLC, CRC-B)
(poly=0x1021 init=0xffff refin=true refout=true xorout=0xffff check=0x906e)
32 BIT:
CRC32, CRC-32/ADCCP, PKZIP, ETHERNET, 802.3
(poly=0x04c11db7 init=0xffffffff refin=true refout=true xorout=0xffffffff check=0xcbf43926)
CKSUM, CRC-32/POSIX
(poly=0x04c11db7 init=0x00000000 refin=false refout=false xorout=0xffffffff check=0x765e7680)

View File

@ -0,0 +1,59 @@
#######################################
# Syntax Coloring Map For FastCRC
#######################################
#######################################
# Datatypes (KEYWORD1)
#######################################
FastCRC7 KEYWORD1
FastCRC8 KEYWORD1
FastCRC14 KEYWORD1
FastCRC16 KEYWORD1
FastCRC32 KEYWORD1
CRC7 KEYWORD1
CRC8 KEYWORD1
CRC14 KEYWORD1
CRC16 KEYWORD1
CRC32 KEYWORD1
#######################################
# Methods and Functions (KEYWORD2)
#######################################
crc7 KEYWORD2
crc7_upd KEYWORD2
ccitt KEYWORD2
ccitt_upd KEYWORD2
kermit KEYWORD2
kermit_upd KEYWORD2
mcrf4xx KEYWORD2
mcrf4xx_upd KEYWORD2
modbus KEYWORD2
modbus_upd KEYWORD2
xmodem KEYWORD2
xmodem_upd KEYWORD2
x25 KEYWORD2
x25_upd KEYWORD2
update KEYWORD2
update_upd KEYWORD2
generic KEYWORD2
crc32 KEYWORD2
crc32_upd KEYWORD2
cksum KEYWORD2
cksum_upd KEYWORD2
darc KEYWORD2
darc_upd KEYWORD2
gsm KEYWORD2
gsm_upd KEYWORD2
eloran KEYWORD2
eloran_upd KEYWORD2
#######################################
# Constants (LITERAL1)
#######################################
CRC_FLAG_NOREFLECT LITERAL1
CRC_FLAG_REFLECT LITERAL1
CRC_FLAG_XOR LITERAL1
CRC_FLAG_NOREFLECT_8 LITERAL1
CRC_FLAG_REFLECT_SWAP LITERAL1

View File

@ -0,0 +1,26 @@
{
"name": "FastCRC",
"keywords": "CRC7, CRC8, CRC16, CRC32",
"description": "Fast CRC routines for Arduino and PC (Teensy 3.x: CRC in hardware)",
"exclude": [
"examples",
"examples_PC"
],
"repository":
{
"type": "git",
"url": "https://github.com/FrankBoesing/FastCRC"
},
"authors":
[
{
"name": "Frank Bösing",
"email": "f.boesing@gmx.de",
"url": "https://github.com/FrankBoesing/FastCRC",
"maintainer": true
}
],
"version": "1.44",
"frameworks": "arduino",
"platforms": "*"
}

View File

@ -0,0 +1,10 @@
name=FastCRC
version=1.44
author=Frank Bösing
maintainer=Frank Boesing<f.boesing@gmx.de>
sentence=Fast CRC routines
paragraph=
category=Data Processing
url=https://github.com/FrankBoesing/FastCRC
architectures=*
#dot_a_linkage=true

View File

@ -0,0 +1,189 @@
/* FastCRC library code is placed under the MIT license
* Copyright (c) 2014 - 2021 Frank Bösing
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
// Teensy 3.0, Teensy 3.1:
// See K20P64M72SF1RM.pdf (Kinetis), Pages 638 - 641 for documentation of CRC Device
// See KINETIS_4N30D.pdf for Errata (Errata ID 2776)
//
// So, ALL HW-calculations are done as 32 bit.
//
//
//
// Thanks to:
// - Catalogue of parametrised CRC algorithms, CRC RevEng
// http://reveng.sourceforge.net/crc-catalogue/
//
// - Danjel McGougan (CRC-Table-Generator)
//
// Set this to 0 for smaller 32BIT-CRC-Tables:
#if !defined(CRC_BIGTABLES)
#define CRC_BIGTABLES 1
#endif
#if !defined(FastCRC_h)
#define FastCRC_h
#if defined(ARDUINO)
#include <Arduino.h>
#endif
#include <inttypes.h>
// ================= DEFINES ===================
#if defined(KINETISK)
#define CRC_SW 0
#define CRC_FLAG_NOREFLECT (((1<<31) | (1<<30)) | ((0<<29) | (0<<28))) //refin=false refout=false
#define CRC_FLAG_REFLECT (((1<<31) | (0<<30)) | ((1<<29) | (0<<28))) //Reflect in- and outgoing bytes (refin=true refout=true)
#define CRC_FLAG_XOR (1<<26) //Perform XOR on result
#define CRC_FLAG_NOREFLECT_8 (0) //For 8-Bit CRC
#define CRC_FLAG_REFLECT_SWAP (((1<<31) | (0<<30)) | ((0<<29) | (1<<28))) //For 16-Bit CRC (byteswap)
#else
#define CRC_SW 1
#endif
// ================= 7-BIT CRC ===================
class FastCRC7
{
public:
FastCRC7();
uint8_t crc7(const uint8_t *data, const size_t datalen); // (MultiMediaCard interface)
uint8_t crc7_upd(const uint8_t *data, const size_t datalen); // Call for subsequent calculations with previous seed.
#if !CRC_SW
uint8_t generic(const uint8_t polyom, const uint8_t seed, const uint32_t flags, const uint8_t *data, const size_t datalen); //Not available in non-hw-variant (not T3.x)
#endif
private:
#if CRC_SW
uint8_t seed;
#else
uint8_t update(const uint8_t *data, const size_t datalen);
#endif
};
// ================= 8-BIT CRC ===================
class FastCRC8
{
public:
FastCRC8();
uint8_t smbus(const uint8_t *data, const size_t datalen); // Alias CRC-8
uint8_t maxim(const uint8_t *data, const size_t datalen); // Equivalent to _crc_ibutton_update() in crc16.h from avr_libc
uint8_t smbus_upd(const uint8_t *data, size_t datalen); // Call for subsequent calculations with previous seed.
uint8_t maxim_upd(const uint8_t *data, size_t datalen); // Call for subsequent calculations with previous seed.
#if !CRC_SW
uint8_t generic(const uint8_t polyom, const uint8_t seed, const uint32_t flags, const uint8_t *data, const size_t datalen); //Not available in non-hw-variant (not T3.x)
#endif
private:
#if CRC_SW
uint8_t seed;
#else
uint8_t update(const uint8_t *data, const size_t datalen);
#endif
};
// ================= 14-BIT CRC ===================
class FastCRC14
{
public:
#if !CRC_SW //NO Software-implemenation so far
FastCRC14();
uint16_t darc(const uint8_t *data, const size_t datalen);
uint16_t gsm(const uint8_t *data, const size_t datalen);
uint16_t eloran(const uint8_t *data, const size_t datalen);
uint16_t ft4(const uint8_t *data, const size_t datalen);
uint16_t darc_upd(const uint8_t *data, size_t len);
uint16_t gsm_upd(const uint8_t *data, size_t len);
uint16_t eloran_upd(const uint8_t *data, size_t len);
uint16_t ft4_upd(const uint8_t *data, size_t len);
#endif
#if !CRC_SW
uint16_t generic(const uint16_t polyom, const uint16_t seed, const uint32_t flags, const uint8_t *data, const size_t datalen); //Not available in non-hw-variant (not T3.x)
#endif
private:
#if CRC_SW
uint16_t seed;
#else
uint16_t update(const uint8_t *data, const size_t datalen);
#endif
};
// ================= 16-BIT CRC ===================
class FastCRC16
{
public:
FastCRC16();
uint16_t ccitt(const uint8_t *data, const size_t datalen); // Alias "false CCITT"
uint16_t mcrf4xx(const uint8_t *data,const size_t datalen); // Equivalent to _crc_ccitt_update() in crc16.h from avr_libc
uint16_t kermit(const uint8_t *data, const size_t datalen); // Alias CRC-16/CCITT, CRC-16/CCITT-TRUE, CRC-CCITT
uint16_t modbus(const uint8_t *data, const size_t datalen); // Equivalent to _crc_16_update() in crc16.h from avr_libc
uint16_t xmodem(const uint8_t *data, const size_t datalen); // Alias ZMODEM, CRC-16/ACORN
uint16_t x25(const uint8_t *data, const size_t datalen); // Alias CRC-16/IBM-SDLC, CRC-16/ISO-HDLC, CRC-B
uint16_t ccitt_upd(const uint8_t *data, size_t len); // Call for subsequent calculations with previous seed
uint16_t mcrf4xx_upd(const uint8_t *data, size_t len); // Call for subsequent calculations with previous seed
uint16_t kermit_upd(const uint8_t *data, size_t len); // Call for subsequent calculations with previous seed
uint16_t modbus_upd(const uint8_t *data, size_t len); // Call for subsequent calculations with previous seed
uint16_t xmodem_upd(const uint8_t *data, size_t len); // Call for subsequent calculations with previous seed
uint16_t x25_upd(const uint8_t *data, size_t len); // Call for subsequent calculations with previous seed
#if !CRC_SW
uint16_t generic(const uint16_t polyom, const uint16_t seed, const uint32_t flags, const uint8_t *data, const size_t datalen); //Not available in non-hw-variant (not T3.x)
#endif
private:
#if CRC_SW
uint16_t seed;
#else
uint16_t update(const uint8_t *data, const size_t datalen);
#endif
};
// ================= 32-BIT CRC ===================
class FastCRC32
{
public:
FastCRC32();
uint32_t crc32(const uint8_t *data, const size_t datalen); // Alias CRC-32/ADCCP, PKZIP, Ethernet, 802.3
uint32_t cksum(const uint8_t *data, const size_t datalen); // Alias CRC-32/POSIX
uint32_t crc32_upd(const uint8_t *data, size_t len); // Call for subsequent calculations with previous seed
uint32_t cksum_upd(const uint8_t *data, size_t len); // Call for subsequent calculations with previous seed
#if !CRC_SW
uint32_t generic(const uint32_t polyom, const uint32_t seed, const uint32_t flags, const uint8_t *data, const size_t datalen); //Not available in non-hw-variant (not T3.x)
#endif
private:
#if CRC_SW
uint32_t seed;
#else
uint32_t update(const uint8_t *data, const size_t datalen);
#endif
};
#endif

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,567 @@
/* FastCRC library code is placed under the MIT license
* Copyright (c) 2014 - 2021 Frank Bösing
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
//
// HW-calculations are 32BIT
//
// Thanks to:
// - Catalogue of parametrised CRC algorithms, CRC RevEng
// http://reveng.sourceforge.net/crc-catalogue/
//
// - Danjel McGougan (CRC-Table-Generator)
//
#if defined(ARDUINO)
#include <Arduino.h>
#endif
#if defined(KINETISK)
#include "mk20dx128.h"
#include "FastCRC.h"
// ===============================================
typedef struct {
union {
uint32_t CRC; //CRC Data register
struct {
uint16_t CRC16;
uint16_t CRC16_1;
};
struct {
uint8_t CRC8;
uint8_t CRC8_1;
uint8_t CRC8_2;
uint8_t CRC8_3;
};
};
uint32_t GPOLY; //CRC Polynomial register
uint32_t CTRL; //CRC Control register
} CRC_T;
static volatile CRC_T * const rCRC = (CRC_T *)0x40032000;
#define CRC_CTRL_WAS 25 // Write CRC Data Register As Seed(1) / Data(0)
#define CRC_CTRL_TCRC 24 // Width of CRC protocol (0=16 BIT, 1=32 BIT)
#define CRC_CTRL_TOTR1 29 // TOTR[1]
// ================= 7-BIT CRC ===================
/** Constructor
* Enables CRC-clock
*/
FastCRC7::FastCRC7(){
SIM_SCGC6 |= SIM_SCGC6_CRC;
}
/** CRC 7
* MultiMediaCard interface
* @param data Pointer to Data
* @param datalen Length of Data
* @return CRC value
*/
uint8_t FastCRC7::crc7(const uint8_t *data, const size_t datalen)
{
// poly=0x09 init=0x00 refin=false refout=false xorout=0x00 check=0x75
return (generic(0x09, 0, CRC_FLAG_NOREFLECT, data, datalen));
}
/** Update
* Call for subsequent calculations with previous seed
* @param data Pointer to Data
* @param datalen Length of Data
* @return CRC value
*/
uint8_t FastCRC7::update(const uint8_t *data, const size_t datalen)
{
const uint8_t *src = data;
const uint8_t *target = src + datalen;
while (((uintptr_t)src & 0x03) != 0 && (src < target)) {
rCRC->CRC8_3 = *src++; //Write 8 BIT
}
while (src <= target-4) {
rCRC->CRC = *( uint32_t *)src; //Write 32 BIT
src += 4;
}
while (src < target) {
rCRC->CRC8_3 = *src++; //Write 8 Bit
}
//TODO: Check handling of CRC_CTRL_TOTR1 for other CRC7s
/*
if (rCRC->CTRL & (1<<CRC_CTRL_TOTR1))
return rCRC->CRC8 >> 1;
else
*/
return rCRC->CRC8_3 >> 1;
}
/** generic function for all 7-Bit CRCs
* @param polynom Polynom
* @param seed Seed
* @param flags Flags
* @param data Pointer to Data
* @param datalen Length of Data
* @return CRC value
*/
uint8_t FastCRC7::generic(const uint8_t polynom, const uint8_t seed, const uint32_t flags, const uint8_t *data,const size_t datalen)
{
rCRC->CTRL = flags | (1<<CRC_CTRL_TCRC) | (1<<CRC_CTRL_WAS); // 32Bit Mode, Prepare to write seed(25)
rCRC->GPOLY = ((uint32_t)polynom)<<(24 + 1); // Set polynom
rCRC->CRC = ((uint32_t)seed<<(24 + 1)); // Write seed
rCRC->CTRL = flags | (1<<CRC_CTRL_TCRC); // Clear WAS Bit - prepare to write data
return update(data, datalen);
}
uint8_t FastCRC7::crc7_upd(const uint8_t *data, size_t datalen){return update(data, datalen);}
// ================= 8-BIT CRC ===================
/** Constructor
* Enables CRC-clock
*/
FastCRC8::FastCRC8(){
SIM_SCGC6 |= SIM_SCGC6_CRC;
}
/** SMBUS CRC
* aka CRC-8
* @param data Pointer to Data
* @param datalen Length of Data
* @return CRC value
*/
uint8_t FastCRC8::smbus(const uint8_t *data, const size_t datalen)
{
// poly=0x07 init=0x00 refin=false refout=false xorout=0x00 check=0xf4
return generic(0x07, 0, CRC_FLAG_NOREFLECT, data, datalen);
}
/** MAXIM 8-Bit CRC
* equivalent to _crc_ibutton_update() in crc16.h from avr_libc
* @param data Pointer to Data
* @param datalen Length of Data
* @return CRC value
*/
uint8_t FastCRC8::maxim(const uint8_t *data, const size_t datalen)
{
// poly=0x31 init=0x00 refin=true refout=true xorout=0x00 check=0xa1
return generic(0x31, 0, CRC_FLAG_REFLECT, data, datalen);
}
/** Update
* Call for subsequent calculations with previous seed
* @param data Pointer to Data
* @param datalen Length of Data
* @return CRC value
*/
uint8_t FastCRC8::update(const uint8_t *data, const size_t datalen)
{
const uint8_t *src = data;
const uint8_t *target = src + datalen;
while (((uintptr_t)src & 0x03) != 0 && (src < target)) {
rCRC->CRC8_3 = *src++; //Write 8 BIT
}
while (src <= target-4) {
rCRC->CRC = *( uint32_t *)src; //Write 32 BIT
src += 4;
}
while (src < target) {
rCRC->CRC8_3 = *src++; //Write 8 Bit
}
if (rCRC->CTRL & (1<<CRC_CTRL_TOTR1))
return rCRC->CRC8;
else
return rCRC->CRC8_3;
}
/** generic function for all 8-Bit CRCs
* @param polynom Polynom
* @param seed Seed
* @param flags Flags
* @param data Pointer to Data
* @param datalen Length of Data
* @return CRC value
*/
uint8_t FastCRC8::generic(const uint8_t polynom, const uint8_t seed, const uint32_t flags, const uint8_t *data,const size_t datalen)
{
rCRC->CTRL = flags | (1<<CRC_CTRL_TCRC) | (1<<CRC_CTRL_WAS); // 32Bit Mode, Prepare to write seed(25)
rCRC->GPOLY = ((uint32_t)polynom)<<24; // Set polynom
rCRC->CRC = ((uint32_t)seed<<24); // Write seed
rCRC->CTRL = flags | (1<<CRC_CTRL_TCRC); // Clear WAS Bit - prepare to write data
return update(data, datalen);
}
uint8_t FastCRC8::smbus_upd(const uint8_t *data, size_t datalen){return update(data, datalen);}
uint8_t FastCRC8::maxim_upd(const uint8_t *data, size_t datalen){return update(data, datalen);}
// ================= 14-BIT CRC ===================
/** Constructor
* Enables CRC-clock
*/
FastCRC14::FastCRC14(){
SIM_SCGC6 |= SIM_SCGC6_CRC;
}
/** CRC-14/DARC
* @param data Pointer to Data
* @param datalen Length of Data
* @return CRC value
*/
uint16_t FastCRC14::darc(const uint8_t *data,const size_t datalen)
{
// poly=0x0805 init=0x0000 refin=true refout=true xorout=0x0000 check=0x082d residue=0x0000
return generic(0x0805, 0x0000, CRC_FLAG_REFLECT, data, datalen);
}
/** CRC-14/GSM
* @param data Pointer to Data
* @param datalen Length of Data
* @return CRC value
*/
uint16_t FastCRC14::gsm(const uint8_t *data,const size_t datalen)
{
// poly=0x202d init=0x0000 refin=false refout=false xorout=0x3fff check=0x30ae residue=0x031e
return generic(0x202d, 0x0000, CRC_FLAG_NOREFLECT | CRC_FLAG_XOR, data, datalen);
}
/** CRC-14/ELORAN
* @param data Pointer to Data
* @param datalen Length of Data
* @return CRC value
*/
uint16_t FastCRC14::eloran(const uint8_t *data,const size_t datalen)
{
// poly=0x60b1 init=0x0000 refin=false refout=false xorout=0x0000 check=0x38d1
return generic(0x60b1, 0x0, CRC_FLAG_NOREFLECT , data, datalen);
}
/** CRC-14/ft4 : TODO
* @param data Pointer to Data
* @param datalen Length of Data
* @return CRC value
*/
/*
uint16_t FastCRC14::ft4(const uint8_t *data,const size_t datalen)
{
return generic(, , , data, datalen);
}
*/
/** Update
* Call for subsequent calculations with previous seed
* @param data Pointer to Data
* @param datalen Length of Data
* @return CRC value
*/
uint16_t FastCRC14::update(const uint8_t *data, const size_t datalen)
{
const uint8_t *src = data;
const uint8_t *target = src + datalen;
while (((uintptr_t)src & 0x03) !=0 && (src < target)) {
rCRC->CRC8_3 = *src++; //Write 8 BIT
}
while (src <= target-4) {
rCRC->CRC = *( uint32_t *)src; //Write 32 BIT
src += 4;
}
while (src < target) {
rCRC->CRC8_3 = *src++; //Write 8 Bit
}
if (rCRC->CTRL & (1<<CRC_CTRL_TOTR1))
return rCRC->CRC16;
else
return rCRC->CRC >> (32 - 14);
}
/** generic function for all 14-Bit CRCs
* @param polynom Polynom
* @param seed Seed
* @param flags Flags
* @param data Pointer to Data
* @param datalen Length of Data
* @return CRC value
*/
uint16_t FastCRC14::generic(const uint16_t polynom, const uint16_t seed, const uint32_t flags, const uint8_t *data, const size_t datalen)
{
rCRC->CTRL = flags | (1<<CRC_CTRL_TCRC) | (1<<CRC_CTRL_WAS);// 32-Bit Mode, prepare to write seed(25)
rCRC->GPOLY = ((uint32_t)polynom) << (32 - 14); // set polynom
rCRC->CRC = ((uint32_t)seed << (32 - 14) ); // this is the seed
rCRC->CTRL = flags | (1<<CRC_CTRL_TCRC); // Clear WAS Bit - prepare to write data
return update(data, datalen);
}
uint16_t FastCRC14::darc_upd(const uint8_t *data, size_t len) {return update(data, len);}
uint16_t FastCRC14::gsm_upd(const uint8_t *data, size_t len) {return update(data, len);}
uint16_t FastCRC14::eloran_upd(const uint8_t *data, size_t len) {return update(data, len);}
//uint16_t FastCRC14::ft4(const uint8_t *data, size_t len) {return update(data, len);}
// ================= 16-BIT CRC ===================
/** Constructor
* Enables CRC-clock
*/
FastCRC16::FastCRC16(){
SIM_SCGC6 |= SIM_SCGC6_CRC;
}
/** CCITT
* Alias "false CCITT"
* @param data Pointer to Data
* @param datalen Length of Data
* @return CRC value
*/
uint16_t FastCRC16::ccitt(const uint8_t *data,const size_t datalen)
{
// poly=0x1021 init=0xffff refin=false refout=false xorout=0x0000 check=0x29b1
return generic(0x1021, 0XFFFF, CRC_FLAG_NOREFLECT, data, datalen);
}
/** MCRF4XX
* equivalent to _crc_ccitt_update() in crc16.h from avr_libc
* @param data Pointer to Data
* @param datalen Length of Data
* @return CRC value
*/
uint16_t FastCRC16::mcrf4xx(const uint8_t *data,const size_t datalen)
{
// poly=0x1021 init=0xffff refin=true refout=true xorout=0x0000 check=0x6f91
return generic(0x1021, 0XFFFF, CRC_FLAG_REFLECT , data, datalen);
}
/** MODBUS
* equivalent to _crc_16_update() in crc16.h from avr_libc
* @param data Pointer to Data
* @param datalen Length of Data
* @return CRC value
*/
uint16_t FastCRC16::modbus(const uint8_t *data, const size_t datalen)
{
// poly=0x8005 init=0xffff refin=true refout=true xorout=0x0000 check=0x4b37
return generic(0x8005, 0XFFFF, CRC_FLAG_REFLECT, data, datalen);
}
/** KERMIT
* Alias CRC-16/CCITT, CRC-16/CCITT-TRUE, CRC-CCITT
* @param data Pointer to Data
* @param datalen Length of Data
* @return CRC value
*/
uint16_t FastCRC16::kermit(const uint8_t *data, const size_t datalen)
{
// poly=0x1021 init=0x0000 refin=true refout=true xorout=0x0000 check=0x2189
// sometimes byteswapped presentation of result
return generic(0x1021, 0x00, CRC_FLAG_REFLECT, data, datalen);
}
/** XMODEM
* Alias ZMODEM, CRC-16/ACORN
* @param data Pointer to Data
* @param datalen Length of Data
* @return CRC value
*/
uint16_t FastCRC16::xmodem(const uint8_t *data, const size_t datalen)
{
//width=16 poly=0x1021 init=0x0000 refin=false refout=false xorout=0x0000 check=0x31c3
return generic(0x1021, 0, CRC_FLAG_NOREFLECT, data, datalen);
}
/** X25
* Alias CRC-16/IBM-SDLC, CRC-16/ISO-HDLC, CRC-B
* @param data Pointer to Data
* @param datalen Length of Data
* @return CRC value
*/
uint16_t FastCRC16::x25(const uint8_t *data, const size_t datalen)
{
// poly=0x1021 init=0xffff refin=true refout=true xorout=0xffff check=0x906e
return generic(0x1021, 0XFFFF, CRC_FLAG_REFLECT | CRC_FLAG_XOR, data, datalen);
}
/** Update
* Call for subsequent calculations with previous seed
* @param data Pointer to Data
* @param datalen Length of Data
* @return CRC value
*/
uint16_t FastCRC16::update(const uint8_t *data, const size_t datalen)
{
const uint8_t *src = data;
const uint8_t *target = src + datalen;
while (((uintptr_t)src & 0x03) !=0 && (src < target)) {
rCRC->CRC8_3 = *src++; //Write 8 BIT
}
while (src <= target-4) {
rCRC->CRC = *( uint32_t *)src; //Write 32 BIT
src += 4;
}
while (src < target) {
rCRC->CRC8_3 = *src++; //Write 8 Bit
}
if (rCRC->CTRL & (1<<CRC_CTRL_TOTR1))
return rCRC->CRC16;
else
return rCRC->CRC16_1;
}
/** generic function for all 16-Bit CRCs
* @param polynom Polynom
* @param seed Seed
* @param flags Flags
* @param data Pointer to Data
* @param datalen Length of Data
* @return CRC value
*/
uint16_t FastCRC16::generic(const uint16_t polynom, const uint16_t seed, const uint32_t flags, const uint8_t *data, const size_t datalen)
{
rCRC->CTRL = flags | (1<<CRC_CTRL_TCRC) | (1<<CRC_CTRL_WAS);// 32-Bit Mode, prepare to write seed(25)
rCRC->GPOLY = ((uint32_t)polynom)<<16; // set polynom
rCRC->CRC = ((uint32_t)seed<<16); // this is the seed
rCRC->CTRL = flags | (1<<CRC_CTRL_TCRC); // Clear WAS Bit - prepare to write data
return update(data, datalen);
}
uint16_t FastCRC16::ccitt_upd(const uint8_t *data, size_t len) {return update(data, len);}
uint16_t FastCRC16::mcrf4xx_upd(const uint8_t *data, size_t len){return update(data, len);}
uint16_t FastCRC16::kermit_upd(const uint8_t *data, size_t len) {return update(data, len);}
uint16_t FastCRC16::modbus_upd(const uint8_t *data, size_t len) {return update(data, len);}
uint16_t FastCRC16::xmodem_upd(const uint8_t *data, size_t len) {return update(data, len);}
uint16_t FastCRC16::x25_upd(const uint8_t *data, size_t len) {return update(data, len);}
// ================= 32-BIT CRC ===================
/** Constructor
* Enables CRC-clock
*/
FastCRC32::FastCRC32(){
SIM_SCGC6 |= SIM_SCGC6_CRC;
}
/** CRC32
* Alias CRC-32/ADCCP, PKZIP, Ethernet, 802.3
* @param data Pointer to Data
* @param datalen Length of Data
* @return CRC value
*/
uint32_t FastCRC32::crc32(const uint8_t *data, const size_t datalen)
{
// poly=0x04c11db7 init=0xffffffff refin=true refout=true xorout=0xffffffff check=0xcbf43926
return generic(0x04C11DB7L, 0XFFFFFFFFL, CRC_FLAG_REFLECT | CRC_FLAG_XOR, data, datalen);
}
/** CKSUM
* Alias CRC-32/POSIX
* @param data Pointer to Data
* @param datalen Length of Data
* @return CRC value
*/
uint32_t FastCRC32::cksum(const uint8_t *data, const size_t datalen)
{
// width=32 poly=0x04c11db7 init=0x00000000 refin=false refout=false xorout=0xffffffff check=0x765e7680
return generic(0x04C11DB7L, 0, CRC_FLAG_NOREFLECT | CRC_FLAG_XOR, data, datalen);
}
/** Update
* Call for subsequent calculations with previous seed
* @param data Pointer to Data
* @param datalen Length of Data
* @return CRC value
*/
//#pragma GCC diagnostic ignored "-Wpointer-arith"
uint32_t FastCRC32::update(const uint8_t *data, const size_t datalen)
{
const uint8_t *src = data;
const uint8_t *target = src + datalen;
while (((uintptr_t)src & 0x03) != 0 && (src < target)) {
rCRC->CRC8_3 = *src++; //Write 8 BIT
}
while (src <= target-4) {
rCRC->CRC = *( uint32_t *)src; //Write 32 BIT
src += 4;
}
while (src < target) {
rCRC->CRC8_3 = *src++; //Write 8 Bit
}
return rCRC->CRC;
}
/** generic function for all 32-Bit CRCs
* @param polynom Polynom
* @param seed Seed
* @param flags Flags
* @param data Pointer to Data
* @param datalen Length of Data
* @return CRC value
*/
uint32_t FastCRC32::generic(const uint32_t polynom, const uint32_t seed, const uint32_t flags, const uint8_t *data, const size_t datalen)
{
rCRC->CTRL = flags | (1<<CRC_CTRL_TCRC) | (1<<CRC_CTRL_WAS); // 32Bit Mode, prepare to write seed(25)
rCRC->GPOLY = polynom; // Set polynom
rCRC->CRC = seed; // This is the seed
rCRC->CTRL = flags | (1<<CRC_CTRL_TCRC); // Clear WAS Bit - prepare to write data
return update(data, datalen);
}
uint32_t FastCRC32::crc32_upd(const uint8_t *data, size_t len){return update(data, len);}
uint32_t FastCRC32::cksum_upd(const uint8_t *data, size_t len){return update(data, len);}
#endif // #if defined(KINETISK)

View File

@ -0,0 +1,541 @@
/* FastCRC library code is placed under the MIT license
* Copyright (c) 2014 - 2021 Frank Bösing
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
//
// Thanks to:
// - Catalogue of parametrised CRC algorithms, CRC RevEng
// http://reveng.sourceforge.net/crc-catalogue/
//
// - Danjel McGougan (CRC-Table-Generator)
//
#if defined(ARDUINO)
#include <Arduino.h>
#endif
#if !defined(KINETISK)
#if !defined(ARDUINO)
#define PROGMEM
#define pgm_read_byte(addr) (*(const unsigned char *)(addr))
#define pgm_read_word(addr) ({ \
typeof(addr) _addr = (addr); \
*(const unsigned short *)(_addr); \
})
#define pgm_read_dword(addr) ({ \
typeof(addr) _addr = (addr); \
*(const unsigned long *)(_addr); \
})
#endif
#include "FastCRC.h"
#include "FastCRC_tables.h"
static inline
uint32_t REV16( uint32_t value)
{
return (value >> 8) | ((value & 0xff) << 8);
}
static inline
uint32_t REV32( uint32_t value)
{
value = (value >> 16) | ((value & 0xffff) << 16);
return ((value >> 8) & 0xff00ff) | ((value & 0xff00ff) << 8);
}
// ================= 7-BIT CRC ===================
/** Constructor
*/
FastCRC7::FastCRC7(){}
/** SMBUS CRC
* aka CRC-8
* @param data Pointer to Data
* @param datalen Length of Data
* @return CRC value
*/
uint8_t FastCRC7::crc7_upd(const uint8_t *data, size_t datalen)
{
uint8_t crc = seed;
if (datalen) do {
crc = pgm_read_byte(&crc_table_crc7[crc ^ *data]);
data++;
} while (--datalen);
seed = crc;
return crc >> 1;
}
uint8_t FastCRC7::crc7(const uint8_t *data, const size_t datalen)
{
// poly=0x09 init=0x00 refin=false refout=false xorout=0x00 check=0x75
seed = 0x00;
return crc7_upd(data, datalen);
}
// ================= 8-BIT CRC ===================
/** Constructor
*/
FastCRC8::FastCRC8(){}
/** SMBUS CRC
* aka CRC-8
* @param data Pointer to Data
* @param datalen Length of Data
* @return CRC value
*/
uint8_t FastCRC8::smbus_upd(const uint8_t *data, size_t datalen)
{
uint8_t crc = seed;
if (datalen) do {
crc = pgm_read_byte(&crc_table_smbus[crc ^ *data]);
data++;
} while (--datalen);
seed = crc;
return crc;
}
uint8_t FastCRC8::smbus(const uint8_t *data, const size_t datalen)
{
// poly=0x07 init=0x00 refin=false refout=false xorout=0x00 check=0xf4
seed = 0x00;
return smbus_upd(data, datalen);
}
/** MAXIM 8-Bit CRC
* equivalent to _crc_ibutton_update() in crc16.h from avr_libc
* @param data Pointer to Data
* @param datalen Length of Data
* @return CRC value
*/
uint8_t FastCRC8::maxim_upd(const uint8_t *data, size_t datalen)
{
uint8_t crc = seed;
if (datalen) do {
crc = pgm_read_byte(&crc_table_maxim[crc ^ *data]);
data++;
} while (--datalen);
seed = crc;
return crc;
}
uint8_t FastCRC8::maxim(const uint8_t *data, const size_t datalen)
{
// poly=0x31 init=0x00 refin=true refout=true xorout=0x00 check=0xa1
seed = 0x00;
return maxim_upd(data, datalen);
}
// ================= 16-BIT CRC ===================
/** Constructor
*/
FastCRC16::FastCRC16(){}
#define crc_n4(crc, data, table) crc ^= data; \
crc = pgm_read_word(&table[(crc & 0xff) + 0x300]) ^ \
pgm_read_word(&table[((crc >> 8) & 0xff) + 0x200]) ^ \
pgm_read_word(&table[((data >> 16) & 0xff) + 0x100]) ^ \
pgm_read_word(&table[data >> 24]);
/** CCITT
* Alias "false CCITT"
* @param data Pointer to Data
* @param datalen Length of Data
* @return CRC value
*/
uint16_t FastCRC16::ccitt_upd(const uint8_t *data, size_t len)
{
uint16_t crc = seed;
while (((uintptr_t)data & 3) && len) {
crc = (crc >> 8) ^ pgm_read_word(&crc_table_ccitt[(crc & 0xff) ^ *data++]);
len--;
}
while (len >= 16) {
len -= 16;
crc_n4(crc, ((uint32_t *)data)[0], crc_table_ccitt);
crc_n4(crc, ((uint32_t *)data)[1], crc_table_ccitt);
crc_n4(crc, ((uint32_t *)data)[2], crc_table_ccitt);
crc_n4(crc, ((uint32_t *)data)[3], crc_table_ccitt);
data += 16;
}
while (len--) {
crc = (crc >> 8) ^ pgm_read_word(&crc_table_ccitt[(crc & 0xff) ^ *data++]);
}
seed = crc;
crc = REV16(crc);
return crc;
}
uint16_t FastCRC16::ccitt(const uint8_t *data,const size_t datalen)
{
// poly=0x1021 init=0xffff refin=false refout=false xorout=0x0000 check=0x29b1
seed = 0xffff;
return ccitt_upd(data, datalen);
}
/** MCRF4XX
* equivalent to _crc_ccitt_update() in crc16.h from avr_libc
* @param data Pointer to Data
* @param datalen Length of Data
* @return CRC value
*/
uint16_t FastCRC16::mcrf4xx_upd(const uint8_t *data, size_t len)
{
uint16_t crc = seed;
while (((uintptr_t)data & 3) && len) {
crc = (crc >> 8) ^ pgm_read_word(&crc_table_mcrf4xx[(crc & 0xff) ^ *data++]);
len--;
}
while (len >= 16) {
len -= 16;
crc_n4(crc, ((uint32_t *)data)[0], crc_table_mcrf4xx);
crc_n4(crc, ((uint32_t *)data)[1], crc_table_mcrf4xx);
crc_n4(crc, ((uint32_t *)data)[2], crc_table_mcrf4xx);
crc_n4(crc, ((uint32_t *)data)[3], crc_table_mcrf4xx);
data += 16;
}
while (len--) {
crc = (crc >> 8) ^ pgm_read_word(&crc_table_mcrf4xx[(crc & 0xff) ^ *data++]);
}
seed = crc;
return crc;
}
uint16_t FastCRC16::mcrf4xx(const uint8_t *data,const size_t datalen)
{
// poly=0x1021 init=0xffff refin=true refout=true xorout=0x0000 check=0x6f91
seed = 0xffff;
return mcrf4xx_upd(data, datalen);
}
/** MODBUS
* equivalent to _crc_16_update() in crc16.h from avr_libc
* @param data Pointer to Data
* @param datalen Length of Data
* @return CRC value
*/
uint16_t FastCRC16::modbus_upd(const uint8_t *data, size_t len)
{
uint16_t crc = seed;
while (((uintptr_t)data & 3) && len) {
crc = (crc >> 8) ^ pgm_read_word(&crc_table_modbus[(crc & 0xff) ^ *data++]);
len--;
}
while (len >= 16) {
len -= 16;
crc_n4(crc, ((uint32_t *)data)[0], crc_table_modbus);
crc_n4(crc, ((uint32_t *)data)[1], crc_table_modbus);
crc_n4(crc, ((uint32_t *)data)[2], crc_table_modbus);
crc_n4(crc, ((uint32_t *)data)[3], crc_table_modbus);
data += 16;
}
while (len--) {
crc = (crc >> 8) ^ pgm_read_word(&crc_table_modbus[(crc & 0xff) ^ *data++]);
}
seed = crc;
return crc;
}
uint16_t FastCRC16::modbus(const uint8_t *data, const size_t datalen)
{
// poly=0x8005 init=0xffff refin=true refout=true xorout=0x0000 check=0x4b37
seed = 0xffff;
return modbus_upd(data, datalen);
}
/** KERMIT
* Alias CRC-16/CCITT, CRC-16/CCITT-TRUE, CRC-CCITT
* @param data Pointer to Data
* @param datalen Length of Data
* @return CRC value
*/
uint16_t FastCRC16::kermit_upd(const uint8_t *data, size_t len)
{
uint16_t crc = seed;
while (((uintptr_t)data & 3) && len) {
crc = (crc >> 8) ^ pgm_read_word(&crc_table_kermit[(crc & 0xff) ^ *data++]);
len--;
}
while (len >= 16) {
len -= 16;
crc_n4(crc, ((uint32_t *)data)[0], crc_table_kermit);
crc_n4(crc, ((uint32_t *)data)[1], crc_table_kermit);
crc_n4(crc, ((uint32_t *)data)[2], crc_table_kermit);
crc_n4(crc, ((uint32_t *)data)[3], crc_table_kermit);
data += 16;
}
while (len--) {
crc = (crc >> 8) ^ pgm_read_word(&crc_table_kermit[(crc & 0xff) ^ *data++]);
}
seed = crc;
return crc;
}
uint16_t FastCRC16::kermit(const uint8_t *data, const size_t datalen)
{
// poly=0x1021 init=0x0000 refin=true refout=true xorout=0x0000 check=0x2189
// sometimes byteswapped presentation of result
seed = 0x0000;
return kermit_upd(data, datalen);
}
/** XMODEM
* Alias ZMODEM, CRC-16/ACORN
* @param data Pointer to Data
* @param datalen Length of Data
* @return CRC value
*/
uint16_t FastCRC16::xmodem_upd(const uint8_t *data, size_t len)
{
uint16_t crc = seed;
while (((uintptr_t)data & 3) && len) {
crc = (crc >> 8) ^ pgm_read_word(&crc_table_xmodem[(crc & 0xff) ^ *data++]);
len--;
}
while (len >= 16) {
len -= 16;
crc_n4(crc, ((uint32_t *)data)[0], crc_table_xmodem);
crc_n4(crc, ((uint32_t *)data)[1], crc_table_xmodem);
crc_n4(crc, ((uint32_t *)data)[2], crc_table_xmodem);
crc_n4(crc, ((uint32_t *)data)[3], crc_table_xmodem);
data += 16;
}
while (len--) {
crc = (crc >> 8) ^ pgm_read_word(&crc_table_xmodem[(crc & 0xff) ^ *data++]);
}
seed = crc;
crc = REV16(crc);
return crc;
}
uint16_t FastCRC16::xmodem(const uint8_t *data, const size_t datalen)
{
//width=16 poly=0x1021 init=0x0000 refin=false refout=false xorout=0x0000 check=0x31c3
seed = 0x0000;
return xmodem_upd(data, datalen);
}
/** X25
* Alias CRC-16/IBM-SDLC, CRC-16/ISO-HDLC, CRC-B
* @param data Pointer to Data
* @param datalen Length of Data
* @return CRC value
*/
uint16_t FastCRC16::x25_upd(const uint8_t *data, size_t len)
{
uint16_t crc = seed;
while (((uintptr_t)data & 3) && len) {
crc = (crc >> 8) ^ pgm_read_word(&crc_table_x25[(crc & 0xff) ^ *data++]);
len--;
}
while (len >= 16) {
len -= 16;
crc_n4(crc, ((uint32_t *)data)[0], crc_table_x25);
crc_n4(crc, ((uint32_t *)data)[1], crc_table_x25);
crc_n4(crc, ((uint32_t *)data)[2], crc_table_x25);
crc_n4(crc, ((uint32_t *)data)[3], crc_table_x25);
data += 16;
}
while (len--) {
crc = (crc >> 8) ^ pgm_read_word(&crc_table_x25[(crc & 0xff) ^ *data++]);
}
seed = crc;
crc = ~crc;
return crc;
}
uint16_t FastCRC16::x25(const uint8_t *data, const size_t datalen)
{
// poly=0x1021 init=0xffff refin=true refout=true xorout=0xffff check=0x906e
seed = 0xffff;
return x25_upd(data, datalen);
}
// ================= 32-BIT CRC ===================
/** Constructor
*/
FastCRC32::FastCRC32(){}
#define crc_n4d(crc, data, table) crc ^= data; \
crc = pgm_read_dword(&table[(crc & 0xff) + 0x300]) ^ \
pgm_read_dword(&table[((crc >> 8) & 0xff) + 0x200]) ^ \
pgm_read_dword(&table[((crc >> 16) & 0xff) + 0x100]) ^ \
pgm_read_dword(&table[(crc >> 24) & 0xff]);
#define crcsm_n4d(crc, data, table) crc ^= data; \
crc = (crc >> 8) ^ pgm_read_dword(&table[crc & 0xff]); \
crc = (crc >> 8) ^ pgm_read_dword(&table[crc & 0xff]); \
crc = (crc >> 8) ^ pgm_read_dword(&table[crc & 0xff]); \
crc = (crc >> 8) ^ pgm_read_dword(&table[crc & 0xff]);
/** CRC32
* Alias CRC-32/ADCCP, PKZIP, Ethernet, 802.3
* @param data Pointer to Data
* @param datalen Length of Data
* @return CRC value
*/
#if CRC_BIGTABLES
#define CRC_TABLE_CRC32 crc_table_crc32_big
#else
#define CRC_TABLE_CRC32 crc_table_crc32
#endif
uint32_t FastCRC32::crc32_upd(const uint8_t *data, size_t len)
{
uint32_t crc = seed;
while (((uintptr_t)data & 3) && len) {
crc = (crc >> 8) ^ pgm_read_dword(&CRC_TABLE_CRC32[(crc & 0xff) ^ *data++]);
len--;
}
while (len >= 16) {
len -= 16;
#if CRC_BIGTABLES
crc_n4d(crc, ((uint32_t *)data)[0], CRC_TABLE_CRC32);
crc_n4d(crc, ((uint32_t *)data)[1], CRC_TABLE_CRC32);
crc_n4d(crc, ((uint32_t *)data)[2], CRC_TABLE_CRC32);
crc_n4d(crc, ((uint32_t *)data)[3], CRC_TABLE_CRC32);
#else
crcsm_n4d(crc, ((uint32_t *)data)[0], CRC_TABLE_CRC32);
crcsm_n4d(crc, ((uint32_t *)data)[1], CRC_TABLE_CRC32);
crcsm_n4d(crc, ((uint32_t *)data)[2], CRC_TABLE_CRC32);
crcsm_n4d(crc, ((uint32_t *)data)[3], CRC_TABLE_CRC32);
#endif
data += 16;
}
while (len--) {
crc = (crc >> 8) ^ pgm_read_dword(&CRC_TABLE_CRC32[(crc & 0xff) ^ *data++]);
}
seed = crc;
crc = ~crc;
return crc;
}
uint32_t FastCRC32::crc32(const uint8_t *data, const size_t datalen)
{
// poly=0x04c11db7 init=0xffffffff refin=true refout=true xorout=0xffffffff check=0xcbf43926
seed = 0xffffffff;
return crc32_upd(data, datalen);
}
/** CKSUM
* Alias CRC-32/POSIX
* @param data Pointer to Data
* @param datalen Length of Data
* @return CRC value
*/
#if CRC_BIGTABLES
#define CRC_TABLE_CKSUM crc_table_cksum_big
#else
#define CRC_TABLE_CKSUM crc_table_cksum
#endif
uint32_t FastCRC32::cksum_upd(const uint8_t *data, size_t len)
{
uint32_t crc = seed;
while (((uintptr_t)data & 3) && len) {
crc = (crc >> 8) ^ pgm_read_dword(&CRC_TABLE_CKSUM[(crc & 0xff) ^ *data++]);
len--;
}
while (len >= 16) {
len -= 16;
#if CRC_BIGTABLES
crc_n4d(crc, ((uint32_t *)data)[0], CRC_TABLE_CKSUM);
crc_n4d(crc, ((uint32_t *)data)[1], CRC_TABLE_CKSUM);
crc_n4d(crc, ((uint32_t *)data)[2], CRC_TABLE_CKSUM);
crc_n4d(crc, ((uint32_t *)data)[3], CRC_TABLE_CKSUM);
#else
crcsm_n4d(crc, ((uint32_t *)data)[0], CRC_TABLE_CKSUM);
crcsm_n4d(crc, ((uint32_t *)data)[1], CRC_TABLE_CKSUM);
crcsm_n4d(crc, ((uint32_t *)data)[2], CRC_TABLE_CKSUM);
crcsm_n4d(crc, ((uint32_t *)data)[3], CRC_TABLE_CKSUM);
#endif
data += 16;
}
while (len--) {
crc = (crc >> 8) ^ pgm_read_dword(&CRC_TABLE_CKSUM[(crc & 0xff) ^ *data++]);
}
seed = crc;
crc = ~REV32(crc);
return crc;
}
uint32_t FastCRC32::cksum(const uint8_t *data, const size_t datalen)
{
// width=32 poly=0x04c11db7 init=0x00000000 refin=false refout=false xorout=0xffffffff check=0x765e7680
seed = 0x00;
return cksum_upd(data, datalen);
}
#endif // #if !defined(KINETISK)

View File

@ -118,6 +118,10 @@
#include "han_Parser.h"
#endif
#ifdef USE_SML_CRC
#include "FastCRC.h"
FastCRC16 FastCRC;
#endif
#ifndef SML_TRX_BUFF_SIZE
#define SML_TRX_BUFF_SIZE 1024
@ -194,6 +198,11 @@ on esp8266 6 filters
A:
decryption flags (8 bits)
C:
crc buffers and algorithm (available when compiled with USE_SML_CRC)
a. crc buffer size (bytes), must hold one full file
b. crc-algorithm: 0=x25, 1=ccitt, 15=autodetect
e.g. 1,=soC,1024,15
*/
//#define MODBUS_DEBUG
@ -467,6 +476,20 @@ typedef union {
#define SML_PREFIX_SIZE 8
#endif
#ifdef USE_SML_CRC
struct SML_CRC_DATA {
uint8_t crcmode; //currently used mode
uint8_t crcdetectstate; //current auto-detection state
uint8_t *crcbuff; //buffer, only allocated on meter that have crc enabled
uint16_t crcbuff_pos; //current buffer wiring position
uint32_t crcfailcnt; //cnt bad-crc telegrams
uint32_t crcfinecnt; //cnt good-crc telegrams
uint32_t overflowcnt; //cnt good-crc telegrams
sint8_t telestartpos; //-1=still searching, 0=found
sint16_t teleendpos; //end of the telegram in the buffer or -1 when waiting for it
};
#endif // USE_SML_CRC
struct METER_DESC {
int8_t srcpin;
uint8_t type;
@ -490,6 +513,10 @@ struct METER_DESC {
uint16_t tout_ms;
SO_FLAGS so_flags;
char meter_id[METER_ID_SIZE];
#ifdef USE_SML_CRC
uint16_t so_sml_crc = 0;
struct SML_CRC_DATA* sml_crc_data;
#endif
#ifdef USE_SML_SPECOPT
uint32_t so_obis1;
uint32_t so_obis2;
@ -498,7 +525,6 @@ struct METER_DESC {
uint8_t so_fcode2;
uint8_t so_bpos2;
#endif // USE_SML_SPECOPT
#ifdef ESP32
#ifndef USE_ESP32_SW_SERIAL
HardwareSerial *meter_ss;
@ -557,6 +583,7 @@ struct METER_DESC {
#define TCP_MODE_FLG 0x7f
// Meter flags
@ -1413,6 +1440,36 @@ uint8_t ebus_CalculateCRC( uint8_t *Data, uint16_t DataLen ) {
return Crc;
}
#ifdef USE_SML_CRC
uint16_t calculateSMLbinCRC(const uint8_t *data, uint16_t length, uint8_t crcmode) {
uint16_t res=0;
switch (crcmode % 6) {
case 0:
res = FastCRC.x25(data, length);
break;
case 1:
res = FastCRC.ccitt(data, length);
break;
case 2:
res = FastCRC.kermit(data, length);
break;
case 3:
res = FastCRC.modbus(data, length);
break;
case 4:
res = FastCRC.xmodem(data, length);
break;
case 5:
res = FastCRC.mcrf4xx(data, length);
break;
}
if (crcmode>5) {
res = (res >> 8) | (res << 8); // swap bytes
}
return res;
}
#endif
void sml_empty_receiver(uint32_t meters) {
while (meter_desc[meters].meter_ss->available()) {
meter_desc[meters].meter_ss->read();
@ -1426,6 +1483,108 @@ void sml_shift_in(uint32_t meters, uint32_t shard) {
if (!mp->sbuff) return;
#ifdef USE_SML_CRC
if ((mp->type=='s') && (mp->sml_crc_data) && (mp->so_sml_crc & 0x0fff)) {
// New handling with CRC validation
// Read data into the temporary buffer
struct SML_CRC_DATA *cp = mp->sml_crc_data;
if (cp->crcbuff_pos < (mp->so_sml_crc & 0x0fff)) {
cp->crcbuff[cp->crcbuff_pos++] = mp->meter_ss->read();
} else {
// Buffer overflow, reset and log an error
cp->overflowcnt++;
AddLog(LOG_LEVEL_INFO, PSTR("SML: CRC buffer overflow, increase crc buffer size in your script modifying the line '1,soC=<buffer size>,<mode>'. Error occured %d times."),cp->overflowcnt);
//Hexdump(&cp->crcbuff[0], cp->crcbuff_pos);
if (cp->teleendpos==-1) {
if (cp->telestartpos==-1) {
AddLog(LOG_LEVEL_DEBUG, "SML: No start sequence was found.");
} else {
AddLog(LOG_LEVEL_DEBUG, "SML: Start sequence was found, but no stop sequence was found.");
}
}
cp->telestartpos=-1;
cp->teleendpos=-1;
cp->crcbuff_pos = 0;
}
// Check for start of message until it is found
if (cp->telestartpos==-1) {
//check start of buffer for start sequence
if(cp->crcbuff_pos>=8) {
if (memcmp(&cp->crcbuff[0], "\x1B\x1B\x1B\x1B\x01\x01\x01\x01", 8) == 0 ) {
//found start sequence
cp->telestartpos=0;
} else {
memmove(&cp->crcbuff[0], &cp->crcbuff[1], cp->crcbuff_pos-1);
cp->crcbuff_pos--;
}
}
} else {
if (cp->teleendpos==-1) {
if(cp->crcbuff_pos>=16 && memcmp(&cp->crcbuff[cp->crcbuff_pos-8], "\x1B\x1B\x1B\x1B\x1A", 5) == 0 )
{
//found end sequence
cp->teleendpos=cp->crcbuff_pos-1;
//AddLog(LOG_LEVEL_INFO, PSTR("SML: Found stop sequence at %d length %d"),mp->teleendpos,len);
//Validate CRC
uint16_t extracted_crc = (cp->crcbuff[cp->crcbuff_pos - 1] << 8) | cp->crcbuff[cp->crcbuff_pos - 2];
// Calculate the CRC for the data portion (excluding start, stop sequences, and CRC bytes)
uint16_t len=cp->teleendpos + 1;
//testing: fake some error for testing
//if (random(0, 50) < 30) {cp->crcbuff[12]=99;}
uint16_t calculated_crc = calculateSMLbinCRC(&cp->crcbuff[0], len-2, cp->crcmode);
if (calculated_crc == extracted_crc) {
cp->crcfinecnt++;
//AddLog(LOG_LEVEL_INFO, PSTR("SML: CRC ok"));
if (len > mp->sbsiz) {
len = mp->sbsiz;
}
for (uint16_t i=8; i<=cp->teleendpos - 8 - mp->sbsiz; i++) {
if (cp->crcbuff[i] == SML_SYNC || ((mp->flag & NO_SYNC_FLG) != 0)) {
if (i+len > cp->teleendpos) len--;
memcpy(mp->sbuff, &cp->crcbuff[i],len);
SML_Decode(meters);
}
}
} else {
cp->crcfailcnt++;
// CRC is invalid, log an error
AddLog(LOG_LEVEL_INFO, PSTR("SML: CRC error: len: %d file-crc: %04x calc-crc: %04x failcnt: %d okcnt: %d mode: %d state: %d"), cp->teleendpos, extracted_crc, calculated_crc, cp->crcfailcnt, cp->crcfinecnt, cp->crcmode, cp->crcdetectstate);
//Hexdump(&cp->crcbuff[0], cp->crcbuff_pos);
}
//auto-detect crc-mode from fine/fail-cnt if autodetect is running
if (cp->crcdetectstate>0){ //state=0 autodetect running
AddLog(LOG_LEVEL_DEBUG, PSTR("SML: CRC autodetection in progress. state: %d. probing mode: %d failcnt: %d okcnt: %d"), cp->crcdetectstate, cp->crcmode, cp->crcfailcnt, cp->crcfinecnt );
//check how far we have come an decide how to go on
if (cp->crcfailcnt>3) { //seems bad choice
if (cp->crcdetectstate>25) {
AddLog(LOG_LEVEL_INFO, "SML: CRC autodetection failed, you can turn of CRC checks of via removing '1,soC=<bufsz>,<mode>' from your meter definition.");
} else {
cp->crcdetectstate++;
}
cp->crcmode++;
if(cp->crcmode>11) cp->crcmode=0; //mode 0-11 supported (6-11 are 1-5 with reversed byte order)
//reset counters and start over
cp->crcfailcnt=0;
cp->crcfinecnt=0;
AddLog(LOG_LEVEL_INFO, PSTR("SML: CRC mode auto-changed to: %d"), cp->crcmode);
}
if (cp->crcfinecnt>3) {
//fine, stop detecting now
AddLog(LOG_LEVEL_DEBUG, PSTR("SML: CRC autodetection ok after probe #%d selected mode: %d"), cp->crcdetectstate, cp->crcmode);
cp->crcdetectstate=0;
}
}
cp->teleendpos=-1;
cp->telestartpos=-1;
cp->crcbuff_pos = 0;
}
}
}
return;
}
#endif
#ifdef USE_SML_DECRYPT
if (mp->use_crypt) {
if (mp->hp) {
@ -1433,7 +1592,7 @@ void sml_shift_in(uint32_t meters, uint32_t shard) {
if (timediff > mp->tout_ms) {
mp->hp->len = 0;
mp->spos = 0;
AddLog(LOG_LEVEL_DEBUG, PSTR("SML: sync"));
AddLog(LOG_LEVEL_DEBUG, "SML: sync");
}
mp->lastms = millis();
uint16_t len;
@ -2916,7 +3075,18 @@ struct METER_DESC *mp = &meter_desc[mnum];
mp->crypflags = strtol(cp, &cp, 10);
break;
#endif // USE_SML_DECRYPT
case '6':
#ifdef USE_SML_CRC
case 'C': //1,=soC,<bufsize>,<crcmode> example: 1,=soC,1024,0 (mode=x25,1=ccitt,15=autodetect)
cp += 2;
mp->so_sml_crc = strtol(cp, &cp, 10)&0x0fff;
if (*cp == ',') {
cp++;
mp->so_sml_crc |= strtol(cp, &cp, 10)<<12;
}
AddLog(LOG_LEVEL_INFO, PSTR("SML: CRC specialoptions (=soC) so_sml_crc='%x'"),mp->so_sml_crc);
break;
#endif // USE_SML_CRC
case '6':
cp += 2;
mp->tout_ms = strtol(cp, &cp, 10);
break;
@ -3008,6 +3178,17 @@ void reset_sml_vars(uint16_t maxmeters) {
mp->so_obis1 = 0;
mp->so_obis2 = 0;
#endif
#ifdef USE_SML_CRC
AddLog(LOG_LEVEL_INFO, "SML: CRC reset");
struct SML_CRC_DATA* cp = mp->sml_crc_data;
if (cp && (mp->so_sml_crc & 0x0fff)) {
AddLog(LOG_LEVEL_INFO, "SML: CRC free buffer");
free(mp->sml_crc_data->crcbuff);
free(mp->sml_crc_data);
mp->sml_crc_data=0;
}
mp->so_sml_crc=0;
#endif // USE_SML_CRC
mp->so_flags.data = 0;
// addresses a bug in meter DWS74
#ifdef DWS74_BUG
@ -3056,6 +3237,9 @@ void reset_sml_vars(uint16_t maxmeters) {
memset(mp->auth, 0, SML_CRYPT_SIZE);
#endif
#endif // USE_SML_DECRYPT
}
}
@ -3369,7 +3553,39 @@ dddef_exit:
// 1,=h—————————————
if (!strncmp_P(lp1 + 1, PSTR(",=h"), 3) || !strncmp_P(lp1 + 1, PSTR(",=so"), 4)) {
if (!strncmp_P(lp1 + 1, PSTR(",=so"), 4)) {
SpecOptions(lp1 + 5, mnum - 1);
SpecOptions(lp1 + 5, mnum - 1);
#ifdef USE_SML_CRC
if (mmp->so_sml_crc & 0x0fff) {
AddLog(LOG_LEVEL_INFO, "SML: CRC active -> init");
if (mmp->sml_crc_data) {
AddLog(LOG_LEVEL_INFO, PSTR("SML: CRC config change - reinit. Buffersize: %d mode: %d"), mmp->so_sml_crc & 0x0fff, (mmp->so_sml_crc & 0xf000)>>12);
free(mmp->sml_crc_data->crcbuff);
free(mmp->sml_crc_data);
}
struct SML_CRC_DATA* cp = (struct SML_CRC_DATA*)calloc(sizeof(struct SML_CRC_DATA), 1);
cp->telestartpos=-1;
cp->teleendpos=-1;
memory += sizeof(struct SML_CRC_DATA);
cp->crcbuff = (uint8_t*)calloc(mmp->so_sml_crc & 0x0fff, 1);
memory += (mmp->so_sml_crc & 0x0fff);
cp->crcmode=(mmp->so_sml_crc & 0xf000)>>12;
if (cp->crcmode == 15) {
//start autodetection probe mode 0 first
cp->crcmode=0;
cp->crcdetectstate=1;
AddLog(LOG_LEVEL_INFO, "SML: CRC mode autodetect");
} else {
//keep mode as given, turn off autodetect
if (cp->crcmode > 11) cp->crcmode=0;
cp->crcdetectstate=0;
AddLog(LOG_LEVEL_INFO, PSTR("SML: CRC mode %d"),cp->crcmode);
}
mmp->sml_crc_data=cp;
}
#endif // USE_SML_CRC
}
} else {
sml_globs.maxvars++;
@ -3399,7 +3615,7 @@ next_line:
*tp = 0;
sml_globs.meter_p = sml_globs.script_meter;
// set serial buffers
// set serial and crc buffers
for (uint32_t meters = 0; meters < sml_globs.meters_used; meters++ ) {
struct METER_DESC *mp = &meter_desc[meters];
if (mp->sbsiz) {
@ -3407,7 +3623,6 @@ next_line:
memory += mp->sbsiz;
}
}
// initialize hardware
typedef void (*function)();
uint8_t cindex = 0;