0.1.6 Fletcher

This commit is contained in:
rob tillaart 2022-09-13 16:31:43 +02:00
parent 3c51c68979
commit cb1107e950
23 changed files with 1377 additions and 146 deletions

View File

@ -2,13 +2,13 @@ compile:
# Choosing to run compilation tests on 2 different Arduino platforms
platforms:
- uno
- due
- zero
# - due
# - zero
- leonardo
- m4
- esp32
- esp8266
- mega2560
# - mega2560
libraries:
- "printHelpers"

View File

@ -1,7 +1,7 @@
//
// FILE: Fletcher.cpp
// AUTHOR: Rob Tillaart
// VERSION: 0.1.5
// VERSION: 0.1.6
// DATE: 2022-01-25
// PURPOSE: Arduino Library for calculating Fletcher's checksum
// URL: https://github.com/RobTillaart/Fletcher
@ -17,7 +17,8 @@
// fix FLETCHER_LIB_VERSION
// 0.1.5 2022-09-08 roll back the optimizations in the standalone functions
// conflict with loop optimization already in.
// update ketwords.txt
// update keywords.txt
// 0.1.6 2022-09-10 stabilize optimizations
#include "Fletcher.h"
@ -40,10 +41,10 @@ uint16_t fletcher16(uint8_t *data, uint16_t length)
s1 += data[i++];
s2 += s1;
}
s1 %= FLETCHER_16;
// this optimization does not work due to the above "32-bit" loop.
// for all three functions.
// s1 = (s1 & 255) + (s1 >> 8);
s1 %= FLETCHER_16;
s2 %= FLETCHER_16;
}
return (s2 << 8) | s1;

View File

@ -2,7 +2,7 @@
//
// FILE: Fletcher.h
// AUTHOR: Rob Tillaart
// VERSION: 0.1.5
// VERSION: 0.1.6
// DATE: 2022-01-25
// PURPOSE: Arduino Library for calculating Fletcher's checksum
// URL: https://github.com/RobTillaart/Fletcher
@ -12,7 +12,7 @@
#include "Arduino.h"
#define FLETCHER_LIB_VERSION (F("0.1.5"))
#define FLETCHER_LIB_VERSION (F("0.1.6"))
#define FLETCHER_16 255
#define FLETCHER_32 65535UL

View File

@ -1,13 +1,14 @@
//
// FILE: Fletcher16.cpp
// AUTHOR: Rob Tillaart
// AUTHOR: Rob Tillaart, Daniel Mohr
// PURPOSE: Arduino class for Fletcher16
// URL: https://github.com/RobTillaart/Fletcher
#include "Fletcher16.h"
#define FLETCHER_16 255
// UINT8_MAX = 255 = ((((uint16_t) 1) << 8) - 1)
#define FLETCHER_16 UINT8_MAX
Fletcher16::Fletcher16()
@ -18,8 +19,8 @@ Fletcher16::Fletcher16()
void Fletcher16::begin(uint8_t s1, uint8_t s2)
{
_s1 = s1;
_s2 = s2;
_s1 = (s1 == FLETCHER_16) ? 0 : s1;
_s2 = (s2 == FLETCHER_16) ? 0 : s2;
_count = 0;
}
@ -27,10 +28,28 @@ void Fletcher16::begin(uint8_t s1, uint8_t s2)
void Fletcher16::add(uint8_t value)
{
_count++;
#if defined(ARDUINO_ARCH_AVR)
uint8_t t = 0xFF - value;
if (t >= _s1) _s1 += value;
else _s1 = _s1 + value + 1;
t = 0xFF - _s1;
if (t >= _s2) _s2 += _s1;
else _s2 = _s2 + _s1 + 1;
#elif defined(ARDUINO_ARCH_SAMD) || defined(ESP32) || defined(ESP8266)
_s1 += value;
_s1 = (_s1 & 255) + (_s1 >> 8);
_s1 = (_s1 & FLETCHER_16) + (_s1 >> 8);
_s2 += _s1;
_s2 = (_s2 & 255) + (_s2 >> 8);
_s2 = (_s2 & FLETCHER_16) + (_s2 >> 8);
#else
// REFERENCE
_s1 += value;
if (_s1 >= FLETCHER_16) _s1 -= FLETCHER_16;
_s2 += _s1;
if (_s2 >= FLETCHER_16) _s2 -= FLETCHER_16;
#endif
}
@ -43,5 +62,19 @@ void Fletcher16::add(const uint8_t * array, uint16_t length)
}
uint16_t Fletcher16::getFletcher()
{
if (_s1 >= FLETCHER_16) _s1 -= FLETCHER_16;
if (_s2 >= FLETCHER_16) _s2 -= FLETCHER_16;
return (((uint16_t)_s2) << 8) | _s1;
};
uint32_t Fletcher16::count()
{
return _count;
};
// -- END OF FILE --

View File

@ -1,7 +1,7 @@
#pragma once
//
// FILE: Fletcher16.h
// AUTHOR: Rob Tillaart
// AUTHOR: Rob Tillaart, Daniel Mohr
// PURPOSE: Arduino class for Fletcher16
// URL: https://github.com/RobTillaart/Fletcher
@ -20,15 +20,19 @@ public:
void add(uint8_t value);
void add(const uint8_t * array, uint16_t length);
uint16_t getFletcher() { return (_s2 << 8) | _s1; };
uint32_t count() { return _count; };
uint16_t getFletcher();
uint32_t count();
private:
#ifdef ARDUINO_ARCH_AVR
uint8_t _s1;
uint8_t _s2;
#else
uint16_t _s1;
uint16_t _s2;
#endif
uint32_t _count;
};
// -- END OF FILE --

View File

@ -1,14 +1,14 @@
//
// FILE: Fletcher32.cpp
// AUTHOR: Rob Tillaart
// AUTHOR: Rob Tillaart, Daniel Mohr
// PURPOSE: Arduino class for Fletcher32
// URL: https://github.com/RobTillaart/Fletcher
#include "Fletcher32.h"
#define FLETCHER_32 65535UL
// UINT16_MAX = 65535UL = ((((uint32_t) 1) << 16) - 1)
#define FLETCHER_32 UINT16_MAX
Fletcher32::Fletcher32()
@ -19,8 +19,8 @@ Fletcher32::Fletcher32()
void Fletcher32::begin(uint16_t s1, uint16_t s2)
{
_s1 = s1;
_s2 = s2;
_s1 = (s1 == FLETCHER_32) ? 0 : s1;
_s2 = (s2 == FLETCHER_32) ? 0 : s2;
_count = 0;
}
@ -28,16 +28,27 @@ void Fletcher32::begin(uint16_t s1, uint16_t s2)
void Fletcher32::add(uint16_t value)
{
_count++;
#ifdef ARDUINO_ARCH_AVR
unsigned int t = _s1;
// Serial.println("__builtin_uadd_overflow");
if (__builtin_uadd_overflow(t, value, &t)) {
t++;
}
_s1 = t;
t = _s2;
if (__builtin_uadd_overflow(t, _s1, &t)) {
t++;
}
_s2 = t;
#elif defined(ARDUINO_ARCH_SAMD) || defined(ESP32) || defined(ESP8266)
_s1 += value;
#if defined(ARDUINO_ARCH_SAMD) || defined(ESP32) || defined(ESP8266)
_s1 = (_s1 & 65535UL) + (_s1 >> 16);
#else
if (_s1 >= FLETCHER_32) _s1 -= FLETCHER_32;
#endif
_s1 = (_s1 & FLETCHER_32) + (_s1 >> 16);
_s2 += _s1;
#if defined(ARDUINO_ARCH_SAMD) || defined(ESP32) || defined(ESP8266)
_s2 = (_s2 & 65535UL) + (_s2 >> 16);
_s2 = (_s2 & FLETCHER_32) + (_s2 >> 16);
#else
_s1 += value;
if (_s1 >= FLETCHER_32) _s1 -= FLETCHER_32;
_s2 += _s1;
if (_s2 >= FLETCHER_32) _s2 -= FLETCHER_32;
#endif
}
@ -52,6 +63,19 @@ void Fletcher32::add(const uint16_t * array, uint16_t length)
}
}
uint32_t Fletcher32::getFletcher()
{
if (_s1 >= FLETCHER_32) _s1 -= FLETCHER_32;
if (_s2 >= FLETCHER_32) _s2 -= FLETCHER_32;
return (((uint32_t)_s2) << 16) | _s1;
};
uint32_t Fletcher32::count()
{
return _count;
};
// -- END OF FILE --

