Use bits from BSides repo

This commit is contained in:
Paul Warren 2023-11-20 17:46:11 +11:00
parent 278055f585
commit 8f1a99fbc1
20 changed files with 4344 additions and 0 deletions

231
include/BSidesMessaging.h Normal file
View File

@ -0,0 +1,231 @@
//
// BSides Badge Serial Bridge Message Format
//
#ifndef __SERIALBRIDGE_MESSAGES_H
#define __SERIALBRIDGE_MESSAGES_H
#include <stdint.h>
#include <stdlib.h>
#include <stdbool.h>
#include <CircularBuffer.h>
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<SerialMessage,SERIALBRIDGE_MESSAGE_QUEUE_MAX_SIZE> 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

41
include/BadgeLog.h Normal file
View File

@ -0,0 +1,41 @@
#ifndef _BADGE_LOG_H_
#define _BADGE_LOG_H_
#include <stdbool.h>
/* 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_

54
include/SerialBridge.h Normal file
View File

@ -0,0 +1,54 @@
#ifndef _SERIAL_BRIDGE_2020_
#define _SERIAL_BRIDGE_2020_
#include <stdint.h>
#include <stddef.h>
#include <stdbool.h>
#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_

25
include/badge_pins.h Normal file
View File

@ -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)

344
include/icm20602.h Normal file
View File

@ -0,0 +1,344 @@
#ifndef _ICM20602_H
#define _ICM20602_H
/***** Includes *****/
#include <stdint.h>
#include <stdbool.h>
/***** 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

1247
lib/crc32/Crc32.cpp Normal file

File diff suppressed because it is too large Load Diff

69
lib/crc32/Crc32.h Normal file
View File

@ -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 <stdint.h>
// size_t
#include <cstddef>
// 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

546
lib/crc32/Crc32.ino Normal file
View File

@ -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)");
}

142
lib/crc32/Crc32Best.ino Normal file
View File

@ -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);
}

170
lib/crc32/Crc32Test.cpp Normal file
View File

@ -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 <cstdlib>
#include <cstdio>
// 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 <windows.h>
#else
#include <ctime>
#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;
}

View File

@ -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 <cstdlib>
#include <cstdio>
#include <vector>
#include <string>
// C++11 multithreading
#include <thread>
#include <future>
// //////////////////////////////////////////////////////////
// test code
/// one gigabyte
const size_t NumBytes = 1024*1024*1024;
#if defined(_WIN32) || defined(_WIN64)
#include <windows.h>
#else
#include <ctime>
#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<std::future<uint32_t>> 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;
}

10
lib/crc32/LICENSE Normal file
View File

@ -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.

26
lib/crc32/Makefile Normal file
View File

@ -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)

38
lib/crc32/changelog.md Normal file
View File

@ -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

43
lib/crc32/crc32.js Normal file
View File

@ -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);
}

25
lib/crc32/readme.md Normal file
View File

@ -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.

98
src/BSidesMessaging.cpp Normal file
View File

@ -0,0 +1,98 @@
#include "BSidesMessaging.h"
#include <string.h>
#include <Crc32.h>
// 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";
}
}

231
src/BadgeLog.cpp Normal file
View File

@ -0,0 +1,231 @@
#include <cstdarg>
#include <cstdbool>
#include <cstddef>
#include <cstdio>
#include <cstring>
#include <Arduino.h>
#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
}
}

252
src/SerialBridge.cpp Normal file
View File

@ -0,0 +1,252 @@
#include <cstdbool>
#include <cstddef>
#include <cstdint>
#ifdef ARDUINO_SAMD_MKRZERO
#ifndef SAMD21
#define SAMD21
#endif
#endif // ARDUINO_SAMD_MKRZERO
#ifdef ESP32
#define HAS_BRIDGELINK
#define BRIDGELINK_NEEDS_FLUSH true
#include <HardwareSerial.h>
#endif
#ifdef SAMD21
#define HAS_BRIDGELINK
#define BRIDGELINK_NEEDS_FLUSH
#include <Arduino.h>
#include "wiring_private.h" // pinPeripheral() function
#endif
#ifdef __unix__
#include <SoftwareSerial.h>
#include <sys/types.h>
#endif
#include <BadgeLog.h>
#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;
}

549
src/icm20602.c Normal file
View File

@ -0,0 +1,549 @@
/***** Includes *****/
#include <stdlib.h>
#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;
}