From ccb790f53247532726135a73f622f874346610ad Mon Sep 17 00:00:00 2001 From: rusefillc <48498823+rusefillc@users.noreply.github.com> Date: Wed, 29 Jun 2022 04:29:40 -0400 Subject: [PATCH] Steal tunerstudio files from RusEFI (#71) * Steal tunerstudio files from RusEFI (cherry picked from commit dcba04fbd31700f5ca4ef4f12a6e220c5713c7d0) * Steal crc32 files from RusEFI (cherry picked from commit bfe88b5297c6fc90c8e647e4144c91edafef25f9) * fix TS steal (cherry picked from commit a77b9761da4c185359bb2d7e10abd6a8e69c740d) * fix crc32 (cherry picked from commit cdb4df09f69c2494316c2b12f97dbe19f6bdb598) * TS stealed from RE (cherry picked from commit ff470e134036372425da44e9e0fb98737f31c9e9) * Steal TS (cherry picked from commit d11406edc2d6b3c1567ce800e207038745a162e7) * Steal Thread Controller (cherry picked from commit 2aa5bbd57150e0d5b51e2e88752bdc8697698861) * Update TunerStudio protocol files (cherry picked from commit 58f14216ec6e7fc4408e52ccc28a4f912e340b05) * byteswap.h (cherry picked from commit 581d647fd49890af4628f0ff5b51e9f193efcac4) * bugfix * one more file to compile, another file not ready - removing from this PR * removing more from this PR Co-authored-by: Andrey Gusakov Co-authored-by: rusefillc --- firmware/Makefile | 13 +- firmware/console/binary/tunerstudio_impl.h | 41 ++++ firmware/console/binary/tunerstudio_io.cpp | 121 ++++++++++ firmware/console/binary/tunerstudio_io.h | 209 ++++++++++++++++++ .../console/binary/tunerstudio_io_serial.cpp | 61 +++++ firmware/util/byteswap.h | 14 ++ firmware/util/math/crc.c | 94 ++++++++ firmware/util/math/crc.h | 22 ++ 8 files changed, 573 insertions(+), 2 deletions(-) create mode 100644 firmware/console/binary/tunerstudio_impl.h create mode 100644 firmware/console/binary/tunerstudio_io.cpp create mode 100644 firmware/console/binary/tunerstudio_io.h create mode 100644 firmware/console/binary/tunerstudio_io_serial.cpp create mode 100644 firmware/util/byteswap.h create mode 100644 firmware/util/math/crc.c create mode 100644 firmware/util/math/crc.h diff --git a/firmware/Makefile b/firmware/Makefile index d62d632..aacde13 100644 --- a/firmware/Makefile +++ b/firmware/Makefile @@ -125,7 +125,8 @@ LDSCRIPT=app.ld # C sources that can be compiled in ARM or THUMB mode depending on the global # setting. -CSRC = $(ALLCSRC) $(BOARDDIR)/board.c +CSRC = $(ALLCSRC) $(BOARDDIR)/board.c \ + util/math/crc.c # C++ sources that can be compiled in ARM or THUMB mode depending on the global # setting. @@ -145,6 +146,8 @@ CPPSRC = $(ALLCPPSRC) \ pump_control.cpp \ uart.cpp \ interpolation.cpp \ + console/binary/tunerstudio_io_serial.cpp \ + console/binary/tunerstudio_io.cpp \ main.cpp # List ASM source files here. @@ -154,7 +157,13 @@ ASMSRC = $(ALLASMSRC) ASMXSRC = $(ALLXASMSRC) # Inclusion directories. -INCDIR = $(CONFDIR) $(ALLINC) boards/ $(BOARDDIR)/io/ +INCDIR = $(CONFDIR) \ + $(ALLINC) \ + util/ \ + util/math/ \ + console/binary/ \ + boards/ \ + $(BOARDDIR)/io/ # Define C warning options here. CWARN = -Wall -Wextra -Wundef -Wstrict-prototypes diff --git a/firmware/console/binary/tunerstudio_impl.h b/firmware/console/binary/tunerstudio_impl.h new file mode 100644 index 0000000..76ee0bf --- /dev/null +++ b/firmware/console/binary/tunerstudio_impl.h @@ -0,0 +1,41 @@ +/** + * @file tunerstudio_impl.h + */ + +#pragma once + +#include +#include + +struct TsChannelBase; + +typedef enum { + TS_PLAIN = 0, + TS_CRC = 1 +} ts_response_format_e; + +class TunerStudioBase { +public: + +protected: + virtual void cmdOutputChannels(TsChannelBase* tsChannel, uint16_t offset, uint16_t count) = 0; +}; + +class TunerStudio : public TunerStudioBase { +public: + int handleCrcCommand(TsChannelBase* tsChannel, char *data, int incomingPacketSize); + bool handlePlainCommand(TsChannelBase* tsChannel, uint8_t command); + + void cmdOutputChannels(TsChannelBase* tsChannel, uint16_t offset, uint16_t count) override; + void handleQueryCommand(TsChannelBase* tsChannel, ts_response_format_e mode); + void handleExecuteCommand(TsChannelBase* tsChannel, char *data, int incomingPacketSize); + void handlePageSelectCommand(TsChannelBase *tsChannel, ts_response_format_e mode); + void handleWriteChunkCommand(TsChannelBase* tsChannel, ts_response_format_e mode, uint16_t offset, uint16_t count, + void *content); + void handleCrc32Check(TsChannelBase *tsChannel, ts_response_format_e mode, uint16_t offset, uint16_t count); + void handleWriteValueCommand(TsChannelBase* tsChannel, ts_response_format_e mode, uint16_t offset, uint8_t value); + void handlePageReadCommand(TsChannelBase* tsChannel, ts_response_format_e mode, uint16_t offset, uint16_t count); + +private: + void sendErrorCode(TsChannelBase* tsChannel, uint8_t code); +}; diff --git a/firmware/console/binary/tunerstudio_io.cpp b/firmware/console/binary/tunerstudio_io.cpp new file mode 100644 index 0000000..cbc9e43 --- /dev/null +++ b/firmware/console/binary/tunerstudio_io.cpp @@ -0,0 +1,121 @@ +/** + * @file tunerstudio_io.cpp + * + * @date Mar 8, 2015 + * @author Andrey Belomutskiy, (c) 2012-2020 + */ + +/* memcpy */ +#include + +#include "tunerstudio_io.h" +#include "crc.h" +#include "byteswap.h" + +size_t TsChannelBase::read(uint8_t* buffer, size_t size) { + return readTimeout(buffer, size, SR5_READ_TIMEOUT); +} + +#define isBigPacket(size) ((size) > BLOCKING_FACTOR + 7) + +void TsChannelBase::copyAndWriteSmallCrcPacket(uint8_t responseCode, const uint8_t* buf, size_t size) { + auto scratchBuffer = this->scratchBuffer; + + // don't transmit too large a buffer + chDbgAssert(!isBigPacket(size), "copyAndWriteSmallCrcPacket tried to transmit too large a packet"); + + // If transmitting data, copy it in to place in the scratch buffer + // We want to prevent the data changing itself (higher priority threads could write + // tsOutputChannels) during the CRC computation. Instead compute the CRC on our + // local buffer that nobody else will write. + if (size) { + memcpy(scratchBuffer + 3, buf, size); + } + + crcAndWriteBuffer(responseCode, size); +} + +void TsChannelBase::crcAndWriteBuffer(uint8_t responseCode, size_t size) { + chDbgAssert(!isBigPacket(size), "crcAndWriteBuffer tried to transmit too large a packet"); + + auto scratchBuffer = this->scratchBuffer; + // Index 0/1 = packet size (big endian) + *(uint16_t*)scratchBuffer = SWAP_UINT16(size + 1); + // Index 2 = response code + scratchBuffer[2] = responseCode; + + // CRC is computed on the responseCode and payload but not length + uint32_t crc = crc32(&scratchBuffer[2], size + 1); // command part of CRC + + // Place the CRC at the end + *reinterpret_cast(&scratchBuffer[size + 3]) = SWAP_UINT32(crc); + + // Write to the underlying stream + write(reinterpret_cast(scratchBuffer), size + 7, true); + flush(); +} + +void TsChannelBase::writeCrcPacketLarge(uint8_t responseCode, const uint8_t* buf, size_t size) { + uint8_t headerBuffer[3]; + uint8_t crcBuffer[4]; + + *(uint16_t*)headerBuffer = SWAP_UINT16(size + 1); + *(uint8_t*)(headerBuffer + 2) = responseCode; + + // Command part of CRC + uint32_t crc = crc32((void*)(headerBuffer + 2), 1); + // Data part of CRC + crc = crc32inc((void*)buf, crc, size); + *(uint32_t*)crcBuffer = SWAP_UINT32(crc); + + // Write header + write(headerBuffer, sizeof(headerBuffer), false); + + // If data, write that + if (size) { + write(buf, size, false); + } + + // Lastly the CRC footer + write(crcBuffer, sizeof(crcBuffer), true); + flush(); +} + +TsChannelBase::TsChannelBase(const char *name) { + this->name = name; +} + +void TsChannelBase::assertPacketSize(size_t size, bool allowLongPackets) { + chDbgAssert(!(isBigPacket(size) && !allowLongPackets), "tried to send disallowed long packet"); +} + +/** + * Adds size to the beginning of a packet and a crc32 at the end. Then send the packet. + */ +void TsChannelBase::writeCrcPacket(uint8_t responseCode, const uint8_t* buf, size_t size, bool allowLongPackets) { + // don't transmit a null buffer... + if (!buf) { + size = 0; + } + + assertPacketSize(size, allowLongPackets); + + if (isBigPacket(size)) { + // for larger packets we do not use a buffer for CRC calculation meaning data is now allowed to modify while pending + writeCrcPacketLarge(responseCode, buf, size); + } else { + // for small packets we use a buffer for CRC calculation + copyAndWriteSmallCrcPacket(responseCode, buf, size); + } +} + +void TsChannelBase::sendResponse(ts_response_format_e mode, const uint8_t * buffer, int size, bool allowLongPackets /* = false */) { + if (mode == TS_CRC) { + writeCrcPacket(TS_RESPONSE_OK, buffer, size, allowLongPackets); + } else { + if (size > 0) { + write(buffer, size, true); + flush(); + } + } +} diff --git a/firmware/console/binary/tunerstudio_io.h b/firmware/console/binary/tunerstudio_io.h new file mode 100644 index 0000000..bc4738e --- /dev/null +++ b/firmware/console/binary/tunerstudio_io.h @@ -0,0 +1,209 @@ +/** + * @file tunerstudio_io.h + * @file TS protocol commands and methods are here + * + * @date Mar 8, 2015 + * @author Andrey Belomutskiy, (c) 2012-2020 + */ + +#pragma once + +/* to get ChibiOS hal config options */ +#include "hal.h" + +#include "tunerstudio_impl.h" + +/* TODO: find better place */ +#define BLOCKING_FACTOR 256 + +/* TODO: From autogenerated, rework! */ +#define TS_BURN_COMMAND 'B' +#define TS_BURN_COMMAND_char B +#define TS_CHUNK_WRITE_COMMAND 'C' +#define TS_CHUNK_WRITE_COMMAND_char C +#define ts_command_e_TS_BENCH_CATEGORY 22 +#define ts_command_e_TS_CLEAR_WARNINGS 17 +#define ts_command_e_TS_COMMAND_1 1 +#define ts_command_e_TS_COMMAND_11 11 +#define ts_command_e_TS_COMMAND_12 12 +#define ts_command_e_TS_COMMAND_13 13 +#define ts_command_e_TS_COMMAND_14 14 +#define ts_command_e_TS_COMMAND_15 15 +#define ts_command_e_TS_COMMAND_16 16 +#define ts_command_e_TS_COMMAND_4 4 +#define ts_command_e_TS_COMMAND_5 5 +#define ts_command_e_TS_COMMAND_9 9 +#define ts_command_e_TS_CRAZY 32 +#define ts_command_e_TS_DEBUG_MODE 0 +#define ts_command_e_TS_GRAB_PEDAL_UP 6 +#define ts_command_e_TS_GRAB_PEDAL_WOT 7 +#define ts_command_e_TS_GRAB_TPS_CLOSED 2 +#define ts_command_e_TS_GRAB_TPS_WOT 3 +#define ts_command_e_TS_IGNITION_CATEGORY 18 +#define ts_command_e_TS_INJECTOR_CATEGORY 19 +#define ts_command_e_TS_RESET_TLE8888 8 +#define ts_command_e_TS_UNUSED_23 23 +#define ts_command_e_TS_UNUSED_25 25 +#define ts_command_e_TS_UNUSED_26 26 +#define ts_command_e_TS_UNUSED_27 27 +#define ts_command_e_TS_UNUSED_28 28 +#define ts_command_e_TS_UNUSED_29 29 +#define ts_command_e_TS_UNUSED_30 30 +#define ts_command_e_TS_UNUSED_31 31 +#define ts_command_e_TS_UNUSED_CJ125_CALIB 24 +#define ts_command_e_TS_WIDEBAND 21 +#define ts_command_e_TS_WRITE_FLASH 10 +#define ts_command_e_TS_X14 20 +#define TS_COMMAND_F 'F' +#define TS_COMMAND_F_char F +#define TS_COMPOSITE_DISABLE 2 +#define TS_COMPOSITE_ENABLE 1 +#define TS_CRC_CHECK_COMMAND 'k' +#define TS_CRC_CHECK_COMMAND_char k +#define TS_EXECUTE 'E' +#define TS_EXECUTE_char E +#define TS_FILE_VERSION 20210312 +#define TS_GET_COMPOSITE_BUFFER_DONE_DIFFERENTLY '8' +#define TS_GET_COMPOSITE_BUFFER_DONE_DIFFERENTLY_char 8 +#define TS_GET_CONFIG_ERROR 'e' +#define TS_GET_CONFIG_ERROR_char e +#define TS_GET_FIRMWARE_VERSION 'V' +#define TS_GET_FIRMWARE_VERSION_char V +#define TS_GET_LOGGER_GET_BUFFER 'L' +#define TS_GET_LOGGER_GET_BUFFER_char L +#define TS_GET_OUTPUTS_SIZE '4' +#define TS_GET_OUTPUTS_SIZE_char 4 +#define TS_GET_STRUCT '9' +#define TS_GET_STRUCT_char 9 +#define TS_GET_TEXT 'G' +#define TS_GET_TEXT_char G +#define TS_HELLO_COMMAND 'S' +#define TS_HELLO_COMMAND_char S +#define TS_IO_TEST_COMMAND 'Z' +#define TS_IO_TEST_COMMAND_char Z +#define TS_ONLINE_PROTOCOL 'z' +#define TS_ONLINE_PROTOCOL_char z +#define TS_OUTPUT_COMMAND 'O' +#define TS_OUTPUT_COMMAND_char O +#define TS_PAGE_COMMAND 'P' +#define TS_PAGE_COMMAND_char P +#define TS_PERF_TRACE_BEGIN '_' +#define TS_PERF_TRACE_BEGIN_char _ +#define TS_PERF_TRACE_GET_BUFFER 'b' +#define TS_PERF_TRACE_GET_BUFFER_char b +#define TS_PROTOCOL "001" +#define TS_QUERY_COMMAND 'Q' +#define TS_QUERY_COMMAND_char Q +#define TS_READ_COMMAND 'R' +#define TS_READ_COMMAND_char R +#define TS_RESPONSE_BURN_OK 4 +#define TS_RESPONSE_COMMAND_OK 7 +#define TS_RESPONSE_CRC_FAILURE 0x82 +#define TS_RESPONSE_FRAMING_ERROR 0x8D +#define TS_RESPONSE_OK 0 +#define TS_RESPONSE_OUT_OF_RANGE 0x84 +#define TS_RESPONSE_UNDERRUN 0x80 +#define TS_RESPONSE_UNRECOGNIZED_COMMAND 0x83 +#define TS_SET_LOGGER_SWITCH 'l' +#define TS_SET_LOGGER_SWITCH_char l +#define TS_SINGLE_WRITE_COMMAND 'W' +#define TS_SINGLE_WRITE_COMMAND_char W +#define TS_TEST_COMMAND 't' +#define TS_TEST_COMMAND_char t +#define TS_TOTAL_OUTPUT_SIZE 1016 + +class TsChannelBase { +public: + TsChannelBase(const char *name); + // Virtual functions - implement these for your underlying transport + virtual void write(const uint8_t* buffer, size_t size, bool isEndOfPacket = false) = 0; + virtual size_t readTimeout(uint8_t* buffer, size_t size, int timeout) = 0; + + // These functions are optional to implement, not all channels need them + virtual void flush() { } + virtual bool isConfigured() const { return true; } + virtual bool isReady() const { return true; } + virtual void stop() { } + + // Base functions that use the above virtual implementation + size_t read(uint8_t* buffer, size_t size); + +#ifdef EFI_CAN_SERIAL + virtual // CAN device needs this function to be virtual for small-packet optimization +#endif + void writeCrcPacket(uint8_t responseCode, const uint8_t* buf, size_t size, bool allowLongPackets = false); + void sendResponse(ts_response_format_e mode, const uint8_t * buffer, int size, bool allowLongPackets = false); + + /** + * See 'blockingFactor' in rusefi.ini + */ + char scratchBuffer[BLOCKING_FACTOR + 30]; + const char *name; + + void assertPacketSize(size_t size, bool allowLongPackets); + void crcAndWriteBuffer(uint8_t responseCode, size_t size); + void copyAndWriteSmallCrcPacket(uint8_t responseCode, const uint8_t* buf, size_t size); + +private: + void writeCrcPacketLarge(uint8_t responseCode, const uint8_t* buf, size_t size); +}; + +// This class represents a channel for a physical async serial poart +class SerialTsChannelBase : public TsChannelBase { +public: + SerialTsChannelBase(const char *name) : TsChannelBase(name) {}; + // Open the serial port with the specified baud rate + virtual void start(uint32_t baud) = 0; +}; + +#if HAL_USE_SERIAL +// This class implements a ChibiOS Serial Driver +class SerialTsChannel : public SerialTsChannelBase { +public: + SerialTsChannel(SerialDriver& driver) : SerialTsChannelBase("Serial"), m_driver(&driver) { } + + void start(uint32_t baud) override; + void stop() override; + + void write(const uint8_t* buffer, size_t size, bool isEndOfPacket) override; + size_t readTimeout(uint8_t* buffer, size_t size, int timeout) override; + +private: + SerialDriver* const m_driver; +}; +#endif // HAL_USE_SERIAL + +#if HAL_USE_UART +// This class implements a ChibiOS UART Driver +class UartTsChannel : public SerialTsChannelBase { +public: + UartTsChannel(UARTDriver& driver) : SerialTsChannelBase("UART"), m_driver(&driver) { } + + void start(uint32_t baud) override; + void stop() override; + + void write(const uint8_t* buffer, size_t size, bool isEndOfPacket) override; + size_t readTimeout(uint8_t* buffer, size_t size, int timeout) override; + +protected: + UARTDriver* const m_driver; + UARTConfig m_config; +}; +#endif // HAL_USE_UART + +#define CRC_VALUE_SIZE 4 +// todo: double-check this +#define CRC_WRAPPING_SIZE (CRC_VALUE_SIZE + 3) + +// that's 1 second +#define BINARY_IO_TIMEOUT TIME_MS2I(1000) + +// that's 1 second +#define SR5_READ_TIMEOUT TIME_MS2I(1000) + +void startSerialChannels(); +SerialTsChannelBase* getBluetoothChannel(); + +void startCanConsole(); + +void sendOkResponse(TsChannelBase *tsChannel, ts_response_format_e mode); diff --git a/firmware/console/binary/tunerstudio_io_serial.cpp b/firmware/console/binary/tunerstudio_io_serial.cpp new file mode 100644 index 0000000..777c3a6 --- /dev/null +++ b/firmware/console/binary/tunerstudio_io_serial.cpp @@ -0,0 +1,61 @@ +/** + * Implementation for hardware-serial TunerStudio ports + */ + +#include "tunerstudio_io.h" +#include "hal.h" + +#if HAL_USE_SERIAL +void SerialTsChannel::start(uint32_t baud) { + SerialConfig cfg = { + .speed = baud, + .cr1 = 0, + .cr2 = USART_CR2_STOP1_BITS | USART_CR2_LINEN, + .cr3 = 0 + }; + + sdStart(m_driver, &cfg); +} + +void SerialTsChannel::stop() { + sdStop(m_driver); +} + +void SerialTsChannel::write(const uint8_t* buffer, size_t size, bool) { + chnWriteTimeout(m_driver, buffer, size, BINARY_IO_TIMEOUT); +} + +size_t SerialTsChannel::readTimeout(uint8_t* buffer, size_t size, int timeout) { + return chnReadTimeout(m_driver, buffer, size, timeout); +} +#endif // HAL_USE_SERIAL + +#if (HAL_USE_UART == TRUE) && (UART_USE_WAIT == TRUE) +void UartTsChannel::start(uint32_t baud) { + m_config.txend1_cb = NULL; + m_config.txend2_cb = NULL; + m_config.rxend_cb = NULL; + m_config.rxchar_cb = NULL; + m_config.rxerr_cb = NULL; + m_config.timeout_cb = NULL; + m_config.speed = baud; + m_config.cr1 = 0; + m_config.cr2 = 0/*USART_CR2_STOP1_BITS*/ | USART_CR2_LINEN; + m_config.cr3 = 0; + + uartStart(m_driver, &m_config); +} + +void UartTsChannel::stop() { + uartStop(m_driver); +} + +void UartTsChannel::write(const uint8_t* buffer, size_t size, bool) { + uartSendTimeout(m_driver, &size, buffer, BINARY_IO_TIMEOUT); +} + +size_t UartTsChannel::readTimeout(uint8_t* buffer, size_t size, int timeout) { + uartReceiveTimeout(m_driver, &size, buffer, timeout); + return size; +} +#endif // HAL_USE_UART diff --git a/firmware/util/byteswap.h b/firmware/util/byteswap.h new file mode 100644 index 0000000..a053d0f --- /dev/null +++ b/firmware/util/byteswap.h @@ -0,0 +1,14 @@ +#pragma once + +// http://en.wikipedia.org/wiki/Endianness + +static inline uint16_t SWAP_UINT16(uint16_t x) +{ + return ((x << 8) | (x >> 8)); +} + +static inline uint32_t SWAP_UINT32(uint32_t x) +{ + return (((x >> 24) & 0x000000ff) | ((x << 8) & 0x00ff0000) | + ((x >> 8) & 0x0000ff00) | ((x << 24) & 0xff000000)); +} \ No newline at end of file diff --git a/firmware/util/math/crc.c b/firmware/util/math/crc.c new file mode 100644 index 0000000..c1734b6 --- /dev/null +++ b/firmware/util/math/crc.c @@ -0,0 +1,94 @@ +/** + * @file crc.c + * @date Sep 20, 2013 + * @author Andrey Belomutskiy, (c) 2012-2020 + */ + +#include "crc.h" + +static const uint32_t crc32_tab[] = { 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 }; + +/** + * Online CRC calculator: + * http://www.zorc.breitbandkatze.de/crc.html + */ +uint32_t crc32(const void *buf, uint32_t size) { + return crc32inc(buf, 0, size); +} + +uint32_t crc32inc(const void *buf, uint32_t crc, uint32_t size) { + const uint8_t *p; + + p = buf; + crc = crc ^ 0xFFFFFFFF; + + while (size--) { + crc = crc32_tab[(crc ^ *p++) & 0xFF] ^ (crc >> 8); + } + + return crc ^ 0xFFFFFFFF; +} + +/** + * http://www.sunshine2k.de/coding/javascript/crc/crc_js.html + * https://stackoverflow.com/questions/38639423/understanding-results-of-crc8-sae-j1850-normal-vs-zero + * j1850 SAE crc8 + */ +uint8_t crc8(const uint8_t *data, uint8_t len) { + uint8_t crc = 0; + + if (data == 0) + return 0; + crc ^= 0xff; + while (len--) { + crc ^= *data++; + for (unsigned k = 0; k < 8; k++) + crc = crc & 0x80 ? (crc << 1) ^ 0x1d : crc << 1; + } + crc &= 0xff; + crc ^= 0xff; + return crc; +} + diff --git a/firmware/util/math/crc.h b/firmware/util/math/crc.h new file mode 100644 index 0000000..d634c97 --- /dev/null +++ b/firmware/util/math/crc.h @@ -0,0 +1,22 @@ +/** + * @file crc.h + * + * @date Sep 20, 2013 + * @author Andrey Belomutskiy, (c) 2012-2020 + */ + +#pragma once + +#include "stdint.h" + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +uint8_t crc8(const uint8_t * buf, uint8_t len); +uint32_t crc32(const void *buf, uint32_t size); +uint32_t crc32inc(const void *buf, uint32_t crc, uint32_t size); + +#ifdef __cplusplus +} +#endif /* __cplusplus */