diff --git a/Serial-Studio.pro b/Serial-Studio.pro index 54dbf60e..64bb5cc5 100644 --- a/Serial-Studio.pro +++ b/Serial-Studio.pro @@ -128,6 +128,7 @@ HEADERS += \ src/AppInfo.h \ src/CSV/Export.h \ src/CSV/Player.h \ + src/IO/Checksum.h \ src/IO/Console.h \ src/IO/DataSources/Network.h \ src/IO/DataSources/Serial.h \ @@ -154,6 +155,7 @@ HEADERS += \ SOURCES += \ src/CSV/Export.cpp \ src/CSV/Player.cpp \ + src/IO/Checksum.cpp \ src/IO/Console.cpp \ src/IO/DataSources/Network.cpp \ src/IO/DataSources/Serial.cpp \ diff --git a/src/IO/Checksum.cpp b/src/IO/Checksum.cpp new file mode 100644 index 00000000..bbdc53e5 --- /dev/null +++ b/src/IO/Checksum.cpp @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2020-2021 Alex Spataru + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "Checksum.h" + +using namespace IO; + +quint8 crc8(const QByteArray &data) +{ + quint8 crc = 0xff; + for (auto i = 0; i < data.length(); i++) + { + crc ^= data.at(i); + for (auto j = 0; j < 8; j++) + { + if ((crc & 0x80) != 0) + crc = (uint8_t)((crc << 1) ^ 0x31); + else + crc <<= 1; + } + } + + return crc; +} + +quint16 crc16(const QByteArray &data) +{ + quint8 x; + quint16 crc = 0xFFFF; + + for (auto i = 0; i < data.length(); ++i) + { + x = crc >> 8 ^ data.at(i); + x ^= x >> 4; + crc = (crc << 8) ^ ((quint16)(x << 12)) ^ ((quint16)(x << 5)) ^ ((quint16)x); + } + + return crc; +} + +quint32 crc32(const QByteArray &data) +{ + quint32 mask; + quint32 crc = 0xFFFFFFFF; + for (auto i = 0; i < data.length(); ++i) + { + crc = crc ^ data.at(i); + for (auto j = 8; j >= 0; j--) + { + mask = -(crc & 1); + crc = (crc >> 1) ^ (0xEDB88320 & mask); + } + } + + return ~crc; +} diff --git a/src/IO/Checksum.h b/src/IO/Checksum.h new file mode 100644 index 00000000..f9377d45 --- /dev/null +++ b/src/IO/Checksum.h @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2020-2021 Alex Spataru + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#ifndef IO_CHECKSUM_H +#define IO_CHECKSUM_H + +#include + +namespace IO +{ +quint8 crc8(const QByteArray &data); +quint16 crc16(const QByteArray &data); +quint32 crc32(const QByteArray &data); +} + +#endif diff --git a/src/IO/Manager.cpp b/src/IO/Manager.cpp index 343c472f..3054f5e1 100644 --- a/src/IO/Manager.cpp +++ b/src/IO/Manager.cpp @@ -535,8 +535,55 @@ void Manager::readFrames() // Buffer is not empty, notify app & remove read data from buffer if (!buffer.isEmpty()) { - emit frameReceived(buffer); - m_dataBuffer.remove(0, sIndex + fIndex + finish.length()); + // Remove frame from buffer + auto index = sIndex + fIndex + finish.length(); + m_dataBuffer.remove(0, index); + + // Check CRC-8 + if (m_dataBuffer.startsWith("crc8:")) + { + if (m_dataBuffer.length() >= 5) + { + quint8 crc = m_dataBuffer.at(4); + if (crc8(buffer) == crc) + emit frameReceived(buffer); + } + } + + // Check CRC-16 + else if (m_dataBuffer.startsWith("crc16:")) + { + if (m_dataBuffer.length() >= 7) + { + quint8 crcA = m_dataBuffer.at(5); + quint8 crcB = m_dataBuffer.at(6); + quint16 crc = (crcA << 8) | (crcB & 0xff); + + if (crc16(buffer) == crc) + emit frameReceived(buffer); + } + } + + // Check CRC-32 + else if (m_dataBuffer.startsWith("crc32:")) + { + if (m_dataBuffer.length() >= 9) + { + quint8 crcA = m_dataBuffer.at(5); + quint8 crcB = m_dataBuffer.at(6); + quint8 crcD = m_dataBuffer.at(7); + quint8 crcC = m_dataBuffer.at(8); + quint32 crc + = (crcA << 24) | (crcB << 16) | (crcC << 8) | (crcD & 0xff); + + if (crc32(buffer) == crc) + emit frameReceived(buffer); + } + } + + // Buffer does not contain CRC code + else + emit frameReceived(buffer); } } diff --git a/src/IO/Manager.h b/src/IO/Manager.h index 368b5fb6..4dfcaf96 100644 --- a/src/IO/Manager.h +++ b/src/IO/Manager.h @@ -27,6 +27,8 @@ #include #include +#include "Checksum.h" + namespace IO { class Manager : public QObject @@ -116,6 +118,8 @@ public: QString separatorSequence() const; QString receivedDataLength() const; + bool validateCrc(const QByteArray &buffer, quint32 crc, ChecksumType type); + Q_INVOKABLE QStringList dataSourcesList() const; Q_INVOKABLE qint64 writeData(const QByteArray &data);