View File

@ -20,12 +20,17 @@ public:
void add(uint16_t value);
void add(const uint16_t * array, uint16_t length);
uint32_t getFletcher() { return (_s2 << 16) | _s1; };
uint32_t count() { return _count; };
uint32_t getFletcher();
uint32_t count();
private:
#ifdef ARDUINO_ARCH_AVR
uint16_t _s1;
uint16_t _s2;
#else
uint32_t _s1;
uint32_t _s2;
#endif
uint32_t _count;
};

View File

@ -7,9 +7,8 @@
#include "Fletcher64.h"
#define FLETCHER_64 4294967295ULL
// UINT32_MAX = 4294967295ULL = ((((uint64_t) 1) << 32) - 1)
#define FLETCHER_64 UINT32_MAX
Fletcher64::Fletcher64()
{
@ -19,8 +18,8 @@ Fletcher64::Fletcher64()
void Fletcher64::begin(uint32_t s1, uint32_t s2)
{
_s1 = s1;
_s2 = s2;
_s1 = (s1 == FLETCHER_64) ? 0 : s1;
_s2 = (s2 == FLETCHER_64) ? 0 : s2;
_count = 0;
}
@ -28,16 +27,23 @@ void Fletcher64::begin(uint32_t s1, uint32_t s2)
void Fletcher64::add(uint32_t value)
{
_count++;
#if defined(ARDUINO_ARCH_AVR) || defined(ESP32) || defined(ESP8266)
uint32_t t = 0xFFFFFFFF - value;
if (t >= _s1) _s1 += value;
else _s1 = _s1 + value + 1;
t = 0xFFFFFFFF - _s1;
if (t >= _s2) _s2 += _s1;
else _s2 = _s2 + _s1 + 1;
#elif defined(ARDUINO_ARCH_SAMD)
_s1 += value;
#if defined(ARDUINO_ARCH_SAMD) || defined(ESP32) || defined(ESP8266)
_s1 = (_s1 & ((((uint64_t) 1) << 32) - 1)) + (_s1 >> 32);
#else
if (_s1 >= FLETCHER_64) _s1 -= FLETCHER_64;
#endif
_s1 = (_s1 & FLETCHER_64) + (_s1 >> 32);
_s2 += _s1;
#if defined(ARDUINO_ARCH_SAMD) || defined(ESP32) || defined(ESP8266)
_s2 = (_s2 & ((((uint64_t) 1) << 32) - 1)) + (_s2 >> 32);
_s2 = (_s2 & FLETCHER_64) + (_s2 >> 32);
#else
_s1 += value;
if (_s1 >= FLETCHER_64) _s1 -= FLETCHER_64;
_s2 += _s1;
if (_s2 >= FLETCHER_64) _s2 -= FLETCHER_64;
#endif
}
@ -52,5 +58,19 @@ void Fletcher64::add(const uint32_t * array, uint16_t length)
}
uint64_t Fletcher64::getFletcher()
{
if (_s1 >= FLETCHER_64) _s1 -= FLETCHER_64;
if (_s2 >= FLETCHER_64) _s2 -= FLETCHER_64;
return (((uint64_t)_s2) << 32) | _s1;
};
uint32_t Fletcher64::count()
{
return _count;
};
// -- END OF FILE --

View File

@ -20,12 +20,17 @@ public:
void add(uint32_t value);
void add(const uint32_t * array, uint16_t length);
uint64_t getFletcher() { return (_s2 << 32) | _s1; };
uint32_t count() { return _count; };
uint64_t getFletcher();
uint32_t count();
private:
#if defined(ARDUINO_ARCH_AVR) || defined(ESP32) || defined(ESP8266)
uint32_t _s1;
uint32_t _s2;
#else
uint64_t _s1;
uint64_t _s2;
#endif
uint32_t _count;
};

View File

