From 7aff6780693061d1eede91368ec9fb998cdbcf2b Mon Sep 17 00:00:00 2001 From: Silvano Seva Date: Tue, 17 May 2022 21:54:46 +0200 Subject: [PATCH] Improved robustness of frame type detection, now based on minimum hamming distance between syncwords --- .../include/protocols/M17/M17Demodulator.h | 8 --- .../include/protocols/M17/M17FrameDecoder.h | 15 +++++ openrtx/include/protocols/M17/M17Utils.h | 30 +++++++--- openrtx/src/protocols/M17/M17Demodulator.cpp | 5 -- openrtx/src/protocols/M17/M17FrameDecoder.cpp | 57 ++++++++++++++----- 5 files changed, 79 insertions(+), 36 deletions(-) mode change 100755 => 100644 openrtx/include/protocols/M17/M17FrameDecoder.h diff --git a/openrtx/include/protocols/M17/M17Demodulator.h b/openrtx/include/protocols/M17/M17Demodulator.h index 7aebf972..2e6f53d6 100644 --- a/openrtx/include/protocols/M17/M17Demodulator.h +++ b/openrtx/include/protocols/M17/M17Demodulator.h @@ -238,14 +238,6 @@ private: */ int8_t quantize(int32_t offset); - /** - * Compute Hamming Distance between two bytes - * - * @param x: first byte - * @param y: second byte - */ - uint8_t hammingDistance(uint8_t x, uint8_t y); - /** * Perform a limited search for a syncword using correlation * diff --git a/openrtx/include/protocols/M17/M17FrameDecoder.h b/openrtx/include/protocols/M17/M17FrameDecoder.h old mode 100755 new mode 100644 index 4d895b48..3304257e --- a/openrtx/include/protocols/M17/M17FrameDecoder.h +++ b/openrtx/include/protocols/M17/M17FrameDecoder.h @@ -25,6 +25,7 @@ #error This header is C++ only! #endif +#include #include #include #include "M17LinkSetupFrame.h" @@ -97,6 +98,17 @@ public: private: + /** + * Determine frame type by searching which syncword among the standard M17 + * ones has the minumum hamming distance from the given one. If the hamming + * distance exceeds a masimum absolute threshold the frame is declared of + * unknown type. + * + * @param syncWord: frame syncword. + * @return frame type based on the given syncword. + */ + M17FrameType getFrameType(const std::array< uint8_t, 2 >& syncWord); + /** * Decode Link Setup Frame data and update the internal LSF field with * the new frame data. @@ -129,6 +141,9 @@ private: M17LinkSetupFrame lsfFromLich; ///< LSF assembled from LICH segments. M17StreamFrame streamFrame; ///< Latest stream dat frame received. M17Viterbi viterbi; ///< Viterbi decoder. + + ///< Maximum allowed hamming distance when determining the frame type. + static constexpr uint8_t MAX_SYNC_HAMM_DISTANCE = 4; }; } // namespace M17 diff --git a/openrtx/include/protocols/M17/M17Utils.h b/openrtx/include/protocols/M17/M17Utils.h index 8a4c5c16..448452ba 100644 --- a/openrtx/include/protocols/M17/M17Utils.h +++ b/openrtx/include/protocols/M17/M17Utils.h @@ -39,9 +39,9 @@ namespace M17 * of bytes. Bits are counted scanning from left to right, thus bit number zero * is the leftmost bit of array[0]. * - * \param array: byte array. - * \param pos: bit position inside the array. - * \return value of the indexed bit, as boolean variable. + * @param array: byte array. + * @param pos: bit position inside the array. + * @return value of the indexed bit, as boolean variable. */ template < size_t N > inline bool getBit(const std::array< uint8_t, N >& array, const size_t pos) @@ -57,9 +57,9 @@ inline bool getBit(const std::array< uint8_t, N >& array, const size_t pos) * of bytes. Bits are counted scanning from left to right, thus bit number zero * is the leftmost bit of array[0]. * - * \param array: byte array. - * \param pos: bit position inside the array. - * \param bit: bit value to be set. + * @param array: byte array. + * @param pos: bit position inside the array. + * @param bit: bit value to be set. */ template < size_t N > inline void setBit(std::array< uint8_t, N >& array, const size_t pos, @@ -78,9 +78,9 @@ inline void setBit(std::array< uint8_t, N >& array, const size_t pos, * symbols are filled from the least significant bit pair to the most * significant bit pair. * - * \param array: byte array. - * \param pos: symbol position inside the array. - * \param symbol: symbol to be set, either -3, -1, +1, +3. + * @param array: byte array. + * @param pos: symbol position inside the array. + * @param symbol: symbol to be set, either -3, -1, +1, +3. */ template < size_t N > inline void setSymbol(std::array< uint8_t, N >& array, const size_t pos, @@ -108,6 +108,18 @@ inline void setSymbol(std::array< uint8_t, N >& array, const size_t pos, } } +/** + * Compute the hamming distance between two bytes. + * + * @param x: first byte. + * @param y: second byte. + * @return hamming distance between x and y. + */ +static inline uint8_t hammingDistance(const uint8_t x, const uint8_t y) +{ + return __builtin_popcount(x ^ y); +} + } // namespace M17 #endif // M17_UTILS_H diff --git a/openrtx/src/protocols/M17/M17Demodulator.cpp b/openrtx/src/protocols/M17/M17Demodulator.cpp index 2711222d..e4086017 100644 --- a/openrtx/src/protocols/M17/M17Demodulator.cpp +++ b/openrtx/src/protocols/M17/M17Demodulator.cpp @@ -310,11 +310,6 @@ bool M17::M17Demodulator::isLocked() return locked; } -uint8_t M17Demodulator::hammingDistance(uint8_t x, uint8_t y) -{ - return __builtin_popcount(x ^ y); -} - int32_t M17Demodulator::syncwordSweep(int32_t offset) { int32_t max_conv = 0, max_index = 0; diff --git a/openrtx/src/protocols/M17/M17FrameDecoder.cpp b/openrtx/src/protocols/M17/M17FrameDecoder.cpp index 89754180..e66cce96 100644 --- a/openrtx/src/protocols/M17/M17FrameDecoder.cpp +++ b/openrtx/src/protocols/M17/M17FrameDecoder.cpp @@ -23,6 +23,7 @@ #include #include #include +#include #include using namespace M17; @@ -51,30 +52,58 @@ M17FrameType M17FrameDecoder::decodeFrame(const frame_t& frame) decorrelate(data); deinterleave(data); + auto type = getFrameType(syncWord); + + switch(type) + { + case M17FrameType::LINK_SETUP: + decodeLSF(data); + break; + + case M17FrameType::STREAM: + decodeStream(data); + break; + + default: + break; + } + + return type; +} + +M17FrameType M17FrameDecoder::getFrameType(const std::array< uint8_t, 2 >& syncWord) +{ // Preamble - if((syncWord[0] == 0x77) && (syncWord[1] == 0x77)) + M17FrameType type = M17FrameType::PREAMBLE; + uint8_t minDistance = hammingDistance(syncWord[0], 0x77) + + hammingDistance(syncWord[1], 0x77); + + // Link setup frame + uint8_t hammDistance = hammingDistance(syncWord[0], LSF_SYNC_WORD[0]) + + hammingDistance(syncWord[1], LSF_SYNC_WORD[1]); + if(hammDistance < minDistance) { - return M17FrameType::PREAMBLE; + type = M17FrameType::LINK_SETUP; + minDistance = hammDistance; } - // Link Setup Frame - if(syncWord == LSF_SYNC_WORD) + // Stream frame + hammDistance = hammingDistance(syncWord[0], STREAM_SYNC_WORD[0]) + + hammingDistance(syncWord[1], STREAM_SYNC_WORD[1]); + if(hammDistance < minDistance) { - decodeLSF(data); - return M17FrameType::LINK_SETUP; + type = M17FrameType::STREAM; + minDistance = hammDistance; } - // Stream data frame - uint8_t hd = __builtin_popcount(syncWord[0] ^ STREAM_SYNC_WORD[0]) - + __builtin_popcount(syncWord[1] ^ STREAM_SYNC_WORD[1]); - if(hd <= 4) + // Check value of minimum hamming distance found, if exceeds the allowed + // limit consider the frame as of unknown type. + if(minDistance > MAX_SYNC_HAMM_DISTANCE) { - decodeStream(data); - return M17FrameType::STREAM; + type = M17FrameType::UNKNOWN; } - // If we get here, we received an unknown frame - return M17FrameType::UNKNOWN; + return type; } void M17FrameDecoder::decodeLSF(const std::array< uint8_t, 46 >& data)