/**************************************************************************\
* Pinoccio Library                                                         *
* https://github.com/Pinoccio/library-pinoccio                             *
* Copyright (c) 2012-2014, Pinoccio Inc. All rights reserved.              *
* ------------------------------------------------------------------------ *
*  This program is free software; you can redistribute it and/or modify it *
*  under the terms of the BSD License as described in license.txt.         *
\**************************************************************************/
#ifndef LIB_PINOCCIO_CRC_H
#define LIB_PINOCCIO_CRC_H

#include <stdint.h>
#include <stdlib.h>

/* Generic CRC implementation, based on code generated by pycrc, using:
 * pycrc --xor-in=0 --reflect-in=false --reflect-out=false
 * --xor-out=0  --algorithm=bit-by-bit-fast --generate=c
 * poly parameter is the poly in hexadecimal form, "rocksoft" style
 * (translating the polynomial into a binary number, dropping the
 * topmost 1-bit).
 */
template<typename T>
T pinoccio_crc_update(T poly, T crc, uint8_t c)
{
    const size_t bits = sizeof(T) * 8;
    // e.g., 0x80 for bits = 8
    const T msb_mask = 1 << (bits - 1);
    for (uint8_t i = 0x80; i > 0; i >>= 1) {
        bool bit = crc & msb_mask;
        if (c & i) {
            bit = !bit;
        }
        crc <<= 1;
        if (bit) {
            crc ^= poly;
        }
    }
    return crc;
}

template<typename T>
T pinoccio_crc_generate(T poly, T initial_crc, uint8_t *data, size_t length)
{
    T crc = initial_crc;
    while (length--)
	crc = pinoccio_crc_update(poly, crc, *data++);
    return crc;
}
#endif // LIB_PINOCCIO_CRC_H