@ -1,6 +1,6 @@
/*
Author: Daniel Mohr
Date: 2022-09-08
Date: 2022-09-13
Purpose: shows stream performance
*/
#include "Arduino.h"
@ -16,65 +16,89 @@
#else
#define MAX_LEN 16384
#endif
union main_value_storage {
uint8_t uint8[MAX_LEN];
uint16_t uint16[MAX_LEN / 2];
uint32_t uint32[MAX_LEN / 4];
} values;
#define DO_N 23
uint32_t myfletcher16(uint8_t *data, const uint16_t length)
#if defined(ARDUINO_ARCH_AVR)
String float2strn(float value, size_t n) {
char strvalout[n];
dtostrf(value, n, 2, strvalout);
return strvalout;
}
#else
String float2strn(float value, size_t n) {
String strval = String(value);
while (strval.length() < n) {
strval = " " + strval;
}
return strval;
}
#endif
uint16_t myfletcher16(uint8_t *data, const size_t length)
{
uint8_t s1 = 0;
uint8_t s2 = 0;
for (size_t i = 0; i < length; i++)
{
// UINT8_MAX = 255 = ((((uint16_t) 1) << 8) - ((uint16_t) 1))
s1 = (uint8_t) (((uint16_t) s1 + (uint16_t) data[i]) % UINT8_MAX);
s2 = (uint8_t) (((uint16_t) s2 + (uint16_t) s1) % UINT8_MAX);
}
return (((uint16_t) s2) << 8) | ((uint16_t) s1);
}
uint32_t myfletcher32(uint16_t *data, const size_t length)
{
uint16_t s1 = 0;
uint16_t s2 = 0;
for (uint16_t i = 0; i < length; i++)
for (size_t i = 0; i < length; i++)
{
s1 = (s1 + data[i]) % ((((uint16_t) 1) << 8) - 1);
s2 = (s2 + s1) % ((((uint16_t) 1) << 8) - 1);
// UINT16_MAX = 65535UL = ((((uint32_t) 1) << 16) - ((uint32_t) 1))
s1 = (uint16_t) (((uint32_t) s1 + (uint32_t) data[i]) % UINT16_MAX);
s2 = (uint16_t) (((uint32_t) s2 + (uint32_t) s1) % UINT16_MAX);
}
return (s2 << 8) | s1;
return (((uint32_t) s2) << 16) | ((uint32_t) s1);
}
uint32_t myfletcher32(uint16_t *data, const uint16_t length)
uint64_t myfletcher64(uint32_t *data, const size_t length)
{
uint32_t s1 = 0;
uint32_t s2 = 0;
for (uint16_t i = 0; i < length; i++)
for (size_t i = 0; i < length; i++)
{
s1 = (s1 + data[i]) % ((((uint32_t) 1) << 16) - 1);
s2 = (s2 + s1) % ((((uint32_t) 1) << 16) - 1);
// UINT32_MAX = 4294967295ULL = ((((uint64_t) 1) << 32) - ((uint64_t) 1))
s1 = (uint32_t) (((uint64_t) s1 + (uint64_t) data[i]) % UINT32_MAX);
s2 = (uint32_t) (((uint64_t) s2 + (uint64_t) s1) % UINT32_MAX);
}
return (s2 << 16) | s1;
return (((uint64_t) s2) << 32) | ((uint64_t) s1);
}
uint64_t myfletcher64(uint32_t *data, const uint16_t length)
{
uint64_t s1 = 0;
uint64_t s2 = 0;
for (uint16_t i = 0; i < length; i++)
{
s1 = (s1 + data[i]) % ((((uint64_t) 1) << 32) - 1);
s2 = (s2 + s1) % ((((uint64_t) 1) << 32) - 1);
}
return (s2 << 32) | s1;
}
void setup()
{
Serial.begin(115200);
while (!Serial);
}
void test_fletcher16() {
Serial.println("Fletcher16");
void test_fletcher16(const byte mode) {
Serial.print("| Fletcher16 | ");
const uint16_t max_len = MAX_LEN;
uint8_t values[max_len];
uint32_t t0, t1;
delay(100);
t0 = micros();
for (uint16_t i = 0; i < max_len; i++) {
values[i] = (uint8_t) random(0, 1 << 8);
if (mode == 0) {
t0 = micros();
for (uint16_t i = 0; i < max_len; i++) {
values.uint8[i] = (uint8_t) random(0, 1 << 8);
}
t1 = micros();
} else {
t0 = micros();
for (uint16_t i = 0; i < max_len; i++) {
values.uint8[i] = 255;
}
t1 = micros();
}
t1 = micros();
Serial.print("Created random list: ");
Serial.print(1024.0 * (t1 - t0) / float(MAX_LEN));
Serial.println(" us/kByte.");
Serial.print(float2strn(1024.0 * (t1 - t0) / float(MAX_LEN), 8));
Serial.print(" us/kByte | ");
Fletcher16 checksum_instance;
uint16_t checksum;
uint32_t totaltime = 0;
@ -82,38 +106,47 @@ void test_fletcher16() {
t0 = micros();
checksum_instance.begin();
for (uint16_t i = 0; i < max_len; i++) {
checksum_instance.add(values[i]);
checksum_instance.add(values.uint8[i]);
}
checksum = checksum_instance.getFletcher();
t1 = micros();
totaltime += t1 - t0;
}
Serial.print("Checksum: ");
uint16_t reference_checksum = myfletcher16(values.uint8, max_len);
Serial.print(reference_checksum);
Serial.print(" | ");
Serial.print(checksum);
Serial.print(" ( != ");
Serial.print(fletcher16(values, max_len));
Serial.print(" != ");
Serial.print(myfletcher16(values, max_len));
Serial.println(" )");
Serial.print("Created checksum: ");
Serial.print(1024.0 * totaltime / float(DO_N * MAX_LEN));
Serial.println(" us/kByte.");
Serial.print(" | ");
Serial.print(float2strn(1024.0 * totaltime / float(DO_N * MAX_LEN), 8));
Serial.print(" us/kByte | ");
if (reference_checksum == checksum) {
Serial.print(" OK ");
} else {
Serial.print(" ERROR ");
}
Serial.println(" |");
}
void test_fletcher32() {
Serial.println("Fletcher32");
void test_fletcher32(const byte mode) {
Serial.print("| Fletcher32 | ");
const uint16_t max_len = MAX_LEN / 2;
uint16_t values[max_len];
uint32_t t0, t1;
delay(100);
t0 = micros();
for (uint16_t i = 0; i < max_len; i++) {
values[i] = (uint16_t) random(0, ((uint32_t) 1) << 16);
if (mode == 0) {
t0 = micros();
for (uint16_t i = 0; i < max_len; i++) {
values.uint16[i] = (uint16_t) random(0, ((uint32_t) 1) << 16);
}
t1 = micros();
} else {
t0 = micros();
for (uint16_t i = 0; i < max_len; i++) {
values.uint16[i] = 65535UL;
}
t1 = micros();
}
t1 = micros();
Serial.print("Created random list: ");
Serial.print(1024.0 * (t1 - t0) / float(MAX_LEN));
Serial.println(" us/kByte.");
Serial.print(float2strn(1024.0 * (t1 - t0) / float(MAX_LEN), 8));
Serial.print(" us/kByte | ");
Fletcher32 checksum_instance;
uint32_t checksum;
uint32_t totaltime = 0;
@ -121,38 +154,47 @@ void test_fletcher32() {
t0 = micros();
checksum_instance.begin();
for (uint16_t i = 0; i < max_len; i++) {
checksum_instance.add(values[i]);
checksum_instance.add(values.uint16[i]);
}
checksum = checksum_instance.getFletcher();
t1 = micros();
totaltime += t1 - t0;
}
Serial.print("Checksum: ");
uint32_t reference_checksum = myfletcher32(values.uint16, max_len);
Serial.print(reference_checksum);
Serial.print(" | ");
Serial.print(checksum);
Serial.print(" ( != ");
Serial.print(fletcher32(values, max_len));
Serial.print(" != ");
Serial.print(myfletcher32(values, max_len));
Serial.println(" )");
Serial.print("Created checksum: ");
Serial.print(1024.0 * totaltime / float(DO_N * MAX_LEN));
Serial.println(" us/kByte.");
Serial.print(" | ");
Serial.print(float2strn(1024.0 * totaltime / float(DO_N * MAX_LEN), 8));
Serial.print(" us/kByte | ");
if (reference_checksum == checksum) {
Serial.print(" OK ");
} else {
Serial.print(" ERROR ");
}
Serial.println(" |");
}
void test_fletcher64() {
Serial.println("Fletcher64");
void test_fletcher64(const byte mode) {
Serial.print("| Fletcher64 | ");
const uint16_t max_len = MAX_LEN / 4;
uint32_t values[max_len];
uint32_t t0, t1;
delay(100);
t0 = micros();
for (uint16_t i = 0; i < max_len; i++) {
values[i] = ((uint32_t) random(0, ((uint32_t) 1) << 16)) + (((uint32_t) random(0, ((uint32_t) 1) << 16)) << 16);
if (mode == 0) {
t0 = micros();
for (uint16_t i = 0; i < max_len; i++) {
values.uint32[i] = ((uint32_t) random(0, ((uint32_t) 1) << 16)) + (((uint32_t) random(0, ((uint32_t) 1) << 16)) << 16);
}
t1 = micros();
} else {
t0 = micros();
for (uint16_t i = 0; i < max_len; i++) {
values.uint32[i] = 4294967295ULL;
}
t1 = micros();
}
t1 = micros();
Serial.print("Created random list: ");
Serial.print(1024.0 * (t1 - t0) / float(MAX_LEN));
Serial.println(" us/kByte.");
Serial.print(float2strn(1024.0 * (t1 - t0) / float(MAX_LEN), 8));
Serial.print(" us/kByte | ");
Fletcher64 checksum_instance;
uint64_t checksum;
uint32_t totaltime = 0;
@ -160,22 +202,31 @@ void test_fletcher64() {
t0 = micros();
checksum_instance.begin();
for (uint16_t i = 0; i < max_len; i++) {
checksum_instance.add(values[i]);
checksum_instance.add(values.uint32[i]);
}
checksum = checksum_instance.getFletcher();
t1 = micros();
totaltime += t1 - t0;
}
Serial.print("Checksum: ");
uint64_t reference_checksum = myfletcher64(values.uint32, max_len);
Serial.print(print64(reference_checksum));
Serial.print(" | ");
Serial.print(print64(checksum));
Serial.print(" ( != ");
Serial.print(print64(fletcher64(values, max_len)));
Serial.print(" != ");
Serial.print(print64(myfletcher64(values, max_len)));
Serial.println(" )");
Serial.print("Created checksum: ");
Serial.print(1024.0 * totaltime / float(DO_N * MAX_LEN));
Serial.println(" us/kByte.");
Serial.print(" | ");
Serial.print(float2strn(1024.0 * totaltime / float(DO_N * MAX_LEN), 8));
Serial.print(" us/kByte | ");
if (reference_checksum == checksum) {
Serial.print(" OK ");
} else {
Serial.print(" ERROR ");
}
Serial.println(" |");
}
void setup()
{
Serial.begin(115200);
while (!Serial);
}
void loop() {
@ -189,14 +240,18 @@ void loop() {
Serial.print(MAX_LEN / 4);
Serial.println(" elements for Fletcher64");
Serial.println("");
test_fletcher16();
Serial.println("+------------+---------------------+--------------------+----------------------+-------------------+---------+");
Serial.println("| alg | created random list | reference checksum | checksum | datarate | correct |");
Serial.println("+------------+---------------------+--------------------+----------------------+-------------------+---------+");
test_fletcher16(0);
test_fletcher16(1);
Serial.println("+------------+---------------------+--------------------+----------------------+-------------------+---------+");
test_fletcher32(0);
test_fletcher32(1);
Serial.println("+------------+---------------------+--------------------+----------------------+-------------------+---------+");
test_fletcher64(0);
test_fletcher64(1);
Serial.println("+------------+---------------------+--------------------+----------------------+-------------------+---------+");
Serial.println("");
delay(1000);
test_fletcher32();
Serial.println("");
delay(1000);
test_fletcher64();
Serial.println("");
delay(1000);
Serial.println("");
}

View File

@ -0,0 +1,55 @@
#pragma once
/*
Author: Daniel Mohr
Date: 2022-09-09
Here are implementations with bit shifts instead of modulo.
*/
uint16_t fletcher16_bit_shift(uint8_t *data, const uint16_t length)
{
uint16_t _s1 = 0;
uint16_t _s2 = 0;
for (uint16_t i = 0; i < length; i++)
{
_s1 += data[i];
_s1 = (_s1 & 255) + (_s1 >> 8);
_s2 += _s1;
_s2 = (_s2 & 255) + (_s2 >> 8);
}
if (_s1 >= 255) _s1 -= 255;
if (_s2 >= 255) _s2 -= 255;
return (_s2 << 8) | _s1;
}
uint32_t fletcher32_bit_shift(uint16_t *data, const uint16_t length)
{
uint32_t _s1 = 0;
uint32_t _s2 = 0;
for (uint16_t i = 0; i < length; i++)
{
_s1 += data[i];
_s1 = (_s1 & 65535UL) + (_s1 >> 16);
_s2 += _s1;
_s2 = (_s2 & 65535UL) + (_s2 >> 16);
}
if (_s1 >= 65535UL) _s1 -= 65535UL;
if (_s2 >= 65535UL) _s2 -= 65535UL;
return (_s2 << 16) | _s1;
}
uint64_t fletcher64_bit_shift(uint32_t *data, const uint16_t length)
{
uint64_t _s1 = 0;
uint64_t _s2 = 0;
for (uint16_t i = 0; i < length; i++)
{
_s1 += data[i];
_s1 = (_s1 & ((((uint64_t) 1) << 32) - 1)) + (_s1 >> 32);
_s2 += _s1;
_s2 = (_s2 & ((((uint64_t) 1) << 32) - 1)) + (_s2 >> 32);
}
if (_s1 >= 4294967295ULL) _s1 -= 4294967295ULL;
if (_s2 >= 4294967295ULL) _s2 -= 4294967295ULL;
return (_s2 << 32) | _s1;
}

View File

@ -0,0 +1,437 @@
/*
Author: Daniel Mohr
Date: 2022-09-10
Purpose: shows stream performance for different implementations
*/
#include "Arduino.h"
#include <stdio.h>
#include "printHelpers.h" // needed for Arduino Nano
#include "basic.h"
#include "Fletcher_v0.1.3.h"
#include "Fletcher_v0.1.4.h"
#include "Fletcher_v0.1.5.h"
#include "Fletcher_v0.1.6.h"
#include "Fletcher_next.h"
#include "Fletcher_if_statement.h"
#include "Fletcher_bit_shift.h"
#include "Fletcher_overflow.h"
#ifdef ARDUINO_ARCH_AVR
#define MAX_LEN 500
#else
#define MAX_LEN 16384
#endif
union main_value_storage {
uint8_t uint8[MAX_LEN];
uint16_t uint16[MAX_LEN/2];
uint32_t uint32[MAX_LEN/4];
} values;
#define DO_N 23
#define n_implementations 9
uint16_t checksum16[n_implementations];
uint32_t checksum32[n_implementations];
uint64_t checksum64[n_implementations];
uint32_t totaltime16[n_implementations];
uint32_t totaltime32[n_implementations];
uint64_t totaltime64[n_implementations];
uint32_t n16 = 0;
uint32_t n32 = 0;
uint32_t n64 = 0;
bool checksum_correct16[n_implementations];
bool checksum_correct32[n_implementations];
bool checksum_correct64[n_implementations];
#if defined(ARDUINO_ARCH_AVR)
String float2strn(float value, size_t n) {
char strvalout[n];
dtostrf(value, n, 2, strvalout);
return strvalout;
}
#else
String float2strn(float value, size_t n) {
String strval = String(value);
while (strval.length() < n) {
strval = " " + strval;
}
return strval;
}
#endif
void test_fletcher16() {
const size_t max_len = MAX_LEN;
for (byte mode = 0; mode < 2; mode++) {
for (size_t i = 0; i < max_len; i++) {
if (mode == 0) {
values.uint8[i] = (uint8_t) random(0, 1 << 8);
} else {
values.uint8[i] = (uint8_t) ((((uint16_t) 1) << 8) - 1);
}
}
uint32_t t0, t1;
for (uint16_t j = 0; j < DO_N; j++) {
size_t index;
/* reference */
index = 0;
t0 = micros();
checksum16[index] = basic_fletcher16(values.uint8, max_len);
t1 = micros();
totaltime16[index] += t1 - t0;
/* 0.1.3 */
index = 1;
t0 = micros();
checksum16[index] = fletcher16_v0_1_3(values.uint8, max_len);
t1 = micros();
totaltime16[index] += t1 - t0;
if (checksum16[index] != checksum16[0]) {
checksum_correct16[index] = false;
}
/* 0.1.4 */
index = 2;
t0 = micros();
checksum16[index] = fletcher16_v0_1_4(values.uint8, max_len);
t1 = micros();
totaltime16[index] += t1 - t0;
if (checksum16[index] != checksum16[0]) {
checksum_correct16[index] = false;
}
/* 0.1.5 */
index = 3;
t0 = micros();
checksum16[index] = fletcher16_v0_1_5(values.uint8, max_len);
t1 = micros();
totaltime16[index] += t1 - t0;
if (checksum16[index] != checksum16[0]) {
checksum_correct16[index] = false;
}
/* 0.1.6 */
index = 4;
t0 = micros();
checksum16[index] = fletcher16_v0_1_6(values.uint8, max_len);
t1 = micros();
totaltime16[index] += t1 - t0;
if (checksum16[index] != checksum16[0]) {
checksum_correct16[index] = false;
}
/* next */
index = 5;
t0 = micros();
checksum16[index] = fletcher16_next(values.uint8, max_len);
t1 = micros();
totaltime16[index] += t1 - t0;
if (checksum16[index] != checksum16[0]) {
checksum_correct16[index] = false;
}
/* if_statement */
index = 6;
t0 = micros();
checksum16[index] = fletcher16_if_statement(values.uint8, max_len);
t1 = micros();
totaltime16[index] += t1 - t0;
if (checksum16[index] != checksum16[0]) {
checksum_correct16[index] = false;
}
/* bit_shift */
index = 7;
t0 = micros();
checksum16[index] = fletcher16_bit_shift(values.uint8, max_len);
t1 = micros();
totaltime16[index] += t1 - t0;
if (checksum16[index] != checksum16[0]) {
checksum_correct16[index] = false;
}
}
}
n16 += DO_N;
}
void test_fletcher32() {
const size_t max_len = MAX_LEN / 2;
for (byte m = 0; m < 2; m++) {
for (size_t i = 0; i < max_len; i++) {
if (m == 0) {
values.uint16[i] = (uint16_t) random(0, ((uint32_t) 1) << 16);
} else {
values.uint16[i] = (uint16_t) ((((uint32_t) 1) << 16) - 1);
}
}
uint32_t t0, t1;
for (uint16_t j = 0; j < DO_N; j++) {
size_t index;
/* reference */
index = 0;
t0 = micros();
checksum32[index] = basic_fletcher32(values.uint16, max_len);
t1 = micros();
totaltime32[index] += t1 - t0;
/* 0.1.3 */
index = 1;
t0 = micros();
checksum32[index] = fletcher32_v0_1_3(values.uint16, max_len);
t1 = micros();
totaltime32[index] += t1 - t0;
if (checksum32[index] != checksum32[0]) {
checksum_correct32[1] = false;
}
/* 0.1.4 */
index = 2;
t0 = micros();
checksum32[index] = fletcher32_v0_1_4(values.uint16, max_len);
t1 = micros();
totaltime32[index] += t1 - t0;
if (checksum32[index] != checksum32[0]) {
checksum_correct32[1] = false;
}
/* 0.1.5 */
index = 3;
t0 = micros();
checksum32[index] = fletcher32_v0_1_5(values.uint16, max_len);
t1 = micros();
totaltime32[index] += t1 - t0;
if (checksum32[index] != checksum32[0]) {
checksum_correct32[1] = false;
}
/* 0.1.6 */
index = 4;
t0 = micros();
checksum32[index] = fletcher32_v0_1_6(values.uint16, max_len);
t1 = micros();
totaltime32[index] += t1 - t0;
if (checksum32[index] != checksum32[0]) {
checksum_correct32[1] = false;
}
/* next */
index = 5;
t0 = micros();
checksum32[index] = fletcher32_next(values.uint16, max_len);
t1 = micros();
totaltime32[index] += t1 - t0;
if (checksum32[index] != checksum32[0]) {
checksum_correct32[1] = false;
}
/* if_statement */
index = 6;
t0 = micros();
checksum32[index] = fletcher32_if_statement(values.uint16, max_len);
t1 = micros();
totaltime32[index] += t1 - t0;
if (checksum32[index] != checksum32[0]) {
checksum_correct32[1] = false;
}
/* bit_shift */
index = 7;
t0 = micros();
checksum32[index] = fletcher32_bit_shift(values.uint16, max_len);
t1 = micros();
totaltime32[index] += t1 - t0;
if (checksum32[index] != checksum32[0]) {
checksum_correct32[1] = false;
}
#ifdef ARDUINO_ARCH_AVR
/* overflow */
index = 8;
t0 = micros();
checksum32[index] = fletcher32_overflow(values.uint16, max_len);
t1 = micros();
totaltime32[index] += t1 - t0;
if (checksum32[index] != checksum32[0]) {
checksum_correct32[1] = false;
}
#endif
}
}
n32 += DO_N;
}
void test_fletcher64() {
const size_t max_len = MAX_LEN / 4;
for (byte m = 0; m < 2; m++) {
for (size_t i = 0; i < max_len; i++) {
if (m == 0) {
values.uint32[i] = ((uint32_t) random(0, ((uint32_t) 1) << 16)) + (((uint32_t) random(0, ((uint32_t) 1) << 16)) << 16);
} else {
values.uint32[i] = (uint32_t) ((((uint64_t) 1) << 32) - 1);
}
}
uint32_t t0, t1;
for (uint16_t j = 0; j < DO_N; j++) {
size_t index;
/* reference */
index = 0;
t0 = micros();
checksum64[index] = basic_fletcher64(values.uint32, max_len);
t1 = micros();
totaltime64[index] += t1 - t0;
/* 0.1.3 */
index = 1;
t0 = micros();
checksum64[index] = fletcher64_v0_1_3(values.uint32, max_len);
t1 = micros();
totaltime64[index] += t1 - t0;
if (checksum64[index] != checksum64[0]) {
checksum_correct64[1] = false;
}
/* 0.1.4 */
index = 2;
t0 = micros();
checksum64[index] = fletcher64_v0_1_4(values.uint32, max_len);
t1 = micros();
totaltime64[index] += t1 - t0;
if (checksum64[index] != checksum64[0]) {
checksum_correct64[1] = false;
}
/* 0.1.5 */
index = 3;
t0 = micros();
checksum64[index] = fletcher64_v0_1_5(values.uint32, max_len);
t1 = micros();
totaltime64[index] += t1 - t0;
if (checksum64[index] != checksum64[0]) {
checksum_correct64[1] = false;
}
/* 0.1.6 */
index = 4;
t0 = micros();
checksum64[index] = fletcher64_v0_1_6(values.uint32, max_len);
t1 = micros();
totaltime64[index] += t1 - t0;
if (checksum64[index] != checksum64[0]) {
checksum_correct64[1] = false;
}
/* next */
index = 5;
t0 = micros();
checksum64[index] = fletcher64_next(values.uint32, max_len);
t1 = micros();
totaltime64[index] += t1 - t0;
if (checksum64[index] != checksum64[0]) {
checksum_correct64[1] = false;
}
/* if_statement */
index = 6;
t0 = micros();
checksum64[index] = fletcher64_if_statement(values.uint32, max_len);
t1 = micros();
totaltime64[index] += t1 - t0;
if (checksum64[index] != checksum64[0]) {
checksum_correct64[1] = false;
}
/* bit_shift */
index = 7;
t0 = micros();
checksum64[index] = fletcher64_bit_shift(values.uint32, max_len);
t1 = micros();
totaltime64[index] += t1 - t0;
if (checksum64[index] != checksum64[0]) {
checksum_correct64[1] = false;
}
/* overflow */
index = 8;
t0 = micros();
checksum64[index] = fletcher64_overflow(values.uint32, max_len);
t1 = micros();
totaltime64[index] += t1 - t0;
if (checksum64[index] != checksum64[0]) {
checksum_correct64[1] = false;
}
}
}
n64 += DO_N;
}
void setup()
{
Serial.begin(115200);
while (!Serial);
for (uint16_t i = 0; i < n_implementations; i++) {
checksum16[i] = 0;
checksum32[i] = 0;
checksum64[i] = 0;
totaltime16[i] = 0;
totaltime32[i] = 0;
totaltime64[i] = 0;
checksum_correct16[i] = true;
checksum_correct32[i] = true;
checksum_correct64[i] = true;
}
}
void loop() {
Serial.print("Using list of ");
Serial.print(MAX_LEN);
Serial.println(" elements for Fletcher16");
Serial.print("Using list of ");
Serial.print(MAX_LEN / 2);
Serial.println(" elements for Fletcher32");
Serial.print("Using list of ");
Serial.print(MAX_LEN / 4);
Serial.println(" elements for Fletcher64");
Serial.println("");
test_fletcher16();
test_fletcher32();
test_fletcher64();
// generate output
Serial.println("data rate in us/kByte:");
Serial.println("+------------+----------+----------+----------+----------+----------+----------+----------+----------+----------+");
Serial.println("| alg | basic | 0.1.3 | 0.1.4 | 0.1.5 | 0.1.6 | next | if | shift | overflow |");
Serial.println("+------------+----------+----------+----------+----------+----------+----------+----------+----------+----------+");
Serial.print("| fletcher16 | ");
for (uint16_t i = 0; i < n_implementations; i++) {
Serial.print(float2strn(1024.0 * totaltime16[i] / float(n16 * MAX_LEN), 8));
Serial.print(" | ");
}
Serial.println("\n+------------+----------+----------+----------+----------+----------+----------+----------+----------+----------+");
Serial.print("| fletcher32 | ");
for (uint16_t i = 0; i < n_implementations; i++) {
Serial.print(float2strn(1024.0 * totaltime32[i] / float(n32 * MAX_LEN), 8));
Serial.print(" | ");
}
Serial.println("\n+------------+----------+----------+----------+----------+----------+----------+----------+----------+----------+");
Serial.print("| fletcher64 | ");
for (uint16_t i = 0; i < n_implementations; i++) {
Serial.print(float2strn(1024.0 * totaltime64[i] / float(n64 * MAX_LEN), 8));
Serial.print(" | ");
}
Serial.println("\n+------------+----------+----------+----------+----------+----------+----------+----------+----------+----------+\n");
Serial.println("checksum always OK?");
Serial.println("+------------+-------+-------+-------+-------+-------+-------+-------+-------+-------+");
Serial.println("| alg | basic | 0.1.3 | 0.1.4 | 0.1.5 | 0.1.6 | next | if | shift | overf |");
Serial.println("+------------+-------+-------+-------+-------+-------+-------+-------+-------+-------+");
Serial.print("| fletcher16 | ");
for (uint16_t i = 0; i < n_implementations; i++) {
if (checksum_correct16[i]) {
Serial.print(" ");
} else {
Serial.print("fail ");
}
Serial.print(" | ");
}
Serial.println("\n+------------+-------+-------+-------+-------+-------+-------+-------+-------+-------+");
Serial.print("| fletcher32 | ");
for (uint16_t i = 0; i < n_implementations; i++) {
//Serial.print(checksum_correct32[i]);
if (checksum_correct32[i]) {
Serial.print(" ");
} else {
Serial.print("fail ");
}
Serial.print(" | ");
}
Serial.println("\n+------------+-------+-------+-------+-------+-------+-------+-------+-------+-------+");
Serial.print("| fletcher64 | ");
for (uint16_t i = 0; i < n_implementations; i++) {
//Serial.print(checksum_correct64[i]);
if (checksum_correct64[i]) {
Serial.print(" ");
} else {
Serial.print("fail ");
}
Serial.print(" | ");
}
Serial.println("\n+------------+-------+-------+-------+-------+-------+-------+-------+-------+-------+\n");
Serial.println("");
}

View File

@ -0,0 +1,53 @@
#pragma once
/*
Author: Daniel Mohr
Date: 2022-09-09
Here are implementations with if statements instead of modulo.
*/
#define FLETCHER_16_if_statement 255
#define FLETCHER_32_if_statement 65535UL
#define FLETCHER_64_if_statement 4294967295ULL
uint16_t fletcher16_if_statement(uint8_t *data, const uint16_t length)
{
uint16_t _s1 = 0;
uint16_t _s2 = 0;
for (uint16_t i = 0; i < length; i++)
{
_s1 += data[i];
if (_s1 >= FLETCHER_16_if_statement) _s1 -= FLETCHER_16_if_statement;
_s2 += _s1;
if (_s2 >= FLETCHER_16_if_statement) _s2 -= FLETCHER_16_if_statement;
}
return (_s2 << 8) | _s1;
}
uint32_t fletcher32_if_statement(uint16_t *data, const uint16_t length)
{
uint32_t _s1 = 0;
uint32_t _s2 = 0;
for (uint16_t i = 0; i < length; i++)
{
_s1 += data[i];
if (_s1 >= FLETCHER_32_if_statement) _s1 -= FLETCHER_32_if_statement;
_s2 += _s1;
if (_s2 >= FLETCHER_32_if_statement) _s2 -= FLETCHER_32_if_statement;
}
return (_s2 << 16) | _s1;
}
uint64_t fletcher64_if_statement(uint32_t *data, const uint16_t length)
{
uint64_t _s1 = 0;
uint64_t _s2 = 0;
for (uint16_t i = 0; i < length; i++)
{
_s1 += data[i];
if (_s1 >= FLETCHER_64_if_statement) _s1 -= FLETCHER_64_if_statement;
_s2 += _s1;
if (_s2 >= FLETCHER_64_if_statement) _s2 -= FLETCHER_64_if_statement;
}
return (_s2 << 32) | _s1;
}

View File

@ -0,0 +1,48 @@
#pragma once
/*
Author: Daniel Mohr
Date: 2022-09-10
Here are implementations, which could be used in the next release.
Fletcher16.cpp
Fletcher16.h
Fletcher32.cpp
Fletcher32.h
Fletcher64.cpp
Fletcher64.h
*/
#include <Fletcher16.h>
#include <Fletcher32.h>
#include <Fletcher64.h>
uint16_t fletcher16_next(uint8_t *data, const size_t length)
{
Fletcher16 checksum_instance;
for (size_t i = 0; i < length; i++)
{
checksum_instance.add(data[i]);
}
return checksum_instance.getFletcher();
}
uint32_t fletcher32_next(uint16_t *data, const size_t length)
{
Fletcher32 checksum_instance;
for (size_t i = 0; i < length; i++)
{
checksum_instance.add(data[i]);
}
return checksum_instance.getFletcher();
}
uint64_t fletcher64_next(uint32_t *data, const size_t length)
{
Fletcher64 checksum_instance;
for (size_t i = 0; i < length; i++)
{
checksum_instance.add(data[i]);
}
return checksum_instance.getFletcher();
}

View File

@ -0,0 +1,44 @@
#pragma once
/*
Author: Daniel Mohr
Date: 2022-09-09
Here are implementations with testing for overflow instead of modulo.
*/
#define FLETCHER_64_overflow 4294967295ULL
#ifdef ARDUINO_ARCH_AVR
uint32_t fletcher32_overflow(uint16_t *data, const uint16_t length)
{
uint16_t _s1 = 0;
uint16_t _s2 = 0;
for (uint16_t i = 0; i < length; i++)
{
if (__builtin_uadd_overflow(_s1, data[i], &_s1)) {
_s1++;
}
if (__builtin_uadd_overflow(_s2, _s1, &_s2)) {
_s2++;
}
}
return (((uint32_t) _s2) << 16) | ((uint32_t) _s1);
}
#endif
uint64_t fletcher64_overflow(uint32_t *data, const uint16_t length)
{
uint32_t _s1 = 0;
uint32_t _s2 = 0;
for (uint16_t i = 0; i < length; i++)
{
if (__builtin_uaddl_overflow(_s1, data[i], &_s1)) {
_s1++;
}
if (__builtin_uaddl_overflow(_s2, _s1, &_s2)) {
_s2++;
}
}
return (((uint64_t) _s2) << 32) | ((uint64_t) _s1);
}

View File

@ -0,0 +1,60 @@
#pragma once
/*
Author: Daniel Mohr
Date: 2022-09-09
Here are implementations, which were used in release '0.1.3'.
Fletcher16.cpp
Fletcher16.h
Fletcher32.cpp
Fletcher32.h
Fletcher64.cpp
Fletcher64.h
*/
#define FLETCHER_16_v0_1_3 255
#define FLETCHER_32_v0_1_3 65535UL
#define FLETCHER_64_v0_1_3 4294967295ULL
uint16_t fletcher16_v0_1_3(uint8_t *data, const uint16_t length)
{
uint16_t _s1 = 0;
uint16_t _s2 = 0;
for (uint16_t i = 0; i < length; i++)
{
_s1 += data[i];
if (_s1 >= FLETCHER_16_v0_1_3) _s1 -= FLETCHER_16_v0_1_3;
_s2 += _s1;
if (_s2 >= FLETCHER_16_v0_1_3) _s2 -= FLETCHER_16_v0_1_3;
}
return (_s2 << 8) | _s1;
}
uint32_t fletcher32_v0_1_3(uint16_t *data, const uint16_t length)
{
uint32_t _s1 = 0;
uint32_t _s2 = 0;
for (uint16_t i = 0; i < length; i++)
{
_s1 += data[i];
if (_s1 >= FLETCHER_32_v0_1_3) _s1 -= FLETCHER_32_v0_1_3;
_s2 += _s1;
if (_s2 >= FLETCHER_32_v0_1_3) _s2 -= FLETCHER_32_v0_1_3;
}
return (_s2 << 16) | _s1;
}
uint64_t fletcher64_v0_1_3(uint32_t *data, const uint16_t length)
{
uint64_t _s1 = 0;
uint64_t _s2 = 0;
for (uint16_t i = 0; i < length; i++)
{
_s1 += data[i];
if (_s1 >= FLETCHER_64_v0_1_3) _s1 -= FLETCHER_64_v0_1_3;
_s2 += _s1;
if (_s2 >= FLETCHER_64_v0_1_3) _s2 -= FLETCHER_64_v0_1_3;
}
return (_s2 << 32) | _s1;
}

View File

@ -0,0 +1,76 @@
#pragma once
/*
Author: Daniel Mohr
Date: 2022-09-09
Here are implementations, which were used in release '0.1.4'.
Fletcher16.cpp
Fletcher16.h
Fletcher32.cpp
Fletcher32.h
Fletcher64.cpp
Fletcher64.h
*/
#define FLETCHER_16_v0_1_4 255
#define FLETCHER_32_v0_1_4 65535UL
#define FLETCHER_64_v0_1_4 4294967295ULL
uint16_t fletcher16_v0_1_4(uint8_t *data, const uint16_t length)
{
uint16_t _s1 = 0;
uint16_t _s2 = 0;
for (uint16_t i = 0; i < length; i++)
{
_s1 += data[i];
_s1 = (_s1 & 255) + (_s1 >> 8);
_s2 += _s1;
_s2 = (_s2 & 255) + (_s2 >> 8);
}
return (_s2 << 8) | _s1;
}
uint32_t fletcher32_v0_1_4(uint16_t *data, const uint16_t length)
{
uint32_t _s1 = 0;
uint32_t _s2 = 0;
for (uint16_t i = 0; i < length; i++)
{
_s1 += data[i];
#if defined(ARDUINO_ARCH_SAMD) || defined(ESP32) || defined(ESP8266)
_s1 = (_s1 & 65535UL) + (_s1 >> 16);
#else
if (_s1 >= FLETCHER_32_v0_1_4) _s1 -= FLETCHER_32_v0_1_4;
#endif
_s2 += _s1;
#if defined(ARDUINO_ARCH_SAMD) || defined(ESP32) || defined(ESP8266)
_s2 = (_s2 & 65535UL) + (_s2 >> 16);
#else
if (_s2 >= FLETCHER_32_v0_1_4) _s2 -= FLETCHER_32_v0_1_4;
#endif
}
return (_s2 << 16) | _s1;
}
uint64_t fletcher64_v0_1_4(uint32_t *data, const uint16_t length)
{
uint64_t _s1 = 0;
uint64_t _s2 = 0;
for (uint16_t i = 0; i < length; i++)
{
_s1 += data[i];
#if defined(ARDUINO_ARCH_SAMD) || defined(ESP32) || defined(ESP8266)
_s1 = (_s1 & ((((uint64_t) 1) << 32) - 1)) + (_s1 >> 32);
#else
if (_s1 >= FLETCHER_64_v0_1_4) _s1 -= FLETCHER_64_v0_1_4;
#endif
_s2 += _s1;
#if defined(ARDUINO_ARCH_SAMD) || defined(ESP32) || defined(ESP8266)
_s2 = (_s2 & ((((uint64_t) 1) << 32) - 1)) + (_s2 >> 32);
#else
if (_s2 >= FLETCHER_64_v0_1_4) _s2 -= FLETCHER_64_v0_1_4;
#endif
}
return (_s2 << 32) | _s1;
}

View File

@ -0,0 +1,76 @@
#pragma once
/*
Author: Daniel Mohr
Date: 2022-09-09
Here are implementations, which were used in release '0.1.5'.
Fletcher16.cpp
Fletcher16.h
Fletcher32.cpp
Fletcher32.h
Fletcher64.cpp
Fletcher64.h
*/
#define FLETCHER_16_v0_1_5 255
#define FLETCHER_32_v0_1_5 65535UL
#define FLETCHER_64_v0_1_5 4294967295ULL
uint16_t fletcher16_v0_1_5(uint8_t *data, const uint16_t length)
{
uint16_t _s1 = 0;
uint16_t _s2 = 0;
for (uint16_t i = 0; i < length; i++)
{
_s1 += data[i];
_s1 = (_s1 & 255) + (_s1 >> 8);
_s2 += _s1;
_s2 = (_s2 & 255) + (_s2 >> 8);
}
return (_s2 << 8) | _s1;
}
uint32_t fletcher32_v0_1_5(uint16_t *data, const uint16_t length)
{
uint32_t _s1 = 0;
uint32_t _s2 = 0;
for (uint16_t i = 0; i < length; i++)
{
_s1 += data[i];
#if defined(ARDUINO_ARCH_SAMD) || defined(ESP32) || defined(ESP8266)
_s1 = (_s1 & 65535UL) + (_s1 >> 16);
#else
if (_s1 >= FLETCHER_32_v0_1_5) _s1 -= FLETCHER_32_v0_1_5;
#endif
_s2 += _s1;
#if defined(ARDUINO_ARCH_SAMD) || defined(ESP32) || defined(ESP8266)
_s2 = (_s2 & 65535UL) + (_s2 >> 16);
#else
if (_s2 >= FLETCHER_32_v0_1_5) _s2 -= FLETCHER_32_v0_1_5;
#endif
}
return (_s2 << 16) | _s1;
}
uint64_t fletcher64_v0_1_5(uint32_t *data, const uint16_t length)
{
uint64_t _s1 = 0;
uint64_t _s2 = 0;
for (uint16_t i = 0; i < length; i++)
{
_s1 += data[i];
#if defined(ARDUINO_ARCH_SAMD) || defined(ESP32) || defined(ESP8266)
_s1 = (_s1 & ((((uint64_t) 1) << 32) - 1)) + (_s1 >> 32);
#else
if (_s1 >= FLETCHER_64_v0_1_5) _s1 -= FLETCHER_64_v0_1_5;
#endif
_s2 += _s1;
#if defined(ARDUINO_ARCH_SAMD) || defined(ESP32) || defined(ESP8266)
_s2 = (_s2 & ((((uint64_t) 1) << 32) - 1)) + (_s2 >> 32);
#else
if (_s2 >= FLETCHER_64_v0_1_5) _s2 -= FLETCHER_64_v0_1_5;
#endif
}
return (_s2 << 32) | _s1;
}

View File

@ -0,0 +1,133 @@
#pragma once
/*
Author: Daniel Mohr
Date: 2022-09-12
Here are implementations, which were used in release '0.1.6'.
Fletcher16.cpp
Fletcher16.h
Fletcher32.cpp
Fletcher32.h
Fletcher64.cpp
Fletcher64.h
*/
#define FLETCHER_16_v0_1_6 255
#define FLETCHER_32_v0_1_6 65535UL
#define FLETCHER_64_v0_1_6 4294967295ULL
uint16_t fletcher16_v0_1_6(uint8_t *data, const uint16_t length)
{
#ifdef ARDUINO_ARCH_AVR
uint8_t _s1 = 0;
uint8_t _s2 = 0;
#else
uint16_t _s1 = 0;
uint16_t _s2 = 0;
#endif
for (uint16_t i = 0; i < length; i++)
{
#if defined(ARDUINO_ARCH_AVR)
uint8_t t = 0xFF - data[i];
if (t >= _s1) _s1 += data[i];
else _s1 = _s1 + data[i] + 1;
t = 0xFF - _s1;
if (t >= _s2) _s2 += _s1;
else _s2 = _s2 + _s1 + 1;
#elif defined(ARDUINO_ARCH_SAMD) || defined(ESP32) || defined(ESP8266)
_s1 += data[i];
_s1 = (_s1 & 255) + (_s1 >> 8);
_s2 += _s1;
_s2 = (_s2 & 255) + (_s2 >> 8);
#else
// REFERENCE
_s1 += data[i];
if (_s1 >= FLETCHER_16_v0_1_6) _s1 -= FLETCHER_16_v0_1_6;
_s2 += _s1;
if (_s2 >= FLETCHER_16_v0_1_6) _s2 -= FLETCHER_16_v0_1_6;
#endif
}
if (_s1 >= FLETCHER_16_v0_1_6) _s1 -= FLETCHER_16_v0_1_6;
if (_s2 >= FLETCHER_16_v0_1_6) _s2 -= FLETCHER_16_v0_1_6;
return (((uint16_t)_s2) << 8) | _s1;
}
uint32_t fletcher32_v0_1_6(uint16_t *data, const uint16_t length)
{
#ifdef ARDUINO_ARCH_AVR
uint16_t _s1 = 0;
uint16_t _s2 = 0;
#else
uint32_t _s1 = 0;
uint32_t _s2 = 0;
#endif
for (uint16_t i = 0; i < length; i++)
{
#ifdef ARDUINO_ARCH_AVR
unsigned int t = _s1;
// Serial.println("__builtin_uadd_overflow");
if (__builtin_uadd_overflow(t, data[i], &t)) {
t++;
}
_s1 = t;
t = _s2;
if (__builtin_uadd_overflow(t, _s1, &t)) {
t++;
}
_s2 = t;
#elif defined(ARDUINO_ARCH_SAMD) || defined(ESP32) || defined(ESP8266)
_s1 += data[i];
_s1 = (_s1 & 65535UL) + (_s1 >> 16);
_s2 += _s1;
_s2 = (_s2 & 65535UL) + (_s2 >> 16);
#else
_s1 += data[i];
if (_s1 >= FLETCHER_32_v0_1_6) _s1 -= FLETCHER_32_v0_1_6;
_s2 += _s1;
if (_s2 >= FLETCHER_32_v0_1_6) _s2 -= FLETCHER_32_v0_1_6;
#endif
}
if (_s1 >= FLETCHER_32_v0_1_6) _s1 -= FLETCHER_32_v0_1_6;
if (_s2 >= FLETCHER_32_v0_1_6) _s2 -= FLETCHER_32_v0_1_6;
return (((uint32_t)_s2) << 16) | _s1;
}
uint64_t fletcher64_v0_1_6(uint32_t *data, const uint16_t length)
{
#if defined(ARDUINO_ARCH_AVR) || defined(ESP32) || defined(ESP8266)
uint32_t _s1 = 0;
uint32_t _s2 = 0;
#else
uint64_t _s1 = 0;
uint64_t _s2 = 0;
#endif
for (uint16_t i = 0; i < length; i++)
{
#if defined(ARDUINO_ARCH_AVR) || defined(ESP32) || defined(ESP8266)
uint32_t t = 0xFFFFFFFF - data[i];
if (t >= _s1) _s1 += data[i];
else _s1 = _s1 + data[i] + 1;
t = 0xFFFFFFFF - _s1;
if (t >= _s2) _s2 += _s1;
else _s2 = _s2 + _s1 + 1;
#elif defined(ARDUINO_ARCH_SAMD)
_s1 += data[i];
_s1 = (_s1 & ((((uint64_t) 1) << 32) - 1)) + (_s1 >> 32);
_s2 += _s1;
_s2 = (_s2 & ((((uint64_t) 1) << 32) - 1)) + (_s2 >> 32);
#else
_s1 += data[i];
if (_s1 >= FLETCHER_64_v0_1_6) _s1 -= FLETCHER_64_v0_1_6;
_s2 += _s1;
if (_s2 >= FLETCHER_64_v0_1_6) _s2 -= FLETCHER_64_v0_1_6;
#endif
}
if (_s1 >= FLETCHER_64_v0_1_6) _s1 -= FLETCHER_64_v0_1_6;
if (_s2 >= FLETCHER_64_v0_1_6) _s2 -= FLETCHER_64_v0_1_6;
return (((uint64_t)_s2) << 32) | _s1;
}

View File

@ -0,0 +1,46 @@
#pragma once
/*
Author: Daniel Mohr
Date: 2022-09-13
Here are basic implementations which should give reference values.
*/
uint16_t basic_fletcher16(uint8_t *data, const size_t length)
{
uint8_t s1 = 0;
uint8_t s2 = 0;
for (size_t i = 0; i < length; i++)
{
// UINT8_MAX = 255 = ((((uint16_t) 1) << 8) - ((uint16_t) 1))
s1 = (uint8_t) (((uint16_t) s1 + (uint16_t) data[i]) % UINT8_MAX);
s2 = (uint8_t) (((uint16_t) s2 + (uint16_t) s1) % UINT8_MAX);
}
return (((uint16_t) s2) << 8) | ((uint16_t) s1);
}
uint32_t basic_fletcher32(uint16_t *data, const size_t length)
{
uint16_t s1 = 0;
uint16_t s2 = 0;
for (size_t i = 0; i < length; i++)
{
// UINT16_MAX = 65535UL = ((((uint32_t) 1) << 16) - ((uint32_t) 1))
s1 = (uint16_t) (((uint32_t) s1 + (uint32_t) data[i]) % UINT16_MAX);
s2 = (uint16_t) (((uint32_t) s2 + (uint32_t) s1) % UINT16_MAX);
}
return (((uint32_t) s2) << 16) | ((uint32_t) s1);
}
uint64_t basic_fletcher64(uint32_t *data, const size_t length)
{
uint32_t s1 = 0;
uint32_t s2 = 0;
for (size_t i = 0; i < length; i++)
{
// UINT32_MAX = 4294967295ULL = ((((uint64_t) 1) << 32) - ((uint64_t) 1))
s1 = (uint32_t) (((uint64_t) s1 + (uint64_t) data[i]) % UINT32_MAX);
s2 = (uint32_t) (((uint64_t) s2 + (uint64_t) s1) % UINT32_MAX);
}
return (((uint64_t) s2) << 32) | ((uint64_t) s1);
}

View File

@ -8,6 +8,9 @@
"name": "Rob Tillaart",
"email": "Rob.Tillaart@gmail.com",
"maintainer": true
},
{
"name": "Daniel Mohr"
}
],
"repository":
@ -15,7 +18,7 @@
"type": "git",
"url": "https://github.com/RobTillaart/Fletcher.git"
},
"version": "0.1.5",
"version": "0.1.6",
"license": "MIT",
"frameworks": "arduino",
"platforms": "*",

View File

@ -1,5 +1,5 @@
name=Fletcher
version=0.1.5
version=0.1.6
author=Rob Tillaart <rob.tillaart@gmail.com>
maintainer=Rob Tillaart <rob.tillaart@gmail.com>
sentence="Arduino Library for calculating Fletcher's checksum.

View File

@ -26,6 +26,9 @@
#include "Arduino.h"
#include "Fletcher.h"
#include "Fletcher16.h"
#include "Fletcher32.h"
#include "Fletcher64.h"
@ -83,6 +86,56 @@ unittest(test_fletcher64)
}
unittest(test_FF_1)
{
uint8_t x[1] = { 0xFF };
uint16_t y[1] = { 0xFFFF };
uint32_t z[1] = { 0xFFFFFFFF };
assertEqual(0, fletcher16(x, 1));
assertEqual(0, fletcher32(y, 1));
assertEqual(0, fletcher64(z, 1));
}
unittest(test_FF_2)
{
uint8_t x[1] = { 0xFF };
uint16_t y[1] = { 0xFFFF };
uint32_t z[1] = { 0xFFFFFFFF };
Fletcher16 FL16;
FL16.begin();
assertEqual(0, FL16.getFletcher());
FL16.begin(0xFF, 0);
assertEqual(0, FL16.getFletcher());
FL16.add(0xFF);
assertEqual(0, FL16.getFletcher());
FL16.add(0xFF);
assertEqual(0, FL16.getFletcher());
Fletcher32 FL32;
FL32.begin();
assertEqual(0, FL32.getFletcher());
FL32.begin(0xFFFF, 0);
assertEqual(0, FL32.getFletcher());
FL32.add(0xFFFF);
assertEqual(0, FL32.getFletcher());
FL32.add(0xFFFF);
assertEqual(0, FL32.getFletcher());
Fletcher64 FL64;
FL64.begin();
assertEqual(0, FL64.getFletcher());
FL64.begin(0xFFFFFFFF, 0);
assertEqual(0, FL64.getFletcher());
FL64.add(0xFFFFFFFF);
assertEqual(0, FL64.getFletcher());
FL64.add(0xFFFFFFFF);
assertEqual(0, FL64.getFletcher());
}
unittest_main()
// --------