GY-63_MS5611/libraries/LUHN/LUHN.cpp
2022-12-30 12:21:53 +01:00

130 lines
2.7 KiB
C++

//
// FILE: LUHN.cpp
// AUTHOR: Rob Tillaart
// VERSION: 0.1.1
// DATE: 2022-12-24
// PURPOSE: Arduino Library for calculating LUHN checksum.
// URL: https://github.com/RobTillaart/LUHN
#include "LUHN.h"
LUHN::LUHN()
{
_luhn = 0;
_count = 0;
}
bool LUHN::isValid(const char * buffer)
{
return isValid((char*)buffer);
}
bool LUHN::isValid(char * buffer)
{
uint16_t checksum = 0;
uint8_t length = strlen(buffer);
if (length == 0) return false;
for (int i = 0; i < length-1; i++)
{
uint8_t x = buffer[i] - '0';
if (i % 2 == 0) checksum += x; // weight 1
else if (x < 5) checksum += x * 2; // weight 2
else checksum += (x * 2 - 10 + 1); // weight 2 + handle overflow.
}
uint8_t a = (10000UL - checksum) % 10;
uint8_t b = buffer[length-1] - '0';
return a == b;
}
char LUHN::generateChecksum(char * buffer)
{
uint16_t checksum = 0;
uint8_t length = strlen(buffer);
for (int i = 0; i < length; i++)
{
uint8_t x = buffer[i] - '0';
if (i % 2 == 0) checksum += x; // weight 1
else if (x < 5) checksum += x * 2; // weight 2
else checksum += (x * 2 - 10 + 1); // weight 2 + handle overflow.
}
return '0' + ((10000UL - checksum) % 10);
}
void LUHN::randomize(uint32_t a, uint32_t b)
{
m_z = a;
m_w = b;
}
bool LUHN::generate(char * buffer, uint8_t length, char * prefix)
{
int len = strlen(prefix);
if (len >= length) return false;
if (length < 2) return false;
strcpy(buffer, prefix);
int i;
for (i = len; i < length-1;)
{
buffer[i++] = '0' + Marsaglia_mod10();
buffer[i] = '\0';
}
char c = generateChecksum(buffer);
buffer[i++] = c;
buffer[i] = '\0';
return true;
}
char LUHN::add(char c)
{
uint8_t x = c - '0';
if (_count % 2 == 0) _luhn += x;
else if (x < 5) _luhn += x * 2;
else _luhn += (x * 2 - 10 + 1);
// correct
if (_luhn > 9) _luhn -= 10;
_count++;
return '0' + (10 - _luhn);
}
char LUHN::reset()
{
uint8_t last = _luhn;
_luhn = 0;
_count = 0;
return '0' + (10 - last);
}
///////////////////////////////////////////////////////////////////////////
//
// PROTECTED
//
///////////////////////////////////////////////////////////////////////////
//
// An example of a simple pseudo-random number generator is the
// Multiply-with-carry method invented by George Marsaglia.
// it has two initializers (not zero) which can be changed
// to seed the generator.
// this is derived work.
//
uint8_t LUHN::Marsaglia_mod10()
{
m_z = 36969L * (m_z & 65535L) + (m_z >> 16);
m_w = 18000L * (m_w & 65535L) + (m_w >> 16);
return (m_z ^ m_w) % 10; // changed
}
// -- END OF FILE --