diff --git a/include/BSidesMessaging.h b/include/BSidesMessaging.h new file mode 100644 index 0000000..891ce88 --- /dev/null +++ b/include/BSidesMessaging.h @@ -0,0 +1,231 @@ +// +// BSides Badge Serial Bridge Message Format +// +#ifndef __SERIALBRIDGE_MESSAGES_H +#define __SERIALBRIDGE_MESSAGES_H +#include +#include +#include +#include + +using namespace std; + +#define SERIALBRIDGE_MESSAGE_MAGIC 0xdeadcafe + +#define SERIALBRIDGE_MESSAGE_SIZE 64 // bytes +#define SERIALBRIDGE_MESSAGE_V1 1 +#define SERIALBRIDGE_MESSAGE_CURRENT_VERSION SERIALBRIDGE_MESSAGE_V1 + +#define SERIALBRIDGE_MESSAGE_QUEUE_MAX_SIZE 10 + +/** + * Serial bridge message types + */ +typedef enum { + SERIALBRIDGE_MESSAGE_TYPE_MIN = 0, + // VBat request/response + VBATRequest = SERIALBRIDGE_MESSAGE_TYPE_MIN, + VBATResponse, + // IRdA send/receive + IRdASend, + IRdACheck, + IRdARecv, + // IMU event + IMUEvent, + // Audio event + AudioEvent, + // Wi-Fi event + WiFiEvent, + // Bluetooth Event + BluetoothEvent, + // SD card event + SDEvent, + // SAO I2C send/receive + SAOWireSend, + SAOWireRequest, + // SAO GPIO read/set + SAOGPIOGet, + SAOGPIOSet, + SAOGPIOVal, + // Set RGB LED state + LEDSet, + // Capsense pad state + Capsense, + // Enable/disable direct capsense feedback to LEDs + CapsenseFeedbackEnable, + // D-pad button state + DPad, + // Call to suspend the SAMD for power saving + SAMD_Suspend, + // Diagnostics ping-pong + Diagnostics_PING, + Diagnostics_PONG, + // ACK/NACK of serial send + Message_ACK, + Message_NACK, + SERIALBRIDGE_MESSAGE_TYPE_MAX, +} MessageType_Enum; + +typedef uint8_t MessageType; + +/** + * Serial bridge message header + */ +typedef struct SerialMessageHeader { + uint32_t magic; + uint8_t seqNo; + uint8_t version; + MessageType type; + uint32_t crc32; +} __attribute((packed)) SerialMessageHeader; + +#define SERIALBRIDGE_MESSAGE_DATA_SIZE_MAX (SERIALBRIDGE_MESSAGE_SIZE - sizeof(SerialMessageHeader)) + +// Padding type to make all messages the same size +typedef struct padding { + uint8_t padding[SERIALBRIDGE_MESSAGE_DATA_SIZE_MAX]; +} __attribute((packed)) padding; + +/* + * VBAT battery value + */ +typedef struct VBATValue { + // The value of the battery voltage + float value; +} __attribute((packed)) VBATValue; + +/** + * IR Code + */ +typedef struct IRCode { + uint8_t code[SERIALBRIDGE_MESSAGE_DATA_SIZE_MAX]; +} __attribute((packed)) IRCode; + + +/** + * IR Component Check + */ +typedef struct IRCheck { + bool checkResult; +} __attribute((packed)) IRCheck; + +/** + * SAO I2C command and data + * - note: this is a preliminary message type, we will want to change this. + */ +typedef struct SAOWireData { + uint8_t cmd; + uint8_t data[128]; +} __attribute((packed)) SAOWireData; + +/** + * SAO GPIO Data state + */ +typedef struct SAOGPIOData { + uint8_t pinmode[2]; + uint8_t pinstate[2]; +} __attribute((packed)) SAOGPIOData; + +/** + * RGB LED State to set + */ +typedef struct RGBLEDState { + uint8_t brightness[8]; + uint8_t red[8]; + uint8_t green[8]; + uint8_t blue[8]; +} __attribute((packed)) RGBLEDState; + +/** + * Capsense pad state + */ +typedef struct CapsenseState { + bool pads[8]; +} __attribute((packed)) CapsenseState; + +typedef struct CapsenseFeedback { + bool enable; +} __attribute((packed)) CapsenseFeedback; + +/** + * DPad state + */ +typedef struct DPadState { + bool up; + bool down; + bool left; + bool right; + bool enter; +} __attribute((packed)) DPadState; + +/** + * Serial bridge message data + */ +typedef struct SerialMessageData { + union { + padding none; + VBATValue vbat; + IRCode code; + SAOWireData i2cData; + SAOGPIOData gpio; + RGBLEDState leds; + CapsenseState capsense; + CapsenseFeedback feedback; + DPadState dpad; + IRCheck ircheck; + } __attribute((packed)) payload; +} __attribute((packed)) SerialMessageData; + +/** + * Serial bridge message structure + */ +typedef struct SerialMessage_v1 { + SerialMessageHeader header; + SerialMessageData data; +} __attribute((packed)) SerialMessage; + +/** + * Serial message queue convenience type + */ +typedef CircularBuffer SerialMessageQueue; + +// MARK: Messaging functionality + +/** + * Populate a message type correctly, setting its version and type fields appropriately + * @internal populates the data section with the (non-typed) data structure + * @return false if datalen too large to fit + */ +bool prepareMessage(SerialMessage &msg, MessageType type, uint8_t seqNo, const void *data, size_t datalen); +/** + * Validate a message is a recognised version and message type + * @return false if message version or type is unknown + */ +bool validateMessage(const SerialMessage &msg); + +/** + * Monotonically-increasing sequence number (not thread-safe) + */ +uint8_t nextSequenceNumber(void); + +/** + * Enqueue a message for processing + * @return false if message not valid, or queue error + */ +bool enqueueMessage(const SerialMessage &msg, SerialMessageQueue &queue); + +/** + * Dequeue a message for proecssing + * @internal populates msgOut section with the message + * @note Will consume the first element of the queue regardless of whether it's a valid message or not + * @note It's up to the caller to guarantee the msg pointee is large enough to hold a SerialMessage + * @return false if message not valid, msgOut is NULL, or no messages available + */ +bool dequeueMessage(SerialMessage *msgOut, SerialMessageQueue &queue); + +/** + * Returns a string describing message type, or "unknown" if it's not a valid type enum + */ +const char* messageType(MessageType type); + +#endif // __SERIALBRIDGE_MESSAGES_H diff --git a/include/BadgeLog.h b/include/BadgeLog.h new file mode 100644 index 0000000..93948b1 --- /dev/null +++ b/include/BadgeLog.h @@ -0,0 +1,41 @@ +#ifndef _BADGE_LOG_H_ +#define _BADGE_LOG_H_ + +#include + +/* Log level definition and config helpers */ +typedef enum { + LOG_NOTSET, + LOG_TRACE, + LOG_DEBUG, + LOG_INFO, + LOG_WARN, + LOG_ERROR, + LOG_CRITICAL, + LOG_PANIC, + _LOG_MAX_LV, +} log_level_e; + +void set_log_level(const log_level_e); + +typedef enum { + LOG_DECORATED = true, + LOG_UNDECORATED = false, + _LOG_MAX_DEC, +} log_decoration_e; + +void set_log_decoration(const log_decoration_e); + +/* All logging calls are simple, short voided functions in order to reduce the + * overhead on the caller - both in coding and calling. The caller can assume + * that a call to the logging subsystem will return quickly and that data + * passed by reference is then safe to deallocate. + */ +void __attribute__ ((format (printf, 2, 3))) +log(const log_level_e, const char * const, ...); +void __attribute__ ((format (printf, 3, 4))) +log(const log_level_e, const log_decoration_e, const char * const, ...); + +void log_dump(); + +#endif//_BADGE_LOG_H_ diff --git a/include/SerialBridge.h b/include/SerialBridge.h new file mode 100644 index 0000000..78a5672 --- /dev/null +++ b/include/SerialBridge.h @@ -0,0 +1,54 @@ +#ifndef _SERIAL_BRIDGE_2020_ +#define _SERIAL_BRIDGE_2020_ + +#include +#include +#include +#include "badge_pins.h" +#include "BSidesMessaging.h" + +#ifdef __AVR__ +#ifndef ssize_t +#define ssize_t int +#endif +#endif + +#define WOULD_BLOCK ((ssize_t)-100) +#ifdef SAMD21 +extern Uart DebugSerial; +#endif + +typedef enum BridgeState { + disconnected, + pending, + live, +} BridgeState; + +class SerialBridgeLink { + public: + SerialBridgeLink(); + void begin(unsigned long baud=9600); + void end(void); + int available(void); + int read(void); + void flush(void); + size_t write(uint8_t); +}; + +class SerialBridge { + public: + SerialBridge(); + void connect(void); + void disconnect(void); + int available(void); + bool sendMessage(const SerialMessage& msg); + bool recvMessage(SerialMessage* msg); + ssize_t send(const void *buf, size_t buf_size); + ssize_t recv(void *buf, size_t buf_size); + private: + SerialBridgeLink link; + void sendAckMessage(uint8_t seqNo); + void sendNackMessage(uint8_t seqNo); +}; + +#endif // _SERIAL_BRIDGE_2020_ diff --git a/include/badge_pins.h b/include/badge_pins.h new file mode 100644 index 0000000..9a10f03 --- /dev/null +++ b/include/badge_pins.h @@ -0,0 +1,25 @@ +// HSPI pins +#define HSPI_MISO 12 +#define HSPI_MOSI 13 +#define HSPI_SCLK 14 +#define HSPI_SS 15 + +// ePaper display +#define EPD_DC 25 +#define EPD_CS 27 +#define EPD_BUSY 35 +#define SRAM_CS -1 +#define EPD_RESET 26 +#define EPD_SPI &SPI3 + +// I2C +#define ESP_SDA 22 +#define ESP_SCL 38 + +// ATMEL UART Bridge +#define UART_RXD (33u) +#define UART_TXD (32U) + +// IMU +#define ESP32_I2C_IMU_SDA ((int)22) +#define ESP32_I2C_IMU_SCL ((int)19) diff --git a/include/icm20602.h b/include/icm20602.h new file mode 100644 index 0000000..9cf933c --- /dev/null +++ b/include/icm20602.h @@ -0,0 +1,344 @@ +#ifndef _ICM20602_H +#define _ICM20602_H + +/***** Includes *****/ + +#include +#include + +/***** Macros *****/ + +/** This initializer will zero out the ICM20602 struct for initialization + * purposes. This is advised as to avoid having uninitialized garbage values + * left within the struct */ +#define ICM20602_INIT() \ + { \ + .id = 0, \ + .hal_wr = NULL, \ + .hal_rd = NULL, \ + .hal_sleep = NULL, \ + .mutex_lock = NULL, \ + .mutex_unlock = NULL, \ + .use_accel = false, \ + .accel_fifo = false, \ + .accel_dlpf = 0, \ + .accel_g = 0, \ + .use_gyro = false, \ + .gyro_fifo = false, \ + .gyro_dlpf = 0, \ + .gyro_dps = 0, \ + .sample_rate_div = 1, \ + .i2c_disable = false, \ + } + +/** This initializer will configure the ICM20602 with settings that should + * yield some actual output on both the gyroscope and the accelerometer. All + * that the developer should need to set manually are the "hal_wr", "hal_rd", + * and "hal_sleep" function pointers. It is recommended to use this for + * testing purposes. */ +#define ICM20602_DEFAULT_INIT() \ + { \ + .id = 0, \ + .hal_wr = NULL, \ + .hal_rd = NULL, \ + .hal_sleep = NULL, \ + .mutex_lock = NULL, \ + .mutex_unlock = NULL, \ + .use_accel = true, \ + .accel_fifo = false, \ + .accel_dlpf = ICM20602_ACCEL_DLPF_10_2_HZ, \ + .accel_g = ICM20602_ACCEL_RANGE_4G, \ + .use_gyro = true, \ + .gyro_fifo = false, \ + .gyro_dlpf = ICM20602_GYRO_DLPF_10_HZ, \ + .gyro_dps = ICM20602_GYRO_RANGE_2000_DPS, \ + .sample_rate_div = 100, \ + .i2c_disable = false, \ + } + +/***** Typedefs *****/ + +/** \brief Function pointer for write function. + * \param id the ID value of the icm20602 device struct + * \param reg ICM20602 register address to target + * \param data pointer to data to write + * \param len number of bytes to write + * \return zero on success, anything else is an error + */ +typedef int8_t (*icm20602_hal_wr)(uint8_t id, uint8_t reg, uint8_t * data, + uint16_t len); + +/** \brief Function pointer for read function. + * \param id the ID value of the icm20602 device struct + * \param reg ICM20602 register address to target + * \param data pointer to data to read + * \param len number of bytes to read + * \return zero on success, anything else is an error + */ +typedef int8_t (*icm20602_hal_rd)(uint8_t id, uint8_t reg, uint8_t * data, + uint16_t len); + +/** \brief Function pointer for sleep function. + * \param ms the total number of milliseconds to sleep for + * \return void + */ +typedef void (*icm20602_hal_sleep)(uint32_t ms); + +/** \brief Function pointer for mutex locking function. + * \param id the ID value of the icm20602 device struct + * \return void + */ +typedef void (*icm20602_mutex_lock)(uint8_t id); + +/** \brief Function pointer for mutex unlocking function. + * \param id the ID value of the icm20602 device struct + * \return void + */ +typedef void (*icm20602_mutex_unlock)(uint8_t id); + +/***** Enums *****/ + +/** Enumerated value corresponds with A_DLPF_CFG in the ACCEL_CONFIG2 register + * unless BYPASS is specified in the name. If BYPASS is used, the DLPF is + * removed from the signal path and ACCEL_FCHOICE_B is set in the + * ACCEL_CONFIG2 register. */ +enum icm20602_accel_dlpf { + ICM20602_ACCEL_DLPF_218_1_HZ = 0, // data clocked at 1kHz + ICM20602_ACCEL_DLPF_99_HZ = 2, // data clocked at 1kHz + ICM20602_ACCEL_DLPF_44_8_HZ = 3, // data clocked at 1kHz + ICM20602_ACCEL_DLPF_21_2_HZ = 4, // data clocked at 1kHz + ICM20602_ACCEL_DLPF_10_2_HZ = 5, // data clocked at 1kHz + ICM20602_ACCEL_DLPF_5_1_HZ = 6, // data clocked at 1kHz + ICM20602_ACCEL_DLPF_420_HZ = 7, // data clocked at 1kHz + ICM20602_ACCEL_DLPF_BYPASS_1046_HZ, // no filter, data clocked at 4kHz +}; + +/** Enumerated value corresponds with ACCEL_FS_SEL in the ACCEL_CONFIG + * register. Values listed are the full +/- G range. */ +enum icm20602_accel_g { + ICM20602_ACCEL_RANGE_2G = 0, + ICM20602_ACCEL_RANGE_4G = 1, + ICM20602_ACCEL_RANGE_8G = 2, + ICM20602_ACCEL_RANGE_16G = 3, +}; + +/** Enumerated value corresponds with DLPF_CFG in the CONFIG register unless + * BYPASS is specified in the name. If BYPASS is used, the DLPF is removed + * from the signal path and FCHOICE_B is set in GYRO_CONFIG register. */ +enum icm20602_gyro_dlpf { + ICM20602_GYRO_DLPF_250_HZ = 0, // data clocked at 8kHz + ICM20602_GYRO_DLPF_176_HZ = 1, // data clocked at 1kHz + ICM20602_GYRO_DLPF_92_HZ = 2, // data clocked at 1kHz + ICM20602_GYRO_DLPF_41_HZ = 3, // data clocked at 1kHz + ICM20602_GYRO_DLPF_20_HZ = 4, // data clocked at 1kHz + ICM20602_GYRO_DLPF_10_HZ = 5, // data clocked at 1kHz + ICM20602_GYRO_DLPF_5_HZ = 6, // data clocked at 1kHz + ICM20602_GYRO_DLPF_3281_HZ = 7, // data clocked at 8kHz + ICM20602_GYRO_DLPF_BYPASS_3281_HZ, // no filter, data clocked at 32kHz + ICM20602_GYRO_DLPF_BYPASS_8173_HZ, // no filter, data clocked at 32kHz +}; + +/** Enumerated value corresponds with FS_SEL in the GYRO_CONFIG register. + * Values listed are the full +/- DPS range. */ +enum icm20602_gyro_dps { + ICM20602_GYRO_RANGE_250_DPS = 0, + ICM20602_GYRO_RANGE_500_DPS = 1, + ICM20602_GYRO_RANGE_1000_DPS = 2, + ICM20602_GYRO_RANGE_2000_DPS = 3, +}; + +/***** Structs *****/ + +struct icm20602_dev { + /// Identifier, can be I2C address, SPI CS line, or some other unique value. + uint8_t id; + + /// Required function pointer for register write function. + icm20602_hal_wr hal_wr; + /// Required function pointer for register read function. + icm20602_hal_rd hal_rd; + /// Required function pointer for system sleep/delay. + icm20602_hal_sleep hal_sleep; + + /// Optional function pointer to mutex lock if needed, NULL otherwise. + icm20602_mutex_lock mutex_lock; + /// Optional function pointer to mutex unlocking if needed, NULL otherwise. + icm20602_mutex_lock mutex_unlock; + + /// Set to "true" to configure the accelerometer. + bool use_accel; + /// Enable or disable fifo for accelerometer. + bool accel_fifo; + /// Select the digital low pass filter to use with the accelerometer. + enum icm20602_accel_dlpf accel_dlpf; + /// Select the accelerometer's g-force range. + enum icm20602_accel_g accel_g; + + /// Set to "true" to configure the gyroscope. + bool use_gyro; + /// Enable or disable fifo for gyroscope. + bool gyro_fifo; + /// Select the digital low pass filter to use with the gyroscope. + enum icm20602_gyro_dlpf gyro_dlpf; + /// Select the gyroscope's degrees per second range. + enum icm20602_gyro_dps gyro_dps; + + /// Divides the data clock for both the accelerometer and gyroscope. + uint8_t sample_rate_div; + + /// Disable hardware I2C communications to chip, recommeded if using SPI. + bool i2c_disable; +}; + +/***** Global Functions *****/ + +/** \brief Initializes the ICM20602 sensor. + * \param config pointer to configuration struct + * \return zero on success, anything else is an error + */ +extern int8_t +icm20602_init(struct icm20602_dev * dev); + +/** \brief Reads current G-force values of accelerometer. + * \param p_x destination for x G value + * \param p_y destination for y G value + * \param p_z destination for z G value + * \return zero on success, anything else is an error + */ +extern int8_t +icm20602_read_accel(struct icm20602_dev * dev, float * p_x, float * p_y, + float * p_z); + +/** \brief Reads current degrees per second values of gyroscope. + * \param p_x destination for x value + * \param p_y destination for y value + * \param p_z destination for z value + * \return zero on success, anything else is an error + */ +extern int8_t +icm20602_read_gyro(struct icm20602_dev * dev, float * p_x, float * p_y, + float * p_z); + +/** \brief Reads current values of accelerometer and gyroscope. + * \param p_ax destination for accelerometer x G value + * \param p_ay destination for accelerometer y G value + * \param p_az destination for accelerometer z G value + * \param p_gx destination for gyroscope x DPS value + * \param p_gy destination for gyroscope y DPS value + * \param p_gz destination for gyroscope z DPS value + * \param p_t destination for temperature degrees C value + * \return zero on success, anything else is an error + */ +extern int8_t +icm20602_read_data(struct icm20602_dev * dev, float * p_ax, float * p_ay, + float * p_az, float * p_gx, float * p_gy, float * p_gz, float * p_t); + +/** \brief Reads current raw values of accelerometer. + * \param p_x destination for x value + * \param p_y destination for y value + * \param p_z destination for z value + * \return zero on success, anything else is an error + */ +extern int8_t +icm20602_read_accel_raw(struct icm20602_dev * dev, int16_t * p_x, int16_t * p_y, + int16_t * p_z); + +/** \brief Reads current raw values of gyroscope. + * \param p_x destination for x value + * \param p_y destination for y value + * \param p_z destination for z value + * \return zero on success, anything else is an error + */ +extern int8_t +icm20602_read_gyro_raw(struct icm20602_dev * dev, int16_t * p_x, int16_t * p_y, + int16_t * p_z); + +/** \brief Reads current raw values of accelerometer and gyroscope. + * \param p_ax destination for accelerometer x value + * \param p_ay destination for accelerometer y value + * \param p_az destination for accelerometer z value + * \param p_gx destination for gyroscope x value + * \param p_gy destination for gyroscope y value + * \param p_gz destination for gyroscope z value + * \param p_t destination for temperature value + * \return zero on success, anything else is an error + */ +extern int8_t +icm20602_read_data_raw(struct icm20602_dev * dev, int16_t * p_ax, + int16_t * p_ay, int16_t * p_az, int16_t * p_gx, int16_t * p_gy, + int16_t * p_gz, int16_t * p_t); + +/** \brief Reads FIFO G-force values of accelerometer. + * \param p_x destination for x G value + * \param p_y destination for y G value + * \param p_z destination for z G value + * \return zero on success, anything else is an error + */ +extern int8_t +icm20602_read_accel_fifo(struct icm20602_dev * dev, float * x, float * y, + float * z); + +/** \brief Reads FIFO degrees per second values of gyroscope. + * \param p_x destination for x value + * \param p_y destination for y value + * \param p_z destination for z value + * \return zero on success, anything else is an error + */ +extern int8_t +icm20602_read_gyro_fifo(struct icm20602_dev * dev, float * x, float * y, + float * z); + +/** \brief Reads FIFO values of accelerometer and gyroscope. Note, both + * accelerometer and gyroscope fifos should be enabled if this + * function is to be used. + * \param p_ax destination for accelerometer x G value + * \param p_ay destination for accelerometer y G value + * \param p_az destination for accelerometer z G value + * \param p_gx destination for gyroscope x DPS value + * \param p_gy destination for gyroscope y DPS value + * \param p_gz destination for gyroscope z DPS value + * \param p_t destination for temperature degrees C value + * \return zero on success, anything else is an error + */ +extern int8_t +icm20602_read_fifo_data(struct icm20602_dev * dev, float * p_ax, float * p_ay, + float * p_az, float * p_gx, float * p_gy, float * p_gz, float * p_t); + +/** \brief Reads FIFO raw values of accelerometer. + * \param p_x destination for x value + * \param p_y destination for y value + * \param p_z destination for z value + * \return zero on success, anything else is an error + */ +extern int8_t +icm20602_read_fifo_accel_raw(struct icm20602_dev * dev, int16_t * p_x, + int16_t * p_y, int16_t * p_z); + +/** \brief Reads FIFO raw values of gyroscope. + * \param p_x destination for x value + * \param p_y destination for y value + * \param p_z destination for z value + * \return zero on success, anything else is an error + */ +extern int8_t +icm20602_read_fifo_gyro_raw(struct icm20602_dev * dev, int16_t * p_x, + int16_t * p_y, int16_t * p_z); + +/** \brief Reads FIFO raw values of accelerometer and gyroscope. Note, both + * accelerometer and gyroscope fifos should be enabled if this + * function is to be used. + * \param p_ax destination for accelerometer x value + * \param p_ay destination for accelerometer y value + * \param p_az destination for accelerometer z value + * \param p_gx destination for gyroscope x value + * \param p_gy destination for gyroscope y value + * \param p_gz destination for gyroscope z value + * \param p_t destination for temperature value + * \return zero on success, anything else is an error + */ +extern int8_t +icm20602_read_fifo_data_raw(struct icm20602_dev * dev, int16_t * p_ax, + int16_t * p_ay, int16_t * p_az, int16_t * p_gx, int16_t * p_gy, + int16_t * p_gz, int16_t * p_t); + +#endif diff --git a/lib/crc32/Crc32.cpp b/lib/crc32/Crc32.cpp new file mode 100644 index 0000000..95ae943 --- /dev/null +++ b/lib/crc32/Crc32.cpp @@ -0,0 +1,1247 @@ +// ////////////////////////////////////////////////////////// +// Crc32.cpp +// Copyright (c) 2011-2019 Stephan Brumme. All rights reserved. +// Slicing-by-16 contributed by Bulat Ziganshin +// Tableless bytewise CRC contributed by Hagai Gold +// see http://create.stephan-brumme.com/disclaimer.html +// + +// if running on an embedded system, you might consider shrinking the +// big Crc32Lookup table: +// - crc32_bitwise doesn't need it at all +// - crc32_halfbyte has its own small lookup table +// - crc32_1byte needs only Crc32Lookup[0] +// - crc32_4bytes needs only Crc32Lookup[0..3] +// - crc32_8bytes needs only Crc32Lookup[0..7] +// - crc32_4x8bytes needs only Crc32Lookup[0..7] +// - crc32_16bytes needs all of Crc32Lookup + +// Manually define it cos PlatformIO is too hard right now +#define __BYTE_ORDER 1234 + +#include "Crc32.h" + +#ifndef __LITTLE_ENDIAN + #define __LITTLE_ENDIAN 1234 +#endif +#ifndef __BIG_ENDIAN + #define __BIG_ENDIAN 4321 +#endif + +// define endianess and some integer data types +#if defined(_MSC_VER) || defined(__MINGW32__) + // Windows always little endian + #define __BYTE_ORDER __LITTLE_ENDIAN + + // intrinsics / prefetching + #if defined(__MINGW32__) || defined(__clang__) + #define PREFETCH(location) __builtin_prefetch(location) + #else + #if defined(__SSE2__) + #include + #define PREFETCH(location) _mm_prefetch(location, _MM_HINT_T0) + #else + #define PREFETCH(location) ; + #endif + #endif +#else + // defines __BYTE_ORDER as __LITTLE_ENDIAN or __BIG_ENDIAN + #include + + // intrinsics / prefetching + #ifdef __GNUC__ + #define PREFETCH(location) __builtin_prefetch(location) + #else + // no prefetching + #define PREFETCH(location) ; + #endif +#endif + +// abort if byte order is undefined +#if !defined(__BYTE_ORDER) +#error undefined byte order, compile with -D__BYTE_ORDER=1234 (if little endian) or -D__BYTE_ORDER=4321 (big endian) +#endif + + +namespace +{ + /// zlib's CRC32 polynomial + const uint32_t Polynomial = 0xEDB88320; + +#if __BYTE_ORDER == __BIG_ENDIAN + /// swap endianess + static inline uint32_t swap(uint32_t x) + { + #if defined(__GNUC__) || defined(__clang__) + return __builtin_bswap32(x); + #else + return (x >> 24) | + ((x >> 8) & 0x0000FF00) | + ((x << 8) & 0x00FF0000) | + (x << 24); + #endif + } +#endif + + /// Slicing-By-16 + #ifdef CRC32_USE_LOOKUP_TABLE_SLICING_BY_16 + const size_t MaxSlice = 16; + #elif defined(CRC32_USE_LOOKUP_TABLE_SLICING_BY_8) + const size_t MaxSlice = 8; + #elif defined(CRC32_USE_LOOKUP_TABLE_SLICING_BY_4) + const size_t MaxSlice = 4; + #elif defined(CRC32_USE_LOOKUP_TABLE_BYTE) + const size_t MaxSlice = 1; + #else + #define NO_LUT // don't need Crc32Lookup at all + #endif + +} // anonymous namespace + +#ifndef NO_LUT +/// forward declaration, table is at the end of this file +extern const uint32_t Crc32Lookup[MaxSlice][256]; // extern is needed to keep compiler happy +#endif + + +/// compute CRC32 (bitwise algorithm) +uint32_t crc32_bitwise(const void* data, size_t length, uint32_t previousCrc32) +{ + uint32_t crc = ~previousCrc32; // same as previousCrc32 ^ 0xFFFFFFFF + const uint8_t* current = (const uint8_t*) data; + + while (length-- != 0) + { + crc ^= *current++; + + for (int j = 0; j < 8; j++) + { + // branch-free + crc = (crc >> 1) ^ (-int32_t(crc & 1) & Polynomial); + + // branching, much slower: + //if (crc & 1) + // crc = (crc >> 1) ^ Polynomial; + //else + // crc = crc >> 1; + } + } + + return ~crc; // same as crc ^ 0xFFFFFFFF +} + + +/// compute CRC32 (half-byte algoritm) +uint32_t crc32_halfbyte(const void* data, size_t length, uint32_t previousCrc32) +{ + uint32_t crc = ~previousCrc32; // same as previousCrc32 ^ 0xFFFFFFFF + const uint8_t* current = (const uint8_t*) data; + + /// look-up table for half-byte, same as crc32Lookup[0][16*i] + static const uint32_t Crc32Lookup16[16] = + { + 0x00000000,0x1DB71064,0x3B6E20C8,0x26D930AC,0x76DC4190,0x6B6B51F4,0x4DB26158,0x5005713C, + 0xEDB88320,0xF00F9344,0xD6D6A3E8,0xCB61B38C,0x9B64C2B0,0x86D3D2D4,0xA00AE278,0xBDBDF21C + }; + + while (length-- != 0) + { + crc = Crc32Lookup16[(crc ^ *current ) & 0x0F] ^ (crc >> 4); + crc = Crc32Lookup16[(crc ^ (*current >> 4)) & 0x0F] ^ (crc >> 4); + current++; + } + + return ~crc; // same as crc ^ 0xFFFFFFFF +} + + +#ifdef CRC32_USE_LOOKUP_TABLE_BYTE +/// compute CRC32 (standard algorithm) +uint32_t crc32_1byte(const void* data, size_t length, uint32_t previousCrc32) +{ + uint32_t crc = ~previousCrc32; // same as previousCrc32 ^ 0xFFFFFFFF + const uint8_t* current = (const uint8_t*) data; + + while (length-- != 0) + crc = (crc >> 8) ^ Crc32Lookup[0][(crc & 0xFF) ^ *current++]; + + return ~crc; // same as crc ^ 0xFFFFFFFF +} +#endif + + +/// compute CRC32 (byte algorithm) without lookup tables +uint32_t crc32_1byte_tableless(const void* data, size_t length, uint32_t previousCrc32) +{ + uint32_t crc = ~previousCrc32; // same as previousCrc32 ^ 0xFFFFFFFF + const uint8_t* current = (const uint8_t*) data; + + while (length-- != 0) + { + uint8_t s = uint8_t(crc) ^ *current++; + + // Hagai Gold made me aware of this table-less algorithm and send me code + + // polynomial 0xEDB88320 can be written in binary as 11101101101110001000001100100000b + // reverse the bits (or just assume bit 0 is the first one) + // and we have bits set at position 0, 1, 2, 4, 5, 7, 8, 10, 11, 12, 16, 22, 23, 26 + // => those are the shift offsets: + //crc = (crc >> 8) ^ + // t ^ + // (t >> 1) ^ (t >> 2) ^ (t >> 4) ^ (t >> 5) ^ // == y + // (t >> 7) ^ (t >> 8) ^ (t >> 10) ^ (t >> 11) ^ // == y >> 6 + // (t >> 12) ^ (t >> 16) ^ // == z + // (t >> 22) ^ (t >> 26) ^ // == z >> 10 + // (t >> 23); + + // the fastest I can come up with: + uint32_t low = (s ^ (s << 6)) & 0xFF; + uint32_t a = (low * ((1 << 23) + (1 << 14) + (1 << 2))); + crc = (crc >> 8) ^ + (low * ((1 << 24) + (1 << 16) + (1 << 8))) ^ + a ^ + (a >> 1) ^ + (low * ((1 << 20) + (1 << 12) )) ^ + (low << 19) ^ + (low << 17) ^ + (low >> 2); + + // Hagai's code: + /*uint32_t t = (s ^ (s << 6)) << 24; + + // some temporaries to optimize XOR + uint32_t x = (t >> 1) ^ (t >> 2); + uint32_t y = x ^ (x >> 3); + uint32_t z = (t >> 12) ^ (t >> 16); + + crc = (crc >> 8) ^ + t ^ (t >> 23) ^ + y ^ (y >> 6) ^ + z ^ (z >> 10);*/ + } + + return ~crc; // same as crc ^ 0xFFFFFFFF +} + + +/// compute CRC32 (byte algorithm) without lookup tables +uint32_t crc32_1byte_tableless2(const void* data, size_t length, uint32_t previousCrc32) +{ + int32_t crc = ~previousCrc32; // note: signed integer, right shift distributes sign bit into lower bits + const uint8_t* current = (const uint8_t*) data; + + while (length-- != 0) + { + crc = crc ^ *current++; + + uint32_t c = (((crc << 31) >> 31) & ((Polynomial >> 7) ^ (Polynomial >> 1))) ^ + (((crc << 30) >> 31) & ((Polynomial >> 6) ^ Polynomial)) ^ + (((crc << 29) >> 31) & (Polynomial >> 5)) ^ + (((crc << 28) >> 31) & (Polynomial >> 4)) ^ + (((crc << 27) >> 31) & (Polynomial >> 3)) ^ + (((crc << 26) >> 31) & (Polynomial >> 2)) ^ + (((crc << 25) >> 31) & (Polynomial >> 1)) ^ + (((crc << 24) >> 31) & Polynomial); + + crc = ((uint32_t)crc >> 8) ^ c; // convert to unsigned integer before right shift + } + + return ~crc; // same as crc ^ 0xFFFFFFFF +} + + +#ifdef CRC32_USE_LOOKUP_TABLE_SLICING_BY_4 +/// compute CRC32 (Slicing-by-4 algorithm) +uint32_t crc32_4bytes(const void* data, size_t length, uint32_t previousCrc32) +{ + uint32_t crc = ~previousCrc32; // same as previousCrc32 ^ 0xFFFFFFFF + const uint32_t* current = (const uint32_t*) data; + + // process four bytes at once (Slicing-by-4) + while (length >= 4) + { +#if __BYTE_ORDER == __BIG_ENDIAN + uint32_t one = *current++ ^ swap(crc); + crc = Crc32Lookup[0][ one & 0xFF] ^ + Crc32Lookup[1][(one>> 8) & 0xFF] ^ + Crc32Lookup[2][(one>>16) & 0xFF] ^ + Crc32Lookup[3][(one>>24) & 0xFF]; +#else + uint32_t one = *current++ ^ crc; + crc = Crc32Lookup[0][(one>>24) & 0xFF] ^ + Crc32Lookup[1][(one>>16) & 0xFF] ^ + Crc32Lookup[2][(one>> 8) & 0xFF] ^ + Crc32Lookup[3][ one & 0xFF]; +#endif + + length -= 4; + } + + const uint8_t* currentChar = (const uint8_t*) current; + // remaining 1 to 3 bytes (standard algorithm) + while (length-- != 0) + crc = (crc >> 8) ^ Crc32Lookup[0][(crc & 0xFF) ^ *currentChar++]; + + return ~crc; // same as crc ^ 0xFFFFFFFF +} +#endif + + +#ifdef CRC32_USE_LOOKUP_TABLE_SLICING_BY_8 +/// compute CRC32 (Slicing-by-8 algorithm) +uint32_t crc32_8bytes(const void* data, size_t length, uint32_t previousCrc32) +{ + uint32_t crc = ~previousCrc32; // same as previousCrc32 ^ 0xFFFFFFFF + const uint32_t* current = (const uint32_t*) data; + + // process eight bytes at once (Slicing-by-8) + while (length >= 8) + { +#if __BYTE_ORDER == __BIG_ENDIAN + uint32_t one = *current++ ^ swap(crc); + uint32_t two = *current++; + crc = Crc32Lookup[0][ two & 0xFF] ^ + Crc32Lookup[1][(two>> 8) & 0xFF] ^ + Crc32Lookup[2][(two>>16) & 0xFF] ^ + Crc32Lookup[3][(two>>24) & 0xFF] ^ + Crc32Lookup[4][ one & 0xFF] ^ + Crc32Lookup[5][(one>> 8) & 0xFF] ^ + Crc32Lookup[6][(one>>16) & 0xFF] ^ + Crc32Lookup[7][(one>>24) & 0xFF]; +#else + uint32_t one = *current++ ^ crc; + uint32_t two = *current++; + crc = Crc32Lookup[0][(two>>24) & 0xFF] ^ + Crc32Lookup[1][(two>>16) & 0xFF] ^ + Crc32Lookup[2][(two>> 8) & 0xFF] ^ + Crc32Lookup[3][ two & 0xFF] ^ + Crc32Lookup[4][(one>>24) & 0xFF] ^ + Crc32Lookup[5][(one>>16) & 0xFF] ^ + Crc32Lookup[6][(one>> 8) & 0xFF] ^ + Crc32Lookup[7][ one & 0xFF]; +#endif + + length -= 8; + } + + const uint8_t* currentChar = (const uint8_t*) current; + // remaining 1 to 7 bytes (standard algorithm) + while (length-- != 0) + crc = (crc >> 8) ^ Crc32Lookup[0][(crc & 0xFF) ^ *currentChar++]; + + return ~crc; // same as crc ^ 0xFFFFFFFF +} + + +/// compute CRC32 (Slicing-by-8 algorithm), unroll inner loop 4 times +uint32_t crc32_4x8bytes(const void* data, size_t length, uint32_t previousCrc32) +{ + uint32_t crc = ~previousCrc32; // same as previousCrc32 ^ 0xFFFFFFFF + const uint32_t* current = (const uint32_t*) data; + + // enabling optimization (at least -O2) automatically unrolls the inner for-loop + const size_t Unroll = 4; + const size_t BytesAtOnce = 8 * Unroll; + + // process 4x eight bytes at once (Slicing-by-8) + while (length >= BytesAtOnce) + { + for (size_t unrolling = 0; unrolling < Unroll; unrolling++) + { +#if __BYTE_ORDER == __BIG_ENDIAN + uint32_t one = *current++ ^ swap(crc); + uint32_t two = *current++; + crc = Crc32Lookup[0][ two & 0xFF] ^ + Crc32Lookup[1][(two>> 8) & 0xFF] ^ + Crc32Lookup[2][(two>>16) & 0xFF] ^ + Crc32Lookup[3][(two>>24) & 0xFF] ^ + Crc32Lookup[4][ one & 0xFF] ^ + Crc32Lookup[5][(one>> 8) & 0xFF] ^ + Crc32Lookup[6][(one>>16) & 0xFF] ^ + Crc32Lookup[7][(one>>24) & 0xFF]; +#else + uint32_t one = *current++ ^ crc; + uint32_t two = *current++; + crc = Crc32Lookup[0][(two>>24) & 0xFF] ^ + Crc32Lookup[1][(two>>16) & 0xFF] ^ + Crc32Lookup[2][(two>> 8) & 0xFF] ^ + Crc32Lookup[3][ two & 0xFF] ^ + Crc32Lookup[4][(one>>24) & 0xFF] ^ + Crc32Lookup[5][(one>>16) & 0xFF] ^ + Crc32Lookup[6][(one>> 8) & 0xFF] ^ + Crc32Lookup[7][ one & 0xFF]; +#endif + + } + + length -= BytesAtOnce; + } + + const uint8_t* currentChar = (const uint8_t*) current; + // remaining 1 to 31 bytes (standard algorithm) + while (length-- != 0) + crc = (crc >> 8) ^ Crc32Lookup[0][(crc & 0xFF) ^ *currentChar++]; + + return ~crc; // same as crc ^ 0xFFFFFFFF +} +#endif // CRC32_USE_LOOKUP_TABLE_SLICING_BY_8 + + +#ifdef CRC32_USE_LOOKUP_TABLE_SLICING_BY_16 +/// compute CRC32 (Slicing-by-16 algorithm) +uint32_t crc32_16bytes(const void* data, size_t length, uint32_t previousCrc32) +{ + uint32_t crc = ~previousCrc32; // same as previousCrc32 ^ 0xFFFFFFFF + const uint32_t* current = (const uint32_t*) data; + + // enabling optimization (at least -O2) automatically unrolls the inner for-loop + const size_t Unroll = 4; + const size_t BytesAtOnce = 16 * Unroll; + + while (length >= BytesAtOnce) + { + for (size_t unrolling = 0; unrolling < Unroll; unrolling++) + { +#if __BYTE_ORDER == __BIG_ENDIAN + uint32_t one = *current++ ^ swap(crc); + uint32_t two = *current++; + uint32_t three = *current++; + uint32_t four = *current++; + crc = Crc32Lookup[ 0][ four & 0xFF] ^ + Crc32Lookup[ 1][(four >> 8) & 0xFF] ^ + Crc32Lookup[ 2][(four >> 16) & 0xFF] ^ + Crc32Lookup[ 3][(four >> 24) & 0xFF] ^ + Crc32Lookup[ 4][ three & 0xFF] ^ + Crc32Lookup[ 5][(three >> 8) & 0xFF] ^ + Crc32Lookup[ 6][(three >> 16) & 0xFF] ^ + Crc32Lookup[ 7][(three >> 24) & 0xFF] ^ + Crc32Lookup[ 8][ two & 0xFF] ^ + Crc32Lookup[ 9][(two >> 8) & 0xFF] ^ + Crc32Lookup[10][(two >> 16) & 0xFF] ^ + Crc32Lookup[11][(two >> 24) & 0xFF] ^ + Crc32Lookup[12][ one & 0xFF] ^ + Crc32Lookup[13][(one >> 8) & 0xFF] ^ + Crc32Lookup[14][(one >> 16) & 0xFF] ^ + Crc32Lookup[15][(one >> 24) & 0xFF]; +#else + uint32_t one = *current++ ^ crc; + uint32_t two = *current++; + uint32_t three = *current++; + uint32_t four = *current++; + crc = Crc32Lookup[ 0][(four >> 24) & 0xFF] ^ + Crc32Lookup[ 1][(four >> 16) & 0xFF] ^ + Crc32Lookup[ 2][(four >> 8) & 0xFF] ^ + Crc32Lookup[ 3][ four & 0xFF] ^ + Crc32Lookup[ 4][(three >> 24) & 0xFF] ^ + Crc32Lookup[ 5][(three >> 16) & 0xFF] ^ + Crc32Lookup[ 6][(three >> 8) & 0xFF] ^ + Crc32Lookup[ 7][ three & 0xFF] ^ + Crc32Lookup[ 8][(two >> 24) & 0xFF] ^ + Crc32Lookup[ 9][(two >> 16) & 0xFF] ^ + Crc32Lookup[10][(two >> 8) & 0xFF] ^ + Crc32Lookup[11][ two & 0xFF] ^ + Crc32Lookup[12][(one >> 24) & 0xFF] ^ + Crc32Lookup[13][(one >> 16) & 0xFF] ^ + Crc32Lookup[14][(one >> 8) & 0xFF] ^ + Crc32Lookup[15][ one & 0xFF]; +#endif + } + + length -= BytesAtOnce; + } + + const uint8_t* currentChar = (const uint8_t*) current; + // remaining 1 to 63 bytes (standard algorithm) + while (length-- != 0) + crc = (crc >> 8) ^ Crc32Lookup[0][(crc & 0xFF) ^ *currentChar++]; + + return ~crc; // same as crc ^ 0xFFFFFFFF +} + + +/// compute CRC32 (Slicing-by-16 algorithm, prefetch upcoming data blocks) +uint32_t crc32_16bytes_prefetch(const void* data, size_t length, uint32_t previousCrc32, size_t prefetchAhead) +{ + // CRC code is identical to crc32_16bytes (including unrolling), only added prefetching + // 256 bytes look-ahead seems to be the sweet spot on Core i7 CPUs + + uint32_t crc = ~previousCrc32; // same as previousCrc32 ^ 0xFFFFFFFF + const uint32_t* current = (const uint32_t*) data; + + // enabling optimization (at least -O2) automatically unrolls the for-loop + const size_t Unroll = 4; + const size_t BytesAtOnce = 16 * Unroll; + + while (length >= BytesAtOnce + prefetchAhead) + { + PREFETCH(((const char*) current) + prefetchAhead); + + for (size_t unrolling = 0; unrolling < Unroll; unrolling++) + { +#if __BYTE_ORDER == __BIG_ENDIAN + uint32_t one = *current++ ^ swap(crc); + uint32_t two = *current++; + uint32_t three = *current++; + uint32_t four = *current++; + crc = Crc32Lookup[ 0][ four & 0xFF] ^ + Crc32Lookup[ 1][(four >> 8) & 0xFF] ^ + Crc32Lookup[ 2][(four >> 16) & 0xFF] ^ + Crc32Lookup[ 3][(four >> 24) & 0xFF] ^ + Crc32Lookup[ 4][ three & 0xFF] ^ + Crc32Lookup[ 5][(three >> 8) & 0xFF] ^ + Crc32Lookup[ 6][(three >> 16) & 0xFF] ^ + Crc32Lookup[ 7][(three >> 24) & 0xFF] ^ + Crc32Lookup[ 8][ two & 0xFF] ^ + Crc32Lookup[ 9][(two >> 8) & 0xFF] ^ + Crc32Lookup[10][(two >> 16) & 0xFF] ^ + Crc32Lookup[11][(two >> 24) & 0xFF] ^ + Crc32Lookup[12][ one & 0xFF] ^ + Crc32Lookup[13][(one >> 8) & 0xFF] ^ + Crc32Lookup[14][(one >> 16) & 0xFF] ^ + Crc32Lookup[15][(one >> 24) & 0xFF]; +#else + uint32_t one = *current++ ^ crc; + uint32_t two = *current++; + uint32_t three = *current++; + uint32_t four = *current++; + crc = Crc32Lookup[ 0][(four >> 24) & 0xFF] ^ + Crc32Lookup[ 1][(four >> 16) & 0xFF] ^ + Crc32Lookup[ 2][(four >> 8) & 0xFF] ^ + Crc32Lookup[ 3][ four & 0xFF] ^ + Crc32Lookup[ 4][(three >> 24) & 0xFF] ^ + Crc32Lookup[ 5][(three >> 16) & 0xFF] ^ + Crc32Lookup[ 6][(three >> 8) & 0xFF] ^ + Crc32Lookup[ 7][ three & 0xFF] ^ + Crc32Lookup[ 8][(two >> 24) & 0xFF] ^ + Crc32Lookup[ 9][(two >> 16) & 0xFF] ^ + Crc32Lookup[10][(two >> 8) & 0xFF] ^ + Crc32Lookup[11][ two & 0xFF] ^ + Crc32Lookup[12][(one >> 24) & 0xFF] ^ + Crc32Lookup[13][(one >> 16) & 0xFF] ^ + Crc32Lookup[14][(one >> 8) & 0xFF] ^ + Crc32Lookup[15][ one & 0xFF]; +#endif + } + + length -= BytesAtOnce; + } + + const uint8_t* currentChar = (const uint8_t*) current; + // remaining 1 to 63 bytes (standard algorithm) + while (length-- != 0) + crc = (crc >> 8) ^ Crc32Lookup[0][(crc & 0xFF) ^ *currentChar++]; + + return ~crc; // same as crc ^ 0xFFFFFFFF +} +#endif + + +/// compute CRC32 using the fastest algorithm for large datasets on modern CPUs +uint32_t crc32_fast(const void* data, size_t length, uint32_t previousCrc32) +{ +#ifdef CRC32_USE_LOOKUP_TABLE_SLICING_BY_16 + return crc32_16bytes (data, length, previousCrc32); +#elif defined(CRC32_USE_LOOKUP_TABLE_SLICING_BY_8) + return crc32_8bytes (data, length, previousCrc32); +#elif defined(CRC32_USE_LOOKUP_TABLE_SLICING_BY_4) + return crc32_4bytes (data, length, previousCrc32); +#elif defined(CRC32_USE_LOOKUP_TABLE_BYTE) + return crc32_1byte (data, length, previousCrc32); +#else + return crc32_halfbyte(data, length, previousCrc32); +#endif +} + + +/// merge two CRC32 such that result = crc32(dataB, lengthB, crc32(dataA, lengthA)) +uint32_t crc32_combine(uint32_t crcA, uint32_t crcB, size_t lengthB) +{ + // based on Mark Adler's crc_combine from + // https://github.com/madler/pigz/blob/master/pigz.c + + // main idea: + // - if you have two equally-sized blocks A and B, + // then you can create a block C = A ^ B + // which has the property crc(C) = crc(A) ^ crc(B) + // - if you append length(B) zeros to A and call it A' (think of it as AAAA000) + // and prepend length(A) zeros to B and call it B' (think of it as 0000BBB) + // then exists a C' = A' ^ B' + // - remember: if you XOR someting with zero, it remains unchanged: X ^ 0 = X + // - that means C' = A concat B so that crc(A concat B) = crc(C') = crc(A') ^ crc(B') + // - the trick is to compute crc(A') based on crc(A) + // and crc(B') based on crc(B) + // - since B' starts with many zeros, the crc of those initial zeros is still zero + // - that means crc(B') = crc(B) + // - unfortunately the trailing zeros of A' change the crc, so usually crc(A') != crc(A) + // - the following code is a fast algorithm to compute crc(A') + // - starting with crc(A) and appending length(B) zeros, needing just log2(length(B)) iterations + // - the details are explained by the original author at + // https://stackoverflow.com/questions/23122312/crc-calculation-of-a-mostly-static-data-stream/23126768 + // + // notes: + // - I squeezed everything into one function to keep global namespace clean (original code two helper functions) + // - most original comments are still in place, I added comments where these helper functions where made inline code + // - performance-wise there isn't any differenze to the original zlib/pigz code + + // degenerated case + if (lengthB == 0) + return crcA; + + /// CRC32 => 32 bits + const uint32_t CrcBits = 32; + + uint32_t odd [CrcBits]; // odd-power-of-two zeros operator + uint32_t even[CrcBits]; // even-power-of-two zeros operator + + // put operator for one zero bit in odd + odd[0] = Polynomial; // CRC-32 polynomial + for (int i = 1; i < (int)CrcBits; i++) + odd[i] = 1 << (i - 1); + + // put operator for two zero bits in even + // same as gf2_matrix_square(even, odd); + for (int i = 0; i < (int)CrcBits; i++) + { + uint32_t vec = odd[i]; + even[i] = 0; + for (int j = 0; vec != 0; j++, vec >>= 1) + if (vec & 1) + even[i] ^= odd[j]; + } + // put operator for four zero bits in odd + // same as gf2_matrix_square(odd, even); + for (int i = 0; i < (int)CrcBits; i++) + { + uint32_t vec = even[i]; + odd[i] = 0; + for (int j = 0; vec != 0; j++, vec >>= 1) + if (vec & 1) + odd[i] ^= even[j]; + } + + // the following loop becomes much shorter if I keep swapping even and odd + uint32_t* a = even; + uint32_t* b = odd; + // apply secondLength zeros to firstCrc32 + for (; lengthB > 0; lengthB >>= 1) + { + // same as gf2_matrix_square(a, b); + for (int i = 0; i < (int)CrcBits; i++) + { + uint32_t vec = b[i]; + a[i] = 0; + for (int j = 0; vec != 0; j++, vec >>= 1) + if (vec & 1) + a[i] ^= b[j]; + } + + // apply zeros operator for this bit + if (lengthB & 1) + { + // same as firstCrc32 = gf2_matrix_times(a, firstCrc32); + uint32_t sum = 0; + for (int i = 0; crcA != 0; i++, crcA >>= 1) + if (crcA & 1) + sum ^= a[i]; + crcA = sum; + } + + // switch even and odd + uint32_t* t = a; a = b; b = t; + } + + // return combined crc + return crcA ^ crcB; +} + + +// ////////////////////////////////////////////////////////// +// constants + + +#ifndef NO_LUT +/// look-up table, already declared above +const uint32_t Crc32Lookup[MaxSlice][256] = +{ + //// same algorithm as crc32_bitwise + //for (int i = 0; i <= 0xFF; i++) + //{ + // uint32_t crc = i; + // for (int j = 0; j < 8; j++) + // crc = (crc >> 1) ^ ((crc & 1) * Polynomial); + // Crc32Lookup[0][i] = crc; + //} + //// ... and the following slicing-by-8 algorithm (from Intel): + //// http://www.intel.com/technology/comms/perfnet/download/CRC_generators.pdf + //// http://sourceforge.net/projects/slicing-by-8/ + //for (int slice = 1; slice < MaxSlice; slice++) + // Crc32Lookup[slice][i] = (Crc32Lookup[slice - 1][i] >> 8) ^ Crc32Lookup[0][Crc32Lookup[slice - 1][i] & 0xFF]; + { + // note: the first number of every second row corresponds to the half-byte look-up table ! + 0x00000000,0x77073096,0xEE0E612C,0x990951BA,0x076DC419,0x706AF48F,0xE963A535,0x9E6495A3, + 0x0EDB8832,0x79DCB8A4,0xE0D5E91E,0x97D2D988,0x09B64C2B,0x7EB17CBD,0xE7B82D07,0x90BF1D91, + 0x1DB71064,0x6AB020F2,0xF3B97148,0x84BE41DE,0x1ADAD47D,0x6DDDE4EB,0xF4D4B551,0x83D385C7, + 0x136C9856,0x646BA8C0,0xFD62F97A,0x8A65C9EC,0x14015C4F,0x63066CD9,0xFA0F3D63,0x8D080DF5, + 0x3B6E20C8,0x4C69105E,0xD56041E4,0xA2677172,0x3C03E4D1,0x4B04D447,0xD20D85FD,0xA50AB56B, + 0x35B5A8FA,0x42B2986C,0xDBBBC9D6,0xACBCF940,0x32D86CE3,0x45DF5C75,0xDCD60DCF,0xABD13D59, + 0x26D930AC,0x51DE003A,0xC8D75180,0xBFD06116,0x21B4F4B5,0x56B3C423,0xCFBA9599,0xB8BDA50F, + 0x2802B89E,0x5F058808,0xC60CD9B2,0xB10BE924,0x2F6F7C87,0x58684C11,0xC1611DAB,0xB6662D3D, + 0x76DC4190,0x01DB7106,0x98D220BC,0xEFD5102A,0x71B18589,0x06B6B51F,0x9FBFE4A5,0xE8B8D433, + 0x7807C9A2,0x0F00F934,0x9609A88E,0xE10E9818,0x7F6A0DBB,0x086D3D2D,0x91646C97,0xE6635C01, + 0x6B6B51F4,0x1C6C6162,0x856530D8,0xF262004E,0x6C0695ED,0x1B01A57B,0x8208F4C1,0xF50FC457, + 0x65B0D9C6,0x12B7E950,0x8BBEB8EA,0xFCB9887C,0x62DD1DDF,0x15DA2D49,0x8CD37CF3,0xFBD44C65, + 0x4DB26158,0x3AB551CE,0xA3BC0074,0xD4BB30E2,0x4ADFA541,0x3DD895D7,0xA4D1C46D,0xD3D6F4FB, + 0x4369E96A,0x346ED9FC,0xAD678846,0xDA60B8D0,0x44042D73,0x33031DE5,0xAA0A4C5F,0xDD0D7CC9, + 0x5005713C,0x270241AA,0xBE0B1010,0xC90C2086,0x5768B525,0x206F85B3,0xB966D409,0xCE61E49F, + 0x5EDEF90E,0x29D9C998,0xB0D09822,0xC7D7A8B4,0x59B33D17,0x2EB40D81,0xB7BD5C3B,0xC0BA6CAD, + 0xEDB88320,0x9ABFB3B6,0x03B6E20C,0x74B1D29A,0xEAD54739,0x9DD277AF,0x04DB2615,0x73DC1683, + 0xE3630B12,0x94643B84,0x0D6D6A3E,0x7A6A5AA8,0xE40ECF0B,0x9309FF9D,0x0A00AE27,0x7D079EB1, + 0xF00F9344,0x8708A3D2,0x1E01F268,0x6906C2FE,0xF762575D,0x806567CB,0x196C3671,0x6E6B06E7, + 0xFED41B76,0x89D32BE0,0x10DA7A5A,0x67DD4ACC,0xF9B9DF6F,0x8EBEEFF9,0x17B7BE43,0x60B08ED5, + 0xD6D6A3E8,0xA1D1937E,0x38D8C2C4,0x4FDFF252,0xD1BB67F1,0xA6BC5767,0x3FB506DD,0x48B2364B, + 0xD80D2BDA,0xAF0A1B4C,0x36034AF6,0x41047A60,0xDF60EFC3,0xA867DF55,0x316E8EEF,0x4669BE79, + 0xCB61B38C,0xBC66831A,0x256FD2A0,0x5268E236,0xCC0C7795,0xBB0B4703,0x220216B9,0x5505262F, + 0xC5BA3BBE,0xB2BD0B28,0x2BB45A92,0x5CB36A04,0xC2D7FFA7,0xB5D0CF31,0x2CD99E8B,0x5BDEAE1D, + 0x9B64C2B0,0xEC63F226,0x756AA39C,0x026D930A,0x9C0906A9,0xEB0E363F,0x72076785,0x05005713, + 0x95BF4A82,0xE2B87A14,0x7BB12BAE,0x0CB61B38,0x92D28E9B,0xE5D5BE0D,0x7CDCEFB7,0x0BDBDF21, + 0x86D3D2D4,0xF1D4E242,0x68DDB3F8,0x1FDA836E,0x81BE16CD,0xF6B9265B,0x6FB077E1,0x18B74777, + 0x88085AE6,0xFF0F6A70,0x66063BCA,0x11010B5C,0x8F659EFF,0xF862AE69,0x616BFFD3,0x166CCF45, + 0xA00AE278,0xD70DD2EE,0x4E048354,0x3903B3C2,0xA7672661,0xD06016F7,0x4969474D,0x3E6E77DB, + 0xAED16A4A,0xD9D65ADC,0x40DF0B66,0x37D83BF0,0xA9BCAE53,0xDEBB9EC5,0x47B2CF7F,0x30B5FFE9, + 0xBDBDF21C,0xCABAC28A,0x53B39330,0x24B4A3A6,0xBAD03605,0xCDD70693,0x54DE5729,0x23D967BF, + 0xB3667A2E,0xC4614AB8,0x5D681B02,0x2A6F2B94,0xB40BBE37,0xC30C8EA1,0x5A05DF1B,0x2D02EF8D, + } + +#if defined(CRC32_USE_LOOKUP_TABLE_SLICING_BY_4) || defined(CRC32_USE_LOOKUP_TABLE_SLICING_BY_8) || defined(CRC32_USE_LOOKUP_TABLE_SLICING_BY_16) + // beyond this point only relevant for Slicing-by-4, Slicing-by-8 and Slicing-by-16 + ,{ + 0x00000000,0x191B3141,0x32366282,0x2B2D53C3,0x646CC504,0x7D77F445,0x565AA786,0x4F4196C7, + 0xC8D98A08,0xD1C2BB49,0xFAEFE88A,0xE3F4D9CB,0xACB54F0C,0xB5AE7E4D,0x9E832D8E,0x87981CCF, + 0x4AC21251,0x53D92310,0x78F470D3,0x61EF4192,0x2EAED755,0x37B5E614,0x1C98B5D7,0x05838496, + 0x821B9859,0x9B00A918,0xB02DFADB,0xA936CB9A,0xE6775D5D,0xFF6C6C1C,0xD4413FDF,0xCD5A0E9E, + 0x958424A2,0x8C9F15E3,0xA7B24620,0xBEA97761,0xF1E8E1A6,0xE8F3D0E7,0xC3DE8324,0xDAC5B265, + 0x5D5DAEAA,0x44469FEB,0x6F6BCC28,0x7670FD69,0x39316BAE,0x202A5AEF,0x0B07092C,0x121C386D, + 0xDF4636F3,0xC65D07B2,0xED705471,0xF46B6530,0xBB2AF3F7,0xA231C2B6,0x891C9175,0x9007A034, + 0x179FBCFB,0x0E848DBA,0x25A9DE79,0x3CB2EF38,0x73F379FF,0x6AE848BE,0x41C51B7D,0x58DE2A3C, + 0xF0794F05,0xE9627E44,0xC24F2D87,0xDB541CC6,0x94158A01,0x8D0EBB40,0xA623E883,0xBF38D9C2, + 0x38A0C50D,0x21BBF44C,0x0A96A78F,0x138D96CE,0x5CCC0009,0x45D73148,0x6EFA628B,0x77E153CA, + 0xBABB5D54,0xA3A06C15,0x888D3FD6,0x91960E97,0xDED79850,0xC7CCA911,0xECE1FAD2,0xF5FACB93, + 0x7262D75C,0x6B79E61D,0x4054B5DE,0x594F849F,0x160E1258,0x0F152319,0x243870DA,0x3D23419B, + 0x65FD6BA7,0x7CE65AE6,0x57CB0925,0x4ED03864,0x0191AEA3,0x188A9FE2,0x33A7CC21,0x2ABCFD60, + 0xAD24E1AF,0xB43FD0EE,0x9F12832D,0x8609B26C,0xC94824AB,0xD05315EA,0xFB7E4629,0xE2657768, + 0x2F3F79F6,0x362448B7,0x1D091B74,0x04122A35,0x4B53BCF2,0x52488DB3,0x7965DE70,0x607EEF31, + 0xE7E6F3FE,0xFEFDC2BF,0xD5D0917C,0xCCCBA03D,0x838A36FA,0x9A9107BB,0xB1BC5478,0xA8A76539, + 0x3B83984B,0x2298A90A,0x09B5FAC9,0x10AECB88,0x5FEF5D4F,0x46F46C0E,0x6DD93FCD,0x74C20E8C, + 0xF35A1243,0xEA412302,0xC16C70C1,0xD8774180,0x9736D747,0x8E2DE606,0xA500B5C5,0xBC1B8484, + 0x71418A1A,0x685ABB5B,0x4377E898,0x5A6CD9D9,0x152D4F1E,0x0C367E5F,0x271B2D9C,0x3E001CDD, + 0xB9980012,0xA0833153,0x8BAE6290,0x92B553D1,0xDDF4C516,0xC4EFF457,0xEFC2A794,0xF6D996D5, + 0xAE07BCE9,0xB71C8DA8,0x9C31DE6B,0x852AEF2A,0xCA6B79ED,0xD37048AC,0xF85D1B6F,0xE1462A2E, + 0x66DE36E1,0x7FC507A0,0x54E85463,0x4DF36522,0x02B2F3E5,0x1BA9C2A4,0x30849167,0x299FA026, + 0xE4C5AEB8,0xFDDE9FF9,0xD6F3CC3A,0xCFE8FD7B,0x80A96BBC,0x99B25AFD,0xB29F093E,0xAB84387F, + 0x2C1C24B0,0x350715F1,0x1E2A4632,0x07317773,0x4870E1B4,0x516BD0F5,0x7A468336,0x635DB277, + 0xCBFAD74E,0xD2E1E60F,0xF9CCB5CC,0xE0D7848D,0xAF96124A,0xB68D230B,0x9DA070C8,0x84BB4189, + 0x03235D46,0x1A386C07,0x31153FC4,0x280E0E85,0x674F9842,0x7E54A903,0x5579FAC0,0x4C62CB81, + 0x8138C51F,0x9823F45E,0xB30EA79D,0xAA1596DC,0xE554001B,0xFC4F315A,0xD7626299,0xCE7953D8, + 0x49E14F17,0x50FA7E56,0x7BD72D95,0x62CC1CD4,0x2D8D8A13,0x3496BB52,0x1FBBE891,0x06A0D9D0, + 0x5E7EF3EC,0x4765C2AD,0x6C48916E,0x7553A02F,0x3A1236E8,0x230907A9,0x0824546A,0x113F652B, + 0x96A779E4,0x8FBC48A5,0xA4911B66,0xBD8A2A27,0xF2CBBCE0,0xEBD08DA1,0xC0FDDE62,0xD9E6EF23, + 0x14BCE1BD,0x0DA7D0FC,0x268A833F,0x3F91B27E,0x70D024B9,0x69CB15F8,0x42E6463B,0x5BFD777A, + 0xDC656BB5,0xC57E5AF4,0xEE530937,0xF7483876,0xB809AEB1,0xA1129FF0,0x8A3FCC33,0x9324FD72, + }, + + { + 0x00000000,0x01C26A37,0x0384D46E,0x0246BE59,0x0709A8DC,0x06CBC2EB,0x048D7CB2,0x054F1685, + 0x0E1351B8,0x0FD13B8F,0x0D9785D6,0x0C55EFE1,0x091AF964,0x08D89353,0x0A9E2D0A,0x0B5C473D, + 0x1C26A370,0x1DE4C947,0x1FA2771E,0x1E601D29,0x1B2F0BAC,0x1AED619B,0x18ABDFC2,0x1969B5F5, + 0x1235F2C8,0x13F798FF,0x11B126A6,0x10734C91,0x153C5A14,0x14FE3023,0x16B88E7A,0x177AE44D, + 0x384D46E0,0x398F2CD7,0x3BC9928E,0x3A0BF8B9,0x3F44EE3C,0x3E86840B,0x3CC03A52,0x3D025065, + 0x365E1758,0x379C7D6F,0x35DAC336,0x3418A901,0x3157BF84,0x3095D5B3,0x32D36BEA,0x331101DD, + 0x246BE590,0x25A98FA7,0x27EF31FE,0x262D5BC9,0x23624D4C,0x22A0277B,0x20E69922,0x2124F315, + 0x2A78B428,0x2BBADE1F,0x29FC6046,0x283E0A71,0x2D711CF4,0x2CB376C3,0x2EF5C89A,0x2F37A2AD, + 0x709A8DC0,0x7158E7F7,0x731E59AE,0x72DC3399,0x7793251C,0x76514F2B,0x7417F172,0x75D59B45, + 0x7E89DC78,0x7F4BB64F,0x7D0D0816,0x7CCF6221,0x798074A4,0x78421E93,0x7A04A0CA,0x7BC6CAFD, + 0x6CBC2EB0,0x6D7E4487,0x6F38FADE,0x6EFA90E9,0x6BB5866C,0x6A77EC5B,0x68315202,0x69F33835, + 0x62AF7F08,0x636D153F,0x612BAB66,0x60E9C151,0x65A6D7D4,0x6464BDE3,0x662203BA,0x67E0698D, + 0x48D7CB20,0x4915A117,0x4B531F4E,0x4A917579,0x4FDE63FC,0x4E1C09CB,0x4C5AB792,0x4D98DDA5, + 0x46C49A98,0x4706F0AF,0x45404EF6,0x448224C1,0x41CD3244,0x400F5873,0x4249E62A,0x438B8C1D, + 0x54F16850,0x55330267,0x5775BC3E,0x56B7D609,0x53F8C08C,0x523AAABB,0x507C14E2,0x51BE7ED5, + 0x5AE239E8,0x5B2053DF,0x5966ED86,0x58A487B1,0x5DEB9134,0x5C29FB03,0x5E6F455A,0x5FAD2F6D, + 0xE1351B80,0xE0F771B7,0xE2B1CFEE,0xE373A5D9,0xE63CB35C,0xE7FED96B,0xE5B86732,0xE47A0D05, + 0xEF264A38,0xEEE4200F,0xECA29E56,0xED60F461,0xE82FE2E4,0xE9ED88D3,0xEBAB368A,0xEA695CBD, + 0xFD13B8F0,0xFCD1D2C7,0xFE976C9E,0xFF5506A9,0xFA1A102C,0xFBD87A1B,0xF99EC442,0xF85CAE75, + 0xF300E948,0xF2C2837F,0xF0843D26,0xF1465711,0xF4094194,0xF5CB2BA3,0xF78D95FA,0xF64FFFCD, + 0xD9785D60,0xD8BA3757,0xDAFC890E,0xDB3EE339,0xDE71F5BC,0xDFB39F8B,0xDDF521D2,0xDC374BE5, + 0xD76B0CD8,0xD6A966EF,0xD4EFD8B6,0xD52DB281,0xD062A404,0xD1A0CE33,0xD3E6706A,0xD2241A5D, + 0xC55EFE10,0xC49C9427,0xC6DA2A7E,0xC7184049,0xC25756CC,0xC3953CFB,0xC1D382A2,0xC011E895, + 0xCB4DAFA8,0xCA8FC59F,0xC8C97BC6,0xC90B11F1,0xCC440774,0xCD866D43,0xCFC0D31A,0xCE02B92D, + 0x91AF9640,0x906DFC77,0x922B422E,0x93E92819,0x96A63E9C,0x976454AB,0x9522EAF2,0x94E080C5, + 0x9FBCC7F8,0x9E7EADCF,0x9C381396,0x9DFA79A1,0x98B56F24,0x99770513,0x9B31BB4A,0x9AF3D17D, + 0x8D893530,0x8C4B5F07,0x8E0DE15E,0x8FCF8B69,0x8A809DEC,0x8B42F7DB,0x89044982,0x88C623B5, + 0x839A6488,0x82580EBF,0x801EB0E6,0x81DCDAD1,0x8493CC54,0x8551A663,0x8717183A,0x86D5720D, + 0xA9E2D0A0,0xA820BA97,0xAA6604CE,0xABA46EF9,0xAEEB787C,0xAF29124B,0xAD6FAC12,0xACADC625, + 0xA7F18118,0xA633EB2F,0xA4755576,0xA5B73F41,0xA0F829C4,0xA13A43F3,0xA37CFDAA,0xA2BE979D, + 0xB5C473D0,0xB40619E7,0xB640A7BE,0xB782CD89,0xB2CDDB0C,0xB30FB13B,0xB1490F62,0xB08B6555, + 0xBBD72268,0xBA15485F,0xB853F606,0xB9919C31,0xBCDE8AB4,0xBD1CE083,0xBF5A5EDA,0xBE9834ED, + }, + + { + 0x00000000,0xB8BC6765,0xAA09C88B,0x12B5AFEE,0x8F629757,0x37DEF032,0x256B5FDC,0x9DD738B9, + 0xC5B428EF,0x7D084F8A,0x6FBDE064,0xD7018701,0x4AD6BFB8,0xF26AD8DD,0xE0DF7733,0x58631056, + 0x5019579F,0xE8A530FA,0xFA109F14,0x42ACF871,0xDF7BC0C8,0x67C7A7AD,0x75720843,0xCDCE6F26, + 0x95AD7F70,0x2D111815,0x3FA4B7FB,0x8718D09E,0x1ACFE827,0xA2738F42,0xB0C620AC,0x087A47C9, + 0xA032AF3E,0x188EC85B,0x0A3B67B5,0xB28700D0,0x2F503869,0x97EC5F0C,0x8559F0E2,0x3DE59787, + 0x658687D1,0xDD3AE0B4,0xCF8F4F5A,0x7733283F,0xEAE41086,0x525877E3,0x40EDD80D,0xF851BF68, + 0xF02BF8A1,0x48979FC4,0x5A22302A,0xE29E574F,0x7F496FF6,0xC7F50893,0xD540A77D,0x6DFCC018, + 0x359FD04E,0x8D23B72B,0x9F9618C5,0x272A7FA0,0xBAFD4719,0x0241207C,0x10F48F92,0xA848E8F7, + 0x9B14583D,0x23A83F58,0x311D90B6,0x89A1F7D3,0x1476CF6A,0xACCAA80F,0xBE7F07E1,0x06C36084, + 0x5EA070D2,0xE61C17B7,0xF4A9B859,0x4C15DF3C,0xD1C2E785,0x697E80E0,0x7BCB2F0E,0xC377486B, + 0xCB0D0FA2,0x73B168C7,0x6104C729,0xD9B8A04C,0x446F98F5,0xFCD3FF90,0xEE66507E,0x56DA371B, + 0x0EB9274D,0xB6054028,0xA4B0EFC6,0x1C0C88A3,0x81DBB01A,0x3967D77F,0x2BD27891,0x936E1FF4, + 0x3B26F703,0x839A9066,0x912F3F88,0x299358ED,0xB4446054,0x0CF80731,0x1E4DA8DF,0xA6F1CFBA, + 0xFE92DFEC,0x462EB889,0x549B1767,0xEC277002,0x71F048BB,0xC94C2FDE,0xDBF98030,0x6345E755, + 0x6B3FA09C,0xD383C7F9,0xC1366817,0x798A0F72,0xE45D37CB,0x5CE150AE,0x4E54FF40,0xF6E89825, + 0xAE8B8873,0x1637EF16,0x048240F8,0xBC3E279D,0x21E91F24,0x99557841,0x8BE0D7AF,0x335CB0CA, + 0xED59B63B,0x55E5D15E,0x47507EB0,0xFFEC19D5,0x623B216C,0xDA874609,0xC832E9E7,0x708E8E82, + 0x28ED9ED4,0x9051F9B1,0x82E4565F,0x3A58313A,0xA78F0983,0x1F336EE6,0x0D86C108,0xB53AA66D, + 0xBD40E1A4,0x05FC86C1,0x1749292F,0xAFF54E4A,0x322276F3,0x8A9E1196,0x982BBE78,0x2097D91D, + 0x78F4C94B,0xC048AE2E,0xD2FD01C0,0x6A4166A5,0xF7965E1C,0x4F2A3979,0x5D9F9697,0xE523F1F2, + 0x4D6B1905,0xF5D77E60,0xE762D18E,0x5FDEB6EB,0xC2098E52,0x7AB5E937,0x680046D9,0xD0BC21BC, + 0x88DF31EA,0x3063568F,0x22D6F961,0x9A6A9E04,0x07BDA6BD,0xBF01C1D8,0xADB46E36,0x15080953, + 0x1D724E9A,0xA5CE29FF,0xB77B8611,0x0FC7E174,0x9210D9CD,0x2AACBEA8,0x38191146,0x80A57623, + 0xD8C66675,0x607A0110,0x72CFAEFE,0xCA73C99B,0x57A4F122,0xEF189647,0xFDAD39A9,0x45115ECC, + 0x764DEE06,0xCEF18963,0xDC44268D,0x64F841E8,0xF92F7951,0x41931E34,0x5326B1DA,0xEB9AD6BF, + 0xB3F9C6E9,0x0B45A18C,0x19F00E62,0xA14C6907,0x3C9B51BE,0x842736DB,0x96929935,0x2E2EFE50, + 0x2654B999,0x9EE8DEFC,0x8C5D7112,0x34E11677,0xA9362ECE,0x118A49AB,0x033FE645,0xBB838120, + 0xE3E09176,0x5B5CF613,0x49E959FD,0xF1553E98,0x6C820621,0xD43E6144,0xC68BCEAA,0x7E37A9CF, + 0xD67F4138,0x6EC3265D,0x7C7689B3,0xC4CAEED6,0x591DD66F,0xE1A1B10A,0xF3141EE4,0x4BA87981, + 0x13CB69D7,0xAB770EB2,0xB9C2A15C,0x017EC639,0x9CA9FE80,0x241599E5,0x36A0360B,0x8E1C516E, + 0x866616A7,0x3EDA71C2,0x2C6FDE2C,0x94D3B949,0x090481F0,0xB1B8E695,0xA30D497B,0x1BB12E1E, + 0x43D23E48,0xFB6E592D,0xE9DBF6C3,0x516791A6,0xCCB0A91F,0x740CCE7A,0x66B96194,0xDE0506F1, + } +#endif // defined(CRC32_USE_LOOKUP_TABLE_SLICING_BY_4) || defined(CRC32_USE_LOOKUP_TABLE_SLICING_BY_8) || defined(CRC32_USE_LOOKUP_TABLE_SLICING_BY_16) +#if defined (CRC32_USE_LOOKUP_TABLE_SLICING_BY_8) || defined(CRC32_USE_LOOKUP_TABLE_SLICING_BY_16) + // beyond this point only relevant for Slicing-by-8 and Slicing-by-16 + ,{ + 0x00000000,0x3D6029B0,0x7AC05360,0x47A07AD0,0xF580A6C0,0xC8E08F70,0x8F40F5A0,0xB220DC10, + 0x30704BC1,0x0D106271,0x4AB018A1,0x77D03111,0xC5F0ED01,0xF890C4B1,0xBF30BE61,0x825097D1, + 0x60E09782,0x5D80BE32,0x1A20C4E2,0x2740ED52,0x95603142,0xA80018F2,0xEFA06222,0xD2C04B92, + 0x5090DC43,0x6DF0F5F3,0x2A508F23,0x1730A693,0xA5107A83,0x98705333,0xDFD029E3,0xE2B00053, + 0xC1C12F04,0xFCA106B4,0xBB017C64,0x866155D4,0x344189C4,0x0921A074,0x4E81DAA4,0x73E1F314, + 0xF1B164C5,0xCCD14D75,0x8B7137A5,0xB6111E15,0x0431C205,0x3951EBB5,0x7EF19165,0x4391B8D5, + 0xA121B886,0x9C419136,0xDBE1EBE6,0xE681C256,0x54A11E46,0x69C137F6,0x2E614D26,0x13016496, + 0x9151F347,0xAC31DAF7,0xEB91A027,0xD6F18997,0x64D15587,0x59B17C37,0x1E1106E7,0x23712F57, + 0x58F35849,0x659371F9,0x22330B29,0x1F532299,0xAD73FE89,0x9013D739,0xD7B3ADE9,0xEAD38459, + 0x68831388,0x55E33A38,0x124340E8,0x2F236958,0x9D03B548,0xA0639CF8,0xE7C3E628,0xDAA3CF98, + 0x3813CFCB,0x0573E67B,0x42D39CAB,0x7FB3B51B,0xCD93690B,0xF0F340BB,0xB7533A6B,0x8A3313DB, + 0x0863840A,0x3503ADBA,0x72A3D76A,0x4FC3FEDA,0xFDE322CA,0xC0830B7A,0x872371AA,0xBA43581A, + 0x9932774D,0xA4525EFD,0xE3F2242D,0xDE920D9D,0x6CB2D18D,0x51D2F83D,0x167282ED,0x2B12AB5D, + 0xA9423C8C,0x9422153C,0xD3826FEC,0xEEE2465C,0x5CC29A4C,0x61A2B3FC,0x2602C92C,0x1B62E09C, + 0xF9D2E0CF,0xC4B2C97F,0x8312B3AF,0xBE729A1F,0x0C52460F,0x31326FBF,0x7692156F,0x4BF23CDF, + 0xC9A2AB0E,0xF4C282BE,0xB362F86E,0x8E02D1DE,0x3C220DCE,0x0142247E,0x46E25EAE,0x7B82771E, + 0xB1E6B092,0x8C869922,0xCB26E3F2,0xF646CA42,0x44661652,0x79063FE2,0x3EA64532,0x03C66C82, + 0x8196FB53,0xBCF6D2E3,0xFB56A833,0xC6368183,0x74165D93,0x49767423,0x0ED60EF3,0x33B62743, + 0xD1062710,0xEC660EA0,0xABC67470,0x96A65DC0,0x248681D0,0x19E6A860,0x5E46D2B0,0x6326FB00, + 0xE1766CD1,0xDC164561,0x9BB63FB1,0xA6D61601,0x14F6CA11,0x2996E3A1,0x6E369971,0x5356B0C1, + 0x70279F96,0x4D47B626,0x0AE7CCF6,0x3787E546,0x85A73956,0xB8C710E6,0xFF676A36,0xC2074386, + 0x4057D457,0x7D37FDE7,0x3A978737,0x07F7AE87,0xB5D77297,0x88B75B27,0xCF1721F7,0xF2770847, + 0x10C70814,0x2DA721A4,0x6A075B74,0x576772C4,0xE547AED4,0xD8278764,0x9F87FDB4,0xA2E7D404, + 0x20B743D5,0x1DD76A65,0x5A7710B5,0x67173905,0xD537E515,0xE857CCA5,0xAFF7B675,0x92979FC5, + 0xE915E8DB,0xD475C16B,0x93D5BBBB,0xAEB5920B,0x1C954E1B,0x21F567AB,0x66551D7B,0x5B3534CB, + 0xD965A31A,0xE4058AAA,0xA3A5F07A,0x9EC5D9CA,0x2CE505DA,0x11852C6A,0x562556BA,0x6B457F0A, + 0x89F57F59,0xB49556E9,0xF3352C39,0xCE550589,0x7C75D999,0x4115F029,0x06B58AF9,0x3BD5A349, + 0xB9853498,0x84E51D28,0xC34567F8,0xFE254E48,0x4C059258,0x7165BBE8,0x36C5C138,0x0BA5E888, + 0x28D4C7DF,0x15B4EE6F,0x521494BF,0x6F74BD0F,0xDD54611F,0xE03448AF,0xA794327F,0x9AF41BCF, + 0x18A48C1E,0x25C4A5AE,0x6264DF7E,0x5F04F6CE,0xED242ADE,0xD044036E,0x97E479BE,0xAA84500E, + 0x4834505D,0x755479ED,0x32F4033D,0x0F942A8D,0xBDB4F69D,0x80D4DF2D,0xC774A5FD,0xFA148C4D, + 0x78441B9C,0x4524322C,0x028448FC,0x3FE4614C,0x8DC4BD5C,0xB0A494EC,0xF704EE3C,0xCA64C78C, + }, + + { + 0x00000000,0xCB5CD3A5,0x4DC8A10B,0x869472AE,0x9B914216,0x50CD91B3,0xD659E31D,0x1D0530B8, + 0xEC53826D,0x270F51C8,0xA19B2366,0x6AC7F0C3,0x77C2C07B,0xBC9E13DE,0x3A0A6170,0xF156B2D5, + 0x03D6029B,0xC88AD13E,0x4E1EA390,0x85427035,0x9847408D,0x531B9328,0xD58FE186,0x1ED33223, + 0xEF8580F6,0x24D95353,0xA24D21FD,0x6911F258,0x7414C2E0,0xBF481145,0x39DC63EB,0xF280B04E, + 0x07AC0536,0xCCF0D693,0x4A64A43D,0x81387798,0x9C3D4720,0x57619485,0xD1F5E62B,0x1AA9358E, + 0xEBFF875B,0x20A354FE,0xA6372650,0x6D6BF5F5,0x706EC54D,0xBB3216E8,0x3DA66446,0xF6FAB7E3, + 0x047A07AD,0xCF26D408,0x49B2A6A6,0x82EE7503,0x9FEB45BB,0x54B7961E,0xD223E4B0,0x197F3715, + 0xE82985C0,0x23755665,0xA5E124CB,0x6EBDF76E,0x73B8C7D6,0xB8E41473,0x3E7066DD,0xF52CB578, + 0x0F580A6C,0xC404D9C9,0x4290AB67,0x89CC78C2,0x94C9487A,0x5F959BDF,0xD901E971,0x125D3AD4, + 0xE30B8801,0x28575BA4,0xAEC3290A,0x659FFAAF,0x789ACA17,0xB3C619B2,0x35526B1C,0xFE0EB8B9, + 0x0C8E08F7,0xC7D2DB52,0x4146A9FC,0x8A1A7A59,0x971F4AE1,0x5C439944,0xDAD7EBEA,0x118B384F, + 0xE0DD8A9A,0x2B81593F,0xAD152B91,0x6649F834,0x7B4CC88C,0xB0101B29,0x36846987,0xFDD8BA22, + 0x08F40F5A,0xC3A8DCFF,0x453CAE51,0x8E607DF4,0x93654D4C,0x58399EE9,0xDEADEC47,0x15F13FE2, + 0xE4A78D37,0x2FFB5E92,0xA96F2C3C,0x6233FF99,0x7F36CF21,0xB46A1C84,0x32FE6E2A,0xF9A2BD8F, + 0x0B220DC1,0xC07EDE64,0x46EAACCA,0x8DB67F6F,0x90B34FD7,0x5BEF9C72,0xDD7BEEDC,0x16273D79, + 0xE7718FAC,0x2C2D5C09,0xAAB92EA7,0x61E5FD02,0x7CE0CDBA,0xB7BC1E1F,0x31286CB1,0xFA74BF14, + 0x1EB014D8,0xD5ECC77D,0x5378B5D3,0x98246676,0x852156CE,0x4E7D856B,0xC8E9F7C5,0x03B52460, + 0xF2E396B5,0x39BF4510,0xBF2B37BE,0x7477E41B,0x6972D4A3,0xA22E0706,0x24BA75A8,0xEFE6A60D, + 0x1D661643,0xD63AC5E6,0x50AEB748,0x9BF264ED,0x86F75455,0x4DAB87F0,0xCB3FF55E,0x006326FB, + 0xF135942E,0x3A69478B,0xBCFD3525,0x77A1E680,0x6AA4D638,0xA1F8059D,0x276C7733,0xEC30A496, + 0x191C11EE,0xD240C24B,0x54D4B0E5,0x9F886340,0x828D53F8,0x49D1805D,0xCF45F2F3,0x04192156, + 0xF54F9383,0x3E134026,0xB8873288,0x73DBE12D,0x6EDED195,0xA5820230,0x2316709E,0xE84AA33B, + 0x1ACA1375,0xD196C0D0,0x5702B27E,0x9C5E61DB,0x815B5163,0x4A0782C6,0xCC93F068,0x07CF23CD, + 0xF6999118,0x3DC542BD,0xBB513013,0x700DE3B6,0x6D08D30E,0xA65400AB,0x20C07205,0xEB9CA1A0, + 0x11E81EB4,0xDAB4CD11,0x5C20BFBF,0x977C6C1A,0x8A795CA2,0x41258F07,0xC7B1FDA9,0x0CED2E0C, + 0xFDBB9CD9,0x36E74F7C,0xB0733DD2,0x7B2FEE77,0x662ADECF,0xAD760D6A,0x2BE27FC4,0xE0BEAC61, + 0x123E1C2F,0xD962CF8A,0x5FF6BD24,0x94AA6E81,0x89AF5E39,0x42F38D9C,0xC467FF32,0x0F3B2C97, + 0xFE6D9E42,0x35314DE7,0xB3A53F49,0x78F9ECEC,0x65FCDC54,0xAEA00FF1,0x28347D5F,0xE368AEFA, + 0x16441B82,0xDD18C827,0x5B8CBA89,0x90D0692C,0x8DD55994,0x46898A31,0xC01DF89F,0x0B412B3A, + 0xFA1799EF,0x314B4A4A,0xB7DF38E4,0x7C83EB41,0x6186DBF9,0xAADA085C,0x2C4E7AF2,0xE712A957, + 0x15921919,0xDECECABC,0x585AB812,0x93066BB7,0x8E035B0F,0x455F88AA,0xC3CBFA04,0x089729A1, + 0xF9C19B74,0x329D48D1,0xB4093A7F,0x7F55E9DA,0x6250D962,0xA90C0AC7,0x2F987869,0xE4C4ABCC, + }, + + { + 0x00000000,0xA6770BB4,0x979F1129,0x31E81A9D,0xF44F2413,0x52382FA7,0x63D0353A,0xC5A73E8E, + 0x33EF4E67,0x959845D3,0xA4705F4E,0x020754FA,0xC7A06A74,0x61D761C0,0x503F7B5D,0xF64870E9, + 0x67DE9CCE,0xC1A9977A,0xF0418DE7,0x56368653,0x9391B8DD,0x35E6B369,0x040EA9F4,0xA279A240, + 0x5431D2A9,0xF246D91D,0xC3AEC380,0x65D9C834,0xA07EF6BA,0x0609FD0E,0x37E1E793,0x9196EC27, + 0xCFBD399C,0x69CA3228,0x582228B5,0xFE552301,0x3BF21D8F,0x9D85163B,0xAC6D0CA6,0x0A1A0712, + 0xFC5277FB,0x5A257C4F,0x6BCD66D2,0xCDBA6D66,0x081D53E8,0xAE6A585C,0x9F8242C1,0x39F54975, + 0xA863A552,0x0E14AEE6,0x3FFCB47B,0x998BBFCF,0x5C2C8141,0xFA5B8AF5,0xCBB39068,0x6DC49BDC, + 0x9B8CEB35,0x3DFBE081,0x0C13FA1C,0xAA64F1A8,0x6FC3CF26,0xC9B4C492,0xF85CDE0F,0x5E2BD5BB, + 0x440B7579,0xE27C7ECD,0xD3946450,0x75E36FE4,0xB044516A,0x16335ADE,0x27DB4043,0x81AC4BF7, + 0x77E43B1E,0xD19330AA,0xE07B2A37,0x460C2183,0x83AB1F0D,0x25DC14B9,0x14340E24,0xB2430590, + 0x23D5E9B7,0x85A2E203,0xB44AF89E,0x123DF32A,0xD79ACDA4,0x71EDC610,0x4005DC8D,0xE672D739, + 0x103AA7D0,0xB64DAC64,0x87A5B6F9,0x21D2BD4D,0xE47583C3,0x42028877,0x73EA92EA,0xD59D995E, + 0x8BB64CE5,0x2DC14751,0x1C295DCC,0xBA5E5678,0x7FF968F6,0xD98E6342,0xE86679DF,0x4E11726B, + 0xB8590282,0x1E2E0936,0x2FC613AB,0x89B1181F,0x4C162691,0xEA612D25,0xDB8937B8,0x7DFE3C0C, + 0xEC68D02B,0x4A1FDB9F,0x7BF7C102,0xDD80CAB6,0x1827F438,0xBE50FF8C,0x8FB8E511,0x29CFEEA5, + 0xDF879E4C,0x79F095F8,0x48188F65,0xEE6F84D1,0x2BC8BA5F,0x8DBFB1EB,0xBC57AB76,0x1A20A0C2, + 0x8816EAF2,0x2E61E146,0x1F89FBDB,0xB9FEF06F,0x7C59CEE1,0xDA2EC555,0xEBC6DFC8,0x4DB1D47C, + 0xBBF9A495,0x1D8EAF21,0x2C66B5BC,0x8A11BE08,0x4FB68086,0xE9C18B32,0xD82991AF,0x7E5E9A1B, + 0xEFC8763C,0x49BF7D88,0x78576715,0xDE206CA1,0x1B87522F,0xBDF0599B,0x8C184306,0x2A6F48B2, + 0xDC27385B,0x7A5033EF,0x4BB82972,0xEDCF22C6,0x28681C48,0x8E1F17FC,0xBFF70D61,0x198006D5, + 0x47ABD36E,0xE1DCD8DA,0xD034C247,0x7643C9F3,0xB3E4F77D,0x1593FCC9,0x247BE654,0x820CEDE0, + 0x74449D09,0xD23396BD,0xE3DB8C20,0x45AC8794,0x800BB91A,0x267CB2AE,0x1794A833,0xB1E3A387, + 0x20754FA0,0x86024414,0xB7EA5E89,0x119D553D,0xD43A6BB3,0x724D6007,0x43A57A9A,0xE5D2712E, + 0x139A01C7,0xB5ED0A73,0x840510EE,0x22721B5A,0xE7D525D4,0x41A22E60,0x704A34FD,0xD63D3F49, + 0xCC1D9F8B,0x6A6A943F,0x5B828EA2,0xFDF58516,0x3852BB98,0x9E25B02C,0xAFCDAAB1,0x09BAA105, + 0xFFF2D1EC,0x5985DA58,0x686DC0C5,0xCE1ACB71,0x0BBDF5FF,0xADCAFE4B,0x9C22E4D6,0x3A55EF62, + 0xABC30345,0x0DB408F1,0x3C5C126C,0x9A2B19D8,0x5F8C2756,0xF9FB2CE2,0xC813367F,0x6E643DCB, + 0x982C4D22,0x3E5B4696,0x0FB35C0B,0xA9C457BF,0x6C636931,0xCA146285,0xFBFC7818,0x5D8B73AC, + 0x03A0A617,0xA5D7ADA3,0x943FB73E,0x3248BC8A,0xF7EF8204,0x519889B0,0x6070932D,0xC6079899, + 0x304FE870,0x9638E3C4,0xA7D0F959,0x01A7F2ED,0xC400CC63,0x6277C7D7,0x539FDD4A,0xF5E8D6FE, + 0x647E3AD9,0xC209316D,0xF3E12BF0,0x55962044,0x90311ECA,0x3646157E,0x07AE0FE3,0xA1D90457, + 0x579174BE,0xF1E67F0A,0xC00E6597,0x66796E23,0xA3DE50AD,0x05A95B19,0x34414184,0x92364A30, + }, + + { + 0x00000000,0xCCAA009E,0x4225077D,0x8E8F07E3,0x844A0EFA,0x48E00E64,0xC66F0987,0x0AC50919, + 0xD3E51BB5,0x1F4F1B2B,0x91C01CC8,0x5D6A1C56,0x57AF154F,0x9B0515D1,0x158A1232,0xD92012AC, + 0x7CBB312B,0xB01131B5,0x3E9E3656,0xF23436C8,0xF8F13FD1,0x345B3F4F,0xBAD438AC,0x767E3832, + 0xAF5E2A9E,0x63F42A00,0xED7B2DE3,0x21D12D7D,0x2B142464,0xE7BE24FA,0x69312319,0xA59B2387, + 0xF9766256,0x35DC62C8,0xBB53652B,0x77F965B5,0x7D3C6CAC,0xB1966C32,0x3F196BD1,0xF3B36B4F, + 0x2A9379E3,0xE639797D,0x68B67E9E,0xA41C7E00,0xAED97719,0x62737787,0xECFC7064,0x205670FA, + 0x85CD537D,0x496753E3,0xC7E85400,0x0B42549E,0x01875D87,0xCD2D5D19,0x43A25AFA,0x8F085A64, + 0x562848C8,0x9A824856,0x140D4FB5,0xD8A74F2B,0xD2624632,0x1EC846AC,0x9047414F,0x5CED41D1, + 0x299DC2ED,0xE537C273,0x6BB8C590,0xA712C50E,0xADD7CC17,0x617DCC89,0xEFF2CB6A,0x2358CBF4, + 0xFA78D958,0x36D2D9C6,0xB85DDE25,0x74F7DEBB,0x7E32D7A2,0xB298D73C,0x3C17D0DF,0xF0BDD041, + 0x5526F3C6,0x998CF358,0x1703F4BB,0xDBA9F425,0xD16CFD3C,0x1DC6FDA2,0x9349FA41,0x5FE3FADF, + 0x86C3E873,0x4A69E8ED,0xC4E6EF0E,0x084CEF90,0x0289E689,0xCE23E617,0x40ACE1F4,0x8C06E16A, + 0xD0EBA0BB,0x1C41A025,0x92CEA7C6,0x5E64A758,0x54A1AE41,0x980BAEDF,0x1684A93C,0xDA2EA9A2, + 0x030EBB0E,0xCFA4BB90,0x412BBC73,0x8D81BCED,0x8744B5F4,0x4BEEB56A,0xC561B289,0x09CBB217, + 0xAC509190,0x60FA910E,0xEE7596ED,0x22DF9673,0x281A9F6A,0xE4B09FF4,0x6A3F9817,0xA6959889, + 0x7FB58A25,0xB31F8ABB,0x3D908D58,0xF13A8DC6,0xFBFF84DF,0x37558441,0xB9DA83A2,0x7570833C, + 0x533B85DA,0x9F918544,0x111E82A7,0xDDB48239,0xD7718B20,0x1BDB8BBE,0x95548C5D,0x59FE8CC3, + 0x80DE9E6F,0x4C749EF1,0xC2FB9912,0x0E51998C,0x04949095,0xC83E900B,0x46B197E8,0x8A1B9776, + 0x2F80B4F1,0xE32AB46F,0x6DA5B38C,0xA10FB312,0xABCABA0B,0x6760BA95,0xE9EFBD76,0x2545BDE8, + 0xFC65AF44,0x30CFAFDA,0xBE40A839,0x72EAA8A7,0x782FA1BE,0xB485A120,0x3A0AA6C3,0xF6A0A65D, + 0xAA4DE78C,0x66E7E712,0xE868E0F1,0x24C2E06F,0x2E07E976,0xE2ADE9E8,0x6C22EE0B,0xA088EE95, + 0x79A8FC39,0xB502FCA7,0x3B8DFB44,0xF727FBDA,0xFDE2F2C3,0x3148F25D,0xBFC7F5BE,0x736DF520, + 0xD6F6D6A7,0x1A5CD639,0x94D3D1DA,0x5879D144,0x52BCD85D,0x9E16D8C3,0x1099DF20,0xDC33DFBE, + 0x0513CD12,0xC9B9CD8C,0x4736CA6F,0x8B9CCAF1,0x8159C3E8,0x4DF3C376,0xC37CC495,0x0FD6C40B, + 0x7AA64737,0xB60C47A9,0x3883404A,0xF42940D4,0xFEEC49CD,0x32464953,0xBCC94EB0,0x70634E2E, + 0xA9435C82,0x65E95C1C,0xEB665BFF,0x27CC5B61,0x2D095278,0xE1A352E6,0x6F2C5505,0xA386559B, + 0x061D761C,0xCAB77682,0x44387161,0x889271FF,0x825778E6,0x4EFD7878,0xC0727F9B,0x0CD87F05, + 0xD5F86DA9,0x19526D37,0x97DD6AD4,0x5B776A4A,0x51B26353,0x9D1863CD,0x1397642E,0xDF3D64B0, + 0x83D02561,0x4F7A25FF,0xC1F5221C,0x0D5F2282,0x079A2B9B,0xCB302B05,0x45BF2CE6,0x89152C78, + 0x50353ED4,0x9C9F3E4A,0x121039A9,0xDEBA3937,0xD47F302E,0x18D530B0,0x965A3753,0x5AF037CD, + 0xFF6B144A,0x33C114D4,0xBD4E1337,0x71E413A9,0x7B211AB0,0xB78B1A2E,0x39041DCD,0xF5AE1D53, + 0x2C8E0FFF,0xE0240F61,0x6EAB0882,0xA201081C,0xA8C40105,0x646E019B,0xEAE10678,0x264B06E6, + } +#endif // CRC32_USE_LOOKUP_TABLE_SLICING_BY_8 || CRC32_USE_LOOKUP_TABLE_SLICING_BY_16 +#ifdef CRC32_USE_LOOKUP_TABLE_SLICING_BY_16 + // beyond this point only relevant for Slicing-by-16 + ,{ + 0x00000000,0x177B1443,0x2EF62886,0x398D3CC5,0x5DEC510C,0x4A97454F,0x731A798A,0x64616DC9, + 0xBBD8A218,0xACA3B65B,0x952E8A9E,0x82559EDD,0xE634F314,0xF14FE757,0xC8C2DB92,0xDFB9CFD1, + 0xACC04271,0xBBBB5632,0x82366AF7,0x954D7EB4,0xF12C137D,0xE657073E,0xDFDA3BFB,0xC8A12FB8, + 0x1718E069,0x0063F42A,0x39EEC8EF,0x2E95DCAC,0x4AF4B165,0x5D8FA526,0x640299E3,0x73798DA0, + 0x82F182A3,0x958A96E0,0xAC07AA25,0xBB7CBE66,0xDF1DD3AF,0xC866C7EC,0xF1EBFB29,0xE690EF6A, + 0x392920BB,0x2E5234F8,0x17DF083D,0x00A41C7E,0x64C571B7,0x73BE65F4,0x4A335931,0x5D484D72, + 0x2E31C0D2,0x394AD491,0x00C7E854,0x17BCFC17,0x73DD91DE,0x64A6859D,0x5D2BB958,0x4A50AD1B, + 0x95E962CA,0x82927689,0xBB1F4A4C,0xAC645E0F,0xC80533C6,0xDF7E2785,0xE6F31B40,0xF1880F03, + 0xDE920307,0xC9E91744,0xF0642B81,0xE71F3FC2,0x837E520B,0x94054648,0xAD887A8D,0xBAF36ECE, + 0x654AA11F,0x7231B55C,0x4BBC8999,0x5CC79DDA,0x38A6F013,0x2FDDE450,0x1650D895,0x012BCCD6, + 0x72524176,0x65295535,0x5CA469F0,0x4BDF7DB3,0x2FBE107A,0x38C50439,0x014838FC,0x16332CBF, + 0xC98AE36E,0xDEF1F72D,0xE77CCBE8,0xF007DFAB,0x9466B262,0x831DA621,0xBA909AE4,0xADEB8EA7, + 0x5C6381A4,0x4B1895E7,0x7295A922,0x65EEBD61,0x018FD0A8,0x16F4C4EB,0x2F79F82E,0x3802EC6D, + 0xE7BB23BC,0xF0C037FF,0xC94D0B3A,0xDE361F79,0xBA5772B0,0xAD2C66F3,0x94A15A36,0x83DA4E75, + 0xF0A3C3D5,0xE7D8D796,0xDE55EB53,0xC92EFF10,0xAD4F92D9,0xBA34869A,0x83B9BA5F,0x94C2AE1C, + 0x4B7B61CD,0x5C00758E,0x658D494B,0x72F65D08,0x169730C1,0x01EC2482,0x38611847,0x2F1A0C04, + 0x6655004F,0x712E140C,0x48A328C9,0x5FD83C8A,0x3BB95143,0x2CC24500,0x154F79C5,0x02346D86, + 0xDD8DA257,0xCAF6B614,0xF37B8AD1,0xE4009E92,0x8061F35B,0x971AE718,0xAE97DBDD,0xB9ECCF9E, + 0xCA95423E,0xDDEE567D,0xE4636AB8,0xF3187EFB,0x97791332,0x80020771,0xB98F3BB4,0xAEF42FF7, + 0x714DE026,0x6636F465,0x5FBBC8A0,0x48C0DCE3,0x2CA1B12A,0x3BDAA569,0x025799AC,0x152C8DEF, + 0xE4A482EC,0xF3DF96AF,0xCA52AA6A,0xDD29BE29,0xB948D3E0,0xAE33C7A3,0x97BEFB66,0x80C5EF25, + 0x5F7C20F4,0x480734B7,0x718A0872,0x66F11C31,0x029071F8,0x15EB65BB,0x2C66597E,0x3B1D4D3D, + 0x4864C09D,0x5F1FD4DE,0x6692E81B,0x71E9FC58,0x15889191,0x02F385D2,0x3B7EB917,0x2C05AD54, + 0xF3BC6285,0xE4C776C6,0xDD4A4A03,0xCA315E40,0xAE503389,0xB92B27CA,0x80A61B0F,0x97DD0F4C, + 0xB8C70348,0xAFBC170B,0x96312BCE,0x814A3F8D,0xE52B5244,0xF2504607,0xCBDD7AC2,0xDCA66E81, + 0x031FA150,0x1464B513,0x2DE989D6,0x3A929D95,0x5EF3F05C,0x4988E41F,0x7005D8DA,0x677ECC99, + 0x14074139,0x037C557A,0x3AF169BF,0x2D8A7DFC,0x49EB1035,0x5E900476,0x671D38B3,0x70662CF0, + 0xAFDFE321,0xB8A4F762,0x8129CBA7,0x9652DFE4,0xF233B22D,0xE548A66E,0xDCC59AAB,0xCBBE8EE8, + 0x3A3681EB,0x2D4D95A8,0x14C0A96D,0x03BBBD2E,0x67DAD0E7,0x70A1C4A4,0x492CF861,0x5E57EC22, + 0x81EE23F3,0x969537B0,0xAF180B75,0xB8631F36,0xDC0272FF,0xCB7966BC,0xF2F45A79,0xE58F4E3A, + 0x96F6C39A,0x818DD7D9,0xB800EB1C,0xAF7BFF5F,0xCB1A9296,0xDC6186D5,0xE5ECBA10,0xF297AE53, + 0x2D2E6182,0x3A5575C1,0x03D84904,0x14A35D47,0x70C2308E,0x67B924CD,0x5E341808,0x494F0C4B, + }, + + { + 0x00000000,0xEFC26B3E,0x04F5D03D,0xEB37BB03,0x09EBA07A,0xE629CB44,0x0D1E7047,0xE2DC1B79, + 0x13D740F4,0xFC152BCA,0x172290C9,0xF8E0FBF7,0x1A3CE08E,0xF5FE8BB0,0x1EC930B3,0xF10B5B8D, + 0x27AE81E8,0xC86CEAD6,0x235B51D5,0xCC993AEB,0x2E452192,0xC1874AAC,0x2AB0F1AF,0xC5729A91, + 0x3479C11C,0xDBBBAA22,0x308C1121,0xDF4E7A1F,0x3D926166,0xD2500A58,0x3967B15B,0xD6A5DA65, + 0x4F5D03D0,0xA09F68EE,0x4BA8D3ED,0xA46AB8D3,0x46B6A3AA,0xA974C894,0x42437397,0xAD8118A9, + 0x5C8A4324,0xB348281A,0x587F9319,0xB7BDF827,0x5561E35E,0xBAA38860,0x51943363,0xBE56585D, + 0x68F38238,0x8731E906,0x6C065205,0x83C4393B,0x61182242,0x8EDA497C,0x65EDF27F,0x8A2F9941, + 0x7B24C2CC,0x94E6A9F2,0x7FD112F1,0x901379CF,0x72CF62B6,0x9D0D0988,0x763AB28B,0x99F8D9B5, + 0x9EBA07A0,0x71786C9E,0x9A4FD79D,0x758DBCA3,0x9751A7DA,0x7893CCE4,0x93A477E7,0x7C661CD9, + 0x8D6D4754,0x62AF2C6A,0x89989769,0x665AFC57,0x8486E72E,0x6B448C10,0x80733713,0x6FB15C2D, + 0xB9148648,0x56D6ED76,0xBDE15675,0x52233D4B,0xB0FF2632,0x5F3D4D0C,0xB40AF60F,0x5BC89D31, + 0xAAC3C6BC,0x4501AD82,0xAE361681,0x41F47DBF,0xA32866C6,0x4CEA0DF8,0xA7DDB6FB,0x481FDDC5, + 0xD1E70470,0x3E256F4E,0xD512D44D,0x3AD0BF73,0xD80CA40A,0x37CECF34,0xDCF97437,0x333B1F09, + 0xC2304484,0x2DF22FBA,0xC6C594B9,0x2907FF87,0xCBDBE4FE,0x24198FC0,0xCF2E34C3,0x20EC5FFD, + 0xF6498598,0x198BEEA6,0xF2BC55A5,0x1D7E3E9B,0xFFA225E2,0x10604EDC,0xFB57F5DF,0x14959EE1, + 0xE59EC56C,0x0A5CAE52,0xE16B1551,0x0EA97E6F,0xEC756516,0x03B70E28,0xE880B52B,0x0742DE15, + 0xE6050901,0x09C7623F,0xE2F0D93C,0x0D32B202,0xEFEEA97B,0x002CC245,0xEB1B7946,0x04D91278, + 0xF5D249F5,0x1A1022CB,0xF12799C8,0x1EE5F2F6,0xFC39E98F,0x13FB82B1,0xF8CC39B2,0x170E528C, + 0xC1AB88E9,0x2E69E3D7,0xC55E58D4,0x2A9C33EA,0xC8402893,0x278243AD,0xCCB5F8AE,0x23779390, + 0xD27CC81D,0x3DBEA323,0xD6891820,0x394B731E,0xDB976867,0x34550359,0xDF62B85A,0x30A0D364, + 0xA9580AD1,0x469A61EF,0xADADDAEC,0x426FB1D2,0xA0B3AAAB,0x4F71C195,0xA4467A96,0x4B8411A8, + 0xBA8F4A25,0x554D211B,0xBE7A9A18,0x51B8F126,0xB364EA5F,0x5CA68161,0xB7913A62,0x5853515C, + 0x8EF68B39,0x6134E007,0x8A035B04,0x65C1303A,0x871D2B43,0x68DF407D,0x83E8FB7E,0x6C2A9040, + 0x9D21CBCD,0x72E3A0F3,0x99D41BF0,0x761670CE,0x94CA6BB7,0x7B080089,0x903FBB8A,0x7FFDD0B4, + 0x78BF0EA1,0x977D659F,0x7C4ADE9C,0x9388B5A2,0x7154AEDB,0x9E96C5E5,0x75A17EE6,0x9A6315D8, + 0x6B684E55,0x84AA256B,0x6F9D9E68,0x805FF556,0x6283EE2F,0x8D418511,0x66763E12,0x89B4552C, + 0x5F118F49,0xB0D3E477,0x5BE45F74,0xB426344A,0x56FA2F33,0xB938440D,0x520FFF0E,0xBDCD9430, + 0x4CC6CFBD,0xA304A483,0x48331F80,0xA7F174BE,0x452D6FC7,0xAAEF04F9,0x41D8BFFA,0xAE1AD4C4, + 0x37E20D71,0xD820664F,0x3317DD4C,0xDCD5B672,0x3E09AD0B,0xD1CBC635,0x3AFC7D36,0xD53E1608, + 0x24354D85,0xCBF726BB,0x20C09DB8,0xCF02F686,0x2DDEEDFF,0xC21C86C1,0x292B3DC2,0xC6E956FC, + 0x104C8C99,0xFF8EE7A7,0x14B95CA4,0xFB7B379A,0x19A72CE3,0xF66547DD,0x1D52FCDE,0xF29097E0, + 0x039BCC6D,0xEC59A753,0x076E1C50,0xE8AC776E,0x0A706C17,0xE5B20729,0x0E85BC2A,0xE147D714, + }, + + { + 0x00000000,0xC18EDFC0,0x586CB9C1,0x99E26601,0xB0D97382,0x7157AC42,0xE8B5CA43,0x293B1583, + 0xBAC3E145,0x7B4D3E85,0xE2AF5884,0x23218744,0x0A1A92C7,0xCB944D07,0x52762B06,0x93F8F4C6, + 0xAEF6C4CB,0x6F781B0B,0xF69A7D0A,0x3714A2CA,0x1E2FB749,0xDFA16889,0x46430E88,0x87CDD148, + 0x1435258E,0xD5BBFA4E,0x4C599C4F,0x8DD7438F,0xA4EC560C,0x656289CC,0xFC80EFCD,0x3D0E300D, + 0x869C8FD7,0x47125017,0xDEF03616,0x1F7EE9D6,0x3645FC55,0xF7CB2395,0x6E294594,0xAFA79A54, + 0x3C5F6E92,0xFDD1B152,0x6433D753,0xA5BD0893,0x8C861D10,0x4D08C2D0,0xD4EAA4D1,0x15647B11, + 0x286A4B1C,0xE9E494DC,0x7006F2DD,0xB1882D1D,0x98B3389E,0x593DE75E,0xC0DF815F,0x01515E9F, + 0x92A9AA59,0x53277599,0xCAC51398,0x0B4BCC58,0x2270D9DB,0xE3FE061B,0x7A1C601A,0xBB92BFDA, + 0xD64819EF,0x17C6C62F,0x8E24A02E,0x4FAA7FEE,0x66916A6D,0xA71FB5AD,0x3EFDD3AC,0xFF730C6C, + 0x6C8BF8AA,0xAD05276A,0x34E7416B,0xF5699EAB,0xDC528B28,0x1DDC54E8,0x843E32E9,0x45B0ED29, + 0x78BEDD24,0xB93002E4,0x20D264E5,0xE15CBB25,0xC867AEA6,0x09E97166,0x900B1767,0x5185C8A7, + 0xC27D3C61,0x03F3E3A1,0x9A1185A0,0x5B9F5A60,0x72A44FE3,0xB32A9023,0x2AC8F622,0xEB4629E2, + 0x50D49638,0x915A49F8,0x08B82FF9,0xC936F039,0xE00DE5BA,0x21833A7A,0xB8615C7B,0x79EF83BB, + 0xEA17777D,0x2B99A8BD,0xB27BCEBC,0x73F5117C,0x5ACE04FF,0x9B40DB3F,0x02A2BD3E,0xC32C62FE, + 0xFE2252F3,0x3FAC8D33,0xA64EEB32,0x67C034F2,0x4EFB2171,0x8F75FEB1,0x169798B0,0xD7194770, + 0x44E1B3B6,0x856F6C76,0x1C8D0A77,0xDD03D5B7,0xF438C034,0x35B61FF4,0xAC5479F5,0x6DDAA635, + 0x77E1359F,0xB66FEA5F,0x2F8D8C5E,0xEE03539E,0xC738461D,0x06B699DD,0x9F54FFDC,0x5EDA201C, + 0xCD22D4DA,0x0CAC0B1A,0x954E6D1B,0x54C0B2DB,0x7DFBA758,0xBC757898,0x25971E99,0xE419C159, + 0xD917F154,0x18992E94,0x817B4895,0x40F59755,0x69CE82D6,0xA8405D16,0x31A23B17,0xF02CE4D7, + 0x63D41011,0xA25ACFD1,0x3BB8A9D0,0xFA367610,0xD30D6393,0x1283BC53,0x8B61DA52,0x4AEF0592, + 0xF17DBA48,0x30F36588,0xA9110389,0x689FDC49,0x41A4C9CA,0x802A160A,0x19C8700B,0xD846AFCB, + 0x4BBE5B0D,0x8A3084CD,0x13D2E2CC,0xD25C3D0C,0xFB67288F,0x3AE9F74F,0xA30B914E,0x62854E8E, + 0x5F8B7E83,0x9E05A143,0x07E7C742,0xC6691882,0xEF520D01,0x2EDCD2C1,0xB73EB4C0,0x76B06B00, + 0xE5489FC6,0x24C64006,0xBD242607,0x7CAAF9C7,0x5591EC44,0x941F3384,0x0DFD5585,0xCC738A45, + 0xA1A92C70,0x6027F3B0,0xF9C595B1,0x384B4A71,0x11705FF2,0xD0FE8032,0x491CE633,0x889239F3, + 0x1B6ACD35,0xDAE412F5,0x430674F4,0x8288AB34,0xABB3BEB7,0x6A3D6177,0xF3DF0776,0x3251D8B6, + 0x0F5FE8BB,0xCED1377B,0x5733517A,0x96BD8EBA,0xBF869B39,0x7E0844F9,0xE7EA22F8,0x2664FD38, + 0xB59C09FE,0x7412D63E,0xEDF0B03F,0x2C7E6FFF,0x05457A7C,0xC4CBA5BC,0x5D29C3BD,0x9CA71C7D, + 0x2735A3A7,0xE6BB7C67,0x7F591A66,0xBED7C5A6,0x97ECD025,0x56620FE5,0xCF8069E4,0x0E0EB624, + 0x9DF642E2,0x5C789D22,0xC59AFB23,0x041424E3,0x2D2F3160,0xECA1EEA0,0x754388A1,0xB4CD5761, + 0x89C3676C,0x484DB8AC,0xD1AFDEAD,0x1021016D,0x391A14EE,0xF894CB2E,0x6176AD2F,0xA0F872EF, + 0x33008629,0xF28E59E9,0x6B6C3FE8,0xAAE2E028,0x83D9F5AB,0x42572A6B,0xDBB54C6A,0x1A3B93AA, + }, + + { + 0x00000000,0x9BA54C6F,0xEC3B9E9F,0x779ED2F0,0x03063B7F,0x98A37710,0xEF3DA5E0,0x7498E98F, + 0x060C76FE,0x9DA93A91,0xEA37E861,0x7192A40E,0x050A4D81,0x9EAF01EE,0xE931D31E,0x72949F71, + 0x0C18EDFC,0x97BDA193,0xE0237363,0x7B863F0C,0x0F1ED683,0x94BB9AEC,0xE325481C,0x78800473, + 0x0A149B02,0x91B1D76D,0xE62F059D,0x7D8A49F2,0x0912A07D,0x92B7EC12,0xE5293EE2,0x7E8C728D, + 0x1831DBF8,0x83949797,0xF40A4567,0x6FAF0908,0x1B37E087,0x8092ACE8,0xF70C7E18,0x6CA93277, + 0x1E3DAD06,0x8598E169,0xF2063399,0x69A37FF6,0x1D3B9679,0x869EDA16,0xF10008E6,0x6AA54489, + 0x14293604,0x8F8C7A6B,0xF812A89B,0x63B7E4F4,0x172F0D7B,0x8C8A4114,0xFB1493E4,0x60B1DF8B, + 0x122540FA,0x89800C95,0xFE1EDE65,0x65BB920A,0x11237B85,0x8A8637EA,0xFD18E51A,0x66BDA975, + 0x3063B7F0,0xABC6FB9F,0xDC58296F,0x47FD6500,0x33658C8F,0xA8C0C0E0,0xDF5E1210,0x44FB5E7F, + 0x366FC10E,0xADCA8D61,0xDA545F91,0x41F113FE,0x3569FA71,0xAECCB61E,0xD95264EE,0x42F72881, + 0x3C7B5A0C,0xA7DE1663,0xD040C493,0x4BE588FC,0x3F7D6173,0xA4D82D1C,0xD346FFEC,0x48E3B383, + 0x3A772CF2,0xA1D2609D,0xD64CB26D,0x4DE9FE02,0x3971178D,0xA2D45BE2,0xD54A8912,0x4EEFC57D, + 0x28526C08,0xB3F72067,0xC469F297,0x5FCCBEF8,0x2B545777,0xB0F11B18,0xC76FC9E8,0x5CCA8587, + 0x2E5E1AF6,0xB5FB5699,0xC2658469,0x59C0C806,0x2D582189,0xB6FD6DE6,0xC163BF16,0x5AC6F379, + 0x244A81F4,0xBFEFCD9B,0xC8711F6B,0x53D45304,0x274CBA8B,0xBCE9F6E4,0xCB772414,0x50D2687B, + 0x2246F70A,0xB9E3BB65,0xCE7D6995,0x55D825FA,0x2140CC75,0xBAE5801A,0xCD7B52EA,0x56DE1E85, + 0x60C76FE0,0xFB62238F,0x8CFCF17F,0x1759BD10,0x63C1549F,0xF86418F0,0x8FFACA00,0x145F866F, + 0x66CB191E,0xFD6E5571,0x8AF08781,0x1155CBEE,0x65CD2261,0xFE686E0E,0x89F6BCFE,0x1253F091, + 0x6CDF821C,0xF77ACE73,0x80E41C83,0x1B4150EC,0x6FD9B963,0xF47CF50C,0x83E227FC,0x18476B93, + 0x6AD3F4E2,0xF176B88D,0x86E86A7D,0x1D4D2612,0x69D5CF9D,0xF27083F2,0x85EE5102,0x1E4B1D6D, + 0x78F6B418,0xE353F877,0x94CD2A87,0x0F6866E8,0x7BF08F67,0xE055C308,0x97CB11F8,0x0C6E5D97, + 0x7EFAC2E6,0xE55F8E89,0x92C15C79,0x09641016,0x7DFCF999,0xE659B5F6,0x91C76706,0x0A622B69, + 0x74EE59E4,0xEF4B158B,0x98D5C77B,0x03708B14,0x77E8629B,0xEC4D2EF4,0x9BD3FC04,0x0076B06B, + 0x72E22F1A,0xE9476375,0x9ED9B185,0x057CFDEA,0x71E41465,0xEA41580A,0x9DDF8AFA,0x067AC695, + 0x50A4D810,0xCB01947F,0xBC9F468F,0x273A0AE0,0x53A2E36F,0xC807AF00,0xBF997DF0,0x243C319F, + 0x56A8AEEE,0xCD0DE281,0xBA933071,0x21367C1E,0x55AE9591,0xCE0BD9FE,0xB9950B0E,0x22304761, + 0x5CBC35EC,0xC7197983,0xB087AB73,0x2B22E71C,0x5FBA0E93,0xC41F42FC,0xB381900C,0x2824DC63, + 0x5AB04312,0xC1150F7D,0xB68BDD8D,0x2D2E91E2,0x59B6786D,0xC2133402,0xB58DE6F2,0x2E28AA9D, + 0x489503E8,0xD3304F87,0xA4AE9D77,0x3F0BD118,0x4B933897,0xD03674F8,0xA7A8A608,0x3C0DEA67, + 0x4E997516,0xD53C3979,0xA2A2EB89,0x3907A7E6,0x4D9F4E69,0xD63A0206,0xA1A4D0F6,0x3A019C99, + 0x448DEE14,0xDF28A27B,0xA8B6708B,0x33133CE4,0x478BD56B,0xDC2E9904,0xABB04BF4,0x3015079B, + 0x428198EA,0xD924D485,0xAEBA0675,0x351F4A1A,0x4187A395,0xDA22EFFA,0xADBC3D0A,0x36197165, + }, + + { + 0x00000000,0xDD96D985,0x605CB54B,0xBDCA6CCE,0xC0B96A96,0x1D2FB313,0xA0E5DFDD,0x7D730658, + 0x5A03D36D,0x87950AE8,0x3A5F6626,0xE7C9BFA3,0x9ABAB9FB,0x472C607E,0xFAE60CB0,0x2770D535, + 0xB407A6DA,0x69917F5F,0xD45B1391,0x09CDCA14,0x74BECC4C,0xA92815C9,0x14E27907,0xC974A082, + 0xEE0475B7,0x3392AC32,0x8E58C0FC,0x53CE1979,0x2EBD1F21,0xF32BC6A4,0x4EE1AA6A,0x937773EF, + 0xB37E4BF5,0x6EE89270,0xD322FEBE,0x0EB4273B,0x73C72163,0xAE51F8E6,0x139B9428,0xCE0D4DAD, + 0xE97D9898,0x34EB411D,0x89212DD3,0x54B7F456,0x29C4F20E,0xF4522B8B,0x49984745,0x940E9EC0, + 0x0779ED2F,0xDAEF34AA,0x67255864,0xBAB381E1,0xC7C087B9,0x1A565E3C,0xA79C32F2,0x7A0AEB77, + 0x5D7A3E42,0x80ECE7C7,0x3D268B09,0xE0B0528C,0x9DC354D4,0x40558D51,0xFD9FE19F,0x2009381A, + 0xBD8D91AB,0x601B482E,0xDDD124E0,0x0047FD65,0x7D34FB3D,0xA0A222B8,0x1D684E76,0xC0FE97F3, + 0xE78E42C6,0x3A189B43,0x87D2F78D,0x5A442E08,0x27372850,0xFAA1F1D5,0x476B9D1B,0x9AFD449E, + 0x098A3771,0xD41CEEF4,0x69D6823A,0xB4405BBF,0xC9335DE7,0x14A58462,0xA96FE8AC,0x74F93129, + 0x5389E41C,0x8E1F3D99,0x33D55157,0xEE4388D2,0x93308E8A,0x4EA6570F,0xF36C3BC1,0x2EFAE244, + 0x0EF3DA5E,0xD36503DB,0x6EAF6F15,0xB339B690,0xCE4AB0C8,0x13DC694D,0xAE160583,0x7380DC06, + 0x54F00933,0x8966D0B6,0x34ACBC78,0xE93A65FD,0x944963A5,0x49DFBA20,0xF415D6EE,0x29830F6B, + 0xBAF47C84,0x6762A501,0xDAA8C9CF,0x073E104A,0x7A4D1612,0xA7DBCF97,0x1A11A359,0xC7877ADC, + 0xE0F7AFE9,0x3D61766C,0x80AB1AA2,0x5D3DC327,0x204EC57F,0xFDD81CFA,0x40127034,0x9D84A9B1, + 0xA06A2517,0x7DFCFC92,0xC036905C,0x1DA049D9,0x60D34F81,0xBD459604,0x008FFACA,0xDD19234F, + 0xFA69F67A,0x27FF2FFF,0x9A354331,0x47A39AB4,0x3AD09CEC,0xE7464569,0x5A8C29A7,0x871AF022, + 0x146D83CD,0xC9FB5A48,0x74313686,0xA9A7EF03,0xD4D4E95B,0x094230DE,0xB4885C10,0x691E8595, + 0x4E6E50A0,0x93F88925,0x2E32E5EB,0xF3A43C6E,0x8ED73A36,0x5341E3B3,0xEE8B8F7D,0x331D56F8, + 0x13146EE2,0xCE82B767,0x7348DBA9,0xAEDE022C,0xD3AD0474,0x0E3BDDF1,0xB3F1B13F,0x6E6768BA, + 0x4917BD8F,0x9481640A,0x294B08C4,0xF4DDD141,0x89AED719,0x54380E9C,0xE9F26252,0x3464BBD7, + 0xA713C838,0x7A8511BD,0xC74F7D73,0x1AD9A4F6,0x67AAA2AE,0xBA3C7B2B,0x07F617E5,0xDA60CE60, + 0xFD101B55,0x2086C2D0,0x9D4CAE1E,0x40DA779B,0x3DA971C3,0xE03FA846,0x5DF5C488,0x80631D0D, + 0x1DE7B4BC,0xC0716D39,0x7DBB01F7,0xA02DD872,0xDD5EDE2A,0x00C807AF,0xBD026B61,0x6094B2E4, + 0x47E467D1,0x9A72BE54,0x27B8D29A,0xFA2E0B1F,0x875D0D47,0x5ACBD4C2,0xE701B80C,0x3A976189, + 0xA9E01266,0x7476CBE3,0xC9BCA72D,0x142A7EA8,0x695978F0,0xB4CFA175,0x0905CDBB,0xD493143E, + 0xF3E3C10B,0x2E75188E,0x93BF7440,0x4E29ADC5,0x335AAB9D,0xEECC7218,0x53061ED6,0x8E90C753, + 0xAE99FF49,0x730F26CC,0xCEC54A02,0x13539387,0x6E2095DF,0xB3B64C5A,0x0E7C2094,0xD3EAF911, + 0xF49A2C24,0x290CF5A1,0x94C6996F,0x495040EA,0x342346B2,0xE9B59F37,0x547FF3F9,0x89E92A7C, + 0x1A9E5993,0xC7088016,0x7AC2ECD8,0xA754355D,0xDA273305,0x07B1EA80,0xBA7B864E,0x67ED5FCB, + 0x409D8AFE,0x9D0B537B,0x20C13FB5,0xFD57E630,0x8024E068,0x5DB239ED,0xE0785523,0x3DEE8CA6, + }, + + { + 0x00000000,0x9D0FE176,0xE16EC4AD,0x7C6125DB,0x19AC8F1B,0x84A36E6D,0xF8C24BB6,0x65CDAAC0, + 0x33591E36,0xAE56FF40,0xD237DA9B,0x4F383BED,0x2AF5912D,0xB7FA705B,0xCB9B5580,0x5694B4F6, + 0x66B23C6C,0xFBBDDD1A,0x87DCF8C1,0x1AD319B7,0x7F1EB377,0xE2115201,0x9E7077DA,0x037F96AC, + 0x55EB225A,0xC8E4C32C,0xB485E6F7,0x298A0781,0x4C47AD41,0xD1484C37,0xAD2969EC,0x3026889A, + 0xCD6478D8,0x506B99AE,0x2C0ABC75,0xB1055D03,0xD4C8F7C3,0x49C716B5,0x35A6336E,0xA8A9D218, + 0xFE3D66EE,0x63328798,0x1F53A243,0x825C4335,0xE791E9F5,0x7A9E0883,0x06FF2D58,0x9BF0CC2E, + 0xABD644B4,0x36D9A5C2,0x4AB88019,0xD7B7616F,0xB27ACBAF,0x2F752AD9,0x53140F02,0xCE1BEE74, + 0x988F5A82,0x0580BBF4,0x79E19E2F,0xE4EE7F59,0x8123D599,0x1C2C34EF,0x604D1134,0xFD42F042, + 0x41B9F7F1,0xDCB61687,0xA0D7335C,0x3DD8D22A,0x581578EA,0xC51A999C,0xB97BBC47,0x24745D31, + 0x72E0E9C7,0xEFEF08B1,0x938E2D6A,0x0E81CC1C,0x6B4C66DC,0xF64387AA,0x8A22A271,0x172D4307, + 0x270BCB9D,0xBA042AEB,0xC6650F30,0x5B6AEE46,0x3EA74486,0xA3A8A5F0,0xDFC9802B,0x42C6615D, + 0x1452D5AB,0x895D34DD,0xF53C1106,0x6833F070,0x0DFE5AB0,0x90F1BBC6,0xEC909E1D,0x719F7F6B, + 0x8CDD8F29,0x11D26E5F,0x6DB34B84,0xF0BCAAF2,0x95710032,0x087EE144,0x741FC49F,0xE91025E9, + 0xBF84911F,0x228B7069,0x5EEA55B2,0xC3E5B4C4,0xA6281E04,0x3B27FF72,0x4746DAA9,0xDA493BDF, + 0xEA6FB345,0x77605233,0x0B0177E8,0x960E969E,0xF3C33C5E,0x6ECCDD28,0x12ADF8F3,0x8FA21985, + 0xD936AD73,0x44394C05,0x385869DE,0xA55788A8,0xC09A2268,0x5D95C31E,0x21F4E6C5,0xBCFB07B3, + 0x8373EFE2,0x1E7C0E94,0x621D2B4F,0xFF12CA39,0x9ADF60F9,0x07D0818F,0x7BB1A454,0xE6BE4522, + 0xB02AF1D4,0x2D2510A2,0x51443579,0xCC4BD40F,0xA9867ECF,0x34899FB9,0x48E8BA62,0xD5E75B14, + 0xE5C1D38E,0x78CE32F8,0x04AF1723,0x99A0F655,0xFC6D5C95,0x6162BDE3,0x1D039838,0x800C794E, + 0xD698CDB8,0x4B972CCE,0x37F60915,0xAAF9E863,0xCF3442A3,0x523BA3D5,0x2E5A860E,0xB3556778, + 0x4E17973A,0xD318764C,0xAF795397,0x3276B2E1,0x57BB1821,0xCAB4F957,0xB6D5DC8C,0x2BDA3DFA, + 0x7D4E890C,0xE041687A,0x9C204DA1,0x012FACD7,0x64E20617,0xF9EDE761,0x858CC2BA,0x188323CC, + 0x28A5AB56,0xB5AA4A20,0xC9CB6FFB,0x54C48E8D,0x3109244D,0xAC06C53B,0xD067E0E0,0x4D680196, + 0x1BFCB560,0x86F35416,0xFA9271CD,0x679D90BB,0x02503A7B,0x9F5FDB0D,0xE33EFED6,0x7E311FA0, + 0xC2CA1813,0x5FC5F965,0x23A4DCBE,0xBEAB3DC8,0xDB669708,0x4669767E,0x3A0853A5,0xA707B2D3, + 0xF1930625,0x6C9CE753,0x10FDC288,0x8DF223FE,0xE83F893E,0x75306848,0x09514D93,0x945EACE5, + 0xA478247F,0x3977C509,0x4516E0D2,0xD81901A4,0xBDD4AB64,0x20DB4A12,0x5CBA6FC9,0xC1B58EBF, + 0x97213A49,0x0A2EDB3F,0x764FFEE4,0xEB401F92,0x8E8DB552,0x13825424,0x6FE371FF,0xF2EC9089, + 0x0FAE60CB,0x92A181BD,0xEEC0A466,0x73CF4510,0x1602EFD0,0x8B0D0EA6,0xF76C2B7D,0x6A63CA0B, + 0x3CF77EFD,0xA1F89F8B,0xDD99BA50,0x40965B26,0x255BF1E6,0xB8541090,0xC435354B,0x593AD43D, + 0x691C5CA7,0xF413BDD1,0x8872980A,0x157D797C,0x70B0D3BC,0xEDBF32CA,0x91DE1711,0x0CD1F667, + 0x5A454291,0xC74AA3E7,0xBB2B863C,0x2624674A,0x43E9CD8A,0xDEE62CFC,0xA2870927,0x3F88E851, + }, + + { + 0x00000000,0xB9FBDBE8,0xA886B191,0x117D6A79,0x8A7C6563,0x3387BE8B,0x22FAD4F2,0x9B010F1A, + 0xCF89CC87,0x7672176F,0x670F7D16,0xDEF4A6FE,0x45F5A9E4,0xFC0E720C,0xED731875,0x5488C39D, + 0x44629F4F,0xFD9944A7,0xECE42EDE,0x551FF536,0xCE1EFA2C,0x77E521C4,0x66984BBD,0xDF639055, + 0x8BEB53C8,0x32108820,0x236DE259,0x9A9639B1,0x019736AB,0xB86CED43,0xA911873A,0x10EA5CD2, + 0x88C53E9E,0x313EE576,0x20438F0F,0x99B854E7,0x02B95BFD,0xBB428015,0xAA3FEA6C,0x13C43184, + 0x474CF219,0xFEB729F1,0xEFCA4388,0x56319860,0xCD30977A,0x74CB4C92,0x65B626EB,0xDC4DFD03, + 0xCCA7A1D1,0x755C7A39,0x64211040,0xDDDACBA8,0x46DBC4B2,0xFF201F5A,0xEE5D7523,0x57A6AECB, + 0x032E6D56,0xBAD5B6BE,0xABA8DCC7,0x1253072F,0x89520835,0x30A9D3DD,0x21D4B9A4,0x982F624C, + 0xCAFB7B7D,0x7300A095,0x627DCAEC,0xDB861104,0x40871E1E,0xF97CC5F6,0xE801AF8F,0x51FA7467, + 0x0572B7FA,0xBC896C12,0xADF4066B,0x140FDD83,0x8F0ED299,0x36F50971,0x27886308,0x9E73B8E0, + 0x8E99E432,0x37623FDA,0x261F55A3,0x9FE48E4B,0x04E58151,0xBD1E5AB9,0xAC6330C0,0x1598EB28, + 0x411028B5,0xF8EBF35D,0xE9969924,0x506D42CC,0xCB6C4DD6,0x7297963E,0x63EAFC47,0xDA1127AF, + 0x423E45E3,0xFBC59E0B,0xEAB8F472,0x53432F9A,0xC8422080,0x71B9FB68,0x60C49111,0xD93F4AF9, + 0x8DB78964,0x344C528C,0x253138F5,0x9CCAE31D,0x07CBEC07,0xBE3037EF,0xAF4D5D96,0x16B6867E, + 0x065CDAAC,0xBFA70144,0xAEDA6B3D,0x1721B0D5,0x8C20BFCF,0x35DB6427,0x24A60E5E,0x9D5DD5B6, + 0xC9D5162B,0x702ECDC3,0x6153A7BA,0xD8A87C52,0x43A97348,0xFA52A8A0,0xEB2FC2D9,0x52D41931, + 0x4E87F0BB,0xF77C2B53,0xE601412A,0x5FFA9AC2,0xC4FB95D8,0x7D004E30,0x6C7D2449,0xD586FFA1, + 0x810E3C3C,0x38F5E7D4,0x29888DAD,0x90735645,0x0B72595F,0xB28982B7,0xA3F4E8CE,0x1A0F3326, + 0x0AE56FF4,0xB31EB41C,0xA263DE65,0x1B98058D,0x80990A97,0x3962D17F,0x281FBB06,0x91E460EE, + 0xC56CA373,0x7C97789B,0x6DEA12E2,0xD411C90A,0x4F10C610,0xF6EB1DF8,0xE7967781,0x5E6DAC69, + 0xC642CE25,0x7FB915CD,0x6EC47FB4,0xD73FA45C,0x4C3EAB46,0xF5C570AE,0xE4B81AD7,0x5D43C13F, + 0x09CB02A2,0xB030D94A,0xA14DB333,0x18B668DB,0x83B767C1,0x3A4CBC29,0x2B31D650,0x92CA0DB8, + 0x8220516A,0x3BDB8A82,0x2AA6E0FB,0x935D3B13,0x085C3409,0xB1A7EFE1,0xA0DA8598,0x19215E70, + 0x4DA99DED,0xF4524605,0xE52F2C7C,0x5CD4F794,0xC7D5F88E,0x7E2E2366,0x6F53491F,0xD6A892F7, + 0x847C8BC6,0x3D87502E,0x2CFA3A57,0x9501E1BF,0x0E00EEA5,0xB7FB354D,0xA6865F34,0x1F7D84DC, + 0x4BF54741,0xF20E9CA9,0xE373F6D0,0x5A882D38,0xC1892222,0x7872F9CA,0x690F93B3,0xD0F4485B, + 0xC01E1489,0x79E5CF61,0x6898A518,0xD1637EF0,0x4A6271EA,0xF399AA02,0xE2E4C07B,0x5B1F1B93, + 0x0F97D80E,0xB66C03E6,0xA711699F,0x1EEAB277,0x85EBBD6D,0x3C106685,0x2D6D0CFC,0x9496D714, + 0x0CB9B558,0xB5426EB0,0xA43F04C9,0x1DC4DF21,0x86C5D03B,0x3F3E0BD3,0x2E4361AA,0x97B8BA42, + 0xC33079DF,0x7ACBA237,0x6BB6C84E,0xD24D13A6,0x494C1CBC,0xF0B7C754,0xE1CAAD2D,0x583176C5, + 0x48DB2A17,0xF120F1FF,0xE05D9B86,0x59A6406E,0xC2A74F74,0x7B5C949C,0x6A21FEE5,0xD3DA250D, + 0x8752E690,0x3EA93D78,0x2FD45701,0x962F8CE9,0x0D2E83F3,0xB4D5581B,0xA5A83262,0x1C53E98A, + }, + + { + 0x00000000,0xAE689191,0x87A02563,0x29C8B4F2,0xD4314C87,0x7A59DD16,0x539169E4,0xFDF9F875, + 0x73139F4F,0xDD7B0EDE,0xF4B3BA2C,0x5ADB2BBD,0xA722D3C8,0x094A4259,0x2082F6AB,0x8EEA673A, + 0xE6273E9E,0x484FAF0F,0x61871BFD,0xCFEF8A6C,0x32167219,0x9C7EE388,0xB5B6577A,0x1BDEC6EB, + 0x9534A1D1,0x3B5C3040,0x129484B2,0xBCFC1523,0x4105ED56,0xEF6D7CC7,0xC6A5C835,0x68CD59A4, + 0x173F7B7D,0xB957EAEC,0x909F5E1E,0x3EF7CF8F,0xC30E37FA,0x6D66A66B,0x44AE1299,0xEAC68308, + 0x642CE432,0xCA4475A3,0xE38CC151,0x4DE450C0,0xB01DA8B5,0x1E753924,0x37BD8DD6,0x99D51C47, + 0xF11845E3,0x5F70D472,0x76B86080,0xD8D0F111,0x25290964,0x8B4198F5,0xA2892C07,0x0CE1BD96, + 0x820BDAAC,0x2C634B3D,0x05ABFFCF,0xABC36E5E,0x563A962B,0xF85207BA,0xD19AB348,0x7FF222D9, + 0x2E7EF6FA,0x8016676B,0xA9DED399,0x07B64208,0xFA4FBA7D,0x54272BEC,0x7DEF9F1E,0xD3870E8F, + 0x5D6D69B5,0xF305F824,0xDACD4CD6,0x74A5DD47,0x895C2532,0x2734B4A3,0x0EFC0051,0xA09491C0, + 0xC859C864,0x663159F5,0x4FF9ED07,0xE1917C96,0x1C6884E3,0xB2001572,0x9BC8A180,0x35A03011, + 0xBB4A572B,0x1522C6BA,0x3CEA7248,0x9282E3D9,0x6F7B1BAC,0xC1138A3D,0xE8DB3ECF,0x46B3AF5E, + 0x39418D87,0x97291C16,0xBEE1A8E4,0x10893975,0xED70C100,0x43185091,0x6AD0E463,0xC4B875F2, + 0x4A5212C8,0xE43A8359,0xCDF237AB,0x639AA63A,0x9E635E4F,0x300BCFDE,0x19C37B2C,0xB7ABEABD, + 0xDF66B319,0x710E2288,0x58C6967A,0xF6AE07EB,0x0B57FF9E,0xA53F6E0F,0x8CF7DAFD,0x229F4B6C, + 0xAC752C56,0x021DBDC7,0x2BD50935,0x85BD98A4,0x784460D1,0xD62CF140,0xFFE445B2,0x518CD423, + 0x5CFDEDF4,0xF2957C65,0xDB5DC897,0x75355906,0x88CCA173,0x26A430E2,0x0F6C8410,0xA1041581, + 0x2FEE72BB,0x8186E32A,0xA84E57D8,0x0626C649,0xFBDF3E3C,0x55B7AFAD,0x7C7F1B5F,0xD2178ACE, + 0xBADAD36A,0x14B242FB,0x3D7AF609,0x93126798,0x6EEB9FED,0xC0830E7C,0xE94BBA8E,0x47232B1F, + 0xC9C94C25,0x67A1DDB4,0x4E696946,0xE001F8D7,0x1DF800A2,0xB3909133,0x9A5825C1,0x3430B450, + 0x4BC29689,0xE5AA0718,0xCC62B3EA,0x620A227B,0x9FF3DA0E,0x319B4B9F,0x1853FF6D,0xB63B6EFC, + 0x38D109C6,0x96B99857,0xBF712CA5,0x1119BD34,0xECE04541,0x4288D4D0,0x6B406022,0xC528F1B3, + 0xADE5A817,0x038D3986,0x2A458D74,0x842D1CE5,0x79D4E490,0xD7BC7501,0xFE74C1F3,0x501C5062, + 0xDEF63758,0x709EA6C9,0x5956123B,0xF73E83AA,0x0AC77BDF,0xA4AFEA4E,0x8D675EBC,0x230FCF2D, + 0x72831B0E,0xDCEB8A9F,0xF5233E6D,0x5B4BAFFC,0xA6B25789,0x08DAC618,0x211272EA,0x8F7AE37B, + 0x01908441,0xAFF815D0,0x8630A122,0x285830B3,0xD5A1C8C6,0x7BC95957,0x5201EDA5,0xFC697C34, + 0x94A42590,0x3ACCB401,0x130400F3,0xBD6C9162,0x40956917,0xEEFDF886,0xC7354C74,0x695DDDE5, + 0xE7B7BADF,0x49DF2B4E,0x60179FBC,0xCE7F0E2D,0x3386F658,0x9DEE67C9,0xB426D33B,0x1A4E42AA, + 0x65BC6073,0xCBD4F1E2,0xE21C4510,0x4C74D481,0xB18D2CF4,0x1FE5BD65,0x362D0997,0x98459806, + 0x16AFFF3C,0xB8C76EAD,0x910FDA5F,0x3F674BCE,0xC29EB3BB,0x6CF6222A,0x453E96D8,0xEB560749, + 0x839B5EED,0x2DF3CF7C,0x043B7B8E,0xAA53EA1F,0x57AA126A,0xF9C283FB,0xD00A3709,0x7E62A698, + 0xF088C1A2,0x5EE05033,0x7728E4C1,0xD9407550,0x24B98D25,0x8AD11CB4,0xA319A846,0x0D7139D7, + } +#endif // CRC32_USE_LOOKUP_TABLE_SLICING_BY_16 +}; +#endif // NO_LUT diff --git a/lib/crc32/Crc32.h b/lib/crc32/Crc32.h new file mode 100644 index 0000000..cf60e0b --- /dev/null +++ b/lib/crc32/Crc32.h @@ -0,0 +1,69 @@ +// ////////////////////////////////////////////////////////// +// Crc32.h +// Copyright (c) 2011-2019 Stephan Brumme. All rights reserved. +// Slicing-by-16 contributed by Bulat Ziganshin +// Tableless bytewise CRC contributed by Hagai Gold +// see http://create.stephan-brumme.com/disclaimer.html +// + +// if running on an embedded system, you might consider shrinking the +// big Crc32Lookup table by undefining these lines: +#define CRC32_USE_LOOKUP_TABLE_BYTE +#define CRC32_USE_LOOKUP_TABLE_SLICING_BY_4 +#define CRC32_USE_LOOKUP_TABLE_SLICING_BY_8 +#define CRC32_USE_LOOKUP_TABLE_SLICING_BY_16 +// - crc32_bitwise doesn't need it at all +// - crc32_halfbyte has its own small lookup table +// - crc32_1byte_tableless and crc32_1byte_tableless2 don't need it at all +// - crc32_1byte needs only Crc32Lookup[0] +// - crc32_4bytes needs only Crc32Lookup[0..3] +// - crc32_8bytes needs only Crc32Lookup[0..7] +// - crc32_4x8bytes needs only Crc32Lookup[0..7] +// - crc32_16bytes needs all of Crc32Lookup +// using the aforementioned #defines the table is automatically fitted to your needs + +// uint8_t, uint32_t, int32_t +#include +// size_t +#include + +// crc32_fast selects the fastest algorithm depending on flags (CRC32_USE_LOOKUP_...) +/// compute CRC32 using the fastest algorithm for large datasets on modern CPUs +uint32_t crc32_fast (const void* data, size_t length, uint32_t previousCrc32 = 0); + +/// merge two CRC32 such that result = crc32(dataB, lengthB, crc32(dataA, lengthA)) +uint32_t crc32_combine (uint32_t crcA, uint32_t crcB, size_t lengthB); + +/// compute CRC32 (bitwise algorithm) +uint32_t crc32_bitwise (const void* data, size_t length, uint32_t previousCrc32 = 0); +/// compute CRC32 (half-byte algoritm) +uint32_t crc32_halfbyte(const void* data, size_t length, uint32_t previousCrc32 = 0); + +#ifdef CRC32_USE_LOOKUP_TABLE_BYTE +/// compute CRC32 (standard algorithm) +uint32_t crc32_1byte (const void* data, size_t length, uint32_t previousCrc32 = 0); +#endif + +/// compute CRC32 (byte algorithm) without lookup tables +uint32_t crc32_1byte_tableless (const void* data, size_t length, uint32_t previousCrc32 = 0); +/// compute CRC32 (byte algorithm) without lookup tables +uint32_t crc32_1byte_tableless2(const void* data, size_t length, uint32_t previousCrc32 = 0); + +#ifdef CRC32_USE_LOOKUP_TABLE_SLICING_BY_4 +/// compute CRC32 (Slicing-by-4 algorithm) +uint32_t crc32_4bytes (const void* data, size_t length, uint32_t previousCrc32 = 0); +#endif + +#ifdef CRC32_USE_LOOKUP_TABLE_SLICING_BY_8 +/// compute CRC32 (Slicing-by-8 algorithm) +uint32_t crc32_8bytes (const void* data, size_t length, uint32_t previousCrc32 = 0); +/// compute CRC32 (Slicing-by-8 algorithm), unroll inner loop 4 times +uint32_t crc32_4x8bytes(const void* data, size_t length, uint32_t previousCrc32 = 0); +#endif + +#ifdef CRC32_USE_LOOKUP_TABLE_SLICING_BY_16 +/// compute CRC32 (Slicing-by-16 algorithm) +uint32_t crc32_16bytes (const void* data, size_t length, uint32_t previousCrc32 = 0); +/// compute CRC32 (Slicing-by-16 algorithm, prefetch upcoming data blocks) +uint32_t crc32_16bytes_prefetch(const void* data, size_t length, uint32_t previousCrc32 = 0, size_t prefetchAhead = 256); +#endif diff --git a/lib/crc32/Crc32.ino b/lib/crc32/Crc32.ino new file mode 100644 index 0000000..28a8960 --- /dev/null +++ b/lib/crc32/Crc32.ino @@ -0,0 +1,546 @@ +// ////////////////////////////////////////////////////////// +// Crc32.ino +// Copyright (c) 2011 Stephan Brumme. All rights reserved. +// see http://create.stephan-brumme.com/disclaimer.html +// + +/// zlib's CRC32 polynomial +const uint32_t Polynomial = 0xEDB88320; + +const size_t NumBytes = 256; +uint8_t data[NumBytes]; +const size_t Repetitions = 4*1024; + + +PROGMEM uint32_t crc32Lookup[8*256] = +{ 0x00000000,0x77073096,0xEE0E612C,0x990951BA,0x076DC419,0x706AF48F,0xE963A535,0x9E6495A3, + 0x0EDB8832,0x79DCB8A4,0xE0D5E91E,0x97D2D988,0x09B64C2B,0x7EB17CBD,0xE7B82D07,0x90BF1D91, + 0x1DB71064,0x6AB020F2,0xF3B97148,0x84BE41DE,0x1ADAD47D,0x6DDDE4EB,0xF4D4B551,0x83D385C7, + 0x136C9856,0x646BA8C0,0xFD62F97A,0x8A65C9EC,0x14015C4F,0x63066CD9,0xFA0F3D63,0x8D080DF5, + 0x3B6E20C8,0x4C69105E,0xD56041E4,0xA2677172,0x3C03E4D1,0x4B04D447,0xD20D85FD,0xA50AB56B, + 0x35B5A8FA,0x42B2986C,0xDBBBC9D6,0xACBCF940,0x32D86CE3,0x45DF5C75,0xDCD60DCF,0xABD13D59, + 0x26D930AC,0x51DE003A,0xC8D75180,0xBFD06116,0x21B4F4B5,0x56B3C423,0xCFBA9599,0xB8BDA50F, + 0x2802B89E,0x5F058808,0xC60CD9B2,0xB10BE924,0x2F6F7C87,0x58684C11,0xC1611DAB,0xB6662D3D, + 0x76DC4190,0x01DB7106,0x98D220BC,0xEFD5102A,0x71B18589,0x06B6B51F,0x9FBFE4A5,0xE8B8D433, + 0x7807C9A2,0x0F00F934,0x9609A88E,0xE10E9818,0x7F6A0DBB,0x086D3D2D,0x91646C97,0xE6635C01, + 0x6B6B51F4,0x1C6C6162,0x856530D8,0xF262004E,0x6C0695ED,0x1B01A57B,0x8208F4C1,0xF50FC457, + 0x65B0D9C6,0x12B7E950,0x8BBEB8EA,0xFCB9887C,0x62DD1DDF,0x15DA2D49,0x8CD37CF3,0xFBD44C65, + 0x4DB26158,0x3AB551CE,0xA3BC0074,0xD4BB30E2,0x4ADFA541,0x3DD895D7,0xA4D1C46D,0xD3D6F4FB, + 0x4369E96A,0x346ED9FC,0xAD678846,0xDA60B8D0,0x44042D73,0x33031DE5,0xAA0A4C5F,0xDD0D7CC9, + 0x5005713C,0x270241AA,0xBE0B1010,0xC90C2086,0x5768B525,0x206F85B3,0xB966D409,0xCE61E49F, + 0x5EDEF90E,0x29D9C998,0xB0D09822,0xC7D7A8B4,0x59B33D17,0x2EB40D81,0xB7BD5C3B,0xC0BA6CAD, + 0xEDB88320,0x9ABFB3B6,0x03B6E20C,0x74B1D29A,0xEAD54739,0x9DD277AF,0x04DB2615,0x73DC1683, + 0xE3630B12,0x94643B84,0x0D6D6A3E,0x7A6A5AA8,0xE40ECF0B,0x9309FF9D,0x0A00AE27,0x7D079EB1, + 0xF00F9344,0x8708A3D2,0x1E01F268,0x6906C2FE,0xF762575D,0x806567CB,0x196C3671,0x6E6B06E7, + 0xFED41B76,0x89D32BE0,0x10DA7A5A,0x67DD4ACC,0xF9B9DF6F,0x8EBEEFF9,0x17B7BE43,0x60B08ED5, + 0xD6D6A3E8,0xA1D1937E,0x38D8C2C4,0x4FDFF252,0xD1BB67F1,0xA6BC5767,0x3FB506DD,0x48B2364B, + 0xD80D2BDA,0xAF0A1B4C,0x36034AF6,0x41047A60,0xDF60EFC3,0xA867DF55,0x316E8EEF,0x4669BE79, + 0xCB61B38C,0xBC66831A,0x256FD2A0,0x5268E236,0xCC0C7795,0xBB0B4703,0x220216B9,0x5505262F, + 0xC5BA3BBE,0xB2BD0B28,0x2BB45A92,0x5CB36A04,0xC2D7FFA7,0xB5D0CF31,0x2CD99E8B,0x5BDEAE1D, + 0x9B64C2B0,0xEC63F226,0x756AA39C,0x026D930A,0x9C0906A9,0xEB0E363F,0x72076785,0x05005713, + 0x95BF4A82,0xE2B87A14,0x7BB12BAE,0x0CB61B38,0x92D28E9B,0xE5D5BE0D,0x7CDCEFB7,0x0BDBDF21, + 0x86D3D2D4,0xF1D4E242,0x68DDB3F8,0x1FDA836E,0x81BE16CD,0xF6B9265B,0x6FB077E1,0x18B74777, + 0x88085AE6,0xFF0F6A70,0x66063BCA,0x11010B5C,0x8F659EFF,0xF862AE69,0x616BFFD3,0x166CCF45, + 0xA00AE278,0xD70DD2EE,0x4E048354,0x3903B3C2,0xA7672661,0xD06016F7,0x4969474D,0x3E6E77DB, + 0xAED16A4A,0xD9D65ADC,0x40DF0B66,0x37D83BF0,0xA9BCAE53,0xDEBB9EC5,0x47B2CF7F,0x30B5FFE9, + 0xBDBDF21C,0xCABAC28A,0x53B39330,0x24B4A3A6,0xBAD03605,0xCDD70693,0x54DE5729,0x23D967BF, + 0xB3667A2E,0xC4614AB8,0x5D681B02,0x2A6F2B94,0xB40BBE37,0xC30C8EA1,0x5A05DF1B,0x2D02EF8D, + + 0x00000000,0x191B3141,0x32366282,0x2B2D53C3,0x646CC504,0x7D77F445,0x565AA786,0x4F4196C7, + 0xC8D98A08,0xD1C2BB49,0xFAEFE88A,0xE3F4D9CB,0xACB54F0C,0xB5AE7E4D,0x9E832D8E,0x87981CCF, + 0x4AC21251,0x53D92310,0x78F470D3,0x61EF4192,0x2EAED755,0x37B5E614,0x1C98B5D7,0x05838496, + 0x821B9859,0x9B00A918,0xB02DFADB,0xA936CB9A,0xE6775D5D,0xFF6C6C1C,0xD4413FDF,0xCD5A0E9E, + 0x958424A2,0x8C9F15E3,0xA7B24620,0xBEA97761,0xF1E8E1A6,0xE8F3D0E7,0xC3DE8324,0xDAC5B265, + 0x5D5DAEAA,0x44469FEB,0x6F6BCC28,0x7670FD69,0x39316BAE,0x202A5AEF,0x0B07092C,0x121C386D, + 0xDF4636F3,0xC65D07B2,0xED705471,0xF46B6530,0xBB2AF3F7,0xA231C2B6,0x891C9175,0x9007A034, + 0x179FBCFB,0x0E848DBA,0x25A9DE79,0x3CB2EF38,0x73F379FF,0x6AE848BE,0x41C51B7D,0x58DE2A3C, + 0xF0794F05,0xE9627E44,0xC24F2D87,0xDB541CC6,0x94158A01,0x8D0EBB40,0xA623E883,0xBF38D9C2, + 0x38A0C50D,0x21BBF44C,0x0A96A78F,0x138D96CE,0x5CCC0009,0x45D73148,0x6EFA628B,0x77E153CA, + 0xBABB5D54,0xA3A06C15,0x888D3FD6,0x91960E97,0xDED79850,0xC7CCA911,0xECE1FAD2,0xF5FACB93, + 0x7262D75C,0x6B79E61D,0x4054B5DE,0x594F849F,0x160E1258,0x0F152319,0x243870DA,0x3D23419B, + 0x65FD6BA7,0x7CE65AE6,0x57CB0925,0x4ED03864,0x0191AEA3,0x188A9FE2,0x33A7CC21,0x2ABCFD60, + 0xAD24E1AF,0xB43FD0EE,0x9F12832D,0x8609B26C,0xC94824AB,0xD05315EA,0xFB7E4629,0xE2657768, + 0x2F3F79F6,0x362448B7,0x1D091B74,0x04122A35,0x4B53BCF2,0x52488DB3,0x7965DE70,0x607EEF31, + 0xE7E6F3FE,0xFEFDC2BF,0xD5D0917C,0xCCCBA03D,0x838A36FA,0x9A9107BB,0xB1BC5478,0xA8A76539, + 0x3B83984B,0x2298A90A,0x09B5FAC9,0x10AECB88,0x5FEF5D4F,0x46F46C0E,0x6DD93FCD,0x74C20E8C, + 0xF35A1243,0xEA412302,0xC16C70C1,0xD8774180,0x9736D747,0x8E2DE606,0xA500B5C5,0xBC1B8484, + 0x71418A1A,0x685ABB5B,0x4377E898,0x5A6CD9D9,0x152D4F1E,0x0C367E5F,0x271B2D9C,0x3E001CDD, + 0xB9980012,0xA0833153,0x8BAE6290,0x92B553D1,0xDDF4C516,0xC4EFF457,0xEFC2A794,0xF6D996D5, + 0xAE07BCE9,0xB71C8DA8,0x9C31DE6B,0x852AEF2A,0xCA6B79ED,0xD37048AC,0xF85D1B6F,0xE1462A2E, + 0x66DE36E1,0x7FC507A0,0x54E85463,0x4DF36522,0x02B2F3E5,0x1BA9C2A4,0x30849167,0x299FA026, + 0xE4C5AEB8,0xFDDE9FF9,0xD6F3CC3A,0xCFE8FD7B,0x80A96BBC,0x99B25AFD,0xB29F093E,0xAB84387F, + 0x2C1C24B0,0x350715F1,0x1E2A4632,0x07317773,0x4870E1B4,0x516BD0F5,0x7A468336,0x635DB277, + 0xCBFAD74E,0xD2E1E60F,0xF9CCB5CC,0xE0D7848D,0xAF96124A,0xB68D230B,0x9DA070C8,0x84BB4189, + 0x03235D46,0x1A386C07,0x31153FC4,0x280E0E85,0x674F9842,0x7E54A903,0x5579FAC0,0x4C62CB81, + 0x8138C51F,0x9823F45E,0xB30EA79D,0xAA1596DC,0xE554001B,0xFC4F315A,0xD7626299,0xCE7953D8, + 0x49E14F17,0x50FA7E56,0x7BD72D95,0x62CC1CD4,0x2D8D8A13,0x3496BB52,0x1FBBE891,0x06A0D9D0, + 0x5E7EF3EC,0x4765C2AD,0x6C48916E,0x7553A02F,0x3A1236E8,0x230907A9,0x0824546A,0x113F652B, + 0x96A779E4,0x8FBC48A5,0xA4911B66,0xBD8A2A27,0xF2CBBCE0,0xEBD08DA1,0xC0FDDE62,0xD9E6EF23, + 0x14BCE1BD,0x0DA7D0FC,0x268A833F,0x3F91B27E,0x70D024B9,0x69CB15F8,0x42E6463B,0x5BFD777A, + 0xDC656BB5,0xC57E5AF4,0xEE530937,0xF7483876,0xB809AEB1,0xA1129FF0,0x8A3FCC33,0x9324FD72, + + 0x00000000,0x01C26A37,0x0384D46E,0x0246BE59,0x0709A8DC,0x06CBC2EB,0x048D7CB2,0x054F1685, + 0x0E1351B8,0x0FD13B8F,0x0D9785D6,0x0C55EFE1,0x091AF964,0x08D89353,0x0A9E2D0A,0x0B5C473D, + 0x1C26A370,0x1DE4C947,0x1FA2771E,0x1E601D29,0x1B2F0BAC,0x1AED619B,0x18ABDFC2,0x1969B5F5, + 0x1235F2C8,0x13F798FF,0x11B126A6,0x10734C91,0x153C5A14,0x14FE3023,0x16B88E7A,0x177AE44D, + 0x384D46E0,0x398F2CD7,0x3BC9928E,0x3A0BF8B9,0x3F44EE3C,0x3E86840B,0x3CC03A52,0x3D025065, + 0x365E1758,0x379C7D6F,0x35DAC336,0x3418A901,0x3157BF84,0x3095D5B3,0x32D36BEA,0x331101DD, + 0x246BE590,0x25A98FA7,0x27EF31FE,0x262D5BC9,0x23624D4C,0x22A0277B,0x20E69922,0x2124F315, + 0x2A78B428,0x2BBADE1F,0x29FC6046,0x283E0A71,0x2D711CF4,0x2CB376C3,0x2EF5C89A,0x2F37A2AD, + 0x709A8DC0,0x7158E7F7,0x731E59AE,0x72DC3399,0x7793251C,0x76514F2B,0x7417F172,0x75D59B45, + 0x7E89DC78,0x7F4BB64F,0x7D0D0816,0x7CCF6221,0x798074A4,0x78421E93,0x7A04A0CA,0x7BC6CAFD, + 0x6CBC2EB0,0x6D7E4487,0x6F38FADE,0x6EFA90E9,0x6BB5866C,0x6A77EC5B,0x68315202,0x69F33835, + 0x62AF7F08,0x636D153F,0x612BAB66,0x60E9C151,0x65A6D7D4,0x6464BDE3,0x662203BA,0x67E0698D, + 0x48D7CB20,0x4915A117,0x4B531F4E,0x4A917579,0x4FDE63FC,0x4E1C09CB,0x4C5AB792,0x4D98DDA5, + 0x46C49A98,0x4706F0AF,0x45404EF6,0x448224C1,0x41CD3244,0x400F5873,0x4249E62A,0x438B8C1D, + 0x54F16850,0x55330267,0x5775BC3E,0x56B7D609,0x53F8C08C,0x523AAABB,0x507C14E2,0x51BE7ED5, + 0x5AE239E8,0x5B2053DF,0x5966ED86,0x58A487B1,0x5DEB9134,0x5C29FB03,0x5E6F455A,0x5FAD2F6D, + 0xE1351B80,0xE0F771B7,0xE2B1CFEE,0xE373A5D9,0xE63CB35C,0xE7FED96B,0xE5B86732,0xE47A0D05, + 0xEF264A38,0xEEE4200F,0xECA29E56,0xED60F461,0xE82FE2E4,0xE9ED88D3,0xEBAB368A,0xEA695CBD, + 0xFD13B8F0,0xFCD1D2C7,0xFE976C9E,0xFF5506A9,0xFA1A102C,0xFBD87A1B,0xF99EC442,0xF85CAE75, + 0xF300E948,0xF2C2837F,0xF0843D26,0xF1465711,0xF4094194,0xF5CB2BA3,0xF78D95FA,0xF64FFFCD, + 0xD9785D60,0xD8BA3757,0xDAFC890E,0xDB3EE339,0xDE71F5BC,0xDFB39F8B,0xDDF521D2,0xDC374BE5, + 0xD76B0CD8,0xD6A966EF,0xD4EFD8B6,0xD52DB281,0xD062A404,0xD1A0CE33,0xD3E6706A,0xD2241A5D, + 0xC55EFE10,0xC49C9427,0xC6DA2A7E,0xC7184049,0xC25756CC,0xC3953CFB,0xC1D382A2,0xC011E895, + 0xCB4DAFA8,0xCA8FC59F,0xC8C97BC6,0xC90B11F1,0xCC440774,0xCD866D43,0xCFC0D31A,0xCE02B92D, + 0x91AF9640,0x906DFC77,0x922B422E,0x93E92819,0x96A63E9C,0x976454AB,0x9522EAF2,0x94E080C5, + 0x9FBCC7F8,0x9E7EADCF,0x9C381396,0x9DFA79A1,0x98B56F24,0x99770513,0x9B31BB4A,0x9AF3D17D, + 0x8D893530,0x8C4B5F07,0x8E0DE15E,0x8FCF8B69,0x8A809DEC,0x8B42F7DB,0x89044982,0x88C623B5, + 0x839A6488,0x82580EBF,0x801EB0E6,0x81DCDAD1,0x8493CC54,0x8551A663,0x8717183A,0x86D5720D, + 0xA9E2D0A0,0xA820BA97,0xAA6604CE,0xABA46EF9,0xAEEB787C,0xAF29124B,0xAD6FAC12,0xACADC625, + 0xA7F18118,0xA633EB2F,0xA4755576,0xA5B73F41,0xA0F829C4,0xA13A43F3,0xA37CFDAA,0xA2BE979D, + 0xB5C473D0,0xB40619E7,0xB640A7BE,0xB782CD89,0xB2CDDB0C,0xB30FB13B,0xB1490F62,0xB08B6555, + 0xBBD72268,0xBA15485F,0xB853F606,0xB9919C31,0xBCDE8AB4,0xBD1CE083,0xBF5A5EDA,0xBE9834ED, + + 0x00000000,0xB8BC6765,0xAA09C88B,0x12B5AFEE,0x8F629757,0x37DEF032,0x256B5FDC,0x9DD738B9, + 0xC5B428EF,0x7D084F8A,0x6FBDE064,0xD7018701,0x4AD6BFB8,0xF26AD8DD,0xE0DF7733,0x58631056, + 0x5019579F,0xE8A530FA,0xFA109F14,0x42ACF871,0xDF7BC0C8,0x67C7A7AD,0x75720843,0xCDCE6F26, + 0x95AD7F70,0x2D111815,0x3FA4B7FB,0x8718D09E,0x1ACFE827,0xA2738F42,0xB0C620AC,0x087A47C9, + 0xA032AF3E,0x188EC85B,0x0A3B67B5,0xB28700D0,0x2F503869,0x97EC5F0C,0x8559F0E2,0x3DE59787, + 0x658687D1,0xDD3AE0B4,0xCF8F4F5A,0x7733283F,0xEAE41086,0x525877E3,0x40EDD80D,0xF851BF68, + 0xF02BF8A1,0x48979FC4,0x5A22302A,0xE29E574F,0x7F496FF6,0xC7F50893,0xD540A77D,0x6DFCC018, + 0x359FD04E,0x8D23B72B,0x9F9618C5,0x272A7FA0,0xBAFD4719,0x0241207C,0x10F48F92,0xA848E8F7, + 0x9B14583D,0x23A83F58,0x311D90B6,0x89A1F7D3,0x1476CF6A,0xACCAA80F,0xBE7F07E1,0x06C36084, + 0x5EA070D2,0xE61C17B7,0xF4A9B859,0x4C15DF3C,0xD1C2E785,0x697E80E0,0x7BCB2F0E,0xC377486B, + 0xCB0D0FA2,0x73B168C7,0x6104C729,0xD9B8A04C,0x446F98F5,0xFCD3FF90,0xEE66507E,0x56DA371B, + 0x0EB9274D,0xB6054028,0xA4B0EFC6,0x1C0C88A3,0x81DBB01A,0x3967D77F,0x2BD27891,0x936E1FF4, + 0x3B26F703,0x839A9066,0x912F3F88,0x299358ED,0xB4446054,0x0CF80731,0x1E4DA8DF,0xA6F1CFBA, + 0xFE92DFEC,0x462EB889,0x549B1767,0xEC277002,0x71F048BB,0xC94C2FDE,0xDBF98030,0x6345E755, + 0x6B3FA09C,0xD383C7F9,0xC1366817,0x798A0F72,0xE45D37CB,0x5CE150AE,0x4E54FF40,0xF6E89825, + 0xAE8B8873,0x1637EF16,0x048240F8,0xBC3E279D,0x21E91F24,0x99557841,0x8BE0D7AF,0x335CB0CA, + 0xED59B63B,0x55E5D15E,0x47507EB0,0xFFEC19D5,0x623B216C,0xDA874609,0xC832E9E7,0x708E8E82, + 0x28ED9ED4,0x9051F9B1,0x82E4565F,0x3A58313A,0xA78F0983,0x1F336EE6,0x0D86C108,0xB53AA66D, + 0xBD40E1A4,0x05FC86C1,0x1749292F,0xAFF54E4A,0x322276F3,0x8A9E1196,0x982BBE78,0x2097D91D, + 0x78F4C94B,0xC048AE2E,0xD2FD01C0,0x6A4166A5,0xF7965E1C,0x4F2A3979,0x5D9F9697,0xE523F1F2, + 0x4D6B1905,0xF5D77E60,0xE762D18E,0x5FDEB6EB,0xC2098E52,0x7AB5E937,0x680046D9,0xD0BC21BC, + 0x88DF31EA,0x3063568F,0x22D6F961,0x9A6A9E04,0x07BDA6BD,0xBF01C1D8,0xADB46E36,0x15080953, + 0x1D724E9A,0xA5CE29FF,0xB77B8611,0x0FC7E174,0x9210D9CD,0x2AACBEA8,0x38191146,0x80A57623, + 0xD8C66675,0x607A0110,0x72CFAEFE,0xCA73C99B,0x57A4F122,0xEF189647,0xFDAD39A9,0x45115ECC, + 0x764DEE06,0xCEF18963,0xDC44268D,0x64F841E8,0xF92F7951,0x41931E34,0x5326B1DA,0xEB9AD6BF, + 0xB3F9C6E9,0x0B45A18C,0x19F00E62,0xA14C6907,0x3C9B51BE,0x842736DB,0x96929935,0x2E2EFE50, + 0x2654B999,0x9EE8DEFC,0x8C5D7112,0x34E11677,0xA9362ECE,0x118A49AB,0x033FE645,0xBB838120, + 0xE3E09176,0x5B5CF613,0x49E959FD,0xF1553E98,0x6C820621,0xD43E6144,0xC68BCEAA,0x7E37A9CF, + 0xD67F4138,0x6EC3265D,0x7C7689B3,0xC4CAEED6,0x591DD66F,0xE1A1B10A,0xF3141EE4,0x4BA87981, + 0x13CB69D7,0xAB770EB2,0xB9C2A15C,0x017EC639,0x9CA9FE80,0x241599E5,0x36A0360B,0x8E1C516E, + 0x866616A7,0x3EDA71C2,0x2C6FDE2C,0x94D3B949,0x090481F0,0xB1B8E695,0xA30D497B,0x1BB12E1E, + 0x43D23E48,0xFB6E592D,0xE9DBF6C3,0x516791A6,0xCCB0A91F,0x740CCE7A,0x66B96194,0xDE0506F1, + + 0x00000000,0x3D6029B0,0x7AC05360,0x47A07AD0,0xF580A6C0,0xC8E08F70,0x8F40F5A0,0xB220DC10, + 0x30704BC1,0x0D106271,0x4AB018A1,0x77D03111,0xC5F0ED01,0xF890C4B1,0xBF30BE61,0x825097D1, + 0x60E09782,0x5D80BE32,0x1A20C4E2,0x2740ED52,0x95603142,0xA80018F2,0xEFA06222,0xD2C04B92, + 0x5090DC43,0x6DF0F5F3,0x2A508F23,0x1730A693,0xA5107A83,0x98705333,0xDFD029E3,0xE2B00053, + 0xC1C12F04,0xFCA106B4,0xBB017C64,0x866155D4,0x344189C4,0x0921A074,0x4E81DAA4,0x73E1F314, + 0xF1B164C5,0xCCD14D75,0x8B7137A5,0xB6111E15,0x0431C205,0x3951EBB5,0x7EF19165,0x4391B8D5, + 0xA121B886,0x9C419136,0xDBE1EBE6,0xE681C256,0x54A11E46,0x69C137F6,0x2E614D26,0x13016496, + 0x9151F347,0xAC31DAF7,0xEB91A027,0xD6F18997,0x64D15587,0x59B17C37,0x1E1106E7,0x23712F57, + 0x58F35849,0x659371F9,0x22330B29,0x1F532299,0xAD73FE89,0x9013D739,0xD7B3ADE9,0xEAD38459, + 0x68831388,0x55E33A38,0x124340E8,0x2F236958,0x9D03B548,0xA0639CF8,0xE7C3E628,0xDAA3CF98, + 0x3813CFCB,0x0573E67B,0x42D39CAB,0x7FB3B51B,0xCD93690B,0xF0F340BB,0xB7533A6B,0x8A3313DB, + 0x0863840A,0x3503ADBA,0x72A3D76A,0x4FC3FEDA,0xFDE322CA,0xC0830B7A,0x872371AA,0xBA43581A, + 0x9932774D,0xA4525EFD,0xE3F2242D,0xDE920D9D,0x6CB2D18D,0x51D2F83D,0x167282ED,0x2B12AB5D, + 0xA9423C8C,0x9422153C,0xD3826FEC,0xEEE2465C,0x5CC29A4C,0x61A2B3FC,0x2602C92C,0x1B62E09C, + 0xF9D2E0CF,0xC4B2C97F,0x8312B3AF,0xBE729A1F,0x0C52460F,0x31326FBF,0x7692156F,0x4BF23CDF, + 0xC9A2AB0E,0xF4C282BE,0xB362F86E,0x8E02D1DE,0x3C220DCE,0x0142247E,0x46E25EAE,0x7B82771E, + 0xB1E6B092,0x8C869922,0xCB26E3F2,0xF646CA42,0x44661652,0x79063FE2,0x3EA64532,0x03C66C82, + 0x8196FB53,0xBCF6D2E3,0xFB56A833,0xC6368183,0x74165D93,0x49767423,0x0ED60EF3,0x33B62743, + 0xD1062710,0xEC660EA0,0xABC67470,0x96A65DC0,0x248681D0,0x19E6A860,0x5E46D2B0,0x6326FB00, + 0xE1766CD1,0xDC164561,0x9BB63FB1,0xA6D61601,0x14F6CA11,0x2996E3A1,0x6E369971,0x5356B0C1, + 0x70279F96,0x4D47B626,0x0AE7CCF6,0x3787E546,0x85A73956,0xB8C710E6,0xFF676A36,0xC2074386, + 0x4057D457,0x7D37FDE7,0x3A978737,0x07F7AE87,0xB5D77297,0x88B75B27,0xCF1721F7,0xF2770847, + 0x10C70814,0x2DA721A4,0x6A075B74,0x576772C4,0xE547AED4,0xD8278764,0x9F87FDB4,0xA2E7D404, + 0x20B743D5,0x1DD76A65,0x5A7710B5,0x67173905,0xD537E515,0xE857CCA5,0xAFF7B675,0x92979FC5, + 0xE915E8DB,0xD475C16B,0x93D5BBBB,0xAEB5920B,0x1C954E1B,0x21F567AB,0x66551D7B,0x5B3534CB, + 0xD965A31A,0xE4058AAA,0xA3A5F07A,0x9EC5D9CA,0x2CE505DA,0x11852C6A,0x562556BA,0x6B457F0A, + 0x89F57F59,0xB49556E9,0xF3352C39,0xCE550589,0x7C75D999,0x4115F029,0x06B58AF9,0x3BD5A349, + 0xB9853498,0x84E51D28,0xC34567F8,0xFE254E48,0x4C059258,0x7165BBE8,0x36C5C138,0x0BA5E888, + 0x28D4C7DF,0x15B4EE6F,0x521494BF,0x6F74BD0F,0xDD54611F,0xE03448AF,0xA794327F,0x9AF41BCF, + 0x18A48C1E,0x25C4A5AE,0x6264DF7E,0x5F04F6CE,0xED242ADE,0xD044036E,0x97E479BE,0xAA84500E, + 0x4834505D,0x755479ED,0x32F4033D,0x0F942A8D,0xBDB4F69D,0x80D4DF2D,0xC774A5FD,0xFA148C4D, + 0x78441B9C,0x4524322C,0x028448FC,0x3FE4614C,0x8DC4BD5C,0xB0A494EC,0xF704EE3C,0xCA64C78C, + + 0x00000000,0xCB5CD3A5,0x4DC8A10B,0x869472AE,0x9B914216,0x50CD91B3,0xD659E31D,0x1D0530B8, + 0xEC53826D,0x270F51C8,0xA19B2366,0x6AC7F0C3,0x77C2C07B,0xBC9E13DE,0x3A0A6170,0xF156B2D5, + 0x03D6029B,0xC88AD13E,0x4E1EA390,0x85427035,0x9847408D,0x531B9328,0xD58FE186,0x1ED33223, + 0xEF8580F6,0x24D95353,0xA24D21FD,0x6911F258,0x7414C2E0,0xBF481145,0x39DC63EB,0xF280B04E, + 0x07AC0536,0xCCF0D693,0x4A64A43D,0x81387798,0x9C3D4720,0x57619485,0xD1F5E62B,0x1AA9358E, + 0xEBFF875B,0x20A354FE,0xA6372650,0x6D6BF5F5,0x706EC54D,0xBB3216E8,0x3DA66446,0xF6FAB7E3, + 0x047A07AD,0xCF26D408,0x49B2A6A6,0x82EE7503,0x9FEB45BB,0x54B7961E,0xD223E4B0,0x197F3715, + 0xE82985C0,0x23755665,0xA5E124CB,0x6EBDF76E,0x73B8C7D6,0xB8E41473,0x3E7066DD,0xF52CB578, + 0x0F580A6C,0xC404D9C9,0x4290AB67,0x89CC78C2,0x94C9487A,0x5F959BDF,0xD901E971,0x125D3AD4, + 0xE30B8801,0x28575BA4,0xAEC3290A,0x659FFAAF,0x789ACA17,0xB3C619B2,0x35526B1C,0xFE0EB8B9, + 0x0C8E08F7,0xC7D2DB52,0x4146A9FC,0x8A1A7A59,0x971F4AE1,0x5C439944,0xDAD7EBEA,0x118B384F, + 0xE0DD8A9A,0x2B81593F,0xAD152B91,0x6649F834,0x7B4CC88C,0xB0101B29,0x36846987,0xFDD8BA22, + 0x08F40F5A,0xC3A8DCFF,0x453CAE51,0x8E607DF4,0x93654D4C,0x58399EE9,0xDEADEC47,0x15F13FE2, + 0xE4A78D37,0x2FFB5E92,0xA96F2C3C,0x6233FF99,0x7F36CF21,0xB46A1C84,0x32FE6E2A,0xF9A2BD8F, + 0x0B220DC1,0xC07EDE64,0x46EAACCA,0x8DB67F6F,0x90B34FD7,0x5BEF9C72,0xDD7BEEDC,0x16273D79, + 0xE7718FAC,0x2C2D5C09,0xAAB92EA7,0x61E5FD02,0x7CE0CDBA,0xB7BC1E1F,0x31286CB1,0xFA74BF14, + 0x1EB014D8,0xD5ECC77D,0x5378B5D3,0x98246676,0x852156CE,0x4E7D856B,0xC8E9F7C5,0x03B52460, + 0xF2E396B5,0x39BF4510,0xBF2B37BE,0x7477E41B,0x6972D4A3,0xA22E0706,0x24BA75A8,0xEFE6A60D, + 0x1D661643,0xD63AC5E6,0x50AEB748,0x9BF264ED,0x86F75455,0x4DAB87F0,0xCB3FF55E,0x006326FB, + 0xF135942E,0x3A69478B,0xBCFD3525,0x77A1E680,0x6AA4D638,0xA1F8059D,0x276C7733,0xEC30A496, + 0x191C11EE,0xD240C24B,0x54D4B0E5,0x9F886340,0x828D53F8,0x49D1805D,0xCF45F2F3,0x04192156, + 0xF54F9383,0x3E134026,0xB8873288,0x73DBE12D,0x6EDED195,0xA5820230,0x2316709E,0xE84AA33B, + 0x1ACA1375,0xD196C0D0,0x5702B27E,0x9C5E61DB,0x815B5163,0x4A0782C6,0xCC93F068,0x07CF23CD, + 0xF6999118,0x3DC542BD,0xBB513013,0x700DE3B6,0x6D08D30E,0xA65400AB,0x20C07205,0xEB9CA1A0, + 0x11E81EB4,0xDAB4CD11,0x5C20BFBF,0x977C6C1A,0x8A795CA2,0x41258F07,0xC7B1FDA9,0x0CED2E0C, + 0xFDBB9CD9,0x36E74F7C,0xB0733DD2,0x7B2FEE77,0x662ADECF,0xAD760D6A,0x2BE27FC4,0xE0BEAC61, + 0x123E1C2F,0xD962CF8A,0x5FF6BD24,0x94AA6E81,0x89AF5E39,0x42F38D9C,0xC467FF32,0x0F3B2C97, + 0xFE6D9E42,0x35314DE7,0xB3A53F49,0x78F9ECEC,0x65FCDC54,0xAEA00FF1,0x28347D5F,0xE368AEFA, + 0x16441B82,0xDD18C827,0x5B8CBA89,0x90D0692C,0x8DD55994,0x46898A31,0xC01DF89F,0x0B412B3A, + 0xFA1799EF,0x314B4A4A,0xB7DF38E4,0x7C83EB41,0x6186DBF9,0xAADA085C,0x2C4E7AF2,0xE712A957, + 0x15921919,0xDECECABC,0x585AB812,0x93066BB7,0x8E035B0F,0x455F88AA,0xC3CBFA04,0x089729A1, + 0xF9C19B74,0x329D48D1,0xB4093A7F,0x7F55E9DA,0x6250D962,0xA90C0AC7,0x2F987869,0xE4C4ABCC, + + 0x00000000,0xA6770BB4,0x979F1129,0x31E81A9D,0xF44F2413,0x52382FA7,0x63D0353A,0xC5A73E8E, + 0x33EF4E67,0x959845D3,0xA4705F4E,0x020754FA,0xC7A06A74,0x61D761C0,0x503F7B5D,0xF64870E9, + 0x67DE9CCE,0xC1A9977A,0xF0418DE7,0x56368653,0x9391B8DD,0x35E6B369,0x040EA9F4,0xA279A240, + 0x5431D2A9,0xF246D91D,0xC3AEC380,0x65D9C834,0xA07EF6BA,0x0609FD0E,0x37E1E793,0x9196EC27, + 0xCFBD399C,0x69CA3228,0x582228B5,0xFE552301,0x3BF21D8F,0x9D85163B,0xAC6D0CA6,0x0A1A0712, + 0xFC5277FB,0x5A257C4F,0x6BCD66D2,0xCDBA6D66,0x081D53E8,0xAE6A585C,0x9F8242C1,0x39F54975, + 0xA863A552,0x0E14AEE6,0x3FFCB47B,0x998BBFCF,0x5C2C8141,0xFA5B8AF5,0xCBB39068,0x6DC49BDC, + 0x9B8CEB35,0x3DFBE081,0x0C13FA1C,0xAA64F1A8,0x6FC3CF26,0xC9B4C492,0xF85CDE0F,0x5E2BD5BB, + 0x440B7579,0xE27C7ECD,0xD3946450,0x75E36FE4,0xB044516A,0x16335ADE,0x27DB4043,0x81AC4BF7, + 0x77E43B1E,0xD19330AA,0xE07B2A37,0x460C2183,0x83AB1F0D,0x25DC14B9,0x14340E24,0xB2430590, + 0x23D5E9B7,0x85A2E203,0xB44AF89E,0x123DF32A,0xD79ACDA4,0x71EDC610,0x4005DC8D,0xE672D739, + 0x103AA7D0,0xB64DAC64,0x87A5B6F9,0x21D2BD4D,0xE47583C3,0x42028877,0x73EA92EA,0xD59D995E, + 0x8BB64CE5,0x2DC14751,0x1C295DCC,0xBA5E5678,0x7FF968F6,0xD98E6342,0xE86679DF,0x4E11726B, + 0xB8590282,0x1E2E0936,0x2FC613AB,0x89B1181F,0x4C162691,0xEA612D25,0xDB8937B8,0x7DFE3C0C, + 0xEC68D02B,0x4A1FDB9F,0x7BF7C102,0xDD80CAB6,0x1827F438,0xBE50FF8C,0x8FB8E511,0x29CFEEA5, + 0xDF879E4C,0x79F095F8,0x48188F65,0xEE6F84D1,0x2BC8BA5F,0x8DBFB1EB,0xBC57AB76,0x1A20A0C2, + 0x8816EAF2,0x2E61E146,0x1F89FBDB,0xB9FEF06F,0x7C59CEE1,0xDA2EC555,0xEBC6DFC8,0x4DB1D47C, + 0xBBF9A495,0x1D8EAF21,0x2C66B5BC,0x8A11BE08,0x4FB68086,0xE9C18B32,0xD82991AF,0x7E5E9A1B, + 0xEFC8763C,0x49BF7D88,0x78576715,0xDE206CA1,0x1B87522F,0xBDF0599B,0x8C184306,0x2A6F48B2, + 0xDC27385B,0x7A5033EF,0x4BB82972,0xEDCF22C6,0x28681C48,0x8E1F17FC,0xBFF70D61,0x198006D5, + 0x47ABD36E,0xE1DCD8DA,0xD034C247,0x7643C9F3,0xB3E4F77D,0x1593FCC9,0x247BE654,0x820CEDE0, + 0x74449D09,0xD23396BD,0xE3DB8C20,0x45AC8794,0x800BB91A,0x267CB2AE,0x1794A833,0xB1E3A387, + 0x20754FA0,0x86024414,0xB7EA5E89,0x119D553D,0xD43A6BB3,0x724D6007,0x43A57A9A,0xE5D2712E, + 0x139A01C7,0xB5ED0A73,0x840510EE,0x22721B5A,0xE7D525D4,0x41A22E60,0x704A34FD,0xD63D3F49, + 0xCC1D9F8B,0x6A6A943F,0x5B828EA2,0xFDF58516,0x3852BB98,0x9E25B02C,0xAFCDAAB1,0x09BAA105, + 0xFFF2D1EC,0x5985DA58,0x686DC0C5,0xCE1ACB71,0x0BBDF5FF,0xADCAFE4B,0x9C22E4D6,0x3A55EF62, + 0xABC30345,0x0DB408F1,0x3C5C126C,0x9A2B19D8,0x5F8C2756,0xF9FB2CE2,0xC813367F,0x6E643DCB, + 0x982C4D22,0x3E5B4696,0x0FB35C0B,0xA9C457BF,0x6C636931,0xCA146285,0xFBFC7818,0x5D8B73AC, + 0x03A0A617,0xA5D7ADA3,0x943FB73E,0x3248BC8A,0xF7EF8204,0x519889B0,0x6070932D,0xC6079899, + 0x304FE870,0x9638E3C4,0xA7D0F959,0x01A7F2ED,0xC400CC63,0x6277C7D7,0x539FDD4A,0xF5E8D6FE, + 0x647E3AD9,0xC209316D,0xF3E12BF0,0x55962044,0x90311ECA,0x3646157E,0x07AE0FE3,0xA1D90457, + 0x579174BE,0xF1E67F0A,0xC00E6597,0x66796E23,0xA3DE50AD,0x05A95B19,0x34414184,0x92364A30, + + 0x00000000,0xCCAA009E,0x4225077D,0x8E8F07E3,0x844A0EFA,0x48E00E64,0xC66F0987,0x0AC50919, + 0xD3E51BB5,0x1F4F1B2B,0x91C01CC8,0x5D6A1C56,0x57AF154F,0x9B0515D1,0x158A1232,0xD92012AC, + 0x7CBB312B,0xB01131B5,0x3E9E3656,0xF23436C8,0xF8F13FD1,0x345B3F4F,0xBAD438AC,0x767E3832, + 0xAF5E2A9E,0x63F42A00,0xED7B2DE3,0x21D12D7D,0x2B142464,0xE7BE24FA,0x69312319,0xA59B2387, + 0xF9766256,0x35DC62C8,0xBB53652B,0x77F965B5,0x7D3C6CAC,0xB1966C32,0x3F196BD1,0xF3B36B4F, + 0x2A9379E3,0xE639797D,0x68B67E9E,0xA41C7E00,0xAED97719,0x62737787,0xECFC7064,0x205670FA, + 0x85CD537D,0x496753E3,0xC7E85400,0x0B42549E,0x01875D87,0xCD2D5D19,0x43A25AFA,0x8F085A64, + 0x562848C8,0x9A824856,0x140D4FB5,0xD8A74F2B,0xD2624632,0x1EC846AC,0x9047414F,0x5CED41D1, + 0x299DC2ED,0xE537C273,0x6BB8C590,0xA712C50E,0xADD7CC17,0x617DCC89,0xEFF2CB6A,0x2358CBF4, + 0xFA78D958,0x36D2D9C6,0xB85DDE25,0x74F7DEBB,0x7E32D7A2,0xB298D73C,0x3C17D0DF,0xF0BDD041, + 0x5526F3C6,0x998CF358,0x1703F4BB,0xDBA9F425,0xD16CFD3C,0x1DC6FDA2,0x9349FA41,0x5FE3FADF, + 0x86C3E873,0x4A69E8ED,0xC4E6EF0E,0x084CEF90,0x0289E689,0xCE23E617,0x40ACE1F4,0x8C06E16A, + 0xD0EBA0BB,0x1C41A025,0x92CEA7C6,0x5E64A758,0x54A1AE41,0x980BAEDF,0x1684A93C,0xDA2EA9A2, + 0x030EBB0E,0xCFA4BB90,0x412BBC73,0x8D81BCED,0x8744B5F4,0x4BEEB56A,0xC561B289,0x09CBB217, + 0xAC509190,0x60FA910E,0xEE7596ED,0x22DF9673,0x281A9F6A,0xE4B09FF4,0x6A3F9817,0xA6959889, + 0x7FB58A25,0xB31F8ABB,0x3D908D58,0xF13A8DC6,0xFBFF84DF,0x37558441,0xB9DA83A2,0x7570833C, + 0x533B85DA,0x9F918544,0x111E82A7,0xDDB48239,0xD7718B20,0x1BDB8BBE,0x95548C5D,0x59FE8CC3, + 0x80DE9E6F,0x4C749EF1,0xC2FB9912,0x0E51998C,0x04949095,0xC83E900B,0x46B197E8,0x8A1B9776, + 0x2F80B4F1,0xE32AB46F,0x6DA5B38C,0xA10FB312,0xABCABA0B,0x6760BA95,0xE9EFBD76,0x2545BDE8, + 0xFC65AF44,0x30CFAFDA,0xBE40A839,0x72EAA8A7,0x782FA1BE,0xB485A120,0x3A0AA6C3,0xF6A0A65D, + 0xAA4DE78C,0x66E7E712,0xE868E0F1,0x24C2E06F,0x2E07E976,0xE2ADE9E8,0x6C22EE0B,0xA088EE95, + 0x79A8FC39,0xB502FCA7,0x3B8DFB44,0xF727FBDA,0xFDE2F2C3,0x3148F25D,0xBFC7F5BE,0x736DF520, + 0xD6F6D6A7,0x1A5CD639,0x94D3D1DA,0x5879D144,0x52BCD85D,0x9E16D8C3,0x1099DF20,0xDC33DFBE, + 0x0513CD12,0xC9B9CD8C,0x4736CA6F,0x8B9CCAF1,0x8159C3E8,0x4DF3C376,0xC37CC495,0x0FD6C40B, + 0x7AA64737,0xB60C47A9,0x3883404A,0xF42940D4,0xFEEC49CD,0x32464953,0xBCC94EB0,0x70634E2E, + 0xA9435C82,0x65E95C1C,0xEB665BFF,0x27CC5B61,0x2D095278,0xE1A352E6,0x6F2C5505,0xA386559B, + 0x061D761C,0xCAB77682,0x44387161,0x889271FF,0x825778E6,0x4EFD7878,0xC0727F9B,0x0CD87F05, + 0xD5F86DA9,0x19526D37,0x97DD6AD4,0x5B776A4A,0x51B26353,0x9D1863CD,0x1397642E,0xDF3D64B0, + 0x83D02561,0x4F7A25FF,0xC1F5221C,0x0D5F2282,0x079A2B9B,0xCB302B05,0x45BF2CE6,0x89152C78, + 0x50353ED4,0x9C9F3E4A,0x121039A9,0xDEBA3937,0xD47F302E,0x18D530B0,0x965A3753,0x5AF037CD, + 0xFF6B144A,0x33C114D4,0xBD4E1337,0x71E413A9,0x7B211AB0,0xB78B1A2E,0x39041DCD,0xF5AE1D53, + 0x2C8E0FFF,0xE0240F61,0x6EAB0882,0xA201081C,0xA8C40105,0x646E019B,0xEAE10678,0x264B06E6 +}; + + +/// compute CRC32 +uint32_t crc32_bitwise(const void* data, size_t length, uint32_t previousCrc32 = 0) +{ + uint32_t crc = ~previousCrc32; // same as previousCrc32 ^ 0xFFFFFFFF + uint8_t* current = (uint8_t*) data; + + while (length--) + { + crc ^= *current++; + + for (uint8_t j = 0; j < 8; j++) + { + //if (crc & 1) + // crc = (crc >> 1) ^ Polynomial; + //else + // crc = crc >> 1; + uint8_t lowestBit = crc & 1; + crc >>= 1; + if (lowestBit) + crc ^= Polynomial; + } + + // fully unrolled + /*uint8_t lowestBit; + lowestBit = crc & 1; + crc >>= 1; + if (lowestBit) + crc ^= Polynomial; + lowestBit = crc & 1; + crc >>= 1; + if (lowestBit) + crc ^= Polynomial; + lowestBit = crc & 1; + crc >>= 1; + if (lowestBit) + crc ^= Polynomial; + lowestBit = crc & 1; + crc >>= 1; + if (lowestBit) + crc ^= Polynomial; + lowestBit = crc & 1; + crc >>= 1; + if (lowestBit) + crc ^= Polynomial; + lowestBit = crc & 1; + crc >>= 1; + if (lowestBit) + crc ^= Polynomial; + lowestBit = crc & 1; + crc >>= 1; + if (lowestBit) + crc ^= Polynomial; + lowestBit = crc & 1; + crc >>= 1; + if (lowestBit) + crc ^= Polynomial;*/ + } + + return ~crc; // same as crc ^ 0xFFFFFFFF +} + + + +/// compute CRC32 +uint32_t crc32_halfbyte(const void* data, size_t length, uint32_t previousCrc32 = 0) +{ + uint32_t crc = ~previousCrc32; // same as previousCrc32 ^ 0xFFFFFFFF + uint8_t* current = (uint8_t*) data; + + /// look-up table for half-byte, same as crc32Lookup[0][16*i] + static PROGMEM uint32_t crc32Lookup16[16] = + { + 0x00000000,0x1DB71064,0x3B6E20C8,0x26D930AC,0x76DC4190,0x6B6B51F4,0x4DB26158,0x5005713C, + 0xEDB88320,0xF00F9344,0xD6D6A3E8,0xCB61B38C,0x9B64C2B0,0x86D3D2D4,0xA00AE278,0xBDBDF21C + }; + + while (length--) + { + crc = pgm_read_dword_near(crc32Lookup16 + ((uint8_t(crc) ^ *current ) & 0x0F)) ^ (crc >> 4); + crc = pgm_read_dword_near(crc32Lookup16 + ((uint8_t(crc) ^ (*current >> 4)) & 0x0F)) ^ (crc >> 4); + current++; + } + + return ~crc; // same as crc ^ 0xFFFFFFFF +} + + +/// compute CRC32 +uint32_t crc32_1byte(const void* data, size_t length, uint32_t previousCrc32 = 0) +{ + uint32_t crc = ~previousCrc32; // same as previousCrc32 ^ 0xFFFFFFFF + uint8_t* current = (uint8_t*) data; + + while (length--) + { + uint8_t offset = uint8_t(crc) ^ *current++; + crc = (crc >> 8) ^ pgm_read_dword_near(crc32Lookup + offset); + } + + return ~crc; // same as crc ^ 0xFFFFFFFF +} + + +/// compute CRC32 +uint32_t crc32_4bytes(const void* data, size_t length, uint32_t previousCrc32 = 0) +{ + uint32_t* current = (uint32_t*) data; + uint32_t crc = ~previousCrc32; // same as previousCrc32 ^ 0xFFFFFFFF + + // process four bytes at once + while (length >= 4) + { + crc ^= *current++; + uint16_t offset3 = 3*256 + ( crc & 0xFF); + uint16_t offset2 = 2*256 + ((crc>> 8) & 0xFF); + uint16_t offset1 = 1*256 + ((crc>>16) & 0xFF); + uint16_t offset0 = 0*256 + ((crc>>24) & 0xFF); + crc = pgm_read_dword_near(crc32Lookup + offset3) ^ + pgm_read_dword_near(crc32Lookup + offset2) ^ + pgm_read_dword_near(crc32Lookup + offset1) ^ + pgm_read_dword_near(crc32Lookup + offset0); + length -= 4; + } + + const uint8_t* currentChar = (uint8_t*) current; + // remaining 1 to 3 bytes (standard CRC table-based algorithm) + while (length--) + { + uint8_t offset = uint8_t(crc) ^ *current++; + crc = (crc >> 8) ^ pgm_read_dword_near(crc32Lookup + offset); + } + + return ~crc; // same as crc ^ 0xFFFFFFFF +} + + +/// compute CRC32 +uint32_t crc32_8bytes(const void* data, size_t length, uint32_t previousCrc32 = 0) +{ + uint32_t* current = (uint32_t*) data; + uint32_t crc = ~previousCrc32; // same as previousCrc32 ^ 0xFFFFFFFF + + // process eight bytes at once + while (length >= 8) + { + uint32_t one = *current++ ^ crc; + uint32_t two = *current++; + uint16_t offset7 = 7*256 + ( one & 0xFF); + uint16_t offset6 = 6*256 + ((one>> 8) & 0xFF); + uint16_t offset5 = 5*256 + ((one>>16) & 0xFF); + uint16_t offset4 = 4*256 + ((one>>24) & 0xFF); + uint16_t offset3 = 3*256 + ( two & 0xFF); + uint16_t offset2 = 2*256 + ((two>> 8) & 0xFF); + uint16_t offset1 = 1*256 + ((two>>16) & 0xFF); + uint16_t offset0 = 0*256 + ((two>>24) & 0xFF); + crc = pgm_read_dword_near(crc32Lookup + offset7) ^ + pgm_read_dword_near(crc32Lookup + offset6) ^ + pgm_read_dword_near(crc32Lookup + offset5) ^ + pgm_read_dword_near(crc32Lookup + offset4) ^ + pgm_read_dword_near(crc32Lookup + offset3) ^ + pgm_read_dword_near(crc32Lookup + offset2) ^ + pgm_read_dword_near(crc32Lookup + offset1) ^ + pgm_read_dword_near(crc32Lookup + offset0); + length -= 8; + } + + uint8_t* currentChar = (uint8_t*) current; + // remaining 1 to 7 bytes (standard CRC table-based algorithm) + while (length--) + { + uint8_t offset = uint8_t(crc) ^ *current++; + crc = (crc >> 8) ^ pgm_read_dword_near(crc32Lookup + offset); + } + + return ~crc; // same as crc ^ 0xFFFFFFFF +} + + +void setup() +{ + Serial.begin(9600); + Serial.println("initialize ..."); + for (size_t i = 0; i < NumBytes; i++) + data[i] = uint8_t(i & 0xFF); +} + + +void loop() +{ + unsigned long now, millisecs, throughput; + uint32_t crc; + + // bitwise + now = millis(); + for (int i = 1; i < Repetitions; i++) + crc = crc32_bitwise(data, NumBytes); + millisecs = millis() - now; + throughput = (unsigned long)Repetitions * NumBytes / millisecs; + Serial.print("crc32_bitwise = "); + Serial.print(crc, HEX); + Serial.print(" ("); + Serial.print(millisecs); + Serial.print("ms, "); + Serial.print(throughput); + Serial.println(" kByte/s)"); + + // half-byte + now = millis(); + for (int i = 1; i < Repetitions; i++) + crc = crc32_halfbyte(data, NumBytes); + millisecs = millis() - now; + throughput = (unsigned long)Repetitions * NumBytes / millisecs; + Serial.print("crc32_halfbyte = "); + Serial.print(crc, HEX); + Serial.print(" ("); + Serial.print(millisecs); + Serial.print("ms, "); + Serial.print(throughput); + Serial.println(" kByte/s)"); + + // 1 byte + now = millis(); + for (int i = 1; i < Repetitions; i++) + crc = crc32_1byte(data, NumBytes); + millisecs = millis() - now; + throughput = (unsigned long)Repetitions * NumBytes / millisecs; + Serial.print("crc32_1byte = "); + Serial.print(crc, HEX); + Serial.print(" ("); + Serial.print(millisecs); + Serial.print("ms, "); + Serial.print(throughput); + Serial.println(" kByte/s)"); + + + // 4 bytes + now = millis(); + for (int i = 1; i < Repetitions; i++) + crc = crc32_4bytes(data, NumBytes); + millisecs = millis() - now; + throughput = (unsigned long)Repetitions * NumBytes / millisecs; + Serial.print("crc32_4bytes = "); + Serial.print(crc, HEX); + Serial.print(" ("); + Serial.print(millisecs); + Serial.print("ms, "); + Serial.print(throughput); + Serial.println(" kByte/s)"); + + + // 8 bytes + now = millis(); + for (int i = 1; i < Repetitions; i++) + crc = crc32_8bytes(data, NumBytes); + millisecs = millis() - now; + throughput = (unsigned long)Repetitions * NumBytes / millisecs; + Serial.print("crc32_8bytes = "); + Serial.print(crc, HEX); + Serial.print(" ("); + Serial.print(millisecs); + Serial.print("ms, "); + Serial.print(throughput); + Serial.println(" kByte/s)"); +} + diff --git a/lib/crc32/Crc32Best.ino b/lib/crc32/Crc32Best.ino new file mode 100644 index 0000000..cc09f17 --- /dev/null +++ b/lib/crc32/Crc32Best.ino @@ -0,0 +1,142 @@ +// ////////////////////////////////////////////////////////// +// Crc32Best.ino +// Copyright (c) 2011 Stephan Brumme. All rights reserved. +// see http://create.stephan-brumme.com/disclaimer.html +// + +/// zlib's CRC32 polynomial +const uint32_t Polynomial = 0xEDB88320; + +const uint16_t NumBytes = 256; +uint8_t data[NumBytes]; + + +PROGMEM uint32_t crc32Lookup[256] = +{ 0x00000000,0x77073096,0xEE0E612C,0x990951BA,0x076DC419,0x706AF48F,0xE963A535,0x9E6495A3, + 0x0EDB8832,0x79DCB8A4,0xE0D5E91E,0x97D2D988,0x09B64C2B,0x7EB17CBD,0xE7B82D07,0x90BF1D91, + 0x1DB71064,0x6AB020F2,0xF3B97148,0x84BE41DE,0x1ADAD47D,0x6DDDE4EB,0xF4D4B551,0x83D385C7, + 0x136C9856,0x646BA8C0,0xFD62F97A,0x8A65C9EC,0x14015C4F,0x63066CD9,0xFA0F3D63,0x8D080DF5, + 0x3B6E20C8,0x4C69105E,0xD56041E4,0xA2677172,0x3C03E4D1,0x4B04D447,0xD20D85FD,0xA50AB56B, + 0x35B5A8FA,0x42B2986C,0xDBBBC9D6,0xACBCF940,0x32D86CE3,0x45DF5C75,0xDCD60DCF,0xABD13D59, + 0x26D930AC,0x51DE003A,0xC8D75180,0xBFD06116,0x21B4F4B5,0x56B3C423,0xCFBA9599,0xB8BDA50F, + 0x2802B89E,0x5F058808,0xC60CD9B2,0xB10BE924,0x2F6F7C87,0x58684C11,0xC1611DAB,0xB6662D3D, + 0x76DC4190,0x01DB7106,0x98D220BC,0xEFD5102A,0x71B18589,0x06B6B51F,0x9FBFE4A5,0xE8B8D433, + 0x7807C9A2,0x0F00F934,0x9609A88E,0xE10E9818,0x7F6A0DBB,0x086D3D2D,0x91646C97,0xE6635C01, + 0x6B6B51F4,0x1C6C6162,0x856530D8,0xF262004E,0x6C0695ED,0x1B01A57B,0x8208F4C1,0xF50FC457, + 0x65B0D9C6,0x12B7E950,0x8BBEB8EA,0xFCB9887C,0x62DD1DDF,0x15DA2D49,0x8CD37CF3,0xFBD44C65, + 0x4DB26158,0x3AB551CE,0xA3BC0074,0xD4BB30E2,0x4ADFA541,0x3DD895D7,0xA4D1C46D,0xD3D6F4FB, + 0x4369E96A,0x346ED9FC,0xAD678846,0xDA60B8D0,0x44042D73,0x33031DE5,0xAA0A4C5F,0xDD0D7CC9, + 0x5005713C,0x270241AA,0xBE0B1010,0xC90C2086,0x5768B525,0x206F85B3,0xB966D409,0xCE61E49F, + 0x5EDEF90E,0x29D9C998,0xB0D09822,0xC7D7A8B4,0x59B33D17,0x2EB40D81,0xB7BD5C3B,0xC0BA6CAD, + 0xEDB88320,0x9ABFB3B6,0x03B6E20C,0x74B1D29A,0xEAD54739,0x9DD277AF,0x04DB2615,0x73DC1683, + 0xE3630B12,0x94643B84,0x0D6D6A3E,0x7A6A5AA8,0xE40ECF0B,0x9309FF9D,0x0A00AE27,0x7D079EB1, + 0xF00F9344,0x8708A3D2,0x1E01F268,0x6906C2FE,0xF762575D,0x806567CB,0x196C3671,0x6E6B06E7, + 0xFED41B76,0x89D32BE0,0x10DA7A5A,0x67DD4ACC,0xF9B9DF6F,0x8EBEEFF9,0x17B7BE43,0x60B08ED5, + 0xD6D6A3E8,0xA1D1937E,0x38D8C2C4,0x4FDFF252,0xD1BB67F1,0xA6BC5767,0x3FB506DD,0x48B2364B, + 0xD80D2BDA,0xAF0A1B4C,0x36034AF6,0x41047A60,0xDF60EFC3,0xA867DF55,0x316E8EEF,0x4669BE79, + 0xCB61B38C,0xBC66831A,0x256FD2A0,0x5268E236,0xCC0C7795,0xBB0B4703,0x220216B9,0x5505262F, + 0xC5BA3BBE,0xB2BD0B28,0x2BB45A92,0x5CB36A04,0xC2D7FFA7,0xB5D0CF31,0x2CD99E8B,0x5BDEAE1D, + 0x9B64C2B0,0xEC63F226,0x756AA39C,0x026D930A,0x9C0906A9,0xEB0E363F,0x72076785,0x05005713, + 0x95BF4A82,0xE2B87A14,0x7BB12BAE,0x0CB61B38,0x92D28E9B,0xE5D5BE0D,0x7CDCEFB7,0x0BDBDF21, + 0x86D3D2D4,0xF1D4E242,0x68DDB3F8,0x1FDA836E,0x81BE16CD,0xF6B9265B,0x6FB077E1,0x18B74777, + 0x88085AE6,0xFF0F6A70,0x66063BCA,0x11010B5C,0x8F659EFF,0xF862AE69,0x616BFFD3,0x166CCF45, + 0xA00AE278,0xD70DD2EE,0x4E048354,0x3903B3C2,0xA7672661,0xD06016F7,0x4969474D,0x3E6E77DB, + 0xAED16A4A,0xD9D65ADC,0x40DF0B66,0x37D83BF0,0xA9BCAE53,0xDEBB9EC5,0x47B2CF7F,0x30B5FFE9, + 0xBDBDF21C,0xCABAC28A,0x53B39330,0x24B4A3A6,0xBAD03605,0xCDD70693,0x54DE5729,0x23D967BF, + 0xB3667A2E,0xC4614AB8,0x5D681B02,0x2A6F2B94,0xB40BBE37,0xC30C8EA1,0x5A05DF1B,0x2D02EF8D +}; + + +/// compute CRC32 +uint32_t crc32_bitwise(const void* data, uint16_t length, uint32_t previousCrc32 = 0) +{ + uint32_t crc = ~previousCrc32; // same as previousCrc32 ^ 0xFFFFFFFF + uint8_t* current = (uint8_t*) data; + + while (length--) + { + crc ^= *current++; + for (uint8_t j = 0; j < 8; j++) + { + //if (crc & 1) + // crc = (crc >> 1) ^ Polynomial; + //else + // crc = crc >> 1; + uint8_t lowestBit = crc & 1; + crc >>= 1; + if (lowestBit) + crc ^= Polynomial; + } + + + // fully unrolled + /*uint8_t lowestBit; + lowestBit = crc & 1; + crc >>= 1; + if (lowestBit) + crc ^= Polynomial; + lowestBit = crc & 1; + crc >>= 1; + if (lowestBit) + crc ^= Polynomial; + lowestBit = crc & 1; + crc >>= 1; + if (lowestBit) + crc ^= Polynomial; + lowestBit = crc & 1; + crc >>= 1; + if (lowestBit) + crc ^= Polynomial; + lowestBit = crc & 1; + crc >>= 1; + if (lowestBit) + crc ^= Polynomial; + lowestBit = crc & 1; + crc >>= 1; + if (lowestBit) + crc ^= Polynomial; + lowestBit = crc & 1; + crc >>= 1; + if (lowestBit) + crc ^= Polynomial; + lowestBit = crc & 1; + crc >>= 1; + if (lowestBit) + crc ^= Polynomial;*/ + } + + return ~crc; // same as crc ^ 0xFFFFFFFF +} + + +/// compute CRC32 +uint32_t crc32_1byte(const void* data, uint16_t length, uint32_t previousCrc32 = 0) +{ + uint32_t crc = ~previousCrc32; // same as previousCrc32 ^ 0xFFFFFFFF + uint8_t* current = (uint8_t*) data; + + while (length--) + { + uint8_t offset = uint8_t(crc) ^ *current++; + crc = (crc >> 8) ^ pgm_read_dword_near(crc32Lookup + offset); + } + + return ~crc; // same as crc ^ 0xFFFFFFFF +} + + +void setup() +{ + Serial.begin(9600); + for (size_t i = 0; i < NumBytes; i++) + data[i] = uint8_t(i & 0xFF); +} + + + +void loop() +{ + uint32_t crc = crc32_bitwise(data, NumBytes); + Serial.println(crc, HEX); +} + diff --git a/lib/crc32/Crc32Test.cpp b/lib/crc32/Crc32Test.cpp new file mode 100644 index 0000000..3a4eb01 --- /dev/null +++ b/lib/crc32/Crc32Test.cpp @@ -0,0 +1,170 @@ +// ////////////////////////////////////////////////////////// +// Crc32Test.cpp +// Copyright (c) 2016-2019 Stephan Brumme. All rights reserved. +// see http://create.stephan-brumme.com/disclaimer.html +// + +#include "Crc32.h" +#include +#include + +// the slicing-by-4/8/16 tests are only performed if the corresponding +// preprocessor symbol is defined in Crc32.h +// simpler algorithms can be enabled/disabled right here: +#define CRC32_TEST_BITWISE +#define CRC32_TEST_HALFBYTE +#define CRC32_TEST_TABLELESS + +// ////////////////////////////////////////////////////////// +// test code + +/// one gigabyte +const size_t NumBytes = 1024*1024*1024; +/// 4k chunks during last test +const size_t DefaultChunkSize = 4*1024; + + +#if defined(_WIN32) || defined(_WIN64) +#include +#else +#include +#endif + +// timing +static double seconds() +{ +#if defined(_WIN32) || defined(_WIN64) + LARGE_INTEGER frequency, now; + QueryPerformanceFrequency(&frequency); + QueryPerformanceCounter (&now); + return now.QuadPart / double(frequency.QuadPart); +#else + timespec now; + clock_gettime(CLOCK_REALTIME, &now); + return now.tv_sec + now.tv_nsec / 1000000000.0; +#endif +} + + +int main(int, char**) +{ + printf("Please wait ...\n"); + + uint32_t randomNumber = 0x27121978; + // initialize + char* data = new char[NumBytes]; + for (size_t i = 0; i < NumBytes; i++) + { + data[i] = char(randomNumber & 0xFF); + // simple LCG, see http://en.wikipedia.org/wiki/Linear_congruential_generator + randomNumber = 1664525 * randomNumber + 1013904223; + } + + // re-use variables + double startTime, duration; + uint32_t crc; + +#ifdef CRC32_TEST_BITWISE + // bitwise + startTime = seconds(); + crc = crc32_bitwise(data, NumBytes); + duration = seconds() - startTime; + printf("bitwise : CRC=%08X, %.3fs, %.3f MB/s\n", + crc, duration, (NumBytes / (1024*1024)) / duration); +#endif // CRC32_TEST_BITWISE + +#ifdef CRC32_TEST_HALFBYTE + // half-byte + startTime = seconds(); + crc = crc32_halfbyte(data, NumBytes); + duration = seconds() - startTime; + printf("half-byte : CRC=%08X, %.3fs, %.3f MB/s\n", + crc, duration, (NumBytes / (1024*1024)) / duration); +#endif // CRC32_TEST_HALFBYTE + +#ifdef CRC32_TEST_TABLELESS + // one byte at once (without lookup tables) + startTime = seconds(); + crc = crc32_1byte_tableless(data, NumBytes); + duration = seconds() - startTime; + printf("tableless (byte) : CRC=%08X, %.3fs, %.3f MB/s\n", + crc, duration, (NumBytes / (1024*1024)) / duration); + + // one byte at once (without lookup tables) + startTime = seconds(); + crc = crc32_1byte_tableless2(data, NumBytes); + duration = seconds() - startTime; + printf("tableless (byte2): CRC=%08X, %.3fs, %.3f MB/s\n", + crc, duration, (NumBytes / (1024*1024)) / duration); +#endif // CRC32_TEST_TABLELESS + +#ifdef CRC32_USE_LOOKUP_TABLE_BYTE + // one byte at once + startTime = seconds(); + crc = crc32_1byte(data, NumBytes); + duration = seconds() - startTime; + printf(" 1 byte at once: CRC=%08X, %.3fs, %.3f MB/s\n", + crc, duration, (NumBytes / (1024*1024)) / duration); +#endif // CRC32_USE_LOOKUP_TABLE_BYTE + +#ifdef CRC32_USE_LOOKUP_TABLE_SLICING_BY_4 + // four bytes at once + startTime = seconds(); + crc = crc32_4bytes(data, NumBytes); + duration = seconds() - startTime; + printf(" 4 bytes at once: CRC=%08X, %.3fs, %.3f MB/s\n", + crc, duration, (NumBytes / (1024*1024)) / duration); +#endif // CRC32_USE_LOOKUP_TABLE_SLICING_BY_4 + +#ifdef CRC32_USE_LOOKUP_TABLE_SLICING_BY_8 + // eight bytes at once + startTime = seconds(); + crc = crc32_8bytes(data, NumBytes); + duration = seconds() - startTime; + printf(" 8 bytes at once: CRC=%08X, %.3fs, %.3f MB/s\n", + crc, duration, (NumBytes / (1024*1024)) / duration); + + // eight bytes at once, unrolled 4 times (=> 32 bytes per loop) + startTime = seconds(); + crc = crc32_4x8bytes(data, NumBytes); + duration = seconds() - startTime; + printf("4x8 bytes at once: CRC=%08X, %.3fs, %.3f MB/s\n", + crc, duration, (NumBytes / (1024*1024)) / duration); +#endif // CRC32_USE_LOOKUP_TABLE_SLICING_BY_8 + +#ifdef CRC32_USE_LOOKUP_TABLE_SLICING_BY_16 + // sixteen bytes at once + startTime = seconds(); + crc = crc32_16bytes(data, NumBytes); + duration = seconds() - startTime; + printf(" 16 bytes at once: CRC=%08X, %.3fs, %.3f MB/s\n", + crc, duration, (NumBytes / (1024*1024)) / duration); + + // sixteen bytes at once + startTime = seconds(); + crc = crc32_16bytes_prefetch(data, NumBytes, 0, 256); + duration = seconds() - startTime; + printf(" 16 bytes at once: CRC=%08X, %.3fs, %.3f MB/s (including prefetching)\n", + crc, duration, (NumBytes / (1024*1024)) / duration); +#endif // CRC32_USE_LOOKUP_TABLE_SLICING_BY_16 + + // process in 4k chunks + startTime = seconds(); + crc = 0; // also default parameter of crc32_xx functions + size_t bytesProcessed = 0; + while (bytesProcessed < NumBytes) + { + size_t bytesLeft = NumBytes - bytesProcessed; + size_t chunkSize = (DefaultChunkSize < bytesLeft) ? DefaultChunkSize : bytesLeft; + + crc = crc32_fast(data + bytesProcessed, chunkSize, crc); + + bytesProcessed += chunkSize; + } + duration = seconds() - startTime; + printf(" chunked : CRC=%08X, %.3fs, %.3f MB/s\n", + crc, duration, (NumBytes / (1024*1024)) / duration); + + delete[] data; + return 0; +} diff --git a/lib/crc32/Crc32TestMultithreaded.cpp b/lib/crc32/Crc32TestMultithreaded.cpp new file mode 100644 index 0000000..0878801 --- /dev/null +++ b/lib/crc32/Crc32TestMultithreaded.cpp @@ -0,0 +1,203 @@ +// ////////////////////////////////////////////////////////// +// Crc32TestMultithreaded.cpp +// Copyright (c) 2019 Stephan Brumme. All rights reserved. +// see http://create.stephan-brumme.com/disclaimer.html +// + +#include "Crc32.h" +#include +#include + +#include +#include + +// C++11 multithreading +#include +#include + +// ////////////////////////////////////////////////////////// +// test code + +/// one gigabyte +const size_t NumBytes = 1024*1024*1024; + + +#if defined(_WIN32) || defined(_WIN64) +#include +#else +#include +#endif + +// timing +static double seconds() +{ +#if defined(_WIN32) || defined(_WIN64) + LARGE_INTEGER frequency, now; + QueryPerformanceFrequency(&frequency); + QueryPerformanceCounter (&now); + return now.QuadPart / double(frequency.QuadPart); +#else + timespec now; + clock_gettime(CLOCK_REALTIME, &now); + return now.tv_sec + now.tv_nsec / 1000000000.0; +#endif +} + +// ////////////////////////////////////////////////////////// +// run a CRC32 algorithm on multiple threads +typedef uint32_t (*Crc32Algorithm)(const void* data, size_t length, uint32_t previousCrc32); +// compute CRC32 of up to maxBlockSize bytes and start recursively a new thread for excess data +uint32_t asyncCrc32(Crc32Algorithm myCrc32, const void* data, size_t numBytes, size_t maxBlockSize) +{ + // last block ? + if (numBytes <= maxBlockSize) + return myCrc32(data, numBytes, 0); // we're done + + // compute CRC of the remaining bytes in a separate thread + auto dataLeft = (const char*)data + maxBlockSize; + auto bytesLeft = numBytes - maxBlockSize; + auto remainder = std::async(std::launch::async, asyncCrc32, myCrc32, dataLeft, bytesLeft, maxBlockSize); + + // compute CRC of the current block + auto currentCrc = myCrc32(data, maxBlockSize, 0); + // get CRC of the remainder + auto remainderCrc = remainder.get(); + // and merge both + return crc32_combine(currentCrc, remainderCrc, bytesLeft); +} +// call: run(crc32_8bytes, data, NumBytes, 8) if you have an octocore CPU +uint32_t run(Crc32Algorithm myCrc32, const void* data, size_t numBytes, size_t numThreads = 0) +{ + // run on all cores + if (numThreads == 0) + numThreads = std::thread::hardware_concurrency(); + + // split data evenly, rounding up + auto defaultBlocksize = (numBytes + numThreads - 1) / numThreads; + + return asyncCrc32(myCrc32, data, numBytes, defaultBlocksize); +} + + +// test original sequential CRC32 algorithm against crc32_combine +bool testCombine(const char* data, size_t maxBytes = 1024) +{ + bool ok = true; + for (size_t lengthA = 1; lengthA < maxBytes; lengthA++) + { + // split bytes into two blocks of lengthA and lengthB + auto lengthB = maxBytes - lengthA; + + // compute CRC of both blocks + auto crcA = crc32_1byte(data, lengthA); + auto crcB = crc32_1byte(data + lengthA, lengthB); + + // CRC of the whole block + auto crcAtOnce = crc32_1byte(data, maxBytes); + // CRC of both blocks in a sequential fashion + auto crcSequential = crc32_1byte(data + lengthA, lengthB, crcA); + + // CRC using the new crc32_combine function + auto crcCombined = crc32_combine(crcA, crcB, lengthB); + + // check results + if (crcAtOnce != crcSequential || crcAtOnce != crcCombined) + { + printf("FAILED @ %d: %08X %08X %08X %08X %08X\n", lengthA, crcA, crcB, crcAtOnce, crcSequential, crcCombined); + ok = false; + } + } + return ok; +} + + +int main(int argc, char* argv[]) +{ + // ////////////////////////////////////////////////////////// + printf("Please wait ...\n"); + + uint32_t randomNumber = 0x27121978; + // initialize + char* data = new char[NumBytes]; + for (size_t i = 0; i < NumBytes; i++) + { + data[i] = char(randomNumber & 0xFF); + // simple LCG, see http://en.wikipedia.org/wiki/Linear_congruential_generator + randomNumber = 1664525 * randomNumber + 1013904223; + } + + // re-use variables + double startTime, duration; + uint32_t crc; + std::vector> futures; + + // number of threads: use all cores by default or set number as command-line parameter + auto numThreads = 0; + if (argc == 2) + numThreads = std::stoi(argv[1]); + if (numThreads <= 0) + numThreads = std::thread::hardware_concurrency(); + printf("use %d threads:\n", numThreads); + + // ////////////////////////////////////////////////////////// + // one byte at once + startTime = seconds(); + crc = run(crc32_1byte, data, NumBytes, numThreads); + duration = seconds() - startTime; + printf(" 1 byte at once / %d threads: CRC=%08X, %.3fs, %.3f MB/s\n", + numThreads, crc, duration, (NumBytes / (1024*1024)) / duration); + + // four bytes at once + startTime = seconds(); + crc = run(crc32_4bytes, data, NumBytes, numThreads); + duration = seconds() - startTime; + printf(" 4 bytes at once / %d threads: CRC=%08X, %.3fs, %.3f MB/s\n", + numThreads, crc, duration, (NumBytes / (1024*1024)) / duration); + + // eight bytes at once + startTime = seconds(); + crc = run(crc32_8bytes, data, NumBytes, numThreads); + duration = seconds() - startTime; + printf(" 8 bytes at once / %d threads: CRC=%08X, %.3fs, %.3f MB/s\n", + numThreads, crc, duration, (NumBytes / (1024*1024)) / duration); + + // eight bytes at once, unrolled 4 times (=> 32 bytes per loop) + startTime = seconds(); + crc = run(crc32_4x8bytes, data, NumBytes, numThreads); + duration = seconds() - startTime; + printf("4x8 bytes at once / %d threads: CRC=%08X, %.3fs, %.3f MB/s\n", + numThreads, crc, duration, (NumBytes / (1024*1024)) / duration); + + // sixteen bytes at once + startTime = seconds(); + crc = run(crc32_16bytes, data, NumBytes, numThreads); + duration = seconds() - startTime; + printf(" 16 bytes at once / %d threads: CRC=%08X, %.3fs, %.3f MB/s\n", + numThreads, crc, duration, (NumBytes / (1024*1024)) / duration); + + // ////////////////////////////////////////////////////////// + // slowly increment number of threads to determine scalability + printf("run slicing-by-8 algorithm with 1 to %d threads:\n", numThreads); + for (auto scaleThreads = 1; scaleThreads <= numThreads; scaleThreads++) + { + // eight bytes at once + startTime = seconds(); + + if (scaleThreads == 1) + crc = crc32_8bytes (data, NumBytes); // single-threaded + else + crc = run(crc32_8bytes, data, NumBytes, scaleThreads); // multi-threaded + + duration = seconds() - startTime; + printf(" 8 bytes at once / %d threads: CRC=%08X, %.3fs, %.3f MB/s\n", + scaleThreads, crc, duration, (NumBytes / (1024*1024)) / duration); + } + + // ////////////////////////////////////////////////////////// + // verify crc32_combine + if (!testCombine(data, 1024)) + printf("ERROR in crc32_combine !!!\n"); + + delete[] data; + return 0; +} diff --git a/lib/crc32/LICENSE b/lib/crc32/LICENSE new file mode 100644 index 0000000..76d0362 --- /dev/null +++ b/lib/crc32/LICENSE @@ -0,0 +1,10 @@ +zlib License + +Copyright (c) 2011-2016 Stephan Brumme + +This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages arising from the use of this software. +Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: +1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. + If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. +2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. +3. This notice may not be removed or altered from any source distribution. diff --git a/lib/crc32/Makefile b/lib/crc32/Makefile new file mode 100644 index 0000000..066c3a0 --- /dev/null +++ b/lib/crc32/Makefile @@ -0,0 +1,26 @@ +# simple Makefile +#CXX = g++ + +# files +PROGRAM = Crc32Test +LIBS = -lrt +HEADERS = Crc32.h +OBJECTS = Crc32.o Crc32Test.o + +# flags +FLAGS = -O3 -Wall -Wextra -pedantic -s + +default: $(PROGRAM) +all: default + +$(PROGRAM): $(OBJECTS) Makefile + $(CXX) $(OBJECTS) $(FLAGS) $(LIBS) -o $(PROGRAM) + +%.o: %.cpp $(HEADERS) Makefile + $(CXX) $(FLAGS) -c $< -o $@ + +clean: + -rm -f $(OBJECTS) $(PROGRAM) + +run: $(PROGRAM) + ./$(PROGRAM) diff --git a/lib/crc32/changelog.md b/lib/crc32/changelog.md new file mode 100644 index 0000000..b87f45d --- /dev/null +++ b/lib/crc32/changelog.md @@ -0,0 +1,38 @@ +# Changelog +This file tracks the main changes to my CRC32 library. + +project website: https://create.stephan-brumme.com/crc32/ +GitHub mirror: https://github.com/stbrumme/crc32/ + +## December 6, 2019 (version 9) +- added support for multi-threaded computation + +## November 27, 2019 +- use C++'s include names +- removed warning on little-endian systems +- fixed typo in comments + +## May 27, 2019 (version 8) +- fixed misspelt preprocessor symbol + +## October 21, 2016 (version 7) +- changed code structure into a library format +- added tableless byte algorithms + +## August 14, 2015 (version 6) +- improved #ifdefs for Cygwin, MinGW and Clang + +## February 4, 2015 (version 5) +- added Slicing-by-16 + +## August 12, 2014 (version 4) +- added Javascript port + +## May 4, 2013 (version 3) +- endian aware, slightly faster Slicing-by-8 + +## November 13, 2011 (version 2) +- improved portability + +## November 10, 2011 (version 1) +- initial release diff --git a/lib/crc32/crc32.js b/lib/crc32/crc32.js new file mode 100644 index 0000000..79b363a --- /dev/null +++ b/lib/crc32/crc32.js @@ -0,0 +1,43 @@ +// ////////////////////////////////////////////////////////// +// crc32.js +// Copyright (c) 2014 Stephan Brumme. All rights reserved. +// see http://create.stephan-brumme.com/disclaimer.html +// + +function hex(what) +{ + // adjust negative numbers + if (what < 0) + what = 0xFFFFFFFF + what + 1; + // convert to hexadecimal string + var result = what.toString(16); + // add leading zeros + return ('0000000' + result).slice(-8); +} + +function crc32_bitwise(text) +{ + // CRC32b polynomial + var Polynomial = 0xEDB88320; + // start value + var crc = 0xFFFFFFFF; + + for (var i = 0; i < text.length; i++) + { + // XOR next byte into state + crc ^= text.charCodeAt(i); + + // process 8 bits + for (var bit = 0; bit < 8; bit++) + { + // look at lowest bit + if ((crc & 1) != 0) + crc = (crc >>> 1) ^ Polynomial; + else + crc = crc >>> 1; + } + } + + // return hex string + return hex(~crc); +} diff --git a/lib/crc32/readme.md b/lib/crc32/readme.md new file mode 100644 index 0000000..a8a84c6 --- /dev/null +++ b/lib/crc32/readme.md @@ -0,0 +1,25 @@ +# Fast CRC32 + +This is a mirror of my CRC32 library hosted at https://create.stephan-brumme.com/crc32/ + +Features in a nutshell: +- C++ code, single file +- the fastest algorithms need about 1 CPU cycle per byte +- endian-aware +- support for multi-threaded computation +- runs even on Arduino, Raspberry Pi, etc. +- quite long posting about it on https://create.stephan-brumme.com/crc32/, describing each implemented algorithm in detail + +Algorithms: +- bitwise +- branch-free bitwise +- half-byte +- tableless full-byte +- Sarwate's original algorithm +- slicing-by-4 +- slicing-by-8 +- slicing-by-16 + +- crc32_combine() "merges" two indepedently computed CRC32 values which is the basis for even faster multi-threaded calculation + +See my website https://create.stephan-brumme.com/crc32/ for documentation, code examples and a benchmark. diff --git a/src/BSidesMessaging.cpp b/src/BSidesMessaging.cpp new file mode 100644 index 0000000..f49fc58 --- /dev/null +++ b/src/BSidesMessaging.cpp @@ -0,0 +1,98 @@ +#include "BSidesMessaging.h" +#include +#include + +// Monotonically-increasing sequence number +static uint8_t monotonicSequenceNumber; + +bool prepareMessage(SerialMessage &msg, MessageType type, uint8_t seqNo, const void *data, size_t datalen) { + if ((datalen > SERIALBRIDGE_MESSAGE_DATA_SIZE_MAX) + || (datalen > 0 && data == NULL) + || (datalen == 0 && data != NULL) + ) { + return false; + } + memset((void*)&msg, 0, sizeof(msg)); + msg.header.magic = SERIALBRIDGE_MESSAGE_MAGIC; + msg.header.seqNo = seqNo; + msg.header.type = type; + msg.header.version = SERIALBRIDGE_MESSAGE_CURRENT_VERSION; + if (datalen > 0) { + memcpy((void*)(&msg.data.payload), data, datalen); + } + uint32_t crc32 = crc32_bitwise((void*)&msg, SERIALBRIDGE_MESSAGE_SIZE, 0); + msg.header.crc32 = crc32; + return true; +} + +bool validateMessage(const SerialMessage &msg) { + if ((msg.header.magic != SERIALBRIDGE_MESSAGE_MAGIC) + || (msg.header.version > SERIALBRIDGE_MESSAGE_CURRENT_VERSION) + || (msg.header.type < SERIALBRIDGE_MESSAGE_TYPE_MIN) + || (msg.header.type >= SERIALBRIDGE_MESSAGE_TYPE_MAX) + ) { + return false; + } + // validate CRC32 + SerialMessage crcCheck = msg; + // Set crc to zero for calculation + crcCheck.header.crc32 = 0; + uint32_t crc32_to_compare = msg.header.crc32; + uint32_t crc32_calculated = crc32_bitwise((void*)&crcCheck, SERIALBRIDGE_MESSAGE_SIZE, 0); + return crc32_to_compare == crc32_calculated; +} + +uint8_t nextSequenceNumber(void) { + return monotonicSequenceNumber++; +} + +bool enqueueMessage(const SerialMessage &msg, SerialMessageQueue &queue) { + if (!validateMessage(msg)) { + return false; + } + queue.push(msg); + return true; +} + +bool dequeueMessage(SerialMessage *msgOut, SerialMessageQueue &queue) { + if (queue.isEmpty() || (msgOut == NULL)) { + return false; + } + // Consume the first message + SerialMessage msg = queue.pop(); + if (!validateMessage(msg)) { + return false; + } + memcpy(msgOut, &msg, SERIALBRIDGE_MESSAGE_SIZE); + return true; +} + +const char* messageType(MessageType type) { + switch (type) { + case VBATRequest: return "VBATRequest"; + case VBATResponse: return "VBATResponse"; + case IRdASend: return "IRdASend"; + case IRdARecv: return "IRdARecv"; + case IRdACheck: return "IRdACheck"; + case IMUEvent: return "IMUEvent"; + case AudioEvent: return "AudioEvent"; + case WiFiEvent: return "WiFiEvent"; + case BluetoothEvent: return "BluetoothEvent"; + case SDEvent: return "SDEvent"; + case SAOWireSend: return "SAOWireSend"; + case SAOWireRequest: return "SAOWireRequest"; + case SAOGPIOGet: return "SAOGPIOGet"; + case SAOGPIOSet: return "SAOGPIOSet"; + case SAOGPIOVal: return "SAOGPIOVal"; + case LEDSet: return "LEDSet"; + case Capsense: return "Capsense"; + case CapsenseFeedbackEnable: return "Capsense feedback enable"; + case DPad: return "DPad"; + case SAMD_Suspend: return "Suspend"; + case Diagnostics_PING: return "PING"; + case Diagnostics_PONG: return "PONG"; + case Message_ACK: return "ACK"; + case Message_NACK: return "NACK"; + default: return "UNKNOWN"; + } +} diff --git a/src/BadgeLog.cpp b/src/BadgeLog.cpp new file mode 100644 index 0000000..45762b2 --- /dev/null +++ b/src/BadgeLog.cpp @@ -0,0 +1,231 @@ +#include +#include +#include +#include +#include + +#include +#include "BadgeLog.h" +#ifdef SAMD21 +#include "SerialBridge.h" +#endif + +/** + * Internal definitions + */ +#ifndef LOG_RINGBUF_SZ +#define LOG_RINGBUF_SZ (4096U) +#endif//LOG_RINGBUF_SZ + +/* Log entries are truncated to a maximum of `LOG_MAX_SZ - 1` characters */ +#ifndef LOG_MAX_SZ +#define LOG_MAX_SZ (256U) +#endif//LOG_MAX_SZ$ + +#ifndef DEFAULT_BADGEOS_LOG_LEVEL +#define DEFAULT_BADGEOS_LOG_LEVEL (LOG_INFO) +#endif//DEFAULT_BADGEOS_LOG_LEVEL + +#ifndef LOG_LEVEL +# ifdef CONFIG_BADGEOS_LOG_LEVEL +# define LOG_LEVEL (CONFIG_BADGEOS_LOG_LEVEL) +# else +# define LOG_LEVEL (DEFAULT_BADGEOS_LOG_LEVEL) +# endif +#endif//LOG_LEVEL + +#ifndef LOG_DECORATE +#define LOG_DECORATE (LOG_DECORATED) +#endif//LOG_DECORATE + +/** + * Logging ringbuffer + */ +static char ringbuf[LOG_RINGBUF_SZ]; +static char *cur_r = ringbuf, *cur_w = ringbuf; +#define _RINGBUF_END (&ringbuf[sizeof(ringbuf)]) + +/* Cursor management */ +static inline size_t _cur_w_sz(bool contig) { + char *stop; + ptrdiff_t sz; + + if (contig) { + stop = cur_r > cur_w ? cur_r : _RINGBUF_END; + } else { + stop = cur_r + sizeof(ringbuf); + } + sz = stop - cur_w; + return (sz >= 0) ? (size_t) sz : 0; +} +static inline void _cur_adv(char **cur_p, const size_t sz) { + *cur_p += sz; + while (*cur_p >= _RINGBUF_END) *cur_p -= LOG_RINGBUF_SZ; +} +/* R/W */ +static inline size_t _ring_rd(char *buf, size_t buf_sz) { + size_t i; + for (i = 0; buf_sz-- >= 0; ++i, ++buf) { + /* Immediately bail if we're about to copy from the write cursor */ + if (cur_r == cur_w) break; + *buf = *cur_r; + /* Check if we hit a NUL before advancing `cur_r` */ + if (*(cur_r++) == '\0') break; + if (cur_r >= _RINGBUF_END) cur_r -= LOG_RINGBUF_SZ; + } + /* Ensure we always NUL terminate */ + *buf = '\0'; + return i; +} +static inline void _ring_wr(const char * buf, size_t buf_sz) { + while (buf_sz-- >= 0 && *buf != '\0') { + *(cur_w++) = *(buf++); + if (cur_w >= _RINGBUF_END) cur_w -= LOG_RINGBUF_SZ; + } + *(cur_w++) = '\0'; +} + +/* Entry truncation logic */ +static const char _trunc_s[] = "[trunc]"; +static inline void _mark_trunc(char * const buf, const size_t buf_sz) { + /* If we don't have room for the marker, do nothing */ + if (sizeof(_trunc_s) < buf_sz) { + strncpy(buf + buf_sz - sizeof(_trunc_s), _trunc_s, sizeof(_trunc_s)); + } +} + +/** + * Actual logging + */ +static log_level_e _g_level = LOG_LEVEL; +void set_log_level(const log_level_e level) { + _g_level = level; +} + +static log_decoration_e _g_decorate = LOG_DECORATE; +void set_log_decoration(const log_decoration_e decorate) { + _g_decorate = decorate; +} + +static const char *_level_as[] = { + [LOG_NOTSET] = "NOT SET", + [LOG_TRACE] = "TRACE", + [LOG_DEBUG] = "DEBUG", + [LOG_INFO] = "INFO", + [LOG_WARN] = "WARN", + [LOG_ERROR] = "ERROR", + [LOG_CRITICAL] = "CRITICAL", + [LOG_PANIC] = "PANIC", + [_LOG_MAX_LV] = "UNKNOWN", +}; + +void _do_log( + const log_level_e level, const log_decoration_e decoration, + const char * const fmt, va_list ap +) { + bool direct; + char *ent, *p; + int sprint_sz, ent_sz = 0; + + /* Bail early if this is below the current level */ + if (level < _g_level) return; + + /* Fastest path is to format directly into the ring buffer */ + if (_cur_w_sz(true) >= LOG_MAX_SZ) { + direct = true; + ent = cur_w; + } else { + direct = false; + ent = (char *) alloca(LOG_MAX_SZ); + } + /* We have a pointer to our current cursor in the entry being formatted */ + p = ent; + + /* If we need to decorate the log entry, attempt to do so but never consume + * more than a quarter of the buffer size (arbitrarily selected). + */ + if (decoration == LOG_DECORATED) { + const size_t dec_max = LOG_MAX_SZ >> 2; + /* Find the appropriate log level string for decoration and fall back + * to the maximum value for "UNKNOWN" if we are out of bounds or NULL. + */ + const char *lv_s = _level_as[level < _LOG_MAX_LV ? level : _LOG_MAX_LV]; + if (lv_s == NULL) lv_s = _level_as[_LOG_MAX_LV]; + /* If we fail here, we can't really recover. Bail immediately without + * advancing the cursor (for direct writes) so that the next entry will + * overwrite the decoration we just wrote, or allow it to fall out of + * the stack once we return (for indirect). + */ + sprint_sz = snprintf(p, dec_max, "[%s:%lu] ", lv_s, millis()); + if (sprint_sz < 0) return; + /* Ensure that if the decoration was truncated we have a close brace */ + if (sprint_sz >= dec_max) { + ent[dec_max - 1] = ']'; + sprint_sz = dec_max; /* Advance to the trailing NUL */ + } + /* Advance the entry cursor and size */ + p += sprint_sz; + ent_sz += sprint_sz; + } + + /* Perform the log string formatting */ + sprint_sz = vsnprintf(p, LOG_MAX_SZ - ent_sz, fmt, ap); + + /* If we didn't error out, we need to either advance the cursor for direct + * writes or use the ringbuf helper to do a potentialy segmented write. + * Otherwise we'll fall through without advancing the cursor/writing to the + * ring buffer. + */ + if (sprint_sz >= 0) { + ent_sz += sprint_sz; + /* If the sum of the prior `ent_sz` and the size returned by + * `vsnprintf()` is equal to or greater than the maximum buffer size, + * that indicates the formatted string was truncated and we filled the + * space in the buffer we allowed ourselves to use (including a NUL). + */ + if (ent_sz >= LOG_MAX_SZ) { + _mark_trunc(ent, LOG_MAX_SZ); + /* We only wrote this much, not including the trailing NUL which will + * be accounted for below. + */ + ent_sz = LOG_MAX_SZ - 1; + } + ent_sz += 1; /* Account for the trailing NUL first */ + if (direct) _cur_adv(&cur_w, (size_t) ent_sz); + else _ring_wr(ent, ent_sz); + } +} + +void log(const log_level_e level, + const char * const fmt, ... +) { + va_list ap; + va_start(ap, fmt); + _do_log(level, _g_decorate, fmt, ap); + va_end(ap); +} + +void log(const log_level_e level, const log_decoration_e decoration, + const char * const fmt, ... +) { + va_list ap; + va_start(ap, fmt); + _do_log(level, decoration, fmt, ap); + va_end(ap); +} + +/* Dump all pending log entries manually */ +void log_dump(void) { + char buf[LOG_MAX_SZ]; + while (_ring_rd(buf, sizeof(buf)) > 0) { +#ifndef __unix__ + Serial.println(buf); +#ifdef SAMD21 + DebugSerial.println(buf); +#endif +#else + printf("%s\n", buf); + fflush(NULL); +#endif + } +} diff --git a/src/SerialBridge.cpp b/src/SerialBridge.cpp new file mode 100644 index 0000000..920f180 --- /dev/null +++ b/src/SerialBridge.cpp @@ -0,0 +1,252 @@ +#include +#include +#include + +#ifdef ARDUINO_SAMD_MKRZERO +#ifndef SAMD21 +#define SAMD21 +#endif +#endif // ARDUINO_SAMD_MKRZERO + +#ifdef ESP32 +#define HAS_BRIDGELINK +#define BRIDGELINK_NEEDS_FLUSH true +#include +#endif +#ifdef SAMD21 +#define HAS_BRIDGELINK +#define BRIDGELINK_NEEDS_FLUSH +#include +#include "wiring_private.h" // pinPeripheral() function +#endif +#ifdef __unix__ +#include +#include +#endif + +#include + +#include "SerialBridge.h" +// Include pin assignments +#include "badge_pins.h" + +#ifdef SAMD21 +// SAMD21 Arduino pinouts for UART bridge use -- we set up a Serial object here on the relevant pins +// UART_RXD on SERCOM4, PAD[0] +// UART_TXD on SERCOM4, PAD[2]; +Uart BridgeLink(&sercom4, UART_RXD, UART_TXD, SERCOM_RX_PAD_0, UART_TX_PAD_2); +Uart DebugSerial(&sercom0, UART_SCI_RXD, UART_SCI_TXD, SERCOM_RX_PAD_3, UART_TX_PAD_2); +void SERCOM4_Handler() +{ + BridgeLink.IrqHandler(); +} +void SERCOM0_Handler() +{ + DebugSerial.IrqHandler(); +} +#endif +#ifdef ESP32 +// ESP32 pinouts don't define a serial bridge on these pins, so we make our own +// We take over UART #1 +HardwareSerial BridgeLink(1); +#endif + +SerialBridgeLink::SerialBridgeLink() +{ +} + +void SerialBridgeLink::begin(unsigned long baud) +{ +log(LOG_INFO, "Connecting Serial Link"); +#ifdef SAMD21 +pinPeripheral(UART_RXD, PIO_SERCOM_ALT); +pinPeripheral(UART_TXD, PIO_SERCOM_ALT); +pinPeripheral(UART_SCI_RXD, PIO_SERCOM); +pinPeripheral(UART_SCI_TXD, PIO_SERCOM); +BridgeLink.begin(baud); +#endif +#ifdef ESP32 +BridgeLink.begin(baud, SERIAL_8N1, UART_RXD, UART_TXD); +#endif +log(LOG_INFO, "Connected"); +} + +void SerialBridgeLink::end(void) +{ +#ifdef HAS_BRIDGELINK + return BridgeLink.end(); +#endif +} + +int SerialBridgeLink::available(void) +{ +#ifdef HAS_BRIDGELINK + return BridgeLink.available(); +#else + return 0; +#endif +} + +int SerialBridgeLink::read(void) +{ +#ifdef HAS_BRIDGELINK + return BridgeLink.read(); +#else + return 0; +#endif +} + +void SerialBridgeLink::flush(void) +{ +#ifdef HAS_BRIDGELINK + return BridgeLink.flush(BRIDGELINK_NEEDS_FLUSH); +#endif +} + +size_t SerialBridgeLink::write(uint8_t value) +{ +#ifdef HAS_BRIDGELINK + return BridgeLink.write(value); +#else + return 0; +#endif +} + +SerialBridge::SerialBridge() +{ + +} + +void SerialBridge::connect(void) +{ + this->link.begin(); +} + +void SerialBridge::disconnect(void) +{ + this->link.end(); +} + +int SerialBridge::available(void) +{ + return this->link.available(); +} + +/* These are intended to ensure we get always get the start and end of a message, but + * we don't currently do anything to mark framing past this. Any application layer + * protocol on to of this wire protocol can handle SYNACKs if need be. + */ +#define SERIALBRIDGE_SYNC (0b11011001U) +#define SERIALBRIDGE_EOF (0b00100110U) +// 1 SYNC transmits appears to be enough for a mostly reliable line during busy messaging +#define SERIALBRIDGE_SYNC_TX (1U) + +bool SerialBridge::sendMessage(const SerialMessage& msg) { + // Send sync bytes + for (int i = 0; i < SERIALBRIDGE_SYNC_TX; ++i) { + if (this->link.write(SERIALBRIDGE_SYNC) != 1) { + return false; + } + } + ssize_t sent = this->send(&msg, SERIALBRIDGE_MESSAGE_SIZE); + if (sent != SERIALBRIDGE_MESSAGE_SIZE) { + return false; + } + // We send a single EOF + if (this->link.write(SERIALBRIDGE_EOF) != 1) { + return false; + } + return true; +} + +void SerialBridge::sendAckMessage(uint8_t seqNo) { + SerialMessage msg; + prepareMessage(msg, Message_ACK, seqNo, NULL, 0); + log(LOG_DEBUG, "ACK message %d", seqNo); + this->sendMessage(msg); +} + +void SerialBridge::sendNackMessage(uint8_t seqNo) { + SerialMessage msg; + prepareMessage(msg, Message_NACK, seqNo, NULL, 0); + log(LOG_DEBUG, "NACK message %d", seqNo); + this->sendMessage(msg); +} + +bool SerialBridge::recvMessage(SerialMessage* msg) { + if (this->link.available() < (SERIALBRIDGE_MESSAGE_SIZE + (SERIALBRIDGE_SYNC_TX))) { + log(LOG_DEBUG, "Not enough bytes to be a minimally valid message"); + return false; + } + // Find a SYNC byte + uint8_t sync = 0; + while ((sync != SERIALBRIDGE_SYNC) && (this->link.available() > 0)) { + sync = this->link.read(); + } + // Consume SYNC bytes + while ((sync == SERIALBRIDGE_SYNC) && (this->link.available() > 0)) { + sync = this->link.read(); + } + // Ensure we haven't just consumed SYNCs + if (sync == SERIALBRIDGE_SYNC) { + log(LOG_ERROR, "Failed to find message"); + return false; + } + // Put the first byte in and consume the rest of the message + uint8_t *buf = (uint8_t*)msg; + buf[0] = sync; + buf++; + ssize_t recvd = this->recv((void*)buf, SERIALBRIDGE_MESSAGE_SIZE - 1) + 1; + if (recvd < (SERIALBRIDGE_MESSAGE_SIZE - 1)) { + log(LOG_DEBUG, "Not a full message: received %d expected %d", recvd, SERIALBRIDGE_MESSAGE_SIZE); + } + // Consume until EOF byte found + sync = 0; + while ((sync != SERIALBRIDGE_EOF) && (this->link.available() > 0)) { + sync = this->link.read(); + } + if (!validateMessage(*msg)) { + log(LOG_ERROR, "Invalid %s message", messageType(msg->header.type)); + // Don't (n)ACK a (n)ACK + if ((msg->header.type != Message_ACK) + && (msg->header.type != Message_NACK)) { + this->sendNackMessage(msg->header.seqNo); + } + return false; + } + // Don't (n)ACK a (n)ACK + if ((msg->header.type != Message_ACK) + && (msg->header.type != Message_NACK)) { + this->sendAckMessage(msg->header.seqNo); + } + return true; +} + +ssize_t SerialBridge::send(const void *buf, size_t buf_size) +{ + size_t i = -1; +#ifdef HAS_BRIDGELINK + uint8_t *p = (uint8_t*) buf; + + for ( i = 0; i < buf_size; i++ ) { + if (this->link.write(p[i]) != 1) goto flush; + } + +flush: + this->link.flush(); +#endif + return (ssize_t)i; +} + +ssize_t SerialBridge::recv(void *buf, size_t buf_size) +{ + uint8_t *p = (uint8_t*)buf; + int offset = -1; +#ifdef HAS_BRIDGELINK + while (this->link.available() && offset < (int)buf_size) { + ++offset; + p[offset] = this->link.read(); + } +#endif + return offset; +} diff --git a/src/icm20602.c b/src/icm20602.c new file mode 100644 index 0000000..5c01c32 --- /dev/null +++ b/src/icm20602.c @@ -0,0 +1,549 @@ +/***** Includes *****/ + +#include +#include "icm20602.h" + +/***** Defines *****/ + +#define REG_XG_OFFS_TC_H 0x04 +#define REG_XG_OFFS_TC_L 0x05 +#define REG_YG_OFFS_TC_H 0x07 +#define REG_YG_OFFS_TC_L 0x08 +#define REG_ZG_OFFS_TC_H 0x0A +#define REG_ZG_OFFS_TC_L 0x0B +#define REG_SELF_TEST_X_ACCEL 0x0D +#define REG_SELF_TEST_Y_ACCEL 0x0E +#define REG_SELF_TEST_Z_ACCEL 0x0F +#define REG_XG_OFFS_USRH 0x13 +#define REG_XG_OFFS_USRL 0x14 +#define REG_YG_OFFS_USRH 0x15 +#define REG_YG_OFFS_USRL 0x16 +#define REG_ZG_OFFS_USRH 0x17 +#define REG_ZG_OFFS_USRL 0x18 +#define REG_SMPLRT_DIV 0x19 +#define REG_CONFIG 0x1A +#define REG_GYRO_CONFIG 0x1B +#define REG_ACCEL_CONFIG 0x1C +#define REG_ACCEL_CONFIG_2 0x1D +#define REG_LP_MODE_CFG 0x1E +#define REG_ACCEL_WOM_X_THR 0x20 +#define REG_ACCEL_WOM_Y_THR 0x21 +#define REG_ACCEL_WOM_Z_THR 0x22 +#define REG_FIFO_EN 0x23 +#define REG_FSYNC_INT 0x36 +#define REG_INT_PIN_CFG 0x37 +#define REG_INT_ENABLE 0x38 +#define REG_FIFO_WM_INT_STATUS 0x39 +#define REG_INT_STATUS 0x3A +#define REG_ACCEL_XOUT_H 0x3B +#define REG_ACCEL_XOUT_L 0x3C +#define REG_ACCEL_YOUT_H 0x3D +#define REG_ACCEL_YOUT_L 0x3E +#define REG_ACCEL_ZOUT_H 0x3F +#define REG_ACCEL_ZOUT_L 0x40 +#define REG_TEMP_OUT_H 0x41 +#define REG_TEMP_OUT_L 0x42 +#define REG_GYRO_XOUT_H 0x43 +#define REG_GYRO_XOUT_L 0x44 +#define REG_GYRO_YOUT_H 0x45 +#define REG_GYRO_YOUT_L 0x46 +#define REG_GYRO_ZOUT_H 0x47 +#define REG_GYRO_ZOUT_L 0x48 +#define REG_SELF_TEST_X_GYRO 0x50 +#define REG_SELF_TEST_Y_GYRO 0x51 +#define REG_SELF_TEST_Z_GYRO 0x52 +#define REG_FIFO_WM_TH1 0x60 +#define REG_FIFO_WM_TH2 0x61 +#define REG_SIGNAL_PATH_RESET 0x68 +#define REG_ACCEL_INTEL_CTRL 0x69 +#define REG_USER_CTRL 0x6A +#define REG_PWR_MGMT_1 0x6B +#define REG_PWR_MGMT_2 0x6C +#define REG_I2C_IF 0x70 +#define REG_FIFO_COUNTH 0x72 +#define REG_FIFO_COUNTL 0x73 +#define REG_FIFO_R_W 0x74 +#define REG_WHO_AM_I 0x75 +#define REG_XA_OFFSET_H 0x77 +#define REG_XA_OFFSET_L 0x78 +#define REG_YA_OFFSET_H 0x7A +#define REG_YA_OFFSET_L 0x7B +#define REG_ZA_OFFSET_H 0x7D +#define REG_ZA_OFFSET_L 0x7E + +#define REG_WHO_AM_I_CONST 0X12 + +/***** Macros *****/ + +#define ON_ERROR_GOTO(cond, symbol) \ + if (!(cond)) { goto symbol; } + +// extra steps, but I'm paranoid about some compilers/systems not handling the +// conversion from uint8_t to int16_t correctly +#define UINT8_TO_INT16(dst, src_high, src_low) \ + do { \ + dst = (src_high); \ + dst <<= 8; \ + dst |= (src_low); \ + } while (0); + +/***** Local Data *****/ + +// TODO: Look into getting real temp sensitivity. +static float _temp_sensitivity = 326.8; + +/***** Local Functions *****/ + +/// Used to convert raw accelerometer readings to G-force. +float +_get_accel_sensitivity(enum icm20602_accel_g accel_g) +{ + float f = 0.0; + + switch (accel_g) { + case (ICM20602_ACCEL_RANGE_2G): + f = 16384.0; + break; + case (ICM20602_ACCEL_RANGE_4G): + f = 8192.0; + break; + case (ICM20602_ACCEL_RANGE_8G): + f = 4096.0; + break; + case (ICM20602_ACCEL_RANGE_16G): + f = 2048.0; + break; + } + + return f; +} + +/// Used to convert raw gyroscope readings to degrees per second. +float +_get_gyro_sensitivity(enum icm20602_gyro_dps gyro_dps) +{ + float f = 0; + + switch (gyro_dps) { + case (ICM20602_GYRO_RANGE_250_DPS): + f = 131.0; + break; + case (ICM20602_GYRO_RANGE_500_DPS): + f = 65.5; + break; + case (ICM20602_GYRO_RANGE_1000_DPS): + f = 32.8; + break; + case (ICM20602_GYRO_RANGE_2000_DPS): + f = 16.4; + break; + } + + return f; +} + +int8_t +_read_data(struct icm20602_dev * dev, uint8_t reg, uint8_t * buf, uint32_t len) +{ + int8_t r = 0; + + if ((!dev->hal_wr) || (!dev->hal_rd) || (!dev->hal_sleep)) { + return false; + } + + if (dev->mutex_lock) { + dev->mutex_lock(dev->id); + } + + r = dev->hal_rd(dev->id, reg, buf, len); + + if (dev->mutex_unlock) { + dev->mutex_unlock(dev->id); + } + + return r; +} + +/***** Global Functions *****/ + +int8_t +icm20602_init(struct icm20602_dev * dev) +{ + uint8_t tmp = 0; + int8_t r = 0; + + if ((!dev->hal_wr) || (!dev->hal_rd) || (!dev->hal_sleep)) { + return false; + } + + // General Procedure: + // 1. reset chip + // 2. set clock for PLL for optimum performance as documented in datasheet + // 3. place accelerometer and gyroscope into standby + // 4. disable fifo + // 5. configure chip + // 6. enable accelerometer and gyroscope + + if (dev->mutex_lock) { + dev->mutex_lock(dev->id); + } + + // full reset of chip + tmp = 0x80; + r = dev->hal_wr(dev->id, REG_PWR_MGMT_1, &tmp, 1); + ON_ERROR_GOTO((0 == r), return_err); + + // TODO: better reset delay value + dev->hal_sleep(1000); + + // verify we are able to read from the chip + r = dev->hal_rd(dev->id, REG_WHO_AM_I, &tmp, 1); + ON_ERROR_GOTO((0 == r), return_err); + if (REG_WHO_AM_I_CONST != tmp) { + r = -1; + ON_ERROR_GOTO((0 == r), return_err); + } + + // set clock to internal PLL + tmp = 0x01; + r = dev->hal_wr(dev->id, REG_PWR_MGMT_1, &tmp, 1); + ON_ERROR_GOTO((0 == r), return_err); + + // place accel and gyro on standby + tmp = 0x3F; + r = dev->hal_wr(dev->id, REG_PWR_MGMT_2, &tmp, 1); + ON_ERROR_GOTO((0 == r), return_err); + + // disable fifo + tmp = 0x00; + r = dev->hal_wr(dev->id, REG_USER_CTRL, &tmp, 1); + ON_ERROR_GOTO((0 == r), return_err); + + if (dev->i2c_disable) { + // disable chip I2C communications + tmp = 0x40; + r = dev->hal_wr(dev->id, REG_I2C_IF, &tmp, 1); + ON_ERROR_GOTO((0 == r), return_err); + } + + if (dev->use_accel) { + if (ICM20602_ACCEL_DLPF_BYPASS_1046_HZ == dev->accel_dlpf) { + tmp = (1 << 3); + r = dev->hal_wr(dev->id, REG_ACCEL_CONFIG_2, &tmp, 1); + ON_ERROR_GOTO((0 == r), return_err); + } + else { + tmp = dev->accel_dlpf; + r = dev->hal_wr(dev->id, REG_ACCEL_CONFIG_2, &tmp, 1); + ON_ERROR_GOTO((0 == r), return_err); + } + + tmp = (dev->accel_g) << 2; + r = dev->hal_wr(dev->id, REG_ACCEL_CONFIG, &tmp, 1); + ON_ERROR_GOTO((0 == r), return_err); + } + + if (dev->use_gyro) { + if (ICM20602_GYRO_DLPF_BYPASS_3281_HZ == dev->gyro_dlpf) { + // bypass dpf and set dps + tmp = 0x00; + r = dev->hal_wr(dev->id, REG_CONFIG, &tmp, 1); + ON_ERROR_GOTO((0 == r), return_err); + + tmp = (dev->gyro_dps << 3) | 0x02; // see table page 37 of datasheet + r = dev->hal_wr(dev->id, REG_GYRO_CONFIG, &tmp, 1); + ON_ERROR_GOTO((0 == r), return_err); + } + else if (ICM20602_GYRO_DLPF_BYPASS_8173_HZ == dev->gyro_dlpf) { + // bypass dpf and set dps + tmp = 0x00; + r = dev->hal_wr(dev->id, REG_CONFIG, &tmp, 1); + ON_ERROR_GOTO((0 == r), return_err); + + tmp = (dev->gyro_dps << 3) | 0x01; // see table page 37 of datasheet + r = dev->hal_wr(dev->id, REG_GYRO_CONFIG, &tmp, 1); + ON_ERROR_GOTO((0 == r), return_err); + } + else { + // configure dpf and set dps + tmp = dev->gyro_dlpf; + r = dev->hal_wr(dev->id, REG_CONFIG, &tmp, 1); + ON_ERROR_GOTO((0 == r), return_err); + + tmp = dev->gyro_dps << 3; + r = dev->hal_wr(dev->id, REG_GYRO_CONFIG, &tmp, 1); + ON_ERROR_GOTO((0 == r), return_err); + } + } + + // enable FIFO if requested + tmp = ((dev->use_accel) && (dev->accel_fifo)) ? 0x08 : 0x00; + tmp |= ((dev->use_gyro) && (dev->gyro_fifo)) ? 0x10 : 0x00; + r = dev->hal_wr(dev->id, REG_FIFO_EN, &tmp, 1); + ON_ERROR_GOTO((0 == r), return_err); + + // configure sample rate divider (TODO: is this gyro only?) + // note: SAMPLE_RATE = INTERNAL_SAMPLE_RATE / (1 + SMPLRT_DIV) + tmp = (0 != dev->sample_rate_div) ? dev->sample_rate_div - 1 : 1; + r = dev->hal_wr(dev->id, REG_SMPLRT_DIV, &tmp, 1); + ON_ERROR_GOTO((0 == r), return_err); + + tmp = 0; + tmp |= (dev->use_gyro) ? 0 : 0x07; // 0 - on, 1 - disabled + tmp |= (dev->use_accel) ? 0 : 0x38; // 0 - on, 1 - disabled + r = dev->hal_wr(dev->id, REG_PWR_MGMT_2, &tmp, 1); + ON_ERROR_GOTO((0 == r), return_err); + +return_err: + + if (dev->mutex_unlock) { + dev->mutex_unlock(dev->id); + } + + return r; +} + +int8_t +icm20602_read_accel(struct icm20602_dev * dev, float * p_x, float * p_y, + float * p_z) +{ + float accel_sensitivity; + int16_t x, y, z; + int8_t r = 0; + + accel_sensitivity = _get_accel_sensitivity(dev->accel_g); + + r = icm20602_read_accel_raw(dev, &x, &y, &z); + if (0 == r) { + *p_x = ((float) x) / accel_sensitivity; + *p_y = ((float) y) / accel_sensitivity; + *p_z = ((float) z) / accel_sensitivity; + } + + return r; +} + +int8_t +icm20602_read_gyro(struct icm20602_dev * dev, float * p_x, float * p_y, + float * p_z) +{ + float gyro_sensitivity; + int16_t x, y, z; + int8_t r = 0; + + gyro_sensitivity = _get_gyro_sensitivity(dev->gyro_dps); + + r = icm20602_read_gyro_raw(dev, &x, &y, &z); + if (0 == r) { + *p_x = ((float) x) / gyro_sensitivity; + *p_y = ((float) y) / gyro_sensitivity; + *p_z = ((float) z) / gyro_sensitivity; + } + + return r; +} + +int8_t +icm20602_read_data(struct icm20602_dev * dev, float * p_ax, float * p_ay, + float * p_az, float * p_gx, float * p_gy, float * p_gz, float * p_t) +{ + float accel_sensitivity; + float gyro_sensitivity; + int16_t ax, ay, az, gx, gy, gz, t; + int8_t r = 0; + + accel_sensitivity = _get_accel_sensitivity(dev->accel_g); + gyro_sensitivity = _get_gyro_sensitivity(dev->gyro_dps); + + r = icm20602_read_data_raw(dev, &ax, &ay, &az, &gx, &gy, &gz, &t); + if (0 == r) { + *p_ax = ((float) ax) / accel_sensitivity; + *p_ay = ((float) ay) / accel_sensitivity; + *p_az = ((float) az) / accel_sensitivity; + *p_gx = ((float) gx) / gyro_sensitivity; + *p_gy = ((float) gy) / gyro_sensitivity; + *p_gz = ((float) gz) / gyro_sensitivity; + *p_t = ((float) t) / _temp_sensitivity; + } + + return r; +} + +int8_t +icm20602_read_accel_raw(struct icm20602_dev * dev, int16_t * p_x, int16_t * p_y, + int16_t * p_z) +{ + uint8_t buf[8] = {0}; + int8_t r = 0; + + r = _read_data(dev, REG_ACCEL_XOUT_H, buf, 8); + if (0 == r) { + UINT8_TO_INT16(*p_x, buf[0], buf[1]); + UINT8_TO_INT16(*p_y, buf[2], buf[3]); + UINT8_TO_INT16(*p_z, buf[4], buf[5]); + // buf[6] and buf[7] hold temperature + } + + return r; +} + +int8_t +icm20602_read_gyro_raw(struct icm20602_dev * dev, int16_t * p_x, int16_t * p_y, + int16_t * p_z) +{ + uint8_t buf[6] = {0}; + int8_t r = 0; + + r = _read_data(dev, REG_GYRO_XOUT_H, buf, 6); + if (0 == r) { + UINT8_TO_INT16(*p_x, buf[0], buf[1]); + UINT8_TO_INT16(*p_y, buf[2], buf[3]); + UINT8_TO_INT16(*p_z, buf[4], buf[5]); + } + + return r; +} + +int8_t +icm20602_read_data_raw(struct icm20602_dev * dev, int16_t * p_ax, + int16_t * p_ay, int16_t * p_az, int16_t * p_gx, int16_t * p_gy, + int16_t * p_gz, int16_t * p_t) +{ + uint8_t buf[14] = {0}; + int8_t r = 0; + + r = _read_data(dev, REG_ACCEL_XOUT_H, buf, 14); + if (0 == r) { + UINT8_TO_INT16(*p_ax, buf[0], buf[1]); + UINT8_TO_INT16(*p_ay, buf[2], buf[3]); + UINT8_TO_INT16(*p_az, buf[4], buf[5]); + UINT8_TO_INT16(*p_t, buf[6], buf[7]); + UINT8_TO_INT16(*p_gx, buf[8], buf[9]); + UINT8_TO_INT16(*p_gy, buf[10], buf[11]); + UINT8_TO_INT16(*p_gz, buf[12], buf[13]); + } + + return r; +} + +int8_t +icm20602_read_accel_fifo(struct icm20602_dev * dev, float * p_x, float * p_y, + float * p_z) +{ + float accel_sensitivity; + int16_t x, y, z; + int8_t r = 0; + + accel_sensitivity = _get_accel_sensitivity(dev->accel_g); + + r = icm20602_read_fifo_accel_raw(dev, &x, &y, &z); + if (0 == r) { + *p_x = ((float) x) / accel_sensitivity; + *p_y = ((float) y) / accel_sensitivity; + *p_z = ((float) z) / accel_sensitivity; + } + + return r; +} + +int8_t +icm20602_read_gyro_fifo(struct icm20602_dev * dev, float * p_x, float * p_y, + float * p_z) +{ + float gyro_sensitivity; + int16_t x, y, z; + int8_t r = 0; + + gyro_sensitivity = _get_gyro_sensitivity(dev->gyro_dps); + + r = icm20602_read_fifo_gyro_raw(dev, &x, &y, &z); + if (0 == r) { + *p_x = ((float) x) / gyro_sensitivity; + *p_y = ((float) y) / gyro_sensitivity; + *p_z = ((float) z) / gyro_sensitivity; + } + + return r; +} + +int8_t +icm20602_read_fifo_data(struct icm20602_dev * dev, float * p_ax, float * p_ay, + float * p_az, float * p_gx, float * p_gy, float * p_gz, float * p_t) +{ + float accel_sensitivity; + float gyro_sensitivity; + int16_t ax, ay, az, gx, gy, gz, t; + int8_t r = 0; + + accel_sensitivity = _get_accel_sensitivity(dev->accel_g); + gyro_sensitivity = _get_gyro_sensitivity(dev->gyro_dps); + + r = icm20602_read_fifo_data_raw(dev, &ax, &ay, &az, &gx, &gy, &gz, &t); + if (0 == r) { + *p_ax = ((float) ax) / accel_sensitivity; + *p_ay = ((float) ay) / accel_sensitivity; + *p_az = ((float) az) / accel_sensitivity; + *p_gx = ((float) gx) / gyro_sensitivity; + *p_gy = ((float) gy) / gyro_sensitivity; + *p_gz = ((float) gz) / gyro_sensitivity; + *p_t = ((float) t) / _temp_sensitivity; + } + + return r; +} + +int8_t +icm20602_read_fifo_accel_raw(struct icm20602_dev * dev, int16_t * p_x, + int16_t * p_y, int16_t * p_z) +{ + uint8_t buf[6] = {0}; + int8_t r = 0; + + r = _read_data(dev, REG_FIFO_R_W, buf, 6); + if (0 == r) { + UINT8_TO_INT16(*p_x, buf[0], buf[1]); + UINT8_TO_INT16(*p_y, buf[2], buf[3]); + UINT8_TO_INT16(*p_z, buf[4], buf[5]); + } + + return r; +} + +int8_t +icm20602_read_fifo_gyro_raw(struct icm20602_dev * dev, int16_t * p_x, + int16_t * p_y, int16_t * p_z) +{ + uint8_t buf[6] = {0}; + int8_t r = 0; + + r = _read_data(dev, REG_FIFO_R_W, buf, 6); + if (0 == r) { + UINT8_TO_INT16(*p_x, buf[0], buf[1]); + UINT8_TO_INT16(*p_y, buf[2], buf[3]); + UINT8_TO_INT16(*p_z, buf[4], buf[5]); + } + + return r; +} + +int8_t +icm20602_read_fifo_data_raw(struct icm20602_dev * dev, int16_t * p_ax, + int16_t * p_ay, int16_t * p_az, int16_t * p_gx, int16_t * p_gy, + int16_t * p_gz, int16_t * p_t) +{ + uint8_t buf[14] = {0}; + int8_t r = 0; + + r = _read_data(dev, REG_FIFO_R_W, buf, 14); + if (0 == r) { + UINT8_TO_INT16(*p_ax, buf[0], buf[1]); + UINT8_TO_INT16(*p_ay, buf[2], buf[3]); + UINT8_TO_INT16(*p_az, buf[4], buf[5]); + UINT8_TO_INT16(*p_t, buf[6], buf[7]); + UINT8_TO_INT16(*p_gx, buf[8], buf[9]); + UINT8_TO_INT16(*p_gy, buf[10], buf[11]); + UINT8_TO_INT16(*p_gz, buf[12], buf[13]); + } + + return r; +}