From 9d56214c73d68f977dbd8db54d84f999722fdb31 Mon Sep 17 00:00:00 2001 From: Timon Zijnge Date: Wed, 17 Dec 2025 15:54:23 +0100 Subject: [PATCH 01/46] manchester * Added manchester code and test --- test/CMakeLists.txt | 1 + test/test_manchester.cpp | 172 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 173 insertions(+) create mode 100644 test/test_manchester.cpp diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 624f38d22..3e15da01c 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -217,6 +217,7 @@ add_executable(etl_tests test_list_shared_pool.cpp test_macros.cpp test_make_string.cpp + test_manchester.cpp test_map.cpp test_math.cpp test_math_functions.cpp diff --git a/test/test_manchester.cpp b/test/test_manchester.cpp new file mode 100644 index 000000000..43f12307b --- /dev/null +++ b/test/test_manchester.cpp @@ -0,0 +1,172 @@ +#include "etl/manchester.h" + +#include "unit_test_framework.h" +#include +#include +#include + +SUITE(test_manchester){ + + TEST(encode8){ + CHECK_EQUAL(0xAAAA, (etl::manchester_encode(0x00U))); +CHECK_EQUAL(0x5555, (etl::manchester_encode(0xFFU))); +CHECK_EQUAL(0xAAA9, (etl::manchester_encode(0x01U))); +CHECK_EQUAL(0x6AAA, (etl::manchester_encode(0x80U))); +} + +TEST(encode16) +{ + CHECK_EQUAL(0x5555AAAA, (etl::manchester_encode(0xFF00UL))); + CHECK_EQUAL(0x6AAAAAA9, (etl::manchester_encode(0x8001UL))); +} + +TEST(encode32) +{ + CHECK_EQUAL(0x6AAAAAA95555AAAA, (etl::manchester_encode(0x8001FF00ULL))); +} + +TEST(encode_span8) +{ + std::array input{0x00, 0xFF, 0x01, 0x80}; + std::array input2{0xFF00, 0x8001}; + std::array input3{0x8001FF00}; + + std::array output1; + std::array output2; + std::array output3; + + std::array output4; + std::array output5; + std::array output6; + + std::array output7; + std::array output8; + std::array output9; + + etl::manchester_encode_span(input, output1); + etl::manchester_encode_span(input, output2); + etl::manchester_encode_span(input, output3); + + etl::manchester_encode_span(input2, output4); + etl::manchester_encode_span(input2, output5); + etl::manchester_encode_span(input2, output6); + + etl::manchester_encode_span(input3, output7); + etl::manchester_encode_span(input3, output8); + etl::manchester_encode_span(input3, output9); + + CHECK_EQUAL(0xAAAA, output1[0]); + CHECK_EQUAL(0x5555, output1[1]); + CHECK_EQUAL(0xAAA9, output1[2]); + CHECK_EQUAL(0x6AAA, output1[3]); + + CHECK_EQUAL(0xAAAA, output2[0]); + CHECK_EQUAL(0x5555, output2[1]); + CHECK_EQUAL(0xAAA9, output2[2]); + CHECK_EQUAL(0x6AAA, output2[3]); + + CHECK_EQUAL(0xAAAA, output3[0]); + CHECK_EQUAL(0x5555, output3[1]); + CHECK_EQUAL(0xAAA9, output3[2]); + CHECK_EQUAL(0x6AAA, output3[3]); + + CHECK_EQUAL(0x5555AAAA, output4[0]); + CHECK_EQUAL(0x6AAAAAA9, output4[1]); + + CHECK_EQUAL(0x5555AAAA, output5[0]); + CHECK_EQUAL(0x6AAAAAA9, output5[1]); + + CHECK_EQUAL(0x5555AAAA, output6[0]); + CHECK_EQUAL(0x6AAAAAA9, output6[1]); + + CHECK_EQUAL(0x6AAAAAA95555AAAA, output7[0]); + CHECK_EQUAL(0x6AAAAAA95555AAAA, output8[0]); + CHECK_EQUAL(0x6AAAAAA95555AAAA, output9[0]); +} + +TEST(encode8_transform) +{ + std::array input{0x00, 0xFF, 0x01, 0x80}; + std::array output; + + std::transform(input.begin(), input.end(), output.begin(), etl::manchester_encode); + + CHECK_EQUAL(0xAAAA, output[0]); + CHECK_EQUAL(0x5555, output[1]); + CHECK_EQUAL(0xAAA9, output[2]); + CHECK_EQUAL(0x6AAA, output[3]); +} + +TEST(encode16_transform) +{ + std::array input{0x00, 0xFF, 0x01, 0x80}; + std::array output; + + etl::span input16{reinterpret_cast(input.data()), 2}; + etl::span output32{reinterpret_cast(output.data()), 2}; + + std::transform(input16.begin(), input16.end(), output32.begin(), etl::manchester_encode); + + CHECK_EQUAL(0xAAAA, output[0]); + CHECK_EQUAL(0x5555, output[1]); + CHECK_EQUAL(0xAAA9, output[2]); + CHECK_EQUAL(0x6AAA, output[3]); +} + +TEST(encode32_transform) +{ + std::array input{0x00, 0xFF, 0x01, 0x80}; + std::array output; + + etl::span input32{reinterpret_cast(input.data()), 1}; + etl::span output64{reinterpret_cast(output.data()), 1}; + + std::transform(input32.begin(), input32.end(), output64.begin(), etl::manchester_encode); + + CHECK_EQUAL(0xAAAA, output[0]); + CHECK_EQUAL(0x5555, output[1]); + CHECK_EQUAL(0xAAA9, output[2]); + CHECK_EQUAL(0x6AAA, output[3]); +} + +TEST(decode16) +{ + CHECK_EQUAL(0x00, (etl::manchester_decode(0xAAAAUL))); + CHECK_EQUAL(0xFF, (etl::manchester_decode(0x5555UL))); + CHECK_EQUAL(0x01, (etl::manchester_decode(0xAAA9UL))); + CHECK_EQUAL(0x80, (etl::manchester_decode(0x6AAAUL))); +} + +TEST(decode32) +{ + CHECK_EQUAL(0xFF00UL, (etl::manchester_decode(0x5555AAAAUL))); + CHECK_EQUAL(0x8001UL, (etl::manchester_decode(0x6AAAAAA9UL))); +} + +TEST(decode64) +{ + CHECK_EQUAL(0x8001FF00ULL, (etl::manchester_decode(0x6AAAAAA95555AAAAULL))); +} + +TEST(valid16) +{ + CHECK_TRUE(etl::manchester_valid(0xAAAAUL)); + CHECK_FALSE(etl::manchester_valid(0xAAA8UL)); + CHECK_TRUE(etl::manchester_valid(0xAAAAUL)); +} + +TEST(valid32) +{ + CHECK_TRUE(etl::manchester_valid(0xAAAAAAAAUL)); + CHECK_FALSE(etl::manchester_valid(0xAAAAAAA8UL)); + CHECK_TRUE(etl::manchester_valid(0xAAAAAAAAUL)); +} + +TEST(valid64) +{ + CHECK_TRUE(etl::manchester_valid(0xAAAAAAAAAAAAAAAAULL)); + CHECK_FALSE(etl::manchester_valid(0xAAAAAAAAAAAAAAA8ULL)); + CHECK_TRUE(etl::manchester_valid(0xAAAAAAAAAAAAAAAAULL)); +} +} +; \ No newline at end of file From c4f211a58559eb975fa29ee374f3059a519d62a5 Mon Sep 17 00:00:00 2001 From: Timon Zijnge Date: Wed, 17 Dec 2025 16:02:04 +0100 Subject: [PATCH 02/46] manchester * Formatting and added missing file --- include/etl/manchester.h | 251 ++++++++++++++++++++++++++++++ test/test_manchester.cpp | 324 +++++++++++++++++++-------------------- 2 files changed, 413 insertions(+), 162 deletions(-) create mode 100644 include/etl/manchester.h diff --git a/include/etl/manchester.h b/include/etl/manchester.h new file mode 100644 index 000000000..2a0e0b4be --- /dev/null +++ b/include/etl/manchester.h @@ -0,0 +1,251 @@ +#ifndef ETL_MANCHESTER_INCLUDED +#define ETL_MANCHESTER_INCLUDED + +// #include +// #include + +// namespace manchester +// { +// void encode(const etl::span &input, const etl::span &output); +// bool decode(const etl::span &input, const etl::span &output); +// } + +///\file + +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl +https://www.etlcpp.com + +Copyright(c) 2021 John Wellbelove + +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 +#include +#include +#include + +namespace etl +{ + //*************************************************************************** + /// Manchester encoding and decoding + //*************************************************************************** + +#if ETL_USING_8BIT_TYPES + //***************************************************************************** + /// Manchester encode 8 bits + ///\ingroup manchester + //***************************************************************************** + template + ETL_CONSTEXPR + typename etl::enable_if::value && etl::is_unsigned::value && (etl::integral_limits::bits == 8U) && + etl::is_integral::value && etl::is_unsigned::value && (etl::integral_limits::bits == 16U), + TOutput>::type + manchester_encode(TInput in) + { + TOutput out = in; + + out = (out | (out << 4U)) & 0x0F0FU; + out = (out | (out << 2U)) & 0x3333U; + out = (out | (out << 1U)) & 0x5555U; + return (out | (out << 1U)) ^ 0xAAAAU; + } +#endif + + //***************************************************************************** + /// Manchester encode 16 bits + ///\ingroup manchester + //***************************************************************************** + template + ETL_CONSTEXPR + typename etl::enable_if::value && etl::is_unsigned::value && (etl::integral_limits::bits == 16U) && + etl::is_integral::value && etl::is_unsigned::value && (etl::integral_limits::bits == 32U), + TOutput>::type + manchester_encode(TInput in) + { + TOutput out = in; + + out = (out | (out << 8U)) & 0x00FF00FFUL; + out = (out | (out << 4U)) & 0x0F0F0F0FUL; + out = (out | (out << 2U)) & 0x33333333UL; + out = (out | (out << 1U)) & 0x55555555UL; + return (out | (out << 1U)) ^ 0xAAAAAAAAUL; + } + +#if ETL_USING_64BIT_TYPES + //***************************************************************************** + /// Manchester encode 32 bits + ///\ingroup manchester + //***************************************************************************** + template + ETL_CONSTEXPR + typename etl::enable_if::value && etl::is_unsigned::value && (etl::integral_limits::bits == 32U) && + etl::is_integral::value && etl::is_unsigned::value && (etl::integral_limits::bits == 64U), + TOutput>::type + manchester_encode(TInput in) + { + TOutput out = in; + + out = (out | (out << 16U)) & 0x0000FFFF0000FFFFULL; + out = (out | (out << 8U)) & 0x00FF00FF00FF00FFULL; + out = (out | (out << 4U)) & 0x0F0F0F0F0F0F0F0FULL; + out = (out | (out << 2U)) & 0x3333333333333333ULL; + out = (out | (out << 1U)) & 0x5555555555555555ULL; + return (out | (out << 1U)) ^ 0xAAAAAAAAAAAAAAAAULL; + } +#endif + + template + struct select_uint; + + template <> + struct select_uint + { + using type = std::uint16_t; + }; + template <> + struct select_uint + { + using type = std::uint32_t; + }; + template <> + struct select_uint + { + using type = std::uint64_t; + }; + + template ::type, typename TEncode = TInput> + typename etl::enable_if::value && etl::is_unsigned::value && + etl::is_integral::value && etl::is_unsigned::value && + etl::is_integral::value && etl::is_unsigned::value && + (etl::integral_limits::bits <= 32) && + (2 * etl::integral_limits::bits == etl::integral_limits::bits), + void>::type + manchester_encode_span(etl::span input, etl::span output) + { + using TOut = typename select_uint::type; + + ETL_ASSERT(output.size() >= input.size(), ""); + ETL_ASSERT((input.size() * sizeof(TInput)) % sizeof(TEncode) == 0, ""); + + etl::span in{reinterpret_cast(input.data()), (sizeof(TInput) * input.size()) / sizeof(TEncode)}; + etl::span out{reinterpret_cast(output.data()), (sizeof(TOutput) * output.size()) / sizeof(TOut)}; + + etl::transform(in.begin(), in.end(), out.begin(), etl::manchester_encode); + } + +#if ETL_USING_8BIT_TYPES + //***************************************************************************** + /// Manchester decode 16 bits + ///\ingroup manchester + //***************************************************************************** + template + ETL_CONSTEXPR + typename etl::enable_if::value && etl::is_unsigned::value && (etl::integral_limits::bits == 16U) && + etl::is_integral::value && etl::is_unsigned::value && (etl::integral_limits::bits == 8U), + TOutput>::type + manchester_decode(TInput in) + { + TInput out = (in ^ 0xAAAAU) & 0x5555U; + out = (out | (out >> 1)) & 0x3333U; + out = (out | (out >> 2)) & 0x0F0FU; + return static_cast(out | (out >> 4U)); + } +#endif + + //***************************************************************************** + /// Manchester valid 16 bits + ///\ingroup manchester + //***************************************************************************** + template + ETL_CONSTEXPR + typename etl::enable_if::value && etl::is_unsigned::value && (etl::integral_limits::bits == 16U), bool>::type + manchester_valid(TInput in) + { + return (((in ^ (in >> 1)) & 0x5555U) == 0x5555U); + } + + //***************************************************************************** + /// Manchester decode 32 bits + ///\ingroup manchester + //***************************************************************************** + template + ETL_CONSTEXPR + typename etl::enable_if::value && etl::is_unsigned::value && (etl::integral_limits::bits == 32U) && + etl::is_integral::value && etl::is_unsigned::value && (etl::integral_limits::bits == 16U), + TOutput>::type + manchester_decode(TInput in) + { + TInput out = (in ^ 0xAAAAAAAAUL) & 0x55555555UL; + out = (out | (out >> 1)) & 0x33333333UL; + out = (out | (out >> 2)) & 0x0F0F0F0FUL; + out = (out | (out >> 4)) & 0x00FF00FFUL; + return static_cast(out | (out >> 8U)); + } + + //***************************************************************************** + /// Manchester valid 32 bits + ///\ingroup manchester + //***************************************************************************** + template + ETL_CONSTEXPR + typename etl::enable_if::value && etl::is_unsigned::value && (etl::integral_limits::bits == 32U), bool>::type + manchester_valid(TInput in) + { + return (((in ^ (in >> 1)) & 0x55555555U) == 0x55555555U); + } + + //***************************************************************************** + /// Manchester decode 64 bits + ///\ingroup manchester + //***************************************************************************** + template + ETL_CONSTEXPR + typename etl::enable_if::value && etl::is_unsigned::value && (etl::integral_limits::bits == 64U) && + etl::is_integral::value && etl::is_unsigned::value && (etl::integral_limits::bits == 32U), + TOutput>::type + manchester_decode(TInput in) + { + TInput out = (in ^ 0xAAAAAAAAAAAAAAAAULL) & 0x5555555555555555ULL; + out = (out | (out >> 1)) & 0x3333333333333333ULL; + out = (out | (out >> 2)) & 0x0F0F0F0F0F0F0F0FULL; + out = (out | (out >> 4)) & 0x00FF00FF00FF00FFULL; + out = (out | (out >> 8)) & 0x0000FFFF0000FFFFULL; + return static_cast(out | (out >> 16U)); + } + + //***************************************************************************** + /// Manchester valid 64 bits + ///\ingroup manchester + //***************************************************************************** + template + ETL_CONSTEXPR + typename etl::enable_if::value && etl::is_unsigned::value && (etl::integral_limits::bits == 64U), bool>::type + manchester_valid(TInput in) + { + return (((in ^ (in >> 1)) & 0x5555555555555555U) == 0x5555555555555555U); + } + +} // namespace etl + +#endif diff --git a/test/test_manchester.cpp b/test/test_manchester.cpp index 43f12307b..44ba85a17 100644 --- a/test/test_manchester.cpp +++ b/test/test_manchester.cpp @@ -5,168 +5,168 @@ #include #include -SUITE(test_manchester){ +SUITE(test_manchester) +{ TEST(encode8){ CHECK_EQUAL(0xAAAA, (etl::manchester_encode(0x00U))); -CHECK_EQUAL(0x5555, (etl::manchester_encode(0xFFU))); -CHECK_EQUAL(0xAAA9, (etl::manchester_encode(0x01U))); -CHECK_EQUAL(0x6AAA, (etl::manchester_encode(0x80U))); -} - -TEST(encode16) -{ - CHECK_EQUAL(0x5555AAAA, (etl::manchester_encode(0xFF00UL))); - CHECK_EQUAL(0x6AAAAAA9, (etl::manchester_encode(0x8001UL))); -} - -TEST(encode32) -{ - CHECK_EQUAL(0x6AAAAAA95555AAAA, (etl::manchester_encode(0x8001FF00ULL))); -} - -TEST(encode_span8) -{ - std::array input{0x00, 0xFF, 0x01, 0x80}; - std::array input2{0xFF00, 0x8001}; - std::array input3{0x8001FF00}; - - std::array output1; - std::array output2; - std::array output3; - - std::array output4; - std::array output5; - std::array output6; - - std::array output7; - std::array output8; - std::array output9; - - etl::manchester_encode_span(input, output1); - etl::manchester_encode_span(input, output2); - etl::manchester_encode_span(input, output3); - - etl::manchester_encode_span(input2, output4); - etl::manchester_encode_span(input2, output5); - etl::manchester_encode_span(input2, output6); - - etl::manchester_encode_span(input3, output7); - etl::manchester_encode_span(input3, output8); - etl::manchester_encode_span(input3, output9); - - CHECK_EQUAL(0xAAAA, output1[0]); - CHECK_EQUAL(0x5555, output1[1]); - CHECK_EQUAL(0xAAA9, output1[2]); - CHECK_EQUAL(0x6AAA, output1[3]); - - CHECK_EQUAL(0xAAAA, output2[0]); - CHECK_EQUAL(0x5555, output2[1]); - CHECK_EQUAL(0xAAA9, output2[2]); - CHECK_EQUAL(0x6AAA, output2[3]); - - CHECK_EQUAL(0xAAAA, output3[0]); - CHECK_EQUAL(0x5555, output3[1]); - CHECK_EQUAL(0xAAA9, output3[2]); - CHECK_EQUAL(0x6AAA, output3[3]); - - CHECK_EQUAL(0x5555AAAA, output4[0]); - CHECK_EQUAL(0x6AAAAAA9, output4[1]); - - CHECK_EQUAL(0x5555AAAA, output5[0]); - CHECK_EQUAL(0x6AAAAAA9, output5[1]); - - CHECK_EQUAL(0x5555AAAA, output6[0]); - CHECK_EQUAL(0x6AAAAAA9, output6[1]); - - CHECK_EQUAL(0x6AAAAAA95555AAAA, output7[0]); - CHECK_EQUAL(0x6AAAAAA95555AAAA, output8[0]); - CHECK_EQUAL(0x6AAAAAA95555AAAA, output9[0]); -} - -TEST(encode8_transform) -{ - std::array input{0x00, 0xFF, 0x01, 0x80}; - std::array output; - - std::transform(input.begin(), input.end(), output.begin(), etl::manchester_encode); - - CHECK_EQUAL(0xAAAA, output[0]); - CHECK_EQUAL(0x5555, output[1]); - CHECK_EQUAL(0xAAA9, output[2]); - CHECK_EQUAL(0x6AAA, output[3]); -} - -TEST(encode16_transform) -{ - std::array input{0x00, 0xFF, 0x01, 0x80}; - std::array output; - - etl::span input16{reinterpret_cast(input.data()), 2}; - etl::span output32{reinterpret_cast(output.data()), 2}; - - std::transform(input16.begin(), input16.end(), output32.begin(), etl::manchester_encode); - - CHECK_EQUAL(0xAAAA, output[0]); - CHECK_EQUAL(0x5555, output[1]); - CHECK_EQUAL(0xAAA9, output[2]); - CHECK_EQUAL(0x6AAA, output[3]); -} - -TEST(encode32_transform) -{ - std::array input{0x00, 0xFF, 0x01, 0x80}; - std::array output; - - etl::span input32{reinterpret_cast(input.data()), 1}; - etl::span output64{reinterpret_cast(output.data()), 1}; - - std::transform(input32.begin(), input32.end(), output64.begin(), etl::manchester_encode); - - CHECK_EQUAL(0xAAAA, output[0]); - CHECK_EQUAL(0x5555, output[1]); - CHECK_EQUAL(0xAAA9, output[2]); - CHECK_EQUAL(0x6AAA, output[3]); -} - -TEST(decode16) -{ - CHECK_EQUAL(0x00, (etl::manchester_decode(0xAAAAUL))); - CHECK_EQUAL(0xFF, (etl::manchester_decode(0x5555UL))); - CHECK_EQUAL(0x01, (etl::manchester_decode(0xAAA9UL))); - CHECK_EQUAL(0x80, (etl::manchester_decode(0x6AAAUL))); -} - -TEST(decode32) -{ - CHECK_EQUAL(0xFF00UL, (etl::manchester_decode(0x5555AAAAUL))); - CHECK_EQUAL(0x8001UL, (etl::manchester_decode(0x6AAAAAA9UL))); -} - -TEST(decode64) -{ - CHECK_EQUAL(0x8001FF00ULL, (etl::manchester_decode(0x6AAAAAA95555AAAAULL))); -} - -TEST(valid16) -{ - CHECK_TRUE(etl::manchester_valid(0xAAAAUL)); - CHECK_FALSE(etl::manchester_valid(0xAAA8UL)); - CHECK_TRUE(etl::manchester_valid(0xAAAAUL)); -} - -TEST(valid32) -{ - CHECK_TRUE(etl::manchester_valid(0xAAAAAAAAUL)); - CHECK_FALSE(etl::manchester_valid(0xAAAAAAA8UL)); - CHECK_TRUE(etl::manchester_valid(0xAAAAAAAAUL)); -} - -TEST(valid64) -{ - CHECK_TRUE(etl::manchester_valid(0xAAAAAAAAAAAAAAAAULL)); - CHECK_FALSE(etl::manchester_valid(0xAAAAAAAAAAAAAAA8ULL)); - CHECK_TRUE(etl::manchester_valid(0xAAAAAAAAAAAAAAAAULL)); -} -} -; \ No newline at end of file + CHECK_EQUAL(0x5555, (etl::manchester_encode(0xFFU))); + CHECK_EQUAL(0xAAA9, (etl::manchester_encode(0x01U))); + CHECK_EQUAL(0x6AAA, (etl::manchester_encode(0x80U))); + } + + TEST(encode16) + { + CHECK_EQUAL(0x5555AAAA, (etl::manchester_encode(0xFF00UL))); + CHECK_EQUAL(0x6AAAAAA9, (etl::manchester_encode(0x8001UL))); + } + + TEST(encode32) + { + CHECK_EQUAL(0x6AAAAAA95555AAAA, (etl::manchester_encode(0x8001FF00ULL))); + } + + TEST(encode_span8) + { + std::array input{0x00, 0xFF, 0x01, 0x80}; + std::array input2{0xFF00, 0x8001}; + std::array input3{0x8001FF00}; + + std::array output1; + std::array output2; + std::array output3; + + std::array output4; + std::array output5; + std::array output6; + + std::array output7; + std::array output8; + std::array output9; + + etl::manchester_encode_span(input, output1); + etl::manchester_encode_span(input, output2); + etl::manchester_encode_span(input, output3); + + etl::manchester_encode_span(input2, output4); + etl::manchester_encode_span(input2, output5); + etl::manchester_encode_span(input2, output6); + + etl::manchester_encode_span(input3, output7); + etl::manchester_encode_span(input3, output8); + etl::manchester_encode_span(input3, output9); + + CHECK_EQUAL(0xAAAA, output1[0]); + CHECK_EQUAL(0x5555, output1[1]); + CHECK_EQUAL(0xAAA9, output1[2]); + CHECK_EQUAL(0x6AAA, output1[3]); + + CHECK_EQUAL(0xAAAA, output2[0]); + CHECK_EQUAL(0x5555, output2[1]); + CHECK_EQUAL(0xAAA9, output2[2]); + CHECK_EQUAL(0x6AAA, output2[3]); + + CHECK_EQUAL(0xAAAA, output3[0]); + CHECK_EQUAL(0x5555, output3[1]); + CHECK_EQUAL(0xAAA9, output3[2]); + CHECK_EQUAL(0x6AAA, output3[3]); + + CHECK_EQUAL(0x5555AAAA, output4[0]); + CHECK_EQUAL(0x6AAAAAA9, output4[1]); + + CHECK_EQUAL(0x5555AAAA, output5[0]); + CHECK_EQUAL(0x6AAAAAA9, output5[1]); + + CHECK_EQUAL(0x5555AAAA, output6[0]); + CHECK_EQUAL(0x6AAAAAA9, output6[1]); + + CHECK_EQUAL(0x6AAAAAA95555AAAA, output7[0]); + CHECK_EQUAL(0x6AAAAAA95555AAAA, output8[0]); + CHECK_EQUAL(0x6AAAAAA95555AAAA, output9[0]); + } + + TEST(encode8_transform) + { + std::array input{0x00, 0xFF, 0x01, 0x80}; + std::array output; + + std::transform(input.begin(), input.end(), output.begin(), etl::manchester_encode); + + CHECK_EQUAL(0xAAAA, output[0]); + CHECK_EQUAL(0x5555, output[1]); + CHECK_EQUAL(0xAAA9, output[2]); + CHECK_EQUAL(0x6AAA, output[3]); + } + + TEST(encode16_transform) + { + std::array input{0x00, 0xFF, 0x01, 0x80}; + std::array output; + + etl::span input16{reinterpret_cast(input.data()), 2}; + etl::span output32{reinterpret_cast(output.data()), 2}; + + std::transform(input16.begin(), input16.end(), output32.begin(), etl::manchester_encode); + + CHECK_EQUAL(0xAAAA, output[0]); + CHECK_EQUAL(0x5555, output[1]); + CHECK_EQUAL(0xAAA9, output[2]); + CHECK_EQUAL(0x6AAA, output[3]); + } + + TEST(encode32_transform) + { + std::array input{0x00, 0xFF, 0x01, 0x80}; + std::array output; + + etl::span input32{reinterpret_cast(input.data()), 1}; + etl::span output64{reinterpret_cast(output.data()), 1}; + + std::transform(input32.begin(), input32.end(), output64.begin(), etl::manchester_encode); + + CHECK_EQUAL(0xAAAA, output[0]); + CHECK_EQUAL(0x5555, output[1]); + CHECK_EQUAL(0xAAA9, output[2]); + CHECK_EQUAL(0x6AAA, output[3]); + } + + TEST(decode16) + { + CHECK_EQUAL(0x00, (etl::manchester_decode(0xAAAAUL))); + CHECK_EQUAL(0xFF, (etl::manchester_decode(0x5555UL))); + CHECK_EQUAL(0x01, (etl::manchester_decode(0xAAA9UL))); + CHECK_EQUAL(0x80, (etl::manchester_decode(0x6AAAUL))); + } + + TEST(decode32) + { + CHECK_EQUAL(0xFF00UL, (etl::manchester_decode(0x5555AAAAUL))); + CHECK_EQUAL(0x8001UL, (etl::manchester_decode(0x6AAAAAA9UL))); + } + + TEST(decode64) + { + CHECK_EQUAL(0x8001FF00ULL, (etl::manchester_decode(0x6AAAAAA95555AAAAULL))); + } + + TEST(valid16) + { + CHECK_TRUE(etl::manchester_valid(0xAAAAUL)); + CHECK_FALSE(etl::manchester_valid(0xAAA8UL)); + CHECK_TRUE(etl::manchester_valid(0xAAAAUL)); + } + + TEST(valid32) + { + CHECK_TRUE(etl::manchester_valid(0xAAAAAAAAUL)); + CHECK_FALSE(etl::manchester_valid(0xAAAAAAA8UL)); + CHECK_TRUE(etl::manchester_valid(0xAAAAAAAAUL)); + } + + TEST(valid64) + { + CHECK_TRUE(etl::manchester_valid(0xAAAAAAAAAAAAAAAAULL)); + CHECK_FALSE(etl::manchester_valid(0xAAAAAAAAAAAAAAA8ULL)); + CHECK_TRUE(etl::manchester_valid(0xAAAAAAAAAAAAAAAAULL)); + } +}; \ No newline at end of file From 724c5c9b271cc87c1004203378bfa23d4ffb4aa6 Mon Sep 17 00:00:00 2001 From: Timon Zijnge Date: Wed, 17 Dec 2025 16:32:50 +0100 Subject: [PATCH 03/46] manchester * Some functions can only be constexpr since C++14 --- include/etl/manchester.h | 12 ++++++------ test/test_manchester.cpp | 1 - 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/include/etl/manchester.h b/include/etl/manchester.h index 2a0e0b4be..a4b84914a 100644 --- a/include/etl/manchester.h +++ b/include/etl/manchester.h @@ -57,7 +57,7 @@ namespace etl ///\ingroup manchester //***************************************************************************** template - ETL_CONSTEXPR + ETL_CONSTEXPR14 typename etl::enable_if::value && etl::is_unsigned::value && (etl::integral_limits::bits == 8U) && etl::is_integral::value && etl::is_unsigned::value && (etl::integral_limits::bits == 16U), TOutput>::type @@ -77,7 +77,7 @@ namespace etl ///\ingroup manchester //***************************************************************************** template - ETL_CONSTEXPR + ETL_CONSTEXPR14 typename etl::enable_if::value && etl::is_unsigned::value && (etl::integral_limits::bits == 16U) && etl::is_integral::value && etl::is_unsigned::value && (etl::integral_limits::bits == 32U), TOutput>::type @@ -98,7 +98,7 @@ namespace etl ///\ingroup manchester //***************************************************************************** template - ETL_CONSTEXPR + ETL_CONSTEXPR14 typename etl::enable_if::value && etl::is_unsigned::value && (etl::integral_limits::bits == 32U) && etl::is_integral::value && etl::is_unsigned::value && (etl::integral_limits::bits == 64U), TOutput>::type @@ -160,7 +160,7 @@ namespace etl ///\ingroup manchester //***************************************************************************** template - ETL_CONSTEXPR + ETL_CONSTEXPR14 typename etl::enable_if::value && etl::is_unsigned::value && (etl::integral_limits::bits == 16U) && etl::is_integral::value && etl::is_unsigned::value && (etl::integral_limits::bits == 8U), TOutput>::type @@ -190,7 +190,7 @@ namespace etl ///\ingroup manchester //***************************************************************************** template - ETL_CONSTEXPR + ETL_CONSTEXPR14 typename etl::enable_if::value && etl::is_unsigned::value && (etl::integral_limits::bits == 32U) && etl::is_integral::value && etl::is_unsigned::value && (etl::integral_limits::bits == 16U), TOutput>::type @@ -220,7 +220,7 @@ namespace etl ///\ingroup manchester //***************************************************************************** template - ETL_CONSTEXPR + ETL_CONSTEXPR14 typename etl::enable_if::value && etl::is_unsigned::value && (etl::integral_limits::bits == 64U) && etl::is_integral::value && etl::is_unsigned::value && (etl::integral_limits::bits == 32U), TOutput>::type diff --git a/test/test_manchester.cpp b/test/test_manchester.cpp index 44ba85a17..fc47e52f0 100644 --- a/test/test_manchester.cpp +++ b/test/test_manchester.cpp @@ -7,7 +7,6 @@ SUITE(test_manchester) { - TEST(encode8){ CHECK_EQUAL(0xAAAA, (etl::manchester_encode(0x00U))); CHECK_EQUAL(0x5555, (etl::manchester_encode(0xFFU))); From fcc7c2fde6b28bb4c2f85267a341d548e3f68098 Mon Sep 17 00:00:00 2001 From: Timon Zijnge Date: Tue, 6 Jan 2026 10:44:23 +0100 Subject: [PATCH 04/46] manchester * Manchester decode and some refactoring --- include/etl/manchester.h | 294 +++++++++++++++++++++++++-------------- test/test_manchester.cpp | 182 +++++++++++------------- 2 files changed, 272 insertions(+), 204 deletions(-) diff --git a/include/etl/manchester.h b/include/etl/manchester.h index a4b84914a..87478d278 100644 --- a/include/etl/manchester.h +++ b/include/etl/manchester.h @@ -51,24 +51,78 @@ namespace etl /// Manchester encoding and decoding //*************************************************************************** + template + struct manchester_encoded + { + static_assert(sizeof(T) == 0, "Manchester encoding type should be one of [uint8_t, uint16_t, uint32_t]"); + }; + + template <> + struct manchester_encoded + { + using type = uint16_t; + }; + template <> + struct manchester_encoded + { + using type = uint32_t; + }; + template <> + struct manchester_encoded + { + using type = uint64_t; + }; + + template + struct manchester_decoded + { + static_assert(sizeof(T) == 0, "Manchester decoding type should be one of [uint16_t, uint32_t, uint64_t]"); + }; + + template <> + struct manchester_decoded + { + using type = uint8_t; + }; + template <> + struct manchester_decoded + { + using type = uint16_t; + }; + template <> + struct manchester_decoded + { + using type = uint32_t; + }; + + template + ETL_CONSTEXPR14 void manchester_encode_in_place(TEncode in, typename manchester_encoded::type& out) ETL_DELETE; + + template + ETL_NODISCARD ETL_CONSTEXPR14 typename manchester_encoded::type manchester_encode(TEncode in) ETL_DELETE; + #if ETL_USING_8BIT_TYPES //***************************************************************************** /// Manchester encode 8 bits ///\ingroup manchester //***************************************************************************** - template - ETL_CONSTEXPR14 - typename etl::enable_if::value && etl::is_unsigned::value && (etl::integral_limits::bits == 8U) && - etl::is_integral::value && etl::is_unsigned::value && (etl::integral_limits::bits == 16U), - TOutput>::type - manchester_encode(TInput in) + template <> + ETL_CONSTEXPR void manchester_encode_in_place(uint8_t in, uint16_t& out) { - TOutput out = in; + out = in; out = (out | (out << 4U)) & 0x0F0FU; out = (out | (out << 2U)) & 0x3333U; out = (out | (out << 1U)) & 0x5555U; - return (out | (out << 1U)) ^ 0xAAAAU; + out = (out | (out << 1U)) ^ 0xAAAAU; + } + + template <> + ETL_NODISCARD ETL_CONSTEXPR14 uint16_t manchester_encode(uint8_t in) + { + uint16_t out {}; + manchester_encode_in_place(in, out); + return out; } #endif @@ -76,20 +130,24 @@ namespace etl /// Manchester encode 16 bits ///\ingroup manchester //***************************************************************************** - template - ETL_CONSTEXPR14 - typename etl::enable_if::value && etl::is_unsigned::value && (etl::integral_limits::bits == 16U) && - etl::is_integral::value && etl::is_unsigned::value && (etl::integral_limits::bits == 32U), - TOutput>::type - manchester_encode(TInput in) + template <> + ETL_CONSTEXPR void manchester_encode_in_place(uint16_t in, uint32_t& out) { - TOutput out = in; + out = in; out = (out | (out << 8U)) & 0x00FF00FFUL; out = (out | (out << 4U)) & 0x0F0F0F0FUL; out = (out | (out << 2U)) & 0x33333333UL; out = (out | (out << 1U)) & 0x55555555UL; - return (out | (out << 1U)) ^ 0xAAAAAAAAUL; + out = (out | (out << 1U)) ^ 0xAAAAAAAAUL; + } + + template <> + ETL_NODISCARD ETL_CONSTEXPR14 uint32_t manchester_encode(uint16_t in) + { + uint32_t out {}; + manchester_encode_in_place(in, out); + return out; } #if ETL_USING_64BIT_TYPES @@ -97,79 +155,77 @@ namespace etl /// Manchester encode 32 bits ///\ingroup manchester //***************************************************************************** - template - ETL_CONSTEXPR14 - typename etl::enable_if::value && etl::is_unsigned::value && (etl::integral_limits::bits == 32U) && - etl::is_integral::value && etl::is_unsigned::value && (etl::integral_limits::bits == 64U), - TOutput>::type - manchester_encode(TInput in) + template <> + ETL_CONSTEXPR void manchester_encode_in_place(uint32_t in, uint64_t& out) { - TOutput out = in; + out = in; out = (out | (out << 16U)) & 0x0000FFFF0000FFFFULL; out = (out | (out << 8U)) & 0x00FF00FF00FF00FFULL; out = (out | (out << 4U)) & 0x0F0F0F0F0F0F0F0FULL; out = (out | (out << 2U)) & 0x3333333333333333ULL; out = (out | (out << 1U)) & 0x5555555555555555ULL; - return (out | (out << 1U)) ^ 0xAAAAAAAAAAAAAAAAULL; + out = (out | (out << 1U)) ^ 0xAAAAAAAAAAAAAAAAULL; } -#endif - template - struct select_uint; - - template <> - struct select_uint - { - using type = std::uint16_t; - }; - template <> - struct select_uint - { - using type = std::uint32_t; - }; template <> - struct select_uint + ETL_NODISCARD ETL_CONSTEXPR14 uint64_t manchester_encode(uint32_t in) { - using type = std::uint64_t; - }; + uint64_t out {}; + manchester_encode_in_place(in, out); + return out; + } +#endif - template ::type, typename TEncode = TInput> - typename etl::enable_if::value && etl::is_unsigned::value && - etl::is_integral::value && etl::is_unsigned::value && - etl::is_integral::value && etl::is_unsigned::value && - (etl::integral_limits::bits <= 32) && - (2 * etl::integral_limits::bits == etl::integral_limits::bits), - void>::type - manchester_encode_span(etl::span input, etl::span output) + // What happens on systems that don't have uint8_t / where CHAR_BIT is e.g. 16? + template + void manchester_encode_span(etl::span input, etl::span output) { - using TOut = typename select_uint::type; + ETL_ASSERT(output.size() >= input.size() * 2, ""); + ETL_ASSERT(input.size() % sizeof(TEncode) == 0, ""); - ETL_ASSERT(output.size() >= input.size(), ""); - ETL_ASSERT((input.size() * sizeof(TInput)) % sizeof(TEncode) == 0, ""); + while (!input.empty()) + { + const TEncode& in = *reinterpret_cast(input.data()); + typename etl::manchester_encoded::type& out = *reinterpret_cast::type*>(output.data()); - etl::span in{reinterpret_cast(input.data()), (sizeof(TInput) * input.size()) / sizeof(TEncode)}; - etl::span out{reinterpret_cast(output.data()), (sizeof(TOutput) * output.size()) / sizeof(TOut)}; + etl::manchester_encode_in_place(in, out); - etl::transform(in.begin(), in.end(), out.begin(), etl::manchester_encode); + input.advance(sizeof(TEncode)); + output.advance(sizeof(etl::manchester_encoded::type)); + } } + + template + ETL_CONSTEXPR void manchester_decode_in_place(TDecode in, typename manchester_decoded::type& out) ETL_DELETE; + + template + ETL_NODISCARD ETL_CONSTEXPR14 typename manchester_decoded::type manchester_decode(TDecode in) ETL_DELETE; + + template + ETL_NODISCARD ETL_CONSTEXPR bool manchester_valid(TDecode encoded) ETL_DELETE; + #if ETL_USING_8BIT_TYPES //***************************************************************************** /// Manchester decode 16 bits ///\ingroup manchester //***************************************************************************** - template - ETL_CONSTEXPR14 - typename etl::enable_if::value && etl::is_unsigned::value && (etl::integral_limits::bits == 16U) && - etl::is_integral::value && etl::is_unsigned::value && (etl::integral_limits::bits == 8U), - TOutput>::type - manchester_decode(TInput in) + template<> + ETL_CONSTEXPR void manchester_decode_in_place(uint16_t in, uint8_t& out) + { + in = (in ^ 0xAAAAU) & 0x5555U; + in = (in | (in >> 1)) & 0x3333U; + in = (in | (in >> 2)) & 0x0F0FU; + out = static_cast(in | (in >> 4U)); + } + + template<> + ETL_NODISCARD ETL_NODISCARD ETL_CONSTEXPR14 uint8_t manchester_decode(uint16_t in) { - TInput out = (in ^ 0xAAAAU) & 0x5555U; - out = (out | (out >> 1)) & 0x3333U; - out = (out | (out >> 2)) & 0x0F0FU; - return static_cast(out | (out >> 4U)); + uint8_t out {}; + manchester_decode_in_place(in, out); + return out; } #endif @@ -177,73 +233,105 @@ namespace etl /// Manchester valid 16 bits ///\ingroup manchester //***************************************************************************** - template - ETL_CONSTEXPR - typename etl::enable_if::value && etl::is_unsigned::value && (etl::integral_limits::bits == 16U), bool>::type - manchester_valid(TInput in) + template <> + ETL_NODISCARD ETL_CONSTEXPR bool manchester_valid(uint16_t encoded) { - return (((in ^ (in >> 1)) & 0x5555U) == 0x5555U); + return (((encoded ^ (encoded >> 1)) & 0x5555U) == 0x5555U); } //***************************************************************************** /// Manchester decode 32 bits ///\ingroup manchester //***************************************************************************** - template - ETL_CONSTEXPR14 - typename etl::enable_if::value && etl::is_unsigned::value && (etl::integral_limits::bits == 32U) && - etl::is_integral::value && etl::is_unsigned::value && (etl::integral_limits::bits == 16U), - TOutput>::type - manchester_decode(TInput in) + template<> + ETL_CONSTEXPR void manchester_decode_in_place(uint32_t in, uint16_t& out) { - TInput out = (in ^ 0xAAAAAAAAUL) & 0x55555555UL; - out = (out | (out >> 1)) & 0x33333333UL; - out = (out | (out >> 2)) & 0x0F0F0F0FUL; - out = (out | (out >> 4)) & 0x00FF00FFUL; - return static_cast(out | (out >> 8U)); + in = (in ^ 0xAAAAAAAAUL) & 0x55555555UL; + in = (in | (in >> 1)) & 0x33333333UL; + in = (in | (in >> 2)) & 0x0F0F0F0FUL; + in = (in | (in >> 4)) & 0x00FF00FFUL; + out = static_cast(in | (in >> 8U)); + } + + template<> + ETL_NODISCARD ETL_CONSTEXPR14 uint16_t manchester_decode(uint32_t in) + { + uint16_t out {}; + manchester_decode_in_place(in, out); + return out; } //***************************************************************************** /// Manchester valid 32 bits ///\ingroup manchester //***************************************************************************** - template - ETL_CONSTEXPR - typename etl::enable_if::value && etl::is_unsigned::value && (etl::integral_limits::bits == 32U), bool>::type - manchester_valid(TInput in) + template <> + ETL_NODISCARD ETL_CONSTEXPR bool manchester_valid(uint32_t encoded) { - return (((in ^ (in >> 1)) & 0x55555555U) == 0x55555555U); + return (((encoded ^ (encoded >> 1)) & 0x55555555U) == 0x55555555U); } //***************************************************************************** /// Manchester decode 64 bits ///\ingroup manchester //***************************************************************************** - template - ETL_CONSTEXPR14 - typename etl::enable_if::value && etl::is_unsigned::value && (etl::integral_limits::bits == 64U) && - etl::is_integral::value && etl::is_unsigned::value && (etl::integral_limits::bits == 32U), - TOutput>::type - manchester_decode(TInput in) + template<> + ETL_CONSTEXPR void manchester_decode_in_place(uint64_t in, uint32_t& out) { - TInput out = (in ^ 0xAAAAAAAAAAAAAAAAULL) & 0x5555555555555555ULL; - out = (out | (out >> 1)) & 0x3333333333333333ULL; - out = (out | (out >> 2)) & 0x0F0F0F0F0F0F0F0FULL; - out = (out | (out >> 4)) & 0x00FF00FF00FF00FFULL; - out = (out | (out >> 8)) & 0x0000FFFF0000FFFFULL; - return static_cast(out | (out >> 16U)); + in = (in ^ 0xAAAAAAAAAAAAAAAAULL) & 0x5555555555555555ULL; + in = (in | (in >> 1)) & 0x3333333333333333ULL; + in = (in | (in >> 2)) & 0x0F0F0F0F0F0F0F0FULL; + in = (in | (in >> 4)) & 0x00FF00FF00FF00FFULL; + in = (in | (in >> 8)) & 0x0000FFFF0000FFFFULL; + out = static_cast(in | (in >> 16U)); + } + + template<> + ETL_NODISCARD ETL_CONSTEXPR14 uint32_t manchester_decode(uint64_t in) + { + uint32_t out {}; + manchester_decode_in_place(in, out); + return out; } //***************************************************************************** /// Manchester valid 64 bits ///\ingroup manchester //***************************************************************************** - template - ETL_CONSTEXPR - typename etl::enable_if::value && etl::is_unsigned::value && (etl::integral_limits::bits == 64U), bool>::type - manchester_valid(TInput in) + template <> + ETL_NODISCARD ETL_CONSTEXPR bool manchester_valid(uint64_t encoded) { - return (((in ^ (in >> 1)) & 0x5555555555555555U) == 0x5555555555555555U); + return (((encoded ^ (encoded >> 1)) & 0x5555555555555555U) == 0x5555555555555555U); + } + + template ::type> + void manchester_decode_span(etl::span input, etl::span output) + { + ETL_ASSERT(input.size() >= output.size() * 2, ""); + ETL_ASSERT(input.size() % sizeof(TDecode) == 0, ""); + + while (!input.empty()) + { + const TDecode& in = *reinterpret_cast(input.data()); + typename etl::manchester_decoded::type& out = *reinterpret_cast::type*>(output.data()); + + etl::manchester_decode_in_place(in, out); + + input.advance(sizeof(TDecode)); + output.advance(sizeof(etl::manchester_decoded::type)); + } + } + + ETL_CONSTEXPR14 void manchester_decode_span_constexpr(etl::span input, etl::span output) + { + ETL_ASSERT(input.size() >= output.size() * 2, ""); + ETL_ASSERT(input.size() % sizeof(uint16_t) == 0, ""); + + for (size_t i = 0; i < output.size(); ++i) + { + const uint16_t encoded = (static_cast(input[i]) << 8) | input[i + 1]; + output[i] = etl::manchester_decode(encoded); + } } } // namespace etl diff --git a/test/test_manchester.cpp b/test/test_manchester.cpp index fc47e52f0..f918a3a9e 100644 --- a/test/test_manchester.cpp +++ b/test/test_manchester.cpp @@ -1,10 +1,11 @@ #include "etl/manchester.h" #include "unit_test_framework.h" -#include -#include +#include +#include #include + SUITE(test_manchester) { TEST(encode8){ @@ -12,6 +13,11 @@ SUITE(test_manchester) CHECK_EQUAL(0x5555, (etl::manchester_encode(0xFFU))); CHECK_EQUAL(0xAAA9, (etl::manchester_encode(0x01U))); CHECK_EQUAL(0x6AAA, (etl::manchester_encode(0x80U))); + + static_assert(0xAAAA == etl::manchester_encode(0x00U)); + static_assert(0x5555 == etl::manchester_encode(0xFFU)); + static_assert(0xAAA9 == etl::manchester_encode(0x01U)); + static_assert(0x6AAA == etl::manchester_encode(0x80U)); } TEST(encode16) @@ -25,103 +31,40 @@ SUITE(test_manchester) CHECK_EQUAL(0x6AAAAAA95555AAAA, (etl::manchester_encode(0x8001FF00ULL))); } - TEST(encode_span8) + TEST(encode_span) { - std::array input{0x00, 0xFF, 0x01, 0x80}; - std::array input2{0xFF00, 0x8001}; - std::array input3{0x8001FF00}; - - std::array output1; - std::array output2; - std::array output3; - - std::array output4; - std::array output5; - std::array output6; - - std::array output7; - std::array output8; - std::array output9; - - etl::manchester_encode_span(input, output1); - etl::manchester_encode_span(input, output2); - etl::manchester_encode_span(input, output3); - - etl::manchester_encode_span(input2, output4); - etl::manchester_encode_span(input2, output5); - etl::manchester_encode_span(input2, output6); - - etl::manchester_encode_span(input3, output7); - etl::manchester_encode_span(input3, output8); - etl::manchester_encode_span(input3, output9); - - CHECK_EQUAL(0xAAAA, output1[0]); - CHECK_EQUAL(0x5555, output1[1]); - CHECK_EQUAL(0xAAA9, output1[2]); - CHECK_EQUAL(0x6AAA, output1[3]); - - CHECK_EQUAL(0xAAAA, output2[0]); - CHECK_EQUAL(0x5555, output2[1]); - CHECK_EQUAL(0xAAA9, output2[2]); - CHECK_EQUAL(0x6AAA, output2[3]); - - CHECK_EQUAL(0xAAAA, output3[0]); - CHECK_EQUAL(0x5555, output3[1]); - CHECK_EQUAL(0xAAA9, output3[2]); - CHECK_EQUAL(0x6AAA, output3[3]); - - CHECK_EQUAL(0x5555AAAA, output4[0]); - CHECK_EQUAL(0x6AAAAAA9, output4[1]); - - CHECK_EQUAL(0x5555AAAA, output5[0]); - CHECK_EQUAL(0x6AAAAAA9, output5[1]); - - CHECK_EQUAL(0x5555AAAA, output6[0]); - CHECK_EQUAL(0x6AAAAAA9, output6[1]); - - CHECK_EQUAL(0x6AAAAAA95555AAAA, output7[0]); - CHECK_EQUAL(0x6AAAAAA95555AAAA, output8[0]); - CHECK_EQUAL(0x6AAAAAA95555AAAA, output9[0]); + etl::array input{0x00, 0xFF, 0x01, 0x80}; + + alignas(uint16_t) etl::array output0; + alignas(uint16_t) etl::array output1; + alignas(uint32_t) etl::array output2; + alignas(uint64_t) etl::array output3; + + etl::manchester_encode_span(input, output0); + etl::manchester_encode_span(input, output1); + etl::manchester_encode_span(input, output2); + etl::manchester_encode_span(input, output3); + + CHECK_EQUAL(0xAA, output0[0]); + CHECK_EQUAL(0xAA, output0[1]); + CHECK_EQUAL(0x55, output0[2]); + CHECK_EQUAL(0x55, output0[3]); + CHECK_EQUAL(0xA9, output0[4]); + CHECK_EQUAL(0xAA, output0[5]); + CHECK_EQUAL(0xAA, output0[6]); + CHECK_EQUAL(0x6A, output0[7]); + + CHECK_TRUE(output0 == output1); + CHECK_TRUE(output0 == output2); + CHECK_TRUE(output0 == output3); } TEST(encode8_transform) { - std::array input{0x00, 0xFF, 0x01, 0x80}; - std::array output; + etl::array input{0x00, 0xFF, 0x01, 0x80}; + etl::array output; - std::transform(input.begin(), input.end(), output.begin(), etl::manchester_encode); - - CHECK_EQUAL(0xAAAA, output[0]); - CHECK_EQUAL(0x5555, output[1]); - CHECK_EQUAL(0xAAA9, output[2]); - CHECK_EQUAL(0x6AAA, output[3]); - } - - TEST(encode16_transform) - { - std::array input{0x00, 0xFF, 0x01, 0x80}; - std::array output; - - etl::span input16{reinterpret_cast(input.data()), 2}; - etl::span output32{reinterpret_cast(output.data()), 2}; - - std::transform(input16.begin(), input16.end(), output32.begin(), etl::manchester_encode); - - CHECK_EQUAL(0xAAAA, output[0]); - CHECK_EQUAL(0x5555, output[1]); - CHECK_EQUAL(0xAAA9, output[2]); - CHECK_EQUAL(0x6AAA, output[3]); - } - - TEST(encode32_transform) - { - std::array input{0x00, 0xFF, 0x01, 0x80}; - std::array output; - - etl::span input32{reinterpret_cast(input.data()), 1}; - etl::span output64{reinterpret_cast(output.data()), 1}; - - std::transform(input32.begin(), input32.end(), output64.begin(), etl::manchester_encode); + etl::transform(input.begin(), input.end(), output.begin(), etl::manchester_encode); CHECK_EQUAL(0xAAAA, output[0]); CHECK_EQUAL(0x5555, output[1]); @@ -131,21 +74,45 @@ SUITE(test_manchester) TEST(decode16) { - CHECK_EQUAL(0x00, (etl::manchester_decode(0xAAAAUL))); - CHECK_EQUAL(0xFF, (etl::manchester_decode(0x5555UL))); - CHECK_EQUAL(0x01, (etl::manchester_decode(0xAAA9UL))); - CHECK_EQUAL(0x80, (etl::manchester_decode(0x6AAAUL))); + CHECK_EQUAL(0x00, (etl::manchester_decode(0xAAAAUL))); + CHECK_EQUAL(0xFF, (etl::manchester_decode(0x5555UL))); + CHECK_EQUAL(0x01, (etl::manchester_decode(0xAAA9UL))); + CHECK_EQUAL(0x80, (etl::manchester_decode(0x6AAAUL))); } TEST(decode32) { - CHECK_EQUAL(0xFF00UL, (etl::manchester_decode(0x5555AAAAUL))); - CHECK_EQUAL(0x8001UL, (etl::manchester_decode(0x6AAAAAA9UL))); + CHECK_EQUAL(0xFF00UL, (etl::manchester_decode(0x5555AAAAUL))); + CHECK_EQUAL(0x8001UL, (etl::manchester_decode(0x6AAAAAA9UL))); } TEST(decode64) { - CHECK_EQUAL(0x8001FF00ULL, (etl::manchester_decode(0x6AAAAAA95555AAAAULL))); + CHECK_EQUAL(0x8001FF00ULL, (etl::manchester_decode(0x6AAAAAA95555AAAAULL))); + } + + TEST(decode_span) + { + etl::array input{0xAA, 0xAA, 0x55, 0x55, 0xA9, 0xAA, 0XAA, 0x6A}; + + alignas(uint8_t) etl::array output0; + alignas(uint8_t) etl::array output1; + alignas(uint16_t) etl::array output2; + alignas(uint32_t) etl::array output3; + + etl::manchester_decode_span(input, output0); + etl::manchester_decode_span(input, output1); + etl::manchester_decode_span(input, output2); + etl::manchester_decode_span(input, output3); + + CHECK_EQUAL(0x00, output0[0]); + CHECK_EQUAL(0xFF, output0[1]); + CHECK_EQUAL(0x01, output0[2]); + CHECK_EQUAL(0x80, output0[3]); + + CHECK_TRUE(output0 == output1); + CHECK_TRUE(output0 == output2); + CHECK_TRUE(output0 == output3); } TEST(valid16) @@ -168,4 +135,17 @@ SUITE(test_manchester) CHECK_FALSE(etl::manchester_valid(0xAAAAAAAAAAAAAAA8ULL)); CHECK_TRUE(etl::manchester_valid(0xAAAAAAAAAAAAAAAAULL)); } -}; \ No newline at end of file +}; + +constexpr etl::array manchester_encoded(etl::span input) +{ + alignas(uint8_t) etl::array output {0, 0, 0, 0}; + etl::manchester_decode_span_constexpr(input, output); + + return output; +} + +constexpr etl::array input{0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0XAA, 0xAA}; + +constexpr etl::array bla = manchester_encoded(input); +static_assert(bla[0] == 0); \ No newline at end of file From 718f15fe7fb45bc9b7bfb3b02f0b5e234b3de60f Mon Sep 17 00:00:00 2001 From: Timon Zijnge Date: Tue, 6 Jan 2026 11:14:20 +0100 Subject: [PATCH 05/46] manchester * Added some missing typenames --- include/etl/manchester.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/include/etl/manchester.h b/include/etl/manchester.h index 87478d278..9b106e8da 100644 --- a/include/etl/manchester.h +++ b/include/etl/manchester.h @@ -187,12 +187,12 @@ namespace etl while (!input.empty()) { const TEncode& in = *reinterpret_cast(input.data()); - typename etl::manchester_encoded::type& out = *reinterpret_cast::type*>(output.data()); + typename etl::manchester_encoded::type& out = *reinterpret_cast::type*>(output.data()); etl::manchester_encode_in_place(in, out); input.advance(sizeof(TEncode)); - output.advance(sizeof(etl::manchester_encoded::type)); + output.advance(sizeof(typename etl::manchester_encoded::type)); } } @@ -313,12 +313,12 @@ namespace etl while (!input.empty()) { const TDecode& in = *reinterpret_cast(input.data()); - typename etl::manchester_decoded::type& out = *reinterpret_cast::type*>(output.data()); + typename etl::manchester_decoded::type& out = *reinterpret_cast::type*>(output.data()); etl::manchester_decode_in_place(in, out); input.advance(sizeof(TDecode)); - output.advance(sizeof(etl::manchester_decoded::type)); + output.advance(sizeof(typename etl::manchester_decoded::type)); } } From 451fc1d5185d864937de76d7bc1b63b38b5e3b84 Mon Sep 17 00:00:00 2001 From: Timon Zijnge Date: Tue, 6 Jan 2026 11:21:57 +0100 Subject: [PATCH 06/46] manchester * constexpr void function not allowed in C++11 --- include/etl/manchester.h | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/include/etl/manchester.h b/include/etl/manchester.h index 9b106e8da..7fde4099d 100644 --- a/include/etl/manchester.h +++ b/include/etl/manchester.h @@ -107,7 +107,7 @@ namespace etl ///\ingroup manchester //***************************************************************************** template <> - ETL_CONSTEXPR void manchester_encode_in_place(uint8_t in, uint16_t& out) + ETL_CONSTEXPR14 void manchester_encode_in_place(uint8_t in, uint16_t& out) { out = in; @@ -131,7 +131,7 @@ namespace etl ///\ingroup manchester //***************************************************************************** template <> - ETL_CONSTEXPR void manchester_encode_in_place(uint16_t in, uint32_t& out) + ETL_CONSTEXPR14 void manchester_encode_in_place(uint16_t in, uint32_t& out) { out = in; @@ -156,7 +156,7 @@ namespace etl ///\ingroup manchester //***************************************************************************** template <> - ETL_CONSTEXPR void manchester_encode_in_place(uint32_t in, uint64_t& out) + ETL_CONSTEXPR14 void manchester_encode_in_place(uint32_t in, uint64_t& out) { out = in; @@ -198,7 +198,7 @@ namespace etl template - ETL_CONSTEXPR void manchester_decode_in_place(TDecode in, typename manchester_decoded::type& out) ETL_DELETE; + ETL_CONSTEXPR14 void manchester_decode_in_place(TDecode in, typename manchester_decoded::type& out) ETL_DELETE; template ETL_NODISCARD ETL_CONSTEXPR14 typename manchester_decoded::type manchester_decode(TDecode in) ETL_DELETE; @@ -212,7 +212,7 @@ namespace etl ///\ingroup manchester //***************************************************************************** template<> - ETL_CONSTEXPR void manchester_decode_in_place(uint16_t in, uint8_t& out) + ETL_CONSTEXPR14 void manchester_decode_in_place(uint16_t in, uint8_t& out) { in = (in ^ 0xAAAAU) & 0x5555U; in = (in | (in >> 1)) & 0x3333U; @@ -244,7 +244,7 @@ namespace etl ///\ingroup manchester //***************************************************************************** template<> - ETL_CONSTEXPR void manchester_decode_in_place(uint32_t in, uint16_t& out) + ETL_CONSTEXPR14 void manchester_decode_in_place(uint32_t in, uint16_t& out) { in = (in ^ 0xAAAAAAAAUL) & 0x55555555UL; in = (in | (in >> 1)) & 0x33333333UL; @@ -276,7 +276,7 @@ namespace etl ///\ingroup manchester //***************************************************************************** template<> - ETL_CONSTEXPR void manchester_decode_in_place(uint64_t in, uint32_t& out) + ETL_CONSTEXPR14 void manchester_decode_in_place(uint64_t in, uint32_t& out) { in = (in ^ 0xAAAAAAAAAAAAAAAAULL) & 0x5555555555555555ULL; in = (in | (in >> 1)) & 0x3333333333333333ULL; From 076fe5d4a351f5acf37da99a5e7857e42d898add Mon Sep 17 00:00:00 2001 From: Timon Zijnge Date: Tue, 6 Jan 2026 11:33:00 +0100 Subject: [PATCH 07/46] manchester * condition on static_assert tests --- CMakeLists.txt | 2 +- test/test_manchester.cpp | 6 +++++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index cbe4564db..ee3d525db 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -13,7 +13,7 @@ endif() project(etl VERSION ${ETL_VERSION} LANGUAGES CXX) -option(BUILD_TESTS "Build unit tests" OFF) +option(BUILD_TESTS "Build unit tests" ON) option(NO_STL "No STL" OFF) # There is a bug on old gcc versions for some targets that causes all system headers # to be implicitly wrapped with 'extern "C"' diff --git a/test/test_manchester.cpp b/test/test_manchester.cpp index f918a3a9e..ae3cefe47 100644 --- a/test/test_manchester.cpp +++ b/test/test_manchester.cpp @@ -14,10 +14,12 @@ SUITE(test_manchester) CHECK_EQUAL(0xAAA9, (etl::manchester_encode(0x01U))); CHECK_EQUAL(0x6AAA, (etl::manchester_encode(0x80U))); +#if ETL_USING_CPP14 static_assert(0xAAAA == etl::manchester_encode(0x00U)); static_assert(0x5555 == etl::manchester_encode(0xFFU)); static_assert(0xAAA9 == etl::manchester_encode(0x01U)); static_assert(0x6AAA == etl::manchester_encode(0x80U)); +#endif } TEST(encode16) @@ -137,6 +139,7 @@ SUITE(test_manchester) } }; +#if ETL_USING_CPP14 constexpr etl::array manchester_encoded(etl::span input) { alignas(uint8_t) etl::array output {0, 0, 0, 0}; @@ -148,4 +151,5 @@ constexpr etl::array manchester_encoded(etl::span input{0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0XAA, 0xAA}; constexpr etl::array bla = manchester_encoded(input); -static_assert(bla[0] == 0); \ No newline at end of file +static_assert(bla[0] == 0); +#endif \ No newline at end of file From eefe86b9904fa397101889d9c31fd1bc73165a6c Mon Sep 17 00:00:00 2001 From: Timon Zijnge Date: Tue, 6 Jan 2026 11:46:06 +0100 Subject: [PATCH 08/46] manchester * revert CMakeLists.txt * Using ETL_STATIC_ASSERT * Some cleanup --- CMakeLists.txt | 2 +- include/etl/manchester.h | 7 +++---- test/test_manchester.cpp | 5 +---- 3 files changed, 5 insertions(+), 9 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index ee3d525db..cbe4564db 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -13,7 +13,7 @@ endif() project(etl VERSION ${ETL_VERSION} LANGUAGES CXX) -option(BUILD_TESTS "Build unit tests" ON) +option(BUILD_TESTS "Build unit tests" OFF) option(NO_STL "No STL" OFF) # There is a bug on old gcc versions for some targets that causes all system headers # to be implicitly wrapped with 'extern "C"' diff --git a/include/etl/manchester.h b/include/etl/manchester.h index 7fde4099d..a86b71add 100644 --- a/include/etl/manchester.h +++ b/include/etl/manchester.h @@ -40,10 +40,9 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ******************************************************************************/ -#include #include #include -#include +#include namespace etl { @@ -54,7 +53,7 @@ namespace etl template struct manchester_encoded { - static_assert(sizeof(T) == 0, "Manchester encoding type should be one of [uint8_t, uint16_t, uint32_t]"); + ETL_STATIC_ASSERT(sizeof(T) == 0, "Manchester encoding type should be one of [uint8_t, uint16_t, uint32_t]"); }; template <> @@ -76,7 +75,7 @@ namespace etl template struct manchester_decoded { - static_assert(sizeof(T) == 0, "Manchester decoding type should be one of [uint16_t, uint32_t, uint64_t]"); + ETL_STATIC_ASSERT(sizeof(T) == 0, "Manchester decoding type should be one of [uint16_t, uint32_t, uint64_t]"); }; template <> diff --git a/test/test_manchester.cpp b/test/test_manchester.cpp index ae3cefe47..cbdb47612 100644 --- a/test/test_manchester.cpp +++ b/test/test_manchester.cpp @@ -15,10 +15,7 @@ SUITE(test_manchester) CHECK_EQUAL(0x6AAA, (etl::manchester_encode(0x80U))); #if ETL_USING_CPP14 - static_assert(0xAAAA == etl::manchester_encode(0x00U)); - static_assert(0x5555 == etl::manchester_encode(0xFFU)); - static_assert(0xAAA9 == etl::manchester_encode(0x01U)); - static_assert(0x6AAA == etl::manchester_encode(0x80U)); + static_assert(0xAAAA == etl::manchester_encode(0x00U), "Compile time manchester encoding failed"); #endif } From f224fbcf619d8e5c1ec5cc8cb1b942c173fd9d13 Mon Sep 17 00:00:00 2001 From: Timon Zijnge Date: Tue, 6 Jan 2026 11:51:10 +0100 Subject: [PATCH 09/46] manchester * Added static_assert message --- test/test_manchester.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/test_manchester.cpp b/test/test_manchester.cpp index cbdb47612..15521af2b 100644 --- a/test/test_manchester.cpp +++ b/test/test_manchester.cpp @@ -148,5 +148,5 @@ constexpr etl::array manchester_encoded(etl::span input{0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0XAA, 0xAA}; constexpr etl::array bla = manchester_encoded(input); -static_assert(bla[0] == 0); +static_assert(bla[0] == 0, "Compile time computation of many values failed"); #endif \ No newline at end of file From 16f9bb8a1e5d2e92ce78927df72a7bc91cffe7f1 Mon Sep 17 00:00:00 2001 From: Timon Zijnge Date: Tue, 6 Jan 2026 12:10:05 +0100 Subject: [PATCH 10/46] manchester * Added compile time tests --- test/test_manchester.cpp | 35 ++++++++++++++++++++++++++++++++--- 1 file changed, 32 insertions(+), 3 deletions(-) diff --git a/test/test_manchester.cpp b/test/test_manchester.cpp index 15521af2b..f70f1fddb 100644 --- a/test/test_manchester.cpp +++ b/test/test_manchester.cpp @@ -23,11 +23,19 @@ SUITE(test_manchester) { CHECK_EQUAL(0x5555AAAA, (etl::manchester_encode(0xFF00UL))); CHECK_EQUAL(0x6AAAAAA9, (etl::manchester_encode(0x8001UL))); + +#if ETL_USING_CPP14 + static_assert(0x5555AAAA == etl::manchester_encode(0xFF00UL), "Compile time manchester encoding failed"); +#endif } TEST(encode32) { CHECK_EQUAL(0x6AAAAAA95555AAAA, (etl::manchester_encode(0x8001FF00ULL))); + +#if ETL_USING_CPP14 + static_assert(0x6AAAAAA95555AAAA == etl::manchester_encode(0x8001FF00ULL), "Compile time manchester encoding failed"); +#endif } TEST(encode_span) @@ -77,17 +85,29 @@ SUITE(test_manchester) CHECK_EQUAL(0xFF, (etl::manchester_decode(0x5555UL))); CHECK_EQUAL(0x01, (etl::manchester_decode(0xAAA9UL))); CHECK_EQUAL(0x80, (etl::manchester_decode(0x6AAAUL))); + +#if ETL_USING_CPP14 + static_assert(0x00 == etl::manchester_decode(0xAAAAUL), "Compile time manchester decoding failed"); +#endif } TEST(decode32) { CHECK_EQUAL(0xFF00UL, (etl::manchester_decode(0x5555AAAAUL))); CHECK_EQUAL(0x8001UL, (etl::manchester_decode(0x6AAAAAA9UL))); + +#if ETL_USING_CPP14 + static_assert(0xFF00UL == etl::manchester_decode(0x5555AAAAUL), "Compile time manchester decoding failed"); +#endif } TEST(decode64) { CHECK_EQUAL(0x8001FF00ULL, (etl::manchester_decode(0x6AAAAAA95555AAAAULL))); + +#if ETL_USING_CPP14 + static_assert(0x8001FF00ULL == etl::manchester_decode(0x6AAAAAA95555AAAAULL), "Compile time manchester decoding failed"); +#endif } TEST(decode_span) @@ -118,21 +138,30 @@ SUITE(test_manchester) { CHECK_TRUE(etl::manchester_valid(0xAAAAUL)); CHECK_FALSE(etl::manchester_valid(0xAAA8UL)); - CHECK_TRUE(etl::manchester_valid(0xAAAAUL)); + +#if ETL_USING_CPP14 + static_assert(etl::manchester_valid(0xAAAAUL), "Compile time manchester validity check failed"); +#endif } TEST(valid32) { CHECK_TRUE(etl::manchester_valid(0xAAAAAAAAUL)); CHECK_FALSE(etl::manchester_valid(0xAAAAAAA8UL)); - CHECK_TRUE(etl::manchester_valid(0xAAAAAAAAUL)); + +#if ETL_USING_CPP14 + static_assert(etl::manchester_valid(0xAAAAAAAAUL), "Compile time manchester validity check failed"); +#endif } TEST(valid64) { CHECK_TRUE(etl::manchester_valid(0xAAAAAAAAAAAAAAAAULL)); CHECK_FALSE(etl::manchester_valid(0xAAAAAAAAAAAAAAA8ULL)); - CHECK_TRUE(etl::manchester_valid(0xAAAAAAAAAAAAAAAAULL)); + +#if ETL_USING_CPP14 + static_assert(etl::manchester_valid(0xAAAAAAAAAAAAAAAAULL), "Compile time manchester validity check failed"); +#endif } }; From 0a6e349f8f4909567ebf101b76eff3c1eb7dbdb4 Mon Sep 17 00:00:00 2001 From: Timon Zijnge Date: Tue, 6 Jan 2026 17:40:23 +0100 Subject: [PATCH 11/46] manchester * Added invert manchester * Some refactoring --- include/etl/manchester.h | 409 ++++++++++++++++++++++----------------- test/test_manchester.cpp | 239 ++++++++++++++++++----- 2 files changed, 420 insertions(+), 228 deletions(-) diff --git a/include/etl/manchester.h b/include/etl/manchester.h index a86b71add..9ac79ac09 100644 --- a/include/etl/manchester.h +++ b/include/etl/manchester.h @@ -1,14 +1,6 @@ #ifndef ETL_MANCHESTER_INCLUDED #define ETL_MANCHESTER_INCLUDED -// #include -// #include - -// namespace manchester -// { -// void encode(const etl::span &input, const etl::span &output); -// bool decode(const etl::span &input, const etl::span &output); -// } ///\file @@ -46,59 +38,72 @@ SOFTWARE. namespace etl { - //*************************************************************************** - /// Manchester encoding and decoding - //*************************************************************************** - - template - struct manchester_encoded - { - ETL_STATIC_ASSERT(sizeof(T) == 0, "Manchester encoding type should be one of [uint8_t, uint16_t, uint32_t]"); - }; - - template <> - struct manchester_encoded - { - using type = uint16_t; - }; - template <> - struct manchester_encoded - { - using type = uint32_t; - }; - template <> - struct manchester_encoded - { - using type = uint64_t; - }; - - template - struct manchester_decoded - { - ETL_STATIC_ASSERT(sizeof(T) == 0, "Manchester decoding type should be one of [uint16_t, uint32_t, uint64_t]"); - }; - - template <> - struct manchester_decoded - { - using type = uint8_t; - }; - template <> - struct manchester_decoded - { - using type = uint16_t; - }; - template <> - struct manchester_decoded - { - using type = uint32_t; - }; - - template - ETL_CONSTEXPR14 void manchester_encode_in_place(TEncode in, typename manchester_encoded::type& out) ETL_DELETE; - - template - ETL_NODISCARD ETL_CONSTEXPR14 typename manchester_encoded::type manchester_encode(TEncode in) ETL_DELETE; + //*************************************************************************** + /// Manchester encoding and decoding + //*************************************************************************** + + template + struct manchester_encoded + { + ETL_STATIC_ASSERT(sizeof(T) == 0, "Manchester encoding type should be one of [uint8_t, uint16_t, uint32_t]"); + }; + + template <> + struct manchester_encoded + { + typedef uint16_t type; + }; + template <> + struct manchester_encoded + { + typedef uint32_t type; + }; + template <> + struct manchester_encoded + { + typedef uint64_t type; + }; + + template + struct manchester_decoded + { + ETL_STATIC_ASSERT(sizeof(T) == 0, "Manchester decoding type should be one of [uint16_t, uint32_t, uint64_t]"); + }; + + template <> + struct manchester_decoded + { + typedef uint8_t type; + }; + template <> + struct manchester_decoded + { + typedef uint16_t type; + }; + template <> + struct manchester_decoded + { + typedef uint32_t type; + }; + + struct manchester_type_normal + { + static const uint64_t invert_mask = 0x0000000000000000; + }; + + struct manchester_type_inverted + { + static const uint64_t invert_mask = 0xFFFFFFFFFFFFFFFF; + }; + + template + struct manchester_base + { + template + static ETL_CONSTEXPR14 void encode_in_place(TChunk in, typename manchester_encoded::type& out) ETL_DELETE; + + template + static ETL_NODISCARD ETL_CONSTEXPR14 typename manchester_encoded::type encode(TChunk in) ETL_DELETE; #if ETL_USING_8BIT_TYPES //***************************************************************************** @@ -106,22 +111,22 @@ namespace etl ///\ingroup manchester //***************************************************************************** template <> - ETL_CONSTEXPR14 void manchester_encode_in_place(uint8_t in, uint16_t& out) + static ETL_CONSTEXPR14 void encode_in_place(uint8_t in, uint16_t& out) { - out = in; + out = in; - out = (out | (out << 4U)) & 0x0F0FU; - out = (out | (out << 2U)) & 0x3333U; - out = (out | (out << 1U)) & 0x5555U; - out = (out | (out << 1U)) ^ 0xAAAAU; + out = (out | (out << 4U)) & 0x0F0FU; + out = (out | (out << 2U)) & 0x3333U; + out = (out | (out << 1U)) & 0x5555U; + out = (out | (out << 1U)) ^ (0xAAAAU ^ static_cast(TType::invert_mask)); } template <> - ETL_NODISCARD ETL_CONSTEXPR14 uint16_t manchester_encode(uint8_t in) + static ETL_NODISCARD ETL_CONSTEXPR14 uint16_t encode(uint8_t in) { - uint16_t out {}; - manchester_encode_in_place(in, out); - return out; + uint16_t out{}; + encode_in_place(in, out); + return out; } #endif @@ -130,23 +135,23 @@ namespace etl ///\ingroup manchester //***************************************************************************** template <> - ETL_CONSTEXPR14 void manchester_encode_in_place(uint16_t in, uint32_t& out) + static ETL_CONSTEXPR14 void encode_in_place(uint16_t in, uint32_t& out) { - out = in; + out = in; - out = (out | (out << 8U)) & 0x00FF00FFUL; - out = (out | (out << 4U)) & 0x0F0F0F0FUL; - out = (out | (out << 2U)) & 0x33333333UL; - out = (out | (out << 1U)) & 0x55555555UL; - out = (out | (out << 1U)) ^ 0xAAAAAAAAUL; + out = (out | (out << 8U)) & 0x00FF00FFUL; + out = (out | (out << 4U)) & 0x0F0F0F0FUL; + out = (out | (out << 2U)) & 0x33333333UL; + out = (out | (out << 1U)) & 0x55555555UL; + out = (out | (out << 1U)) ^ (0xAAAAAAAAUL ^ static_cast(TType::invert_mask)); } template <> - ETL_NODISCARD ETL_CONSTEXPR14 uint32_t manchester_encode(uint16_t in) + static ETL_NODISCARD ETL_CONSTEXPR14 uint32_t encode(uint16_t in) { - uint32_t out {}; - manchester_encode_in_place(in, out); - return out; + uint32_t out{}; + encode_in_place(in, out); + return out; } #if ETL_USING_64BIT_TYPES @@ -155,76 +160,75 @@ namespace etl ///\ingroup manchester //***************************************************************************** template <> - ETL_CONSTEXPR14 void manchester_encode_in_place(uint32_t in, uint64_t& out) + static ETL_CONSTEXPR14 void encode_in_place(uint32_t in, uint64_t& out) { - out = in; - - out = (out | (out << 16U)) & 0x0000FFFF0000FFFFULL; - out = (out | (out << 8U)) & 0x00FF00FF00FF00FFULL; - out = (out | (out << 4U)) & 0x0F0F0F0F0F0F0F0FULL; - out = (out | (out << 2U)) & 0x3333333333333333ULL; - out = (out | (out << 1U)) & 0x5555555555555555ULL; - out = (out | (out << 1U)) ^ 0xAAAAAAAAAAAAAAAAULL; + out = in; + + out = (out | (out << 16U)) & 0x0000FFFF0000FFFFULL; + out = (out | (out << 8U)) & 0x00FF00FF00FF00FFULL; + out = (out | (out << 4U)) & 0x0F0F0F0F0F0F0F0FULL; + out = (out | (out << 2U)) & 0x3333333333333333ULL; + out = (out | (out << 1U)) & 0x5555555555555555ULL; + out = (out | (out << 1U)) ^ (0xAAAAAAAAAAAAAAAAULL ^ TType::invert_mask); } template <> - ETL_NODISCARD ETL_CONSTEXPR14 uint64_t manchester_encode(uint32_t in) + static ETL_NODISCARD ETL_CONSTEXPR14 uint64_t encode(uint32_t in) { - uint64_t out {}; - manchester_encode_in_place(in, out); - return out; + uint64_t out{}; + encode_in_place(in, out); + return out; } #endif // What happens on systems that don't have uint8_t / where CHAR_BIT is e.g. 16? - template - void manchester_encode_span(etl::span input, etl::span output) + template + static void encode_span(etl::span source, etl::span destination) { - ETL_ASSERT(output.size() >= input.size() * 2, ""); - ETL_ASSERT(input.size() % sizeof(TEncode) == 0, ""); + ETL_ASSERT(destination.size() >= source.size() * 2, "Manchester encoding requires destination storage to be at least twice the size of the source storage"); + ETL_ASSERT(source.size() % sizeof(TChunk) == 0, "Manchester encoding requires the source storage size to be an integer multiple of the encoding chunk size"); - while (!input.empty()) - { - const TEncode& in = *reinterpret_cast(input.data()); - typename etl::manchester_encoded::type& out = *reinterpret_cast::type*>(output.data()); + while (!source.empty()) + { + const TChunk& in = *reinterpret_cast(source.data()); + typename etl::manchester_encoded::type& out = *reinterpret_cast::type*>(destination.data()); - etl::manchester_encode_in_place(in, out); + encode_in_place(in, out); - input.advance(sizeof(TEncode)); - output.advance(sizeof(typename etl::manchester_encoded::type)); - } + source.advance(sizeof(TChunk)); + destination.advance(sizeof(typename etl::manchester_encoded::type)); + } } + template + static ETL_CONSTEXPR14 void decode_in_place(TChunk in, typename manchester_decoded::type& out) ETL_DELETE; - template - ETL_CONSTEXPR14 void manchester_decode_in_place(TDecode in, typename manchester_decoded::type& out) ETL_DELETE; + template + static ETL_NODISCARD ETL_CONSTEXPR14 typename manchester_decoded::type decode(TChunk in) ETL_DELETE; - template - ETL_NODISCARD ETL_CONSTEXPR14 typename manchester_decoded::type manchester_decode(TDecode in) ETL_DELETE; - - template - ETL_NODISCARD ETL_CONSTEXPR bool manchester_valid(TDecode encoded) ETL_DELETE; + template + static ETL_NODISCARD ETL_CONSTEXPR bool valid(TChunk encoded) ETL_DELETE; #if ETL_USING_8BIT_TYPES //***************************************************************************** /// Manchester decode 16 bits ///\ingroup manchester //***************************************************************************** - template<> - ETL_CONSTEXPR14 void manchester_decode_in_place(uint16_t in, uint8_t& out) + template <> + static ETL_CONSTEXPR14 void decode_in_place(uint16_t in, uint8_t& out) { - in = (in ^ 0xAAAAU) & 0x5555U; - in = (in | (in >> 1)) & 0x3333U; - in = (in | (in >> 2)) & 0x0F0FU; - out = static_cast(in | (in >> 4U)); + in = (in ^ (0xAAAAU ^ static_cast(TType::invert_mask))) & 0x5555U; + in = (in | (in >> 1)) & 0x3333U; + in = (in | (in >> 2)) & 0x0F0FU; + out = static_cast(in | (in >> 4U)); } - template<> - ETL_NODISCARD ETL_NODISCARD ETL_CONSTEXPR14 uint8_t manchester_decode(uint16_t in) + template <> + static ETL_NODISCARD ETL_NODISCARD ETL_CONSTEXPR14 uint8_t decode(uint16_t in) { - uint8_t out {}; - manchester_decode_in_place(in, out); - return out; + uint8_t out{}; + decode_in_place(in, out); + return out; } #endif @@ -233,31 +237,31 @@ namespace etl ///\ingroup manchester //***************************************************************************** template <> - ETL_NODISCARD ETL_CONSTEXPR bool manchester_valid(uint16_t encoded) + static ETL_NODISCARD ETL_CONSTEXPR bool valid(uint16_t encoded) { - return (((encoded ^ (encoded >> 1)) & 0x5555U) == 0x5555U); + return (((encoded ^ (encoded >> 1)) & 0x5555U) == 0x5555U); } //***************************************************************************** /// Manchester decode 32 bits ///\ingroup manchester //***************************************************************************** - template<> - ETL_CONSTEXPR14 void manchester_decode_in_place(uint32_t in, uint16_t& out) + template <> + static ETL_CONSTEXPR14 void decode_in_place(uint32_t in, uint16_t& out) { - in = (in ^ 0xAAAAAAAAUL) & 0x55555555UL; - in = (in | (in >> 1)) & 0x33333333UL; - in = (in | (in >> 2)) & 0x0F0F0F0FUL; - in = (in | (in >> 4)) & 0x00FF00FFUL; - out = static_cast(in | (in >> 8U)); + in = (in ^ (0xAAAAAAAAUL ^ static_cast(TType::invert_mask))) & 0x55555555UL; + in = (in | (in >> 1)) & 0x33333333UL; + in = (in | (in >> 2)) & 0x0F0F0F0FUL; + in = (in | (in >> 4)) & 0x00FF00FFUL; + out = static_cast(in | (in >> 8U)); } - template<> - ETL_NODISCARD ETL_CONSTEXPR14 uint16_t manchester_decode(uint32_t in) + template <> + static ETL_NODISCARD ETL_CONSTEXPR14 uint16_t decode(uint32_t in) { - uint16_t out {}; - manchester_decode_in_place(in, out); - return out; + uint16_t out{}; + decode_in_place(in, out); + return out; } //***************************************************************************** @@ -265,32 +269,33 @@ namespace etl ///\ingroup manchester //***************************************************************************** template <> - ETL_NODISCARD ETL_CONSTEXPR bool manchester_valid(uint32_t encoded) + static ETL_NODISCARD ETL_CONSTEXPR bool valid(uint32_t encoded) { - return (((encoded ^ (encoded >> 1)) & 0x55555555U) == 0x55555555U); + return (((encoded ^ (encoded >> 1)) & 0x55555555U) == 0x55555555U); } +#if ETL_USING_64BIT_TYPES //***************************************************************************** /// Manchester decode 64 bits ///\ingroup manchester //***************************************************************************** - template<> - ETL_CONSTEXPR14 void manchester_decode_in_place(uint64_t in, uint32_t& out) + template <> + static ETL_CONSTEXPR14 void decode_in_place(uint64_t in, uint32_t& out) { - in = (in ^ 0xAAAAAAAAAAAAAAAAULL) & 0x5555555555555555ULL; - in = (in | (in >> 1)) & 0x3333333333333333ULL; - in = (in | (in >> 2)) & 0x0F0F0F0F0F0F0F0FULL; - in = (in | (in >> 4)) & 0x00FF00FF00FF00FFULL; - in = (in | (in >> 8)) & 0x0000FFFF0000FFFFULL; - out = static_cast(in | (in >> 16U)); + in = (in ^ (0xAAAAAAAAAAAAAAAAULL ^ TType::invert_mask)) & 0x5555555555555555ULL; + in = (in | (in >> 1)) & 0x3333333333333333ULL; + in = (in | (in >> 2)) & 0x0F0F0F0F0F0F0F0FULL; + in = (in | (in >> 4)) & 0x00FF00FF00FF00FFULL; + in = (in | (in >> 8)) & 0x0000FFFF0000FFFFULL; + out = static_cast(in | (in >> 16U)); } - template<> - ETL_NODISCARD ETL_CONSTEXPR14 uint32_t manchester_decode(uint64_t in) + template <> + static ETL_NODISCARD ETL_CONSTEXPR14 uint32_t decode(uint64_t in) { - uint32_t out {}; - manchester_decode_in_place(in, out); - return out; + uint32_t out{}; + decode_in_place(in, out); + return out; } //***************************************************************************** @@ -298,41 +303,93 @@ namespace etl ///\ingroup manchester //***************************************************************************** template <> - ETL_NODISCARD ETL_CONSTEXPR bool manchester_valid(uint64_t encoded) + static ETL_NODISCARD ETL_CONSTEXPR bool valid(uint64_t encoded) { - return (((encoded ^ (encoded >> 1)) & 0x5555555555555555U) == 0x5555555555555555U); + return (((encoded ^ (encoded >> 1)) & 0x5555555555555555U) == 0x5555555555555555U); } +#endif - template ::type> - void manchester_decode_span(etl::span input, etl::span output) + static ETL_CONSTEXPR14 void valid_span(etl::span encoded) { - ETL_ASSERT(input.size() >= output.size() * 2, ""); - ETL_ASSERT(input.size() % sizeof(TDecode) == 0, ""); + ETL_ASSERT(encoded.size() % sizeof(uint16_t) == 0, ""); - while (!input.empty()) + for (size_t i = 0; i < destination.size(); i += 2) + { + const uint16_t encoded = (static_cast(source[i]) << 8) | source[i + 1]; + if (!valid(encoded)) { - const TDecode& in = *reinterpret_cast(input.data()); - typename etl::manchester_decoded::type& out = *reinterpret_cast::type*>(output.data()); + return false; + } + } + + return true; + } - etl::manchester_decode_in_place(in, out); + template ::type> + static void decode_span(etl::span source, etl::span destination) + { + typedef typename manchester_decoded::type TChunkDecoded; + + ETL_ASSERT(destination.size() * 2 >= source.size(), "Manchester decoding requires destination storage to be no less than half the source storage"); + ETL_ASSERT(source.size() % sizeof(TChunk) == 0, "Manchester decoding requires the source storage size to be an integer multiple of the decoding chunk size"); + + size_t dest_index = 0; + size_t source_index = 0; + for (size_t i = 0; i < source.size() / sizeof(TChunk); ++i) + { + TChunk encoded = 0; + memcpy(&encoded, &source[source_index], sizeof(TChunk)); + const TChunkDecoded decoded = decode(encoded); + memcpy(&destination[dest_index], &decoded, sizeof(TChunkDecoded)); + + source_index += sizeof(TChunk); + dest_index += sizeof(TChunkDecoded); + } + } - input.advance(sizeof(TDecode)); - output.advance(sizeof(typename etl::manchester_decoded::type)); - } + template <> + static ETL_CONSTEXPR14 void decode_span::type>(etl::span source, etl::span destination) + { + typedef typename manchester_encoded::type TChunk; + typedef uint_least8_t TChunkDecoded; + + ETL_ASSERT(destination.size() * 2 >= source.size(), "Manchester decoding requires destination storage to be no less than half the source storage"); + ETL_ASSERT(source.size() % sizeof(TChunk) == 0, "Manchester decoding requires the source storage size to be an integer multiple of the decoding chunk size"); + + size_t dest_index = 0; + size_t source_index = 0; + for (size_t i = 0; i < source.size() / sizeof(TChunk); ++i) + { + const TChunk encoded = static_cast((source[source_index + 1] << 8) | source[source_index]); + destination[dest_index] = decode(encoded); + + source_index += sizeof(TChunk); + dest_index += sizeof(TChunkDecoded); + } } - ETL_CONSTEXPR14 void manchester_decode_span_constexpr(etl::span input, etl::span output) + template ::type> + static void decode_span_fast(etl::span source, etl::span destination) { - ETL_ASSERT(input.size() >= output.size() * 2, ""); - ETL_ASSERT(input.size() % sizeof(uint16_t) == 0, ""); + ETL_ASSERT(destination.size() * 2 >= source.size(), "Manchester decoding requires destination storage to be no less than half the source storage"); + ETL_ASSERT(source.size() % sizeof(TChunk) == 0, "Manchester decoding requires the source storage size to be an integer multiple of the decoding chunk size"); - for (size_t i = 0; i < output.size(); ++i) - { - const uint16_t encoded = (static_cast(input[i]) << 8) | input[i + 1]; - output[i] = etl::manchester_decode(encoded); - } + while (!source.empty()) + { + const TChunk& in = *reinterpret_cast(source.data()); + typename etl::manchester_decoded::type& out = *reinterpret_cast::type*>(destination.data()); + + decode_in_place(in, out); + + source.advance(sizeof(TChunk)); + destination.advance(sizeof(typename etl::manchester_decoded::type)); + } } + }; + + typedef manchester_base manchester; + typedef manchester_base manchester_inverted; -} // namespace etl +} // namespace etl #endif diff --git a/test/test_manchester.cpp b/test/test_manchester.cpp index f70f1fddb..b54fd5dcd 100644 --- a/test/test_manchester.cpp +++ b/test/test_manchester.cpp @@ -8,33 +8,65 @@ SUITE(test_manchester) { - TEST(encode8){ - CHECK_EQUAL(0xAAAA, (etl::manchester_encode(0x00U))); - CHECK_EQUAL(0x5555, (etl::manchester_encode(0xFFU))); - CHECK_EQUAL(0xAAA9, (etl::manchester_encode(0x01U))); - CHECK_EQUAL(0x6AAA, (etl::manchester_encode(0x80U))); + TEST(encode_uint8_t) + { + CHECK_EQUAL(0xAAAA, (etl::manchester::encode(0x00U))); + CHECK_EQUAL(0x5555, (etl::manchester::encode(0xFFU))); + CHECK_EQUAL(0xAAA9, (etl::manchester::encode(0x01U))); + CHECK_EQUAL(0x6AAA, (etl::manchester::encode(0x80U))); #if ETL_USING_CPP14 - static_assert(0xAAAA == etl::manchester_encode(0x00U), "Compile time manchester encoding failed"); + static_assert(0xAAAA == etl::manchester::encode(0x00U), "Compile time manchester encoding failed"); #endif } - TEST(encode16) + TEST(encode_uint8_t_inverted) { - CHECK_EQUAL(0x5555AAAA, (etl::manchester_encode(0xFF00UL))); - CHECK_EQUAL(0x6AAAAAA9, (etl::manchester_encode(0x8001UL))); + CHECK_EQUAL(0x5555, (etl::manchester_inverted::encode(0x00U))); + CHECK_EQUAL(0xAAAA, (etl::manchester_inverted::encode(0xFFU))); + CHECK_EQUAL(0x5556, (etl::manchester_inverted::encode(0x01U))); + CHECK_EQUAL(0x9555, (etl::manchester_inverted::encode(0x80U))); #if ETL_USING_CPP14 - static_assert(0x5555AAAA == etl::manchester_encode(0xFF00UL), "Compile time manchester encoding failed"); + static_assert(0x5555 == etl::manchester_inverted::encode(0x00U), "Compile time manchester encoding failed"); #endif } - TEST(encode32) + TEST(encode_uint16_t) { - CHECK_EQUAL(0x6AAAAAA95555AAAA, (etl::manchester_encode(0x8001FF00ULL))); + CHECK_EQUAL(0x5555AAAA, (etl::manchester::encode(0xFF00UL))); + CHECK_EQUAL(0x6AAAAAA9, (etl::manchester::encode(0x8001UL))); #if ETL_USING_CPP14 - static_assert(0x6AAAAAA95555AAAA == etl::manchester_encode(0x8001FF00ULL), "Compile time manchester encoding failed"); + static_assert(0x5555AAAA == etl::manchester::encode(0xFF00UL), "Compile time manchester encoding failed"); +#endif + } + + TEST(encode_uint16_t_inverted) + { + CHECK_EQUAL(0xAAAA5555, (etl::manchester_inverted::encode(0xFF00UL))); + CHECK_EQUAL(0x95555556, (etl::manchester_inverted::encode(0x8001UL))); + +#if ETL_USING_CPP14 + static_assert(0xAAAA5555 == etl::manchester_inverted::encode(0xFF00UL), "Compile time manchester encoding failed"); +#endif + } + + TEST(encode_uint32_t) + { + CHECK_EQUAL(0x6AAAAAA95555AAAA, (etl::manchester::encode(0x8001FF00ULL))); + +#if ETL_USING_CPP14 + static_assert(0x6AAAAAA95555AAAA == etl::manchester::encode(0x8001FF00ULL), "Compile time manchester encoding failed"); +#endif + } + + TEST(encode_uint32_t_inverted) + { + CHECK_EQUAL(0x95555556AAAA5555, (etl::manchester_inverted::encode(0x8001FF00ULL))); + +#if ETL_USING_CPP14 + static_assert(0x95555556AAAA5555 == etl::manchester_inverted::encode(0x8001FF00ULL), "Compile time manchester encoding failed"); #endif } @@ -47,10 +79,10 @@ SUITE(test_manchester) alignas(uint32_t) etl::array output2; alignas(uint64_t) etl::array output3; - etl::manchester_encode_span(input, output0); - etl::manchester_encode_span(input, output1); - etl::manchester_encode_span(input, output2); - etl::manchester_encode_span(input, output3); + etl::manchester::encode_span(input, output0); + etl::manchester::encode_span(input, output1); + etl::manchester::encode_span(input, output2); + etl::manchester::encode_span(input, output3); CHECK_EQUAL(0xAA, output0[0]); CHECK_EQUAL(0xAA, output0[1]); @@ -66,47 +98,93 @@ SUITE(test_manchester) CHECK_TRUE(output0 == output3); } - TEST(encode8_transform) + TEST(encode_span_inverted) + { + etl::array input{0x00, 0xFF, 0x01, 0x80}; + + alignas(uint16_t) etl::array output0; + alignas(uint16_t) etl::array output1; + alignas(uint32_t) etl::array output2; + alignas(uint64_t) etl::array output3; + + etl::manchester_inverted::encode_span(input, output0); + etl::manchester_inverted::encode_span(input, output1); + etl::manchester_inverted::encode_span(input, output2); + etl::manchester_inverted::encode_span(input, output3); + + CHECK_EQUAL(0x55, output0[0]); + CHECK_EQUAL(0x55, output0[1]); + CHECK_EQUAL(0xAA, output0[2]); + CHECK_EQUAL(0xAA, output0[3]); + CHECK_EQUAL(0x56, output0[4]); + CHECK_EQUAL(0x55, output0[5]); + CHECK_EQUAL(0x55, output0[6]); + CHECK_EQUAL(0x95, output0[7]); + + CHECK_TRUE(output0 == output1); + CHECK_TRUE(output0 == output2); + CHECK_TRUE(output0 == output3); + } + + TEST(decode_uint16_t) + { + CHECK_EQUAL(0x00, (etl::manchester::decode(0xAAAAUL))); + CHECK_EQUAL(0xFF, (etl::manchester::decode(0x5555UL))); + CHECK_EQUAL(0x01, (etl::manchester::decode(0xAAA9UL))); + CHECK_EQUAL(0x80, (etl::manchester::decode(0x6AAAUL))); + +#if ETL_USING_CPP14 + static_assert(0x00 == etl::manchester::decode(0xAAAAUL), "Compile time manchester decoding failed"); +#endif + } + + TEST(decode_uint16_t_inverted) { - etl::array input{0x00, 0xFF, 0x01, 0x80}; - etl::array output; + CHECK_EQUAL(0x00, (etl::manchester_inverted::decode(0x5555UL))); + CHECK_EQUAL(0xFF, (etl::manchester_inverted::decode(0xAAAAUL))); + CHECK_EQUAL(0x01, (etl::manchester_inverted::decode(0x5556UL))); + CHECK_EQUAL(0x80, (etl::manchester_inverted::decode(0x9555UL))); + +#if ETL_USING_CPP14 + static_assert(0x00 == etl::manchester_inverted::decode(0x5555UL), "Compile time manchester decoding failed"); +#endif + } - etl::transform(input.begin(), input.end(), output.begin(), etl::manchester_encode); + TEST(decode_uint32_t) + { + CHECK_EQUAL(0xFF00UL, (etl::manchester::decode(0x5555AAAAUL))); + CHECK_EQUAL(0x8001UL, (etl::manchester::decode(0x6AAAAAA9UL))); - CHECK_EQUAL(0xAAAA, output[0]); - CHECK_EQUAL(0x5555, output[1]); - CHECK_EQUAL(0xAAA9, output[2]); - CHECK_EQUAL(0x6AAA, output[3]); +#if ETL_USING_CPP14 + static_assert(0xFF00UL == etl::manchester::decode(0x5555AAAAUL), "Compile time manchester decoding failed"); +#endif } - TEST(decode16) + TEST(decode_uint32_t_inverted) { - CHECK_EQUAL(0x00, (etl::manchester_decode(0xAAAAUL))); - CHECK_EQUAL(0xFF, (etl::manchester_decode(0x5555UL))); - CHECK_EQUAL(0x01, (etl::manchester_decode(0xAAA9UL))); - CHECK_EQUAL(0x80, (etl::manchester_decode(0x6AAAUL))); + CHECK_EQUAL(0xFF00UL, (etl::manchester_inverted::decode(0xAAAA5555UL))); + CHECK_EQUAL(0x8001UL, (etl::manchester_inverted::decode(0x95555556UL))); #if ETL_USING_CPP14 - static_assert(0x00 == etl::manchester_decode(0xAAAAUL), "Compile time manchester decoding failed"); + static_assert(0xFF00UL == etl::manchester_inverted::decode(0xAAAA5555UL), "Compile time manchester decoding failed"); #endif } - TEST(decode32) + TEST(decode_uint64_t) { - CHECK_EQUAL(0xFF00UL, (etl::manchester_decode(0x5555AAAAUL))); - CHECK_EQUAL(0x8001UL, (etl::manchester_decode(0x6AAAAAA9UL))); + CHECK_EQUAL(0x8001FF00ULL, (etl::manchester::decode(0x6AAAAAA95555AAAAULL))); #if ETL_USING_CPP14 - static_assert(0xFF00UL == etl::manchester_decode(0x5555AAAAUL), "Compile time manchester decoding failed"); + static_assert(0x8001FF00ULL == etl::manchester::decode(0x6AAAAAA95555AAAAULL), "Compile time manchester decoding failed"); #endif } - TEST(decode64) + TEST(decode_uint64_t_inverted) { - CHECK_EQUAL(0x8001FF00ULL, (etl::manchester_decode(0x6AAAAAA95555AAAAULL))); + CHECK_EQUAL(0x8001FF00ULL, (etl::manchester_inverted::decode(0x95555556AAAA5555ULL))); #if ETL_USING_CPP14 - static_assert(0x8001FF00ULL == etl::manchester_decode(0x6AAAAAA95555AAAAULL), "Compile time manchester decoding failed"); + static_assert(0x8001FF00ULL == etl::manchester_inverted::decode(0x95555556AAAA5555ULL), "Compile time manchester decoding failed"); #endif } @@ -119,10 +197,58 @@ SUITE(test_manchester) alignas(uint16_t) etl::array output2; alignas(uint32_t) etl::array output3; - etl::manchester_decode_span(input, output0); - etl::manchester_decode_span(input, output1); - etl::manchester_decode_span(input, output2); - etl::manchester_decode_span(input, output3); + etl::manchester::decode_span(input, output0); + etl::manchester::decode_span(input, output1); + etl::manchester::decode_span(input, output2); + etl::manchester::decode_span(input, output3); + + CHECK_EQUAL(0x00, output0[0]); + CHECK_EQUAL(0xFF, output0[1]); + CHECK_EQUAL(0x01, output0[2]); + CHECK_EQUAL(0x80, output0[3]); + + CHECK_TRUE(output0 == output1); + CHECK_TRUE(output0 == output2); + CHECK_TRUE(output0 == output3); + } + + TEST(decode_span_inverted) + { + etl::array input{0x55, 0x55, 0xAA, 0xAA, 0x56, 0x55, 0X55, 0x95}; + + alignas(uint8_t) etl::array output0; + alignas(uint8_t) etl::array output1; + alignas(uint16_t) etl::array output2; + alignas(uint32_t) etl::array output3; + + etl::manchester_inverted::decode_span(input, output0); + etl::manchester_inverted::decode_span(input, output1); + etl::manchester_inverted::decode_span(input, output2); + etl::manchester_inverted::decode_span(input, output3); + + CHECK_EQUAL(0x00, output0[0]); + CHECK_EQUAL(0xFF, output0[1]); + CHECK_EQUAL(0x01, output0[2]); + CHECK_EQUAL(0x80, output0[3]); + + CHECK_TRUE(output0 == output1); + CHECK_TRUE(output0 == output2); + CHECK_TRUE(output0 == output3); + } + + TEST(decode_span_fast) + { + etl::array input{0xAA, 0xAA, 0x55, 0x55, 0xA9, 0xAA, 0XAA, 0x6A}; + + alignas(uint8_t) etl::array output0; + alignas(uint8_t) etl::array output1; + alignas(uint16_t) etl::array output2; + alignas(uint32_t) etl::array output3; + + etl::manchester::decode_span_fast(input, output0); + etl::manchester::decode_span_fast(input, output1); + etl::manchester::decode_span_fast(input, output2); + etl::manchester::decode_span_fast(input, output3); CHECK_EQUAL(0x00, output0[0]); CHECK_EQUAL(0xFF, output0[1]); @@ -136,31 +262,40 @@ SUITE(test_manchester) TEST(valid16) { - CHECK_TRUE(etl::manchester_valid(0xAAAAUL)); - CHECK_FALSE(etl::manchester_valid(0xAAA8UL)); + CHECK_TRUE(etl::manchester::valid(0xAAAAUL)); + CHECK_TRUE(etl::manchester_inverted::valid(0xAAAAUL)); + CHECK_FALSE(etl::manchester::valid(0xAAA8UL)); + CHECK_FALSE(etl::manchester_inverted::valid(0xAAA8UL)); #if ETL_USING_CPP14 - static_assert(etl::manchester_valid(0xAAAAUL), "Compile time manchester validity check failed"); + static_assert(etl::manchester::valid(0xAAAAUL), "Compile time manchester validity check failed"); + static_assert(etl::manchester_inverted::valid(0xAAAAUL), "Compile time manchester validity check failed"); #endif } TEST(valid32) { - CHECK_TRUE(etl::manchester_valid(0xAAAAAAAAUL)); - CHECK_FALSE(etl::manchester_valid(0xAAAAAAA8UL)); + CHECK_TRUE(etl::manchester::valid(0xAAAAAAAAUL)); + CHECK_TRUE(etl::manchester_inverted::valid(0xAAAAAAAAUL)); + CHECK_FALSE(etl::manchester::valid(0xAAAAAAA8UL)); + CHECK_FALSE(etl::manchester_inverted::valid(0xAAAAAAA8UL)); #if ETL_USING_CPP14 - static_assert(etl::manchester_valid(0xAAAAAAAAUL), "Compile time manchester validity check failed"); + static_assert(etl::manchester::valid(0xAAAAAAAAUL), "Compile time manchester validity check failed"); + static_assert(etl::manchester_inverted::valid(0xAAAAAAAAUL), "Compile time manchester validity check failed"); #endif } TEST(valid64) { - CHECK_TRUE(etl::manchester_valid(0xAAAAAAAAAAAAAAAAULL)); - CHECK_FALSE(etl::manchester_valid(0xAAAAAAAAAAAAAAA8ULL)); + CHECK_TRUE(etl::manchester::valid(0xAAAAAAAAAAAAAAAAULL)); + CHECK_TRUE(etl::manchester_inverted::valid(0xAAAAAAAAAAAAAAAAULL)); + CHECK_FALSE(etl::manchester::valid(0xAAAAAAAAAAAAAAA8ULL)); + CHECK_FALSE(etl::manchester_inverted::valid(0xAAAAAAAAAAAAAAA8ULL)); #if ETL_USING_CPP14 - static_assert(etl::manchester_valid(0xAAAAAAAAAAAAAAAAULL), "Compile time manchester validity check failed"); + static_assert(etl::manchester::valid(0xAAAAAAAAAAAAAAAAULL), "Compile time manchester validity check failed"); + static_assert(etl::manchester_inverted::valid(0xAAAAAAAAAAAAAAAAULL), "Compile time manchester validity check failed"); #endif } }; @@ -169,7 +304,7 @@ SUITE(test_manchester) constexpr etl::array manchester_encoded(etl::span input) { alignas(uint8_t) etl::array output {0, 0, 0, 0}; - etl::manchester_decode_span_constexpr(input, output); + etl::manchester::decode_span(input, output); return output; } From 49a92054b8e036f62f0bdd0d4a7644be1a28d89a Mon Sep 17 00:00:00 2001 From: Timon Zijnge Date: Wed, 7 Jan 2026 10:03:29 +0100 Subject: [PATCH 12/46] manchester * Disable test for now * Move ETL_NODISCARD before static --- include/etl/manchester.h | 24 ++++++++++++------------ test/test_manchester.cpp | 22 +++++++++++----------- 2 files changed, 23 insertions(+), 23 deletions(-) diff --git a/include/etl/manchester.h b/include/etl/manchester.h index 9ac79ac09..0bbbfd4d6 100644 --- a/include/etl/manchester.h +++ b/include/etl/manchester.h @@ -103,7 +103,7 @@ namespace etl static ETL_CONSTEXPR14 void encode_in_place(TChunk in, typename manchester_encoded::type& out) ETL_DELETE; template - static ETL_NODISCARD ETL_CONSTEXPR14 typename manchester_encoded::type encode(TChunk in) ETL_DELETE; + ETL_NODISCARD static ETL_CONSTEXPR14 typename manchester_encoded::type encode(TChunk in) ETL_DELETE; #if ETL_USING_8BIT_TYPES //***************************************************************************** @@ -122,7 +122,7 @@ namespace etl } template <> - static ETL_NODISCARD ETL_CONSTEXPR14 uint16_t encode(uint8_t in) + ETL_NODISCARD static ETL_CONSTEXPR14 uint16_t encode(uint8_t in) { uint16_t out{}; encode_in_place(in, out); @@ -147,7 +147,7 @@ namespace etl } template <> - static ETL_NODISCARD ETL_CONSTEXPR14 uint32_t encode(uint16_t in) + ETL_NODISCARD static ETL_CONSTEXPR14 uint32_t encode(uint16_t in) { uint32_t out{}; encode_in_place(in, out); @@ -173,7 +173,7 @@ namespace etl } template <> - static ETL_NODISCARD ETL_CONSTEXPR14 uint64_t encode(uint32_t in) + ETL_NODISCARD static ETL_CONSTEXPR14 uint64_t encode(uint32_t in) { uint64_t out{}; encode_in_place(in, out); @@ -204,10 +204,10 @@ namespace etl static ETL_CONSTEXPR14 void decode_in_place(TChunk in, typename manchester_decoded::type& out) ETL_DELETE; template - static ETL_NODISCARD ETL_CONSTEXPR14 typename manchester_decoded::type decode(TChunk in) ETL_DELETE; + ETL_NODISCARD static ETL_CONSTEXPR14 typename manchester_decoded::type decode(TChunk in) ETL_DELETE; template - static ETL_NODISCARD ETL_CONSTEXPR bool valid(TChunk encoded) ETL_DELETE; + ETL_NODISCARD static ETL_CONSTEXPR bool valid(TChunk encoded) ETL_DELETE; #if ETL_USING_8BIT_TYPES //***************************************************************************** @@ -224,7 +224,7 @@ namespace etl } template <> - static ETL_NODISCARD ETL_NODISCARD ETL_CONSTEXPR14 uint8_t decode(uint16_t in) + ETL_NODISCARD static ETL_NODISCARD ETL_CONSTEXPR14 uint8_t decode(uint16_t in) { uint8_t out{}; decode_in_place(in, out); @@ -237,7 +237,7 @@ namespace etl ///\ingroup manchester //***************************************************************************** template <> - static ETL_NODISCARD ETL_CONSTEXPR bool valid(uint16_t encoded) + ETL_NODISCARD static ETL_CONSTEXPR bool valid(uint16_t encoded) { return (((encoded ^ (encoded >> 1)) & 0x5555U) == 0x5555U); } @@ -257,7 +257,7 @@ namespace etl } template <> - static ETL_NODISCARD ETL_CONSTEXPR14 uint16_t decode(uint32_t in) + ETL_NODISCARD static ETL_CONSTEXPR14 uint16_t decode(uint32_t in) { uint16_t out{}; decode_in_place(in, out); @@ -269,7 +269,7 @@ namespace etl ///\ingroup manchester //***************************************************************************** template <> - static ETL_NODISCARD ETL_CONSTEXPR bool valid(uint32_t encoded) + ETL_NODISCARD static ETL_CONSTEXPR bool valid(uint32_t encoded) { return (((encoded ^ (encoded >> 1)) & 0x55555555U) == 0x55555555U); } @@ -291,7 +291,7 @@ namespace etl } template <> - static ETL_NODISCARD ETL_CONSTEXPR14 uint32_t decode(uint64_t in) + ETL_NODISCARD static ETL_CONSTEXPR14 uint32_t decode(uint64_t in) { uint32_t out{}; decode_in_place(in, out); @@ -303,7 +303,7 @@ namespace etl ///\ingroup manchester //***************************************************************************** template <> - static ETL_NODISCARD ETL_CONSTEXPR bool valid(uint64_t encoded) + ETL_NODISCARD static ETL_CONSTEXPR bool valid(uint64_t encoded) { return (((encoded ^ (encoded >> 1)) & 0x5555555555555555U) == 0x5555555555555555U); } diff --git a/test/test_manchester.cpp b/test/test_manchester.cpp index b54fd5dcd..7e169267e 100644 --- a/test/test_manchester.cpp +++ b/test/test_manchester.cpp @@ -300,17 +300,17 @@ SUITE(test_manchester) } }; -#if ETL_USING_CPP14 -constexpr etl::array manchester_encoded(etl::span input) -{ - alignas(uint8_t) etl::array output {0, 0, 0, 0}; - etl::manchester::decode_span(input, output); +// #if ETL_USING_CPP14 +// constexpr etl::array manchester_encoded(etl::span input) +// { +// alignas(uint8_t) etl::array output {0, 0, 0, 0}; +// etl::manchester::decode_span(input, output); - return output; -} +// return output; +// } -constexpr etl::array input{0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0XAA, 0xAA}; +// constexpr etl::array input{0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0XAA, 0xAA}; -constexpr etl::array bla = manchester_encoded(input); -static_assert(bla[0] == 0, "Compile time computation of many values failed"); -#endif \ No newline at end of file +// constexpr etl::array bla = manchester_encoded(input); +// static_assert(bla[0] == 0, "Compile time computation of many values failed"); +// #endif \ No newline at end of file From cfb93a073cccb1dd42f51bde671f01458ba5543a Mon Sep 17 00:00:00 2001 From: Timon Zijnge Date: Wed, 7 Jan 2026 10:24:37 +0100 Subject: [PATCH 13/46] manchester * Test for valid_span --- include/etl/manchester.h | 10 +++++----- test/test_manchester.cpp | 14 ++++++++++++++ 2 files changed, 19 insertions(+), 5 deletions(-) diff --git a/include/etl/manchester.h b/include/etl/manchester.h index 0bbbfd4d6..0c8beb863 100644 --- a/include/etl/manchester.h +++ b/include/etl/manchester.h @@ -224,7 +224,7 @@ namespace etl } template <> - ETL_NODISCARD static ETL_NODISCARD ETL_CONSTEXPR14 uint8_t decode(uint16_t in) + ETL_NODISCARD static ETL_CONSTEXPR14 uint8_t decode(uint16_t in) { uint8_t out{}; decode_in_place(in, out); @@ -309,14 +309,14 @@ namespace etl } #endif - static ETL_CONSTEXPR14 void valid_span(etl::span encoded) + static ETL_CONSTEXPR14 bool valid_span(etl::span encoded) { ETL_ASSERT(encoded.size() % sizeof(uint16_t) == 0, ""); - for (size_t i = 0; i < destination.size(); i += 2) + for (size_t i = 0; i < encoded.size(); i += 2) { - const uint16_t encoded = (static_cast(source[i]) << 8) | source[i + 1]; - if (!valid(encoded)) + const uint16_t chunk = static_cast((encoded[i + 1] << 8) | encoded[i]); + if (!valid(chunk)) { return false; } diff --git a/test/test_manchester.cpp b/test/test_manchester.cpp index 7e169267e..8c8fa5527 100644 --- a/test/test_manchester.cpp +++ b/test/test_manchester.cpp @@ -296,6 +296,20 @@ SUITE(test_manchester) #if ETL_USING_CPP14 static_assert(etl::manchester::valid(0xAAAAAAAAAAAAAAAAULL), "Compile time manchester validity check failed"); static_assert(etl::manchester_inverted::valid(0xAAAAAAAAAAAAAAAAULL), "Compile time manchester validity check failed"); +#endif + } + + TEST(valid_span) + { + constexpr etl::array encoded1{0xAA, 0xAA, 0x55, 0x55, 0xA9, 0xAA, 0XAA, 0x6A}; + constexpr etl::array encoded2{0xAA, 0xAA, 0x55, 0x55, 0xA9, 0xAA, 0XAB, 0x6A}; + + CHECK_TRUE(etl::manchester::valid_span(encoded1)); + CHECK_FALSE(etl::manchester::valid_span(encoded2)); + +#if ETL_USING_CPP14 + static_assert(etl::manchester::valid_span(encoded1), "Compile time manchester validity check failed"); + static_assert(!etl::manchester::valid_span(encoded2), "Compile time manchester validity check failed"); #endif } }; From ef6f408770f867d6966207c4bd16321093d69498 Mon Sep 17 00:00:00 2001 From: Timon Zijnge Date: Wed, 7 Jan 2026 10:39:12 +0100 Subject: [PATCH 14/46] manchester * Remove redundant (?) storage specifiers for template specializations. Storage specifier already given in base template --- include/etl/manchester.h | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/include/etl/manchester.h b/include/etl/manchester.h index 0c8beb863..c85472f9b 100644 --- a/include/etl/manchester.h +++ b/include/etl/manchester.h @@ -111,7 +111,7 @@ namespace etl ///\ingroup manchester //***************************************************************************** template <> - static ETL_CONSTEXPR14 void encode_in_place(uint8_t in, uint16_t& out) + ETL_CONSTEXPR14 void encode_in_place(uint8_t in, uint16_t& out) { out = in; @@ -122,7 +122,7 @@ namespace etl } template <> - ETL_NODISCARD static ETL_CONSTEXPR14 uint16_t encode(uint8_t in) + ETL_NODISCARD ETL_CONSTEXPR14 uint16_t encode(uint8_t in) { uint16_t out{}; encode_in_place(in, out); @@ -135,7 +135,7 @@ namespace etl ///\ingroup manchester //***************************************************************************** template <> - static ETL_CONSTEXPR14 void encode_in_place(uint16_t in, uint32_t& out) + ETL_CONSTEXPR14 void encode_in_place(uint16_t in, uint32_t& out) { out = in; @@ -147,7 +147,7 @@ namespace etl } template <> - ETL_NODISCARD static ETL_CONSTEXPR14 uint32_t encode(uint16_t in) + ETL_NODISCARD ETL_CONSTEXPR14 uint32_t encode(uint16_t in) { uint32_t out{}; encode_in_place(in, out); @@ -160,7 +160,7 @@ namespace etl ///\ingroup manchester //***************************************************************************** template <> - static ETL_CONSTEXPR14 void encode_in_place(uint32_t in, uint64_t& out) + ETL_CONSTEXPR14 void encode_in_place(uint32_t in, uint64_t& out) { out = in; @@ -173,7 +173,7 @@ namespace etl } template <> - ETL_NODISCARD static ETL_CONSTEXPR14 uint64_t encode(uint32_t in) + ETL_NODISCARD ETL_CONSTEXPR14 uint64_t encode(uint32_t in) { uint64_t out{}; encode_in_place(in, out); @@ -215,7 +215,7 @@ namespace etl ///\ingroup manchester //***************************************************************************** template <> - static ETL_CONSTEXPR14 void decode_in_place(uint16_t in, uint8_t& out) + ETL_CONSTEXPR14 void decode_in_place(uint16_t in, uint8_t& out) { in = (in ^ (0xAAAAU ^ static_cast(TType::invert_mask))) & 0x5555U; in = (in | (in >> 1)) & 0x3333U; @@ -224,7 +224,7 @@ namespace etl } template <> - ETL_NODISCARD static ETL_CONSTEXPR14 uint8_t decode(uint16_t in) + ETL_NODISCARD ETL_CONSTEXPR14 uint8_t decode(uint16_t in) { uint8_t out{}; decode_in_place(in, out); @@ -237,7 +237,7 @@ namespace etl ///\ingroup manchester //***************************************************************************** template <> - ETL_NODISCARD static ETL_CONSTEXPR bool valid(uint16_t encoded) + ETL_NODISCARD ETL_CONSTEXPR bool valid(uint16_t encoded) { return (((encoded ^ (encoded >> 1)) & 0x5555U) == 0x5555U); } @@ -247,7 +247,7 @@ namespace etl ///\ingroup manchester //***************************************************************************** template <> - static ETL_CONSTEXPR14 void decode_in_place(uint32_t in, uint16_t& out) + ETL_CONSTEXPR14 void decode_in_place(uint32_t in, uint16_t& out) { in = (in ^ (0xAAAAAAAAUL ^ static_cast(TType::invert_mask))) & 0x55555555UL; in = (in | (in >> 1)) & 0x33333333UL; @@ -257,7 +257,7 @@ namespace etl } template <> - ETL_NODISCARD static ETL_CONSTEXPR14 uint16_t decode(uint32_t in) + ETL_NODISCARD ETL_CONSTEXPR14 uint16_t decode(uint32_t in) { uint16_t out{}; decode_in_place(in, out); @@ -269,7 +269,7 @@ namespace etl ///\ingroup manchester //***************************************************************************** template <> - ETL_NODISCARD static ETL_CONSTEXPR bool valid(uint32_t encoded) + ETL_NODISCARD ETL_CONSTEXPR bool valid(uint32_t encoded) { return (((encoded ^ (encoded >> 1)) & 0x55555555U) == 0x55555555U); } @@ -280,7 +280,7 @@ namespace etl ///\ingroup manchester //***************************************************************************** template <> - static ETL_CONSTEXPR14 void decode_in_place(uint64_t in, uint32_t& out) + ETL_CONSTEXPR14 void decode_in_place(uint64_t in, uint32_t& out) { in = (in ^ (0xAAAAAAAAAAAAAAAAULL ^ TType::invert_mask)) & 0x5555555555555555ULL; in = (in | (in >> 1)) & 0x3333333333333333ULL; @@ -291,7 +291,7 @@ namespace etl } template <> - ETL_NODISCARD static ETL_CONSTEXPR14 uint32_t decode(uint64_t in) + ETL_NODISCARD ETL_CONSTEXPR14 uint32_t decode(uint64_t in) { uint32_t out{}; decode_in_place(in, out); @@ -303,13 +303,13 @@ namespace etl ///\ingroup manchester //***************************************************************************** template <> - ETL_NODISCARD static ETL_CONSTEXPR bool valid(uint64_t encoded) + ETL_NODISCARD ETL_CONSTEXPR bool valid(uint64_t encoded) { return (((encoded ^ (encoded >> 1)) & 0x5555555555555555U) == 0x5555555555555555U); } #endif - static ETL_CONSTEXPR14 bool valid_span(etl::span encoded) + ETL_NODISCARD static ETL_CONSTEXPR14 bool valid_span(etl::span encoded) { ETL_ASSERT(encoded.size() % sizeof(uint16_t) == 0, ""); From 53b28cc1f3daf9e231e74ecd03eec60d3b26b820 Mon Sep 17 00:00:00 2001 From: Timon Zijnge Date: Wed, 7 Jan 2026 11:46:17 +0100 Subject: [PATCH 15/46] manchester * refactoring to get rid of specialized template functions in template class --- include/etl/manchester.h | 262 +++++++++++++++++++++------------------ 1 file changed, 143 insertions(+), 119 deletions(-) diff --git a/include/etl/manchester.h b/include/etl/manchester.h index c85472f9b..748ee1fb9 100644 --- a/include/etl/manchester.h +++ b/include/etl/manchester.h @@ -1,7 +1,6 @@ #ifndef ETL_MANCHESTER_INCLUDED #define ETL_MANCHESTER_INCLUDED - ///\file /****************************************************************************** @@ -86,6 +85,34 @@ namespace etl typedef uint32_t type; }; + template + struct is_supported_encode_input + { + static const bool value = +#if ETL_USING_8BIT_TYPES + etl::is_same::value || +#endif + etl::is_same::value +#if ETL_USING_64BIT_TYPES + || etl::is_same::value +#endif + ; + }; + + template + struct is_supported_decode_input + { + static const bool value = +#if ETL_USING_8BIT_TYPES + etl::is_same::value || +#endif + etl::is_same::value +#if ETL_USING_64BIT_TYPES + || etl::is_same::value +#endif + ; + }; + struct manchester_type_normal { static const uint64_t invert_mask = 0x0000000000000000; @@ -99,19 +126,10 @@ namespace etl template struct manchester_base { - template - static ETL_CONSTEXPR14 void encode_in_place(TChunk in, typename manchester_encoded::type& out) ETL_DELETE; - - template - ETL_NODISCARD static ETL_CONSTEXPR14 typename manchester_encoded::type encode(TChunk in) ETL_DELETE; - #if ETL_USING_8BIT_TYPES - //***************************************************************************** - /// Manchester encode 8 bits - ///\ingroup manchester - //***************************************************************************** - template <> - ETL_CONSTEXPR14 void encode_in_place(uint8_t in, uint16_t& out) + template + static ETL_CONSTEXPR14 typename etl::enable_if::value, void>::type + encode_in_place(TChunk in, uint16_t& out) { out = in; @@ -120,22 +138,11 @@ namespace etl out = (out | (out << 1U)) & 0x5555U; out = (out | (out << 1U)) ^ (0xAAAAU ^ static_cast(TType::invert_mask)); } - - template <> - ETL_NODISCARD ETL_CONSTEXPR14 uint16_t encode(uint8_t in) - { - uint16_t out{}; - encode_in_place(in, out); - return out; - } #endif - //***************************************************************************** - /// Manchester encode 16 bits - ///\ingroup manchester - //***************************************************************************** - template <> - ETL_CONSTEXPR14 void encode_in_place(uint16_t in, uint32_t& out) + template + static ETL_CONSTEXPR14 typename etl::enable_if::value, void>::type + encode_in_place(TChunk in, uint32_t& out) { out = in; @@ -146,21 +153,10 @@ namespace etl out = (out | (out << 1U)) ^ (0xAAAAAAAAUL ^ static_cast(TType::invert_mask)); } - template <> - ETL_NODISCARD ETL_CONSTEXPR14 uint32_t encode(uint16_t in) - { - uint32_t out{}; - encode_in_place(in, out); - return out; - } - #if ETL_USING_64BIT_TYPES - //***************************************************************************** - /// Manchester encode 32 bits - ///\ingroup manchester - //***************************************************************************** - template <> - ETL_CONSTEXPR14 void encode_in_place(uint32_t in, uint64_t& out) + template + static ETL_CONSTEXPR14 typename etl::enable_if::value, void>::type + encode_in_place(TChunk in, uint64_t& out) { out = in; @@ -171,9 +167,36 @@ namespace etl out = (out | (out << 1U)) & 0x5555555555555555ULL; out = (out | (out << 1U)) ^ (0xAAAAAAAAAAAAAAAAULL ^ TType::invert_mask); } +#endif + + template + static typename etl::enable_if::value, void>::type + encode_in_place(TChunk in, typename manchester_encoded::type& out) = delete; + +#if ETL_USING_8BIT_TYPES + template + ETL_NODISCARD static ETL_CONSTEXPR14 typename etl::enable_if::value, uint16_t>::type + encode(TChunk in) + { + uint16_t out{}; + encode_in_place(in, out); + return out; + } +#endif - template <> - ETL_NODISCARD ETL_CONSTEXPR14 uint64_t encode(uint32_t in) + template + ETL_NODISCARD static ETL_CONSTEXPR14 typename etl::enable_if::value, uint32_t>::type + encode(TChunk in) + { + uint32_t out{}; + encode_in_place(in, out); + return out; + } + +#if ETL_USING_64BIT_TYPES + template + ETL_NODISCARD static ETL_CONSTEXPR14 typename etl::enable_if::value, uint64_t>::type + encode(TChunk in) { uint64_t out{}; encode_in_place(in, out); @@ -181,7 +204,10 @@ namespace etl } #endif - // What happens on systems that don't have uint8_t / where CHAR_BIT is e.g. 16? + template + static typename etl::enable_if::value, typename manchester_encoded::type>::type + encode(TChunk in) = delete; + template static void encode_span(etl::span source, etl::span destination) { @@ -200,54 +226,21 @@ namespace etl } } - template - static ETL_CONSTEXPR14 void decode_in_place(TChunk in, typename manchester_decoded::type& out) ETL_DELETE; - - template - ETL_NODISCARD static ETL_CONSTEXPR14 typename manchester_decoded::type decode(TChunk in) ETL_DELETE; - - template - ETL_NODISCARD static ETL_CONSTEXPR bool valid(TChunk encoded) ETL_DELETE; - #if ETL_USING_8BIT_TYPES - //***************************************************************************** - /// Manchester decode 16 bits - ///\ingroup manchester - //***************************************************************************** - template <> - ETL_CONSTEXPR14 void decode_in_place(uint16_t in, uint8_t& out) + template + static ETL_CONSTEXPR14 typename etl::enable_if::value, void>::type + decode_in_place(TChunk in, uint8_t& out) { in = (in ^ (0xAAAAU ^ static_cast(TType::invert_mask))) & 0x5555U; in = (in | (in >> 1)) & 0x3333U; in = (in | (in >> 2)) & 0x0F0FU; out = static_cast(in | (in >> 4U)); } - - template <> - ETL_NODISCARD ETL_CONSTEXPR14 uint8_t decode(uint16_t in) - { - uint8_t out{}; - decode_in_place(in, out); - return out; - } #endif - //***************************************************************************** - /// Manchester valid 16 bits - ///\ingroup manchester - //***************************************************************************** - template <> - ETL_NODISCARD ETL_CONSTEXPR bool valid(uint16_t encoded) - { - return (((encoded ^ (encoded >> 1)) & 0x5555U) == 0x5555U); - } - - //***************************************************************************** - /// Manchester decode 32 bits - ///\ingroup manchester - //***************************************************************************** - template <> - ETL_CONSTEXPR14 void decode_in_place(uint32_t in, uint16_t& out) + template + static ETL_CONSTEXPR14 typename etl::enable_if::value, void>::type + decode_in_place(TChunk in, uint16_t& out) { in = (in ^ (0xAAAAAAAAUL ^ static_cast(TType::invert_mask))) & 0x55555555UL; in = (in | (in >> 1)) & 0x33333333UL; @@ -256,31 +249,10 @@ namespace etl out = static_cast(in | (in >> 8U)); } - template <> - ETL_NODISCARD ETL_CONSTEXPR14 uint16_t decode(uint32_t in) - { - uint16_t out{}; - decode_in_place(in, out); - return out; - } - - //***************************************************************************** - /// Manchester valid 32 bits - ///\ingroup manchester - //***************************************************************************** - template <> - ETL_NODISCARD ETL_CONSTEXPR bool valid(uint32_t encoded) - { - return (((encoded ^ (encoded >> 1)) & 0x55555555U) == 0x55555555U); - } - #if ETL_USING_64BIT_TYPES - //***************************************************************************** - /// Manchester decode 64 bits - ///\ingroup manchester - //***************************************************************************** - template <> - ETL_CONSTEXPR14 void decode_in_place(uint64_t in, uint32_t& out) + template + static ETL_CONSTEXPR14 typename etl::enable_if::value, void>::type + decode_in_place(TChunk in, uint32_t& out) { in = (in ^ (0xAAAAAAAAAAAAAAAAULL ^ TType::invert_mask)) & 0x5555555555555555ULL; in = (in | (in >> 1)) & 0x3333333333333333ULL; @@ -289,26 +261,76 @@ namespace etl in = (in | (in >> 8)) & 0x0000FFFF0000FFFFULL; out = static_cast(in | (in >> 16U)); } +#endif - template <> - ETL_NODISCARD ETL_CONSTEXPR14 uint32_t decode(uint64_t in) + template + static typename etl::enable_if::value, void>::type + decode_in_place(TChunk in, typename manchester_decoded::type& out) = delete; + +#if ETL_USING_8BIT_TYPES + template + ETL_NODISCARD static ETL_CONSTEXPR14 typename etl::enable_if::value, uint8_t>::type + decode(TChunk in) + { + uint8_t out{}; + decode_in_place(in, out); + return out; + } +#endif + + template + ETL_NODISCARD static ETL_CONSTEXPR14 typename etl::enable_if::value, uint16_t>::type + decode(TChunk in) + { + uint16_t out{}; + decode_in_place(in, out); + return out; + } + +#if ETL_USING_64BIT_TYPES + template + ETL_NODISCARD static ETL_CONSTEXPR14 typename etl::enable_if::value, uint32_t>::type + decode(TChunk in) { uint32_t out{}; decode_in_place(in, out); return out; } +#endif + + template + static typename etl::enable_if::value, typename manchester_decoded::type>::type + decode(TChunk in) = delete; - //***************************************************************************** - /// Manchester valid 64 bits - ///\ingroup manchester - //***************************************************************************** - template <> - ETL_NODISCARD ETL_CONSTEXPR bool valid(uint64_t encoded) +#if ETL_USING_8BIT_TYPES + template + ETL_NODISCARD static ETL_CONSTEXPR typename etl::enable_if::value, bool>::type + valid(TChunk encoded) + { + return (((encoded ^ (encoded >> 1)) & 0x5555U) == 0x5555U); + } +#endif + + template + ETL_NODISCARD static ETL_CONSTEXPR typename etl::enable_if::value, bool>::type + valid(TChunk encoded) + { + return (((encoded ^ (encoded >> 1)) & 0x55555555U) == 0x55555555U); + } + +#if ETL_USING_64BIT_TYPES + template + ETL_NODISCARD static ETL_CONSTEXPR typename etl::enable_if::value, bool>::type + valid(TChunk encoded) { return (((encoded ^ (encoded >> 1)) & 0x5555555555555555U) == 0x5555555555555555U); } #endif + template + static typename etl::enable_if::value, bool>::type + valid(TChunk encoded) = delete; + ETL_NODISCARD static ETL_CONSTEXPR14 bool valid_span(etl::span encoded) { ETL_ASSERT(encoded.size() % sizeof(uint16_t) == 0, ""); @@ -326,7 +348,8 @@ namespace etl } template ::type> - static void decode_span(etl::span source, etl::span destination) + static typename etl::enable_if::type>::value, void>::type + decode_span(etl::span source, etl::span destination) { typedef typename manchester_decoded::type TChunkDecoded; @@ -347,11 +370,12 @@ namespace etl } } - template <> - static ETL_CONSTEXPR14 void decode_span::type>(etl::span source, etl::span destination) + template ::type> + static ETL_CONSTEXPR14 typename etl::enable_if::type>::value, void>::type + decode_span(etl::span source, etl::span destination) { typedef typename manchester_encoded::type TChunk; - typedef uint_least8_t TChunkDecoded; + typedef uint_least8_t TChunkDecoded; ETL_ASSERT(destination.size() * 2 >= source.size(), "Manchester decoding requires destination storage to be no less than half the source storage"); ETL_ASSERT(source.size() % sizeof(TChunk) == 0, "Manchester decoding requires the source storage size to be an integer multiple of the decoding chunk size"); From 1e42a5a7177590e5ac7cbd39d53b0358833a7413 Mon Sep 17 00:00:00 2001 From: Timon Zijnge Date: Wed, 7 Jan 2026 11:55:16 +0100 Subject: [PATCH 16/46] manchester * cleanup --- include/etl/manchester.h | 57 +++++----------------------------------- 1 file changed, 6 insertions(+), 51 deletions(-) diff --git a/include/etl/manchester.h b/include/etl/manchester.h index 748ee1fb9..d4c28fd52 100644 --- a/include/etl/manchester.h +++ b/include/etl/manchester.h @@ -173,37 +173,15 @@ namespace etl static typename etl::enable_if::value, void>::type encode_in_place(TChunk in, typename manchester_encoded::type& out) = delete; -#if ETL_USING_8BIT_TYPES - template - ETL_NODISCARD static ETL_CONSTEXPR14 typename etl::enable_if::value, uint16_t>::type - encode(TChunk in) - { - uint16_t out{}; - encode_in_place(in, out); - return out; - } -#endif - template - ETL_NODISCARD static ETL_CONSTEXPR14 typename etl::enable_if::value, uint32_t>::type + ETL_NODISCARD static ETL_CONSTEXPR14 typename etl::enable_if::value, typename manchester_encoded::type>::type encode(TChunk in) { - uint32_t out{}; + typename manchester_encoded::type out = 0; encode_in_place(in, out); return out; } -#if ETL_USING_64BIT_TYPES - template - ETL_NODISCARD static ETL_CONSTEXPR14 typename etl::enable_if::value, uint64_t>::type - encode(TChunk in) - { - uint64_t out{}; - encode_in_place(in, out); - return out; - } -#endif - template static typename etl::enable_if::value, typename manchester_encoded::type>::type encode(TChunk in) = delete; @@ -267,37 +245,15 @@ namespace etl static typename etl::enable_if::value, void>::type decode_in_place(TChunk in, typename manchester_decoded::type& out) = delete; -#if ETL_USING_8BIT_TYPES - template - ETL_NODISCARD static ETL_CONSTEXPR14 typename etl::enable_if::value, uint8_t>::type - decode(TChunk in) - { - uint8_t out{}; - decode_in_place(in, out); - return out; - } -#endif - template - ETL_NODISCARD static ETL_CONSTEXPR14 typename etl::enable_if::value, uint16_t>::type + ETL_NODISCARD static ETL_CONSTEXPR14 typename etl::enable_if::value, typename manchester_decoded::type>::type decode(TChunk in) { - uint16_t out{}; + typename manchester_decoded::type out = 0; decode_in_place(in, out); return out; } -#if ETL_USING_64BIT_TYPES - template - ETL_NODISCARD static ETL_CONSTEXPR14 typename etl::enable_if::value, uint32_t>::type - decode(TChunk in) - { - uint32_t out{}; - decode_in_place(in, out); - return out; - } -#endif - template static typename etl::enable_if::value, typename manchester_decoded::type>::type decode(TChunk in) = delete; @@ -347,7 +303,7 @@ namespace etl return true; } - template ::type> + template static typename etl::enable_if::type>::value, void>::type decode_span(etl::span source, etl::span destination) { @@ -374,8 +330,7 @@ namespace etl static ETL_CONSTEXPR14 typename etl::enable_if::type>::value, void>::type decode_span(etl::span source, etl::span destination) { - typedef typename manchester_encoded::type TChunk; - typedef uint_least8_t TChunkDecoded; + typedef uint_least8_t TChunkDecoded; ETL_ASSERT(destination.size() * 2 >= source.size(), "Manchester decoding requires destination storage to be no less than half the source storage"); ETL_ASSERT(source.size() % sizeof(TChunk) == 0, "Manchester decoding requires the source storage size to be an integer multiple of the decoding chunk size"); From 2746b11bd3f31d8c938b9783cecaee0792c75242 Mon Sep 17 00:00:00 2001 From: Timon Zijnge Date: Wed, 7 Jan 2026 13:48:54 +0100 Subject: [PATCH 17/46] manchester * Added documentation comments * Some refactoring --- include/etl/manchester.h | 368 +++++++++++++++++++++++++-------------- 1 file changed, 242 insertions(+), 126 deletions(-) diff --git a/include/etl/manchester.h b/include/etl/manchester.h index d4c28fd52..e277a4070 100644 --- a/include/etl/manchester.h +++ b/include/etl/manchester.h @@ -35,12 +35,54 @@ SOFTWARE. #include #include +///\defgroup manchester manchester +/// Manchester encoding and decoding +///\ingroup utilities + namespace etl { //*************************************************************************** - /// Manchester encoding and decoding + /// Type trait to determine if a type is supported as an encode input. + ///\tparam TChunk The input type to check. //*************************************************************************** + template + struct is_supported_encode_input + { + static const bool value = +#if ETL_USING_8BIT_TYPES + etl::is_same::value || +#endif + etl::is_same::value +#if ETL_USING_64BIT_TYPES + || etl::is_same::value +#endif + ; + }; + //*************************************************************************** + /// Type trait to determine if a type is supported as a decode input. + ///\tparam TChunk The input type to check. + //*************************************************************************** + template + struct is_supported_decode_input + { + static const bool value = +#if ETL_USING_8BIT_TYPES + etl::is_same::value || +#endif + etl::is_same::value +#if ETL_USING_64BIT_TYPES + || etl::is_same::value +#endif + ; + }; + + //*************************************************************************** + ///\ingroup manchester + /// Type trait to determine the encoded type for a given decoded type. + /// Encoding doubles the bit width: uint8_t->uint16_t, uint16_t->uint32_t, etc. + ///\tparam T The input type to encode. + //*************************************************************************** template struct manchester_encoded { @@ -63,6 +105,12 @@ namespace etl typedef uint64_t type; }; + //*************************************************************************** + ///\ingroup manchester + /// Type trait to determine the decoded type for a given encoded type. + /// Decoding halves the bit width: uint16_t->uint8_t, uint32_t->uint16_t, etc. + ///\tparam T The encoded type to decode. + //*************************************************************************** template struct manchester_decoded { @@ -85,107 +133,128 @@ namespace etl typedef uint32_t type; }; - template - struct is_supported_encode_input + //*************************************************************************** + /// Normal Manchester encoding type (no inversion). + //*************************************************************************** + struct manchester_type_normal { - static const bool value = -#if ETL_USING_8BIT_TYPES - etl::is_same::value || -#endif - etl::is_same::value #if ETL_USING_64BIT_TYPES - || etl::is_same::value + static const uint64_t inversion_mask = 0x0000000000000000ULL; +#else + static const uint32_t inversion_mask = 0x00000000UL; #endif - ; }; - template - struct is_supported_decode_input + //*************************************************************************** + /// Inverted Manchester encoding type. + //*************************************************************************** + struct manchester_type_inverted { - static const bool value = -#if ETL_USING_8BIT_TYPES - etl::is_same::value || -#endif - etl::is_same::value #if ETL_USING_64BIT_TYPES - || etl::is_same::value + static const uint64_t inversion_mask = 0xFFFFFFFFFFFFFFFFULL; +#else + static const uint32_t inversion_mask = 0xFFFFFFFFUL; #endif - ; }; - struct manchester_type_normal + //*************************************************************************** + ///\ingroup manchester + /// Base template class for Manchester encoding and decoding. + ///\tparam TType The Manchester encoding type (normal or inverted). + //*************************************************************************** + template + struct manchester_base { - static const uint64_t invert_mask = 0x0000000000000000; - }; + ETL_STATIC_ASSERT((etl::is_same::value || + etl::is_same::value), + "TManchesterType must be manchester_type_normal or manchester_type_inverted"); - struct manchester_type_inverted - { - static const uint64_t invert_mask = 0xFFFFFFFFFFFFFFFF; - }; + //************************************************************************* + // Encoding functions + //************************************************************************* - template - struct manchester_base - { #if ETL_USING_8BIT_TYPES + //************************************************************************* + /// Encode a uint8_t value in place to a uint16_t. + ///\param decoded The value to encode. + ///\param encoded The encoded value. + //************************************************************************* template static ETL_CONSTEXPR14 typename etl::enable_if::value, void>::type - encode_in_place(TChunk in, uint16_t& out) + encode_in_place(TChunk decoded, uint16_t& encoded) { - out = in; + encoded = decoded; - out = (out | (out << 4U)) & 0x0F0FU; - out = (out | (out << 2U)) & 0x3333U; - out = (out | (out << 1U)) & 0x5555U; - out = (out | (out << 1U)) ^ (0xAAAAU ^ static_cast(TType::invert_mask)); + encoded = (encoded | (encoded << 4U)) & 0x0F0FU; + encoded = (encoded | (encoded << 2U)) & 0x3333U; + encoded = (encoded | (encoded << 1U)) & 0x5555U; + encoded = (encoded | (encoded << 1U)) ^ (0xAAAAU ^ static_cast(TManchesterType::inversion_mask)); } #endif + //************************************************************************* + /// Encode a uint16_t value in place to a uint32_t. + ///\param decoded The value to encode. + ///\param encoded The encoded value. + //************************************************************************* template static ETL_CONSTEXPR14 typename etl::enable_if::value, void>::type - encode_in_place(TChunk in, uint32_t& out) + encode_in_place(TChunk decoded, uint32_t& encoded) { - out = in; + encoded = decoded; - out = (out | (out << 8U)) & 0x00FF00FFUL; - out = (out | (out << 4U)) & 0x0F0F0F0FUL; - out = (out | (out << 2U)) & 0x33333333UL; - out = (out | (out << 1U)) & 0x55555555UL; - out = (out | (out << 1U)) ^ (0xAAAAAAAAUL ^ static_cast(TType::invert_mask)); + encoded = (encoded | (encoded << 8U)) & 0x00FF00FFUL; + encoded = (encoded | (encoded << 4U)) & 0x0F0F0F0FUL; + encoded = (encoded | (encoded << 2U)) & 0x33333333UL; + encoded = (encoded | (encoded << 1U)) & 0x55555555UL; + encoded = (encoded | (encoded << 1U)) ^ (0xAAAAAAAAUL ^ static_cast(TManchesterType::inversion_mask)); } -#if ETL_USING_64BIT_TYPES + //************************************************************************* + /// Encode a uint32_t value in place to a uint64_t. + ///\param decoded The value to encode. + ///\param encoded The encoded value. + //************************************************************************* template static ETL_CONSTEXPR14 typename etl::enable_if::value, void>::type - encode_in_place(TChunk in, uint64_t& out) + encode_in_place(TChunk decoded, uint64_t& encoded) { - out = in; - - out = (out | (out << 16U)) & 0x0000FFFF0000FFFFULL; - out = (out | (out << 8U)) & 0x00FF00FF00FF00FFULL; - out = (out | (out << 4U)) & 0x0F0F0F0F0F0F0F0FULL; - out = (out | (out << 2U)) & 0x3333333333333333ULL; - out = (out | (out << 1U)) & 0x5555555555555555ULL; - out = (out | (out << 1U)) ^ (0xAAAAAAAAAAAAAAAAULL ^ TType::invert_mask); + encoded = decoded; + + encoded = (encoded | (encoded << 16U)) & 0x0000FFFF0000FFFFULL; + encoded = (encoded | (encoded << 8U)) & 0x00FF00FF00FF00FFULL; + encoded = (encoded | (encoded << 4U)) & 0x0F0F0F0F0F0F0F0FULL; + encoded = (encoded | (encoded << 2U)) & 0x3333333333333333ULL; + encoded = (encoded | (encoded << 1U)) & 0x5555555555555555ULL; + encoded = (encoded | (encoded << 1U)) ^ (0xAAAAAAAAAAAAAAAAULL ^ TManchesterType::inversion_mask); } #endif template static typename etl::enable_if::value, void>::type - encode_in_place(TChunk in, typename manchester_encoded::type& out) = delete; + encode_in_place(TChunk decoded, typename manchester_encoded::type& encoded) ETL_DELETE; + //************************************************************************* + /// Encode a value and return the Manchester encoded result. + ///\param decoded The value to encode. + ///\return The Manchester encoded value. + //************************************************************************* template - ETL_NODISCARD static ETL_CONSTEXPR14 typename etl::enable_if::value, typename manchester_encoded::type>::type - encode(TChunk in) + ETL_NODISCARD static ETL_CONSTEXPR14 typename manchester_encoded::type encode(TChunk decoded) { - typename manchester_encoded::type out = 0; - encode_in_place(in, out); - return out; + ETL_STATIC_ASSERT(is_supported_encode_input::value, "TChunk must be a supported encode input type"); + + typename manchester_encoded::type encoded = 0; + encode_in_place(decoded, encoded); + return encoded; } - template - static typename etl::enable_if::value, typename manchester_encoded::type>::type - encode(TChunk in) = delete; - + //************************************************************************* + /// Encode a span of data. + ///\param source The source data to encode. + ///\param destination The destination buffer for encoded data. + ///\tparam TChunk The chunk size for encoding (default: uint_least8_t). + //************************************************************************* template static void encode_span(etl::span source, etl::span destination) { @@ -194,99 +263,115 @@ namespace etl while (!source.empty()) { - const TChunk& in = *reinterpret_cast(source.data()); - typename etl::manchester_encoded::type& out = *reinterpret_cast::type*>(destination.data()); + const TChunk& decoded = *reinterpret_cast(source.data()); + typename etl::manchester_encoded::type& encoded = *reinterpret_cast::type*>(destination.data()); - encode_in_place(in, out); + encode_in_place(decoded, encoded); source.advance(sizeof(TChunk)); destination.advance(sizeof(typename etl::manchester_encoded::type)); } } + //************************************************************************* + // Decoding functions + //************************************************************************* + +#if ETL_USING_8BIT_TYPES #if ETL_USING_8BIT_TYPES + //************************************************************************* + /// Decode a uint16_t value in place to a uint8_t. + ///\param encoded The value to decode. + ///\param decoded The decoded value. + //************************************************************************* template static ETL_CONSTEXPR14 typename etl::enable_if::value, void>::type - decode_in_place(TChunk in, uint8_t& out) + decode_in_place(TChunk encoded, uint8_t& decoded) { - in = (in ^ (0xAAAAU ^ static_cast(TType::invert_mask))) & 0x5555U; - in = (in | (in >> 1)) & 0x3333U; - in = (in | (in >> 2)) & 0x0F0FU; - out = static_cast(in | (in >> 4U)); + encoded = (encoded ^ (0xAAAAU ^ static_cast(TManchesterType::inversion_mask))) & 0x5555U; + encoded = (encoded | (encoded >> 1)) & 0x3333U; + encoded = (encoded | (encoded >> 2)) & 0x0F0FU; + decoded = static_cast(encoded | (encoded >> 4U)); } #endif + //************************************************************************* + /// Decode a uint32_t value in place to a uint16_t. + ///\param encoded The value to decode. + ///\param decoded The decoded value. + //************************************************************************* template static ETL_CONSTEXPR14 typename etl::enable_if::value, void>::type - decode_in_place(TChunk in, uint16_t& out) + decode_in_place(TChunk encoded, uint16_t& decoded) { - in = (in ^ (0xAAAAAAAAUL ^ static_cast(TType::invert_mask))) & 0x55555555UL; - in = (in | (in >> 1)) & 0x33333333UL; - in = (in | (in >> 2)) & 0x0F0F0F0FUL; - in = (in | (in >> 4)) & 0x00FF00FFUL; - out = static_cast(in | (in >> 8U)); + encoded = (encoded ^ (0xAAAAAAAAUL ^ static_cast(TManchesterType::inversion_mask))) & 0x55555555UL; + encoded = (encoded | (encoded >> 1)) & 0x33333333UL; + encoded = (encoded | (encoded >> 2)) & 0x0F0F0F0FUL; + encoded = (encoded | (encoded >> 4)) & 0x00FF00FFUL; + decoded = static_cast(encoded | (encoded >> 8U)); } #if ETL_USING_64BIT_TYPES + //************************************************************************* + /// Decode a uint64_t value in place to a uint32_t. + ///\param encoded The value to decode. + ///\param decoded The decoded value. + //************************************************************************* template static ETL_CONSTEXPR14 typename etl::enable_if::value, void>::type - decode_in_place(TChunk in, uint32_t& out) + decode_in_place(TChunk encoded, uint32_t& decoded) { - in = (in ^ (0xAAAAAAAAAAAAAAAAULL ^ TType::invert_mask)) & 0x5555555555555555ULL; - in = (in | (in >> 1)) & 0x3333333333333333ULL; - in = (in | (in >> 2)) & 0x0F0F0F0F0F0F0F0FULL; - in = (in | (in >> 4)) & 0x00FF00FF00FF00FFULL; - in = (in | (in >> 8)) & 0x0000FFFF0000FFFFULL; - out = static_cast(in | (in >> 16U)); + encoded = (encoded ^ (0xAAAAAAAAAAAAAAAAULL ^ TManchesterType::inversion_mask)) & 0x5555555555555555ULL; + encoded = (encoded | (encoded >> 1)) & 0x3333333333333333ULL; + encoded = (encoded | (encoded >> 2)) & 0x0F0F0F0F0F0F0F0FULL; + encoded = (encoded | (encoded >> 4)) & 0x00FF00FF00FF00FFULL; + encoded = (encoded | (encoded >> 8)) & 0x0000FFFF0000FFFFULL; + decoded = static_cast(encoded | (encoded >> 16U)); } #endif template static typename etl::enable_if::value, void>::type - decode_in_place(TChunk in, typename manchester_decoded::type& out) = delete; + decode_in_place(TChunk encoded, typename manchester_decoded::type& decoded) ETL_DELETE; + //************************************************************************* + /// Decode a value and return the Manchester decoded result. + ///\param encoded The value to decode. + ///\return The Manchester decoded value. + //************************************************************************* template - ETL_NODISCARD static ETL_CONSTEXPR14 typename etl::enable_if::value, typename manchester_decoded::type>::type - decode(TChunk in) + ETL_NODISCARD static ETL_CONSTEXPR14 typename manchester_decoded::type decode(TChunk encoded) { - typename manchester_decoded::type out = 0; - decode_in_place(in, out); - return out; + ETL_STATIC_ASSERT(is_supported_decode_input::value, "TChunk must be a supported decode input type"); + + typename manchester_decoded::type decoded = 0; + decode_in_place(encoded, decoded); + return decoded; } - template - static typename etl::enable_if::value, typename manchester_decoded::type>::type - decode(TChunk in) = delete; - -#if ETL_USING_8BIT_TYPES - template - ETL_NODISCARD static ETL_CONSTEXPR typename etl::enable_if::value, bool>::type - valid(TChunk encoded) - { - return (((encoded ^ (encoded >> 1)) & 0x5555U) == 0x5555U); - } -#endif + //************************************************************************* + // Validation functions + //************************************************************************* + //************************************************************************* + /// Validate that a value contains valid Manchester encoded data. + ///\param encoded The encoded value to validate. + ///\return True if the value is valid Manchester encoding. + //************************************************************************* template - ETL_NODISCARD static ETL_CONSTEXPR typename etl::enable_if::value, bool>::type - valid(TChunk encoded) + ETL_NODISCARD static ETL_CONSTEXPR bool valid(TChunk encoded) { - return (((encoded ^ (encoded >> 1)) & 0x55555555U) == 0x55555555U); + ETL_STATIC_ASSERT(is_supported_decode_input::value, "TChunk must be a supported decode input type"); + + const TChunk mask = static_cast(0x5555555555555555ULL); + return (((encoded ^ (encoded >> 1)) & mask) == mask); } -#if ETL_USING_64BIT_TYPES - template - ETL_NODISCARD static ETL_CONSTEXPR typename etl::enable_if::value, bool>::type - valid(TChunk encoded) - { - return (((encoded ^ (encoded >> 1)) & 0x5555555555555555U) == 0x5555555555555555U); - } -#endif - - template - static typename etl::enable_if::value, bool>::type - valid(TChunk encoded) = delete; - + //************************************************************************* + /// Validate that a span contains valid Manchester encoded data. + ///\param encoded The span of encoded data to validate. + ///\return True if all data is valid Manchester encoding. + //************************************************************************* ETL_NODISCARD static ETL_CONSTEXPR14 bool valid_span(etl::span encoded) { ETL_ASSERT(encoded.size() % sizeof(uint16_t) == 0, ""); @@ -303,6 +388,16 @@ namespace etl return true; } + //************************************************************************* + // Span decoding functions + //************************************************************************* + + //************************************************************************* + /// Decode a span of data using specified chunk type. + ///\param source The source encoded data to decode. + ///\param destination The destination buffer for decoded data. + ///\tparam TChunk The chunk type for decoding. + //************************************************************************* template static typename etl::enable_if::type>::value, void>::type decode_span(etl::span source, etl::span destination) @@ -316,16 +411,22 @@ namespace etl size_t source_index = 0; for (size_t i = 0; i < source.size() / sizeof(TChunk); ++i) { - TChunk encoded = 0; - memcpy(&encoded, &source[source_index], sizeof(TChunk)); - const TChunkDecoded decoded = decode(encoded); - memcpy(&destination[dest_index], &decoded, sizeof(TChunkDecoded)); + TChunk encoded_value = 0; + memcpy(&encoded_value, &source[source_index], sizeof(TChunk)); + const TChunkDecoded decoded_value = decode(encoded_value); + memcpy(&destination[dest_index], &decoded_value, sizeof(TChunkDecoded)); source_index += sizeof(TChunk); dest_index += sizeof(TChunkDecoded); } } + //************************************************************************* + /// Decode a span of data using default chunk type (optimized version). + ///\param source The source encoded data to decode. + ///\param destination The destination buffer for decoded data. + ///\tparam TChunk The chunk type for decoding (default type). + //************************************************************************* template ::type> static ETL_CONSTEXPR14 typename etl::enable_if::type>::value, void>::type decode_span(etl::span source, etl::span destination) @@ -339,14 +440,20 @@ namespace etl size_t source_index = 0; for (size_t i = 0; i < source.size() / sizeof(TChunk); ++i) { - const TChunk encoded = static_cast((source[source_index + 1] << 8) | source[source_index]); - destination[dest_index] = decode(encoded); + const TChunk encoded_value = static_cast((source[source_index + 1] << 8) | source[source_index]); + destination[dest_index] = decode(encoded_value); source_index += sizeof(TChunk); dest_index += sizeof(TChunkDecoded); } } + //************************************************************************* + /// Fast decode a span of data using pointer arithmetic. + ///\param source The source encoded data to decode. + ///\param destination The destination buffer for decoded data. + ///\tparam TChunk The chunk size for decoding (default: uint16_t). + //************************************************************************* template ::type> static void decode_span_fast(etl::span source, etl::span destination) { @@ -355,10 +462,10 @@ namespace etl while (!source.empty()) { - const TChunk& in = *reinterpret_cast(source.data()); - typename etl::manchester_decoded::type& out = *reinterpret_cast::type*>(destination.data()); + const TChunk& encoded = *reinterpret_cast(source.data()); + typename etl::manchester_decoded::type& decoded = *reinterpret_cast::type*>(destination.data()); - decode_in_place(in, out); + decode_in_place(encoded, decoded); source.advance(sizeof(TChunk)); destination.advance(sizeof(typename etl::manchester_decoded::type)); @@ -366,7 +473,16 @@ namespace etl } }; + //*************************************************************************** + ///\ingroup manchester + /// Manchester encoder using normal encoding (no inversion). + //*************************************************************************** typedef manchester_base manchester; + + //*************************************************************************** + ///\ingroup manchester + /// Manchester encoder using inverted encoding. + //*************************************************************************** typedef manchester_base manchester_inverted; } // namespace etl From fd391c45158049fb5336d84e0374e993f34e0eae Mon Sep 17 00:00:00 2001 From: Timon Zijnge Date: Wed, 7 Jan 2026 14:08:54 +0100 Subject: [PATCH 18/46] manchester * introducing namespace detail_manchester --- include/etl/manchester.h | 251 ++++++++++++++++++++------------------- 1 file changed, 126 insertions(+), 125 deletions(-) diff --git a/include/etl/manchester.h b/include/etl/manchester.h index e277a4070..b84adb23d 100644 --- a/include/etl/manchester.h +++ b/include/etl/manchester.h @@ -41,121 +41,122 @@ SOFTWARE. namespace etl { - //*************************************************************************** - /// Type trait to determine if a type is supported as an encode input. - ///\tparam TChunk The input type to check. - //*************************************************************************** - template - struct is_supported_encode_input + namespace private_manchester { - static const bool value = + //************************************************************************* + /// Type trait to determine if a type is supported as an encode input. + ///\tparam TChunk The input type to check. + //************************************************************************* + template + struct is_supported_encode_input + { + static const bool value = #if ETL_USING_8BIT_TYPES - etl::is_same::value || + etl::is_same::value || #endif - etl::is_same::value + etl::is_same::value #if ETL_USING_64BIT_TYPES - || etl::is_same::value + || etl::is_same::value #endif - ; - }; + ; + }; - //*************************************************************************** - /// Type trait to determine if a type is supported as a decode input. - ///\tparam TChunk The input type to check. - //*************************************************************************** - template - struct is_supported_decode_input - { - static const bool value = + //************************************************************************* + /// Type trait to determine if a type is supported as a decode input. + ///\tparam TChunk The input type to check. + //************************************************************************* + template + struct is_supported_decode_input + { + static const bool value = #if ETL_USING_8BIT_TYPES - etl::is_same::value || + etl::is_same::value || #endif - etl::is_same::value + etl::is_same::value #if ETL_USING_64BIT_TYPES - || etl::is_same::value + || etl::is_same::value #endif - ; - }; + ; + }; - //*************************************************************************** - ///\ingroup manchester - /// Type trait to determine the encoded type for a given decoded type. - /// Encoding doubles the bit width: uint8_t->uint16_t, uint16_t->uint32_t, etc. - ///\tparam T The input type to encode. - //*************************************************************************** - template - struct manchester_encoded - { - ETL_STATIC_ASSERT(sizeof(T) == 0, "Manchester encoding type should be one of [uint8_t, uint16_t, uint32_t]"); - }; + //************************************************************************* + /// Type trait to determine the encoded type for a given decoded type. + /// Encoding doubles the bit width: uint8_t->uint16_t, uint16_t->uint32_t, etc. + ///\tparam T The decoded type. + //************************************************************************* + template + struct manchester_encoded + { + ETL_STATIC_ASSERT(sizeof(T) == 0, "Manchester encoding type should be one of [uint8_t, uint16_t, uint32_t]"); + }; - template <> - struct manchester_encoded - { - typedef uint16_t type; - }; - template <> - struct manchester_encoded - { - typedef uint32_t type; - }; - template <> - struct manchester_encoded - { - typedef uint64_t type; - }; + template <> + struct manchester_encoded + { + typedef uint16_t type; + }; + template <> + struct manchester_encoded + { + typedef uint32_t type; + }; + template <> + struct manchester_encoded + { + typedef uint64_t type; + }; - //*************************************************************************** - ///\ingroup manchester - /// Type trait to determine the decoded type for a given encoded type. - /// Decoding halves the bit width: uint16_t->uint8_t, uint32_t->uint16_t, etc. - ///\tparam T The encoded type to decode. - //*************************************************************************** - template - struct manchester_decoded - { - ETL_STATIC_ASSERT(sizeof(T) == 0, "Manchester decoding type should be one of [uint16_t, uint32_t, uint64_t]"); - }; + //************************************************************************* + /// Type trait to determine the decoded type for a given encoded type. + /// Decoding halves the bit width: uint16_t->uint8_t, uint32_t->uint16_t, etc. + ///\tparam T The encoded type. + //************************************************************************* + template + struct manchester_decoded + { + ETL_STATIC_ASSERT(sizeof(T) == 0, "Manchester decoding type should be one of [uint16_t, uint32_t, uint64_t]"); + }; - template <> - struct manchester_decoded - { - typedef uint8_t type; - }; - template <> - struct manchester_decoded - { - typedef uint16_t type; - }; - template <> - struct manchester_decoded - { - typedef uint32_t type; - }; + template <> + struct manchester_decoded + { + typedef uint8_t type; + }; + template <> + struct manchester_decoded + { + typedef uint16_t type; + }; + template <> + struct manchester_decoded + { + typedef uint32_t type; + }; - //*************************************************************************** - /// Normal Manchester encoding type (no inversion). - //*************************************************************************** - struct manchester_type_normal - { + //************************************************************************* + /// Normal Manchester encoding type (no inversion). + //************************************************************************* + struct manchester_type_normal + { #if ETL_USING_64BIT_TYPES - static const uint64_t inversion_mask = 0x0000000000000000ULL; + static const uint64_t inversion_mask = 0x0000000000000000ULL; #else - static const uint32_t inversion_mask = 0x00000000UL; + static const uint32_t inversion_mask = 0x00000000UL; #endif - }; + }; - //*************************************************************************** - /// Inverted Manchester encoding type. - //*************************************************************************** - struct manchester_type_inverted - { + //************************************************************************* + /// Inverted Manchester encoding type. + //************************************************************************* + struct manchester_type_inverted + { #if ETL_USING_64BIT_TYPES - static const uint64_t inversion_mask = 0xFFFFFFFFFFFFFFFFULL; + static const uint64_t inversion_mask = 0xFFFFFFFFFFFFFFFFULL; #else - static const uint32_t inversion_mask = 0xFFFFFFFFUL; + static const uint32_t inversion_mask = 0xFFFFFFFFUL; #endif - }; + }; + } // namespace private_manchester //*************************************************************************** ///\ingroup manchester @@ -165,8 +166,8 @@ namespace etl template struct manchester_base { - ETL_STATIC_ASSERT((etl::is_same::value || - etl::is_same::value), + ETL_STATIC_ASSERT((etl::is_same::value || + etl::is_same::value), "TManchesterType must be manchester_type_normal or manchester_type_inverted"); //************************************************************************* @@ -231,8 +232,8 @@ namespace etl #endif template - static typename etl::enable_if::value, void>::type - encode_in_place(TChunk decoded, typename manchester_encoded::type& encoded) ETL_DELETE; + static typename etl::enable_if::value, void>::type + encode_in_place(TChunk decoded, typename private_manchester::manchester_encoded::type& encoded) ETL_DELETE; //************************************************************************* /// Encode a value and return the Manchester encoded result. @@ -240,11 +241,11 @@ namespace etl ///\return The Manchester encoded value. //************************************************************************* template - ETL_NODISCARD static ETL_CONSTEXPR14 typename manchester_encoded::type encode(TChunk decoded) + ETL_NODISCARD static ETL_CONSTEXPR14 typename private_manchester::manchester_encoded::type encode(TChunk decoded) { - ETL_STATIC_ASSERT(is_supported_encode_input::value, "TChunk must be a supported encode input type"); - - typename manchester_encoded::type encoded = 0; + ETL_STATIC_ASSERT(private_manchester::is_supported_encode_input::value, "TChunk must be a supported encode input type"); + + typename private_manchester::manchester_encoded::type encoded = 0; encode_in_place(decoded, encoded); return encoded; } @@ -263,13 +264,13 @@ namespace etl while (!source.empty()) { - const TChunk& decoded = *reinterpret_cast(source.data()); - typename etl::manchester_encoded::type& encoded = *reinterpret_cast::type*>(destination.data()); + const TChunk& decoded = *reinterpret_cast(source.data()); + typename etl::private_manchester::manchester_encoded::type& encoded = *reinterpret_cast::type*>(destination.data()); encode_in_place(decoded, encoded); source.advance(sizeof(TChunk)); - destination.advance(sizeof(typename etl::manchester_encoded::type)); + destination.advance(sizeof(typename etl::private_manchester::manchester_encoded::type)); } } @@ -331,8 +332,8 @@ namespace etl #endif template - static typename etl::enable_if::value, void>::type - decode_in_place(TChunk encoded, typename manchester_decoded::type& decoded) ETL_DELETE; + static typename etl::enable_if::value, void>::type + decode_in_place(TChunk encoded, typename private_manchester::manchester_decoded::type& decoded) ETL_DELETE; //************************************************************************* /// Decode a value and return the Manchester decoded result. @@ -340,11 +341,11 @@ namespace etl ///\return The Manchester decoded value. //************************************************************************* template - ETL_NODISCARD static ETL_CONSTEXPR14 typename manchester_decoded::type decode(TChunk encoded) + ETL_NODISCARD static ETL_CONSTEXPR14 typename private_manchester::manchester_decoded::type decode(TChunk encoded) { - ETL_STATIC_ASSERT(is_supported_decode_input::value, "TChunk must be a supported decode input type"); - - typename manchester_decoded::type decoded = 0; + ETL_STATIC_ASSERT(private_manchester::is_supported_decode_input::value, "TChunk must be a supported decode input type"); + + typename private_manchester::manchester_decoded::type decoded = 0; decode_in_place(encoded, decoded); return decoded; } @@ -359,10 +360,10 @@ namespace etl ///\return True if the value is valid Manchester encoding. //************************************************************************* template - ETL_NODISCARD static ETL_CONSTEXPR bool valid(TChunk encoded) + ETL_NODISCARD static ETL_CONSTEXPR14 bool valid(TChunk encoded) { - ETL_STATIC_ASSERT(is_supported_decode_input::value, "TChunk must be a supported decode input type"); - + ETL_STATIC_ASSERT(private_manchester::is_supported_decode_input::value, "TChunk must be a supported decode input type"); + const TChunk mask = static_cast(0x5555555555555555ULL); return (((encoded ^ (encoded >> 1)) & mask) == mask); } @@ -399,10 +400,10 @@ namespace etl ///\tparam TChunk The chunk type for decoding. //************************************************************************* template - static typename etl::enable_if::type>::value, void>::type + static typename etl::enable_if::type>::value, void>::type decode_span(etl::span source, etl::span destination) { - typedef typename manchester_decoded::type TChunkDecoded; + typedef typename private_manchester::manchester_decoded::type TChunkDecoded; ETL_ASSERT(destination.size() * 2 >= source.size(), "Manchester decoding requires destination storage to be no less than half the source storage"); ETL_ASSERT(source.size() % sizeof(TChunk) == 0, "Manchester decoding requires the source storage size to be an integer multiple of the decoding chunk size"); @@ -427,8 +428,8 @@ namespace etl ///\param destination The destination buffer for decoded data. ///\tparam TChunk The chunk type for decoding (default type). //************************************************************************* - template ::type> - static ETL_CONSTEXPR14 typename etl::enable_if::type>::value, void>::type + template ::type> + static ETL_CONSTEXPR14 typename etl::enable_if::type>::value, void>::type decode_span(etl::span source, etl::span destination) { typedef uint_least8_t TChunkDecoded; @@ -454,7 +455,7 @@ namespace etl ///\param destination The destination buffer for decoded data. ///\tparam TChunk The chunk size for decoding (default: uint16_t). //************************************************************************* - template ::type> + template ::type> static void decode_span_fast(etl::span source, etl::span destination) { ETL_ASSERT(destination.size() * 2 >= source.size(), "Manchester decoding requires destination storage to be no less than half the source storage"); @@ -462,13 +463,13 @@ namespace etl while (!source.empty()) { - const TChunk& encoded = *reinterpret_cast(source.data()); - typename etl::manchester_decoded::type& decoded = *reinterpret_cast::type*>(destination.data()); + const TChunk& encoded = *reinterpret_cast(source.data()); + typename etl::private_manchester::manchester_decoded::type& decoded = *reinterpret_cast::type*>(destination.data()); decode_in_place(encoded, decoded); source.advance(sizeof(TChunk)); - destination.advance(sizeof(typename etl::manchester_decoded::type)); + destination.advance(sizeof(typename etl::private_manchester::manchester_decoded::type)); } } }; @@ -477,13 +478,13 @@ namespace etl ///\ingroup manchester /// Manchester encoder using normal encoding (no inversion). //*************************************************************************** - typedef manchester_base manchester; - + typedef manchester_base manchester; + //*************************************************************************** - ///\ingroup manchester + ///\ingroup manchester /// Manchester encoder using inverted encoding. //*************************************************************************** - typedef manchester_base manchester_inverted; + typedef manchester_base manchester_inverted; } // namespace etl From bb6f6aace478617cb78d552c2d111ce322ff2d95 Mon Sep 17 00:00:00 2001 From: Timon Zijnge Date: Wed, 7 Jan 2026 14:37:51 +0100 Subject: [PATCH 19/46] manchester * Some refactoring * Update tests --- include/etl/manchester.h | 26 ++++++++++++------------- test/test_manchester.cpp | 41 +++++++++++++++++++++------------------- 2 files changed, 35 insertions(+), 32 deletions(-) diff --git a/include/etl/manchester.h b/include/etl/manchester.h index b84adb23d..f2ba70e83 100644 --- a/include/etl/manchester.h +++ b/include/etl/manchester.h @@ -48,7 +48,7 @@ namespace etl ///\tparam TChunk The input type to check. //************************************************************************* template - struct is_supported_encode_input + struct is_encodable { static const bool value = #if ETL_USING_8BIT_TYPES @@ -66,7 +66,7 @@ namespace etl ///\tparam TChunk The input type to check. //************************************************************************* template - struct is_supported_decode_input + struct is_decodable { static const bool value = #if ETL_USING_8BIT_TYPES @@ -232,7 +232,7 @@ namespace etl #endif template - static typename etl::enable_if::value, void>::type + static typename etl::enable_if::value, void>::type encode_in_place(TChunk decoded, typename private_manchester::manchester_encoded::type& encoded) ETL_DELETE; //************************************************************************* @@ -243,7 +243,7 @@ namespace etl template ETL_NODISCARD static ETL_CONSTEXPR14 typename private_manchester::manchester_encoded::type encode(TChunk decoded) { - ETL_STATIC_ASSERT(private_manchester::is_supported_encode_input::value, "TChunk must be a supported encode input type"); + ETL_STATIC_ASSERT(private_manchester::is_encodable::value, "TChunk must be an encodable type"); typename private_manchester::manchester_encoded::type encoded = 0; encode_in_place(decoded, encoded); @@ -332,7 +332,7 @@ namespace etl #endif template - static typename etl::enable_if::value, void>::type + static typename etl::enable_if::value, void>::type decode_in_place(TChunk encoded, typename private_manchester::manchester_decoded::type& decoded) ETL_DELETE; //************************************************************************* @@ -343,7 +343,7 @@ namespace etl template ETL_NODISCARD static ETL_CONSTEXPR14 typename private_manchester::manchester_decoded::type decode(TChunk encoded) { - ETL_STATIC_ASSERT(private_manchester::is_supported_decode_input::value, "TChunk must be a supported decode input type"); + ETL_STATIC_ASSERT(private_manchester::is_decodable::value, "TChunk must be a decodable type"); typename private_manchester::manchester_decoded::type decoded = 0; decode_in_place(encoded, decoded); @@ -362,7 +362,7 @@ namespace etl template ETL_NODISCARD static ETL_CONSTEXPR14 bool valid(TChunk encoded) { - ETL_STATIC_ASSERT(private_manchester::is_supported_decode_input::value, "TChunk must be a supported decode input type"); + ETL_STATIC_ASSERT(private_manchester::is_decodable::value, "TChunk must be a decodable type"); const TChunk mask = static_cast(0x5555555555555555ULL); return (((encoded ^ (encoded >> 1)) & mask) == mask); @@ -403,7 +403,7 @@ namespace etl static typename etl::enable_if::type>::value, void>::type decode_span(etl::span source, etl::span destination) { - typedef typename private_manchester::manchester_decoded::type TChunkDecoded; + typedef typename private_manchester::manchester_decoded::type TDecoded; ETL_ASSERT(destination.size() * 2 >= source.size(), "Manchester decoding requires destination storage to be no less than half the source storage"); ETL_ASSERT(source.size() % sizeof(TChunk) == 0, "Manchester decoding requires the source storage size to be an integer multiple of the decoding chunk size"); @@ -414,11 +414,11 @@ namespace etl { TChunk encoded_value = 0; memcpy(&encoded_value, &source[source_index], sizeof(TChunk)); - const TChunkDecoded decoded_value = decode(encoded_value); - memcpy(&destination[dest_index], &decoded_value, sizeof(TChunkDecoded)); + const TDecoded decoded_value = decode(encoded_value); + memcpy(&destination[dest_index], &decoded_value, sizeof(TDecoded)); source_index += sizeof(TChunk); - dest_index += sizeof(TChunkDecoded); + dest_index += sizeof(TDecoded); } } @@ -432,7 +432,7 @@ namespace etl static ETL_CONSTEXPR14 typename etl::enable_if::type>::value, void>::type decode_span(etl::span source, etl::span destination) { - typedef uint_least8_t TChunkDecoded; + typedef uint_least8_t TDecoded; ETL_ASSERT(destination.size() * 2 >= source.size(), "Manchester decoding requires destination storage to be no less than half the source storage"); ETL_ASSERT(source.size() % sizeof(TChunk) == 0, "Manchester decoding requires the source storage size to be an integer multiple of the decoding chunk size"); @@ -445,7 +445,7 @@ namespace etl destination[dest_index] = decode(encoded_value); source_index += sizeof(TChunk); - dest_index += sizeof(TChunkDecoded); + dest_index += sizeof(TDecoded); } } diff --git a/test/test_manchester.cpp b/test/test_manchester.cpp index 8c8fa5527..5ce0a83f3 100644 --- a/test/test_manchester.cpp +++ b/test/test_manchester.cpp @@ -192,10 +192,10 @@ SUITE(test_manchester) { etl::array input{0xAA, 0xAA, 0x55, 0x55, 0xA9, 0xAA, 0XAA, 0x6A}; - alignas(uint8_t) etl::array output0; - alignas(uint8_t) etl::array output1; - alignas(uint16_t) etl::array output2; - alignas(uint32_t) etl::array output3; + etl::array output0; + etl::array output1; + etl::array output2; + etl::array output3; etl::manchester::decode_span(input, output0); etl::manchester::decode_span(input, output1); @@ -216,10 +216,10 @@ SUITE(test_manchester) { etl::array input{0x55, 0x55, 0xAA, 0xAA, 0x56, 0x55, 0X55, 0x95}; - alignas(uint8_t) etl::array output0; - alignas(uint8_t) etl::array output1; - alignas(uint16_t) etl::array output2; - alignas(uint32_t) etl::array output3; + etl::array output0; + etl::array output1; + etl::array output2; + etl::array output3; etl::manchester_inverted::decode_span(input, output0); etl::manchester_inverted::decode_span(input, output1); @@ -314,17 +314,20 @@ SUITE(test_manchester) } }; -// #if ETL_USING_CPP14 -// constexpr etl::array manchester_encoded(etl::span input) -// { -// alignas(uint8_t) etl::array output {0, 0, 0, 0}; -// etl::manchester::decode_span(input, output); +#if ETL_USING_CPP14 +constexpr etl::array manchester_decoded(etl::span input) +{ + etl::array output {0, 0, 0, 0}; + etl::manchester::decode_span(input, output); -// return output; -// } + return output; +} -// constexpr etl::array input{0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0XAA, 0xAA}; +constexpr etl::array input{0xAA, 0xAA, 0x55, 0x55, 0xA9, 0xAA, 0XAA, 0x6A}; -// constexpr etl::array bla = manchester_encoded(input); -// static_assert(bla[0] == 0, "Compile time computation of many values failed"); -// #endif \ No newline at end of file +constexpr etl::array decoded = manchester_decoded(input); +static_assert(decoded[0] == 0x00, "Compile time decoding on range failed"); +static_assert(decoded[1] == 0xFF, "Compile time decoding on range failed"); +static_assert(decoded[2] == 0x01, "Compile time decoding on range failed"); +static_assert(decoded[3] == 0x80, "Compile time decoding on range failed"); +#endif \ No newline at end of file From eebf60cacfe3c89d011e125781fb5f918d1d7a26 Mon Sep 17 00:00:00 2001 From: Timon Zijnge Date: Thu, 8 Jan 2026 17:07:06 +0100 Subject: [PATCH 20/46] manchester * Some refactoring * Removed possible undefined behavior by refactoring encode_span * constexpr version of encode_span * Static assertion for rare case where code doesn't work because CHAR_BIT is not the same as the number of bits in uint_least8_t --- include/etl/manchester.h | 70 +++++++--- test/test_manchester.cpp | 268 ++++++++++++++++++++------------------- 2 files changed, 196 insertions(+), 142 deletions(-) diff --git a/include/etl/manchester.h b/include/etl/manchester.h index f2ba70e83..7afa4482f 100644 --- a/include/etl/manchester.h +++ b/include/etl/manchester.h @@ -170,6 +170,8 @@ namespace etl etl::is_same::value), "TManchesterType must be manchester_type_normal or manchester_type_inverted"); + ETL_STATIC_ASSERT(CHAR_BIT == etl::numeric_limits::digits, "Manchester requires uint_least8_t to have the same number of bits as CHAR (CHAR_BITS)"); + //************************************************************************* // Encoding functions //************************************************************************* @@ -251,26 +253,62 @@ namespace etl } //************************************************************************* - /// Encode a span of data. + /// Encode a span of data with the selected chunk size. ///\param source The source data to encode. ///\param destination The destination buffer for encoded data. ///\tparam TChunk The chunk size for encoding (default: uint_least8_t). //************************************************************************* - template - static void encode_span(etl::span source, etl::span destination) + template + static typename etl::enable_if::value, void>::type + encode_span(etl::span source, etl::span destination) { + typedef TChunk TDecoded; + typedef typename etl::private_manchester::manchester_encoded::type TEncoded; + ETL_ASSERT(destination.size() >= source.size() * 2, "Manchester encoding requires destination storage to be at least twice the size of the source storage"); - ETL_ASSERT(source.size() % sizeof(TChunk) == 0, "Manchester encoding requires the source storage size to be an integer multiple of the encoding chunk size"); + ETL_ASSERT(source.size() % sizeof(TDecoded) == 0, "Manchester encoding requires the source storage size to be an integer multiple of the encoding chunk size"); - while (!source.empty()) + size_t dest_index = 0; + size_t source_index = 0; + for (size_t i = 0; i < source.size() / sizeof(TDecoded); ++i) { - const TChunk& decoded = *reinterpret_cast(source.data()); - typename etl::private_manchester::manchester_encoded::type& encoded = *reinterpret_cast::type*>(destination.data()); + TDecoded decoded_value = 0; + memcpy(&decoded_value, &source[source_index], sizeof(TDecoded)); + const TEncoded encoded_value = encode(decoded_value); + memcpy(&destination[dest_index], &encoded_value, sizeof(TEncoded)); - encode_in_place(decoded, encoded); + source_index += sizeof(TDecoded); + dest_index += sizeof(TEncoded); + } + } - source.advance(sizeof(TChunk)); - destination.advance(sizeof(typename etl::private_manchester::manchester_encoded::type)); + //************************************************************************* + /// Encode a span of data with the minimum chunk size. This version is + /// constexpr so that it can be used to decode data at compile time. + ///\param source The source data to encode. + ///\param destination The destination buffer for encoded data. + ///\tparam TChunk The chunk size for encoding (default: uint_least8_t). + //************************************************************************* + template + static typename etl::enable_if::value, void>::type + constexpr encode_span(etl::span source, etl::span destination) + { + typedef TChunk TDecoded; + typedef typename etl::private_manchester::manchester_encoded::type TEncoded; + + ETL_ASSERT(destination.size() >= source.size() * 2, "Manchester encoding requires destination storage to be at least twice the size of the source storage"); + ETL_ASSERT(source.size() % sizeof(TDecoded) == 0, "Manchester encoding requires the source storage size to be an integer multiple of the encoding chunk size"); + + size_t dest_index = 0; + size_t source_index = 0; + for (size_t i = 0; i < source.size() / sizeof(TDecoded); ++i) + { + const TEncoded encoded_value = encode(source[source_index]); + destination[dest_index] = static_cast(encoded_value); + destination[dest_index + 1] = static_cast(encoded_value >> CHAR_BIT); + + source_index += sizeof(TDecoded); + dest_index += sizeof(TEncoded); } } @@ -404,26 +442,28 @@ namespace etl decode_span(etl::span source, etl::span destination) { typedef typename private_manchester::manchester_decoded::type TDecoded; + typedef TChunk TEncoded; ETL_ASSERT(destination.size() * 2 >= source.size(), "Manchester decoding requires destination storage to be no less than half the source storage"); ETL_ASSERT(source.size() % sizeof(TChunk) == 0, "Manchester decoding requires the source storage size to be an integer multiple of the decoding chunk size"); size_t dest_index = 0; size_t source_index = 0; - for (size_t i = 0; i < source.size() / sizeof(TChunk); ++i) + for (size_t i = 0; i < source.size() / sizeof(TEncoded); ++i) { TChunk encoded_value = 0; - memcpy(&encoded_value, &source[source_index], sizeof(TChunk)); + memcpy(&encoded_value, &source[source_index], sizeof(TEncoded)); const TDecoded decoded_value = decode(encoded_value); memcpy(&destination[dest_index], &decoded_value, sizeof(TDecoded)); - source_index += sizeof(TChunk); + source_index += sizeof(TEncoded); dest_index += sizeof(TDecoded); } } //************************************************************************* - /// Decode a span of data using default chunk type (optimized version). + /// Decode a span of data using the smalles chunk type. This version is + /// constexpr so that it can be used to decode data at compile time. ///\param source The source encoded data to decode. ///\param destination The destination buffer for decoded data. ///\tparam TChunk The chunk type for decoding (default type). @@ -441,7 +481,7 @@ namespace etl size_t source_index = 0; for (size_t i = 0; i < source.size() / sizeof(TChunk); ++i) { - const TChunk encoded_value = static_cast((source[source_index + 1] << 8) | source[source_index]); + const TChunk encoded_value = static_cast((source[source_index + 1] << CHAR_BIT) | source[source_index]); destination[dest_index] = decode(encoded_value); source_index += sizeof(TChunk); diff --git a/test/test_manchester.cpp b/test/test_manchester.cpp index 5ce0a83f3..9ddecb50c 100644 --- a/test/test_manchester.cpp +++ b/test/test_manchester.cpp @@ -70,60 +70,78 @@ SUITE(test_manchester) #endif } + constexpr etl::array manchester_encoded(etl::span decoded) + { + etl::array encoded {0, 0, 0, 0, 0, 0, 0, 0}; + etl::manchester::encode_span(decoded, encoded); + return encoded; + } + TEST(encode_span) { - etl::array input{0x00, 0xFF, 0x01, 0x80}; - - alignas(uint16_t) etl::array output0; - alignas(uint16_t) etl::array output1; - alignas(uint32_t) etl::array output2; - alignas(uint64_t) etl::array output3; - - etl::manchester::encode_span(input, output0); - etl::manchester::encode_span(input, output1); - etl::manchester::encode_span(input, output2); - etl::manchester::encode_span(input, output3); - - CHECK_EQUAL(0xAA, output0[0]); - CHECK_EQUAL(0xAA, output0[1]); - CHECK_EQUAL(0x55, output0[2]); - CHECK_EQUAL(0x55, output0[3]); - CHECK_EQUAL(0xA9, output0[4]); - CHECK_EQUAL(0xAA, output0[5]); - CHECK_EQUAL(0xAA, output0[6]); - CHECK_EQUAL(0x6A, output0[7]); - - CHECK_TRUE(output0 == output1); - CHECK_TRUE(output0 == output2); - CHECK_TRUE(output0 == output3); + constexpr etl::array decoded{0x00, 0xFF, 0x01, 0x80}; + + etl::array encoded0; + etl::array encoded1; + etl::array encoded2; + etl::array encoded3; + + etl::manchester::encode_span(decoded, encoded0); + etl::manchester::encode_span(decoded, encoded1); + etl::manchester::encode_span(decoded, encoded2); + etl::manchester::encode_span(decoded, encoded3); + + CHECK_EQUAL(0xAA, encoded0[0]); + CHECK_EQUAL(0xAA, encoded0[1]); + CHECK_EQUAL(0x55, encoded0[2]); + CHECK_EQUAL(0x55, encoded0[3]); + CHECK_EQUAL(0xA9, encoded0[4]); + CHECK_EQUAL(0xAA, encoded0[5]); + CHECK_EQUAL(0xAA, encoded0[6]); + CHECK_EQUAL(0x6A, encoded0[7]); + + CHECK_TRUE(encoded0 == encoded1); + CHECK_TRUE(encoded0 == encoded2); + CHECK_TRUE(encoded0 == encoded3); + +#if ETL_USING_CPP14 + static_assert(manchester_encoded(decoded)[0] == 0xAA, "Compile time encoding on range failed"); + static_assert(manchester_encoded(decoded)[1] == 0xAA, "Compile time encoding on range failed"); + static_assert(manchester_encoded(decoded)[2] == 0x55, "Compile time encoding on range failed"); + static_assert(manchester_encoded(decoded)[3] == 0x55, "Compile time encoding on range failed"); + static_assert(manchester_encoded(decoded)[4] == 0xA9, "Compile time encoding on range failed"); + static_assert(manchester_encoded(decoded)[5] == 0xAA, "Compile time encoding on range failed"); + static_assert(manchester_encoded(decoded)[6] == 0xAA, "Compile time encoding on range failed"); + static_assert(manchester_encoded(decoded)[7] == 0x6A, "Compile time encoding on range failed"); +#endif } TEST(encode_span_inverted) { - etl::array input{0x00, 0xFF, 0x01, 0x80}; - - alignas(uint16_t) etl::array output0; - alignas(uint16_t) etl::array output1; - alignas(uint32_t) etl::array output2; - alignas(uint64_t) etl::array output3; - - etl::manchester_inverted::encode_span(input, output0); - etl::manchester_inverted::encode_span(input, output1); - etl::manchester_inverted::encode_span(input, output2); - etl::manchester_inverted::encode_span(input, output3); - - CHECK_EQUAL(0x55, output0[0]); - CHECK_EQUAL(0x55, output0[1]); - CHECK_EQUAL(0xAA, output0[2]); - CHECK_EQUAL(0xAA, output0[3]); - CHECK_EQUAL(0x56, output0[4]); - CHECK_EQUAL(0x55, output0[5]); - CHECK_EQUAL(0x55, output0[6]); - CHECK_EQUAL(0x95, output0[7]); - - CHECK_TRUE(output0 == output1); - CHECK_TRUE(output0 == output2); - CHECK_TRUE(output0 == output3); + etl::array decoded{0x00, 0xFF, 0x01, 0x80}; + + etl::array encoded0; + etl::array encoded1; + etl::array encoded2; + etl::array encoded3; + + etl::manchester_inverted::encode_span(decoded, encoded0); + etl::manchester_inverted::encode_span(decoded, encoded1); + etl::manchester_inverted::encode_span(decoded, encoded2); + etl::manchester_inverted::encode_span(decoded, encoded3); + + CHECK_EQUAL(0x55, encoded0[0]); + CHECK_EQUAL(0x55, encoded0[1]); + CHECK_EQUAL(0xAA, encoded0[2]); + CHECK_EQUAL(0xAA, encoded0[3]); + CHECK_EQUAL(0x56, encoded0[4]); + CHECK_EQUAL(0x55, encoded0[5]); + CHECK_EQUAL(0x55, encoded0[6]); + CHECK_EQUAL(0x95, encoded0[7]); + + CHECK_TRUE(encoded0 == encoded1); + CHECK_TRUE(encoded0 == encoded2); + CHECK_TRUE(encoded0 == encoded3); } TEST(decode_uint16_t) @@ -188,76 +206,90 @@ SUITE(test_manchester) #endif } + constexpr etl::array manchester_decoded(etl::span encoded) + { + etl::array decoded {0, 0, 0, 0}; + etl::manchester::decode_span(encoded, decoded); + return decoded; + } + TEST(decode_span) { - etl::array input{0xAA, 0xAA, 0x55, 0x55, 0xA9, 0xAA, 0XAA, 0x6A}; - - etl::array output0; - etl::array output1; - etl::array output2; - etl::array output3; - - etl::manchester::decode_span(input, output0); - etl::manchester::decode_span(input, output1); - etl::manchester::decode_span(input, output2); - etl::manchester::decode_span(input, output3); - - CHECK_EQUAL(0x00, output0[0]); - CHECK_EQUAL(0xFF, output0[1]); - CHECK_EQUAL(0x01, output0[2]); - CHECK_EQUAL(0x80, output0[3]); - - CHECK_TRUE(output0 == output1); - CHECK_TRUE(output0 == output2); - CHECK_TRUE(output0 == output3); + constexpr etl::array encoded{0xAA, 0xAA, 0x55, 0x55, 0xA9, 0xAA, 0XAA, 0x6A}; + + etl::array decoded0; + etl::array decoded1; + etl::array decoded2; + etl::array decoded3; + + etl::manchester::decode_span(encoded, decoded0); + etl::manchester::decode_span(encoded, decoded1); + etl::manchester::decode_span(encoded, decoded2); + etl::manchester::decode_span(encoded, decoded3); + + CHECK_EQUAL(0x00, decoded0[0]); + CHECK_EQUAL(0xFF, decoded0[1]); + CHECK_EQUAL(0x01, decoded0[2]); + CHECK_EQUAL(0x80, decoded0[3]); + +#if ETL_USING_CPP14 + static_assert(manchester_decoded(encoded)[0] == 0x00, "Compile time decoding on range failed"); + static_assert(manchester_decoded(encoded)[1] == 0xFF, "Compile time decoding on range failed"); + static_assert(manchester_decoded(encoded)[2] == 0x01, "Compile time decoding on range failed"); + static_assert(manchester_decoded(encoded)[3] == 0x80, "Compile time decoding on range failed"); +#endif + + CHECK_TRUE(decoded0 == decoded1); + CHECK_TRUE(decoded0 == decoded2); + CHECK_TRUE(decoded0 == decoded3); } TEST(decode_span_inverted) { - etl::array input{0x55, 0x55, 0xAA, 0xAA, 0x56, 0x55, 0X55, 0x95}; - - etl::array output0; - etl::array output1; - etl::array output2; - etl::array output3; - - etl::manchester_inverted::decode_span(input, output0); - etl::manchester_inverted::decode_span(input, output1); - etl::manchester_inverted::decode_span(input, output2); - etl::manchester_inverted::decode_span(input, output3); - - CHECK_EQUAL(0x00, output0[0]); - CHECK_EQUAL(0xFF, output0[1]); - CHECK_EQUAL(0x01, output0[2]); - CHECK_EQUAL(0x80, output0[3]); - - CHECK_TRUE(output0 == output1); - CHECK_TRUE(output0 == output2); - CHECK_TRUE(output0 == output3); + etl::array encoded{0x55, 0x55, 0xAA, 0xAA, 0x56, 0x55, 0X55, 0x95}; + + etl::array decoded0; + etl::array decoded1; + etl::array decoded2; + etl::array decoded3; + + etl::manchester_inverted::decode_span(encoded, decoded0); + etl::manchester_inverted::decode_span(encoded, decoded1); + etl::manchester_inverted::decode_span(encoded, decoded2); + etl::manchester_inverted::decode_span(encoded, decoded3); + + CHECK_EQUAL(0x00, decoded0[0]); + CHECK_EQUAL(0xFF, decoded0[1]); + CHECK_EQUAL(0x01, decoded0[2]); + CHECK_EQUAL(0x80, decoded0[3]); + + CHECK_TRUE(decoded0 == decoded1); + CHECK_TRUE(decoded0 == decoded2); + CHECK_TRUE(decoded0 == decoded3); } TEST(decode_span_fast) { - etl::array input{0xAA, 0xAA, 0x55, 0x55, 0xA9, 0xAA, 0XAA, 0x6A}; - - alignas(uint8_t) etl::array output0; - alignas(uint8_t) etl::array output1; - alignas(uint16_t) etl::array output2; - alignas(uint32_t) etl::array output3; - - etl::manchester::decode_span_fast(input, output0); - etl::manchester::decode_span_fast(input, output1); - etl::manchester::decode_span_fast(input, output2); - etl::manchester::decode_span_fast(input, output3); - - CHECK_EQUAL(0x00, output0[0]); - CHECK_EQUAL(0xFF, output0[1]); - CHECK_EQUAL(0x01, output0[2]); - CHECK_EQUAL(0x80, output0[3]); - - CHECK_TRUE(output0 == output1); - CHECK_TRUE(output0 == output2); - CHECK_TRUE(output0 == output3); + etl::array encoded{0xAA, 0xAA, 0x55, 0x55, 0xA9, 0xAA, 0XAA, 0x6A}; + + etl::array decoded0; + etl::array decoded1; + etl::array decoded2; + etl::array decoded3; + + etl::manchester::decode_span_fast(encoded, decoded0); + etl::manchester::decode_span_fast(encoded, decoded1); + etl::manchester::decode_span_fast(encoded, decoded2); + etl::manchester::decode_span_fast(encoded, decoded3); + + CHECK_EQUAL(0x00, decoded0[0]); + CHECK_EQUAL(0xFF, decoded0[1]); + CHECK_EQUAL(0x01, decoded0[2]); + CHECK_EQUAL(0x80, decoded0[3]); + + CHECK_TRUE(decoded0 == decoded1); + CHECK_TRUE(decoded0 == decoded2); + CHECK_TRUE(decoded0 == decoded3); } TEST(valid16) @@ -312,22 +344,4 @@ SUITE(test_manchester) static_assert(!etl::manchester::valid_span(encoded2), "Compile time manchester validity check failed"); #endif } -}; - -#if ETL_USING_CPP14 -constexpr etl::array manchester_decoded(etl::span input) -{ - etl::array output {0, 0, 0, 0}; - etl::manchester::decode_span(input, output); - - return output; -} - -constexpr etl::array input{0xAA, 0xAA, 0x55, 0x55, 0xA9, 0xAA, 0XAA, 0x6A}; - -constexpr etl::array decoded = manchester_decoded(input); -static_assert(decoded[0] == 0x00, "Compile time decoding on range failed"); -static_assert(decoded[1] == 0xFF, "Compile time decoding on range failed"); -static_assert(decoded[2] == 0x01, "Compile time decoding on range failed"); -static_assert(decoded[3] == 0x80, "Compile time decoding on range failed"); -#endif \ No newline at end of file +}; \ No newline at end of file From 528050267238e68b9746e4aa85e8648a76099124 Mon Sep 17 00:00:00 2001 From: Timon Zijnge Date: Mon, 12 Jan 2026 16:06:02 +0100 Subject: [PATCH 21/46] manchester * renamed valid to is_valid --- include/etl/manchester.h | 6 +++--- test/test_manchester.cpp | 44 ++++++++++++++++++++-------------------- 2 files changed, 25 insertions(+), 25 deletions(-) diff --git a/include/etl/manchester.h b/include/etl/manchester.h index 7afa4482f..b766cc38c 100644 --- a/include/etl/manchester.h +++ b/include/etl/manchester.h @@ -398,7 +398,7 @@ namespace etl ///\return True if the value is valid Manchester encoding. //************************************************************************* template - ETL_NODISCARD static ETL_CONSTEXPR14 bool valid(TChunk encoded) + ETL_NODISCARD static ETL_CONSTEXPR14 bool is_valid(TChunk encoded) { ETL_STATIC_ASSERT(private_manchester::is_decodable::value, "TChunk must be a decodable type"); @@ -411,14 +411,14 @@ namespace etl ///\param encoded The span of encoded data to validate. ///\return True if all data is valid Manchester encoding. //************************************************************************* - ETL_NODISCARD static ETL_CONSTEXPR14 bool valid_span(etl::span encoded) + ETL_NODISCARD static ETL_CONSTEXPR14 bool is_valid_span(etl::span encoded) { ETL_ASSERT(encoded.size() % sizeof(uint16_t) == 0, ""); for (size_t i = 0; i < encoded.size(); i += 2) { const uint16_t chunk = static_cast((encoded[i + 1] << 8) | encoded[i]); - if (!valid(chunk)) + if (!is_valid(chunk)) { return false; } diff --git a/test/test_manchester.cpp b/test/test_manchester.cpp index 9ddecb50c..9e74c5140 100644 --- a/test/test_manchester.cpp +++ b/test/test_manchester.cpp @@ -294,40 +294,40 @@ SUITE(test_manchester) TEST(valid16) { - CHECK_TRUE(etl::manchester::valid(0xAAAAUL)); - CHECK_TRUE(etl::manchester_inverted::valid(0xAAAAUL)); - CHECK_FALSE(etl::manchester::valid(0xAAA8UL)); - CHECK_FALSE(etl::manchester_inverted::valid(0xAAA8UL)); + CHECK_TRUE(etl::manchester::is_valid(0xAAAAUL)); + CHECK_TRUE(etl::manchester_inverted::is_valid(0xAAAAUL)); + CHECK_FALSE(etl::manchester::is_valid(0xAAA8UL)); + CHECK_FALSE(etl::manchester_inverted::is_valid(0xAAA8UL)); #if ETL_USING_CPP14 - static_assert(etl::manchester::valid(0xAAAAUL), "Compile time manchester validity check failed"); - static_assert(etl::manchester_inverted::valid(0xAAAAUL), "Compile time manchester validity check failed"); + static_assert(etl::manchester::is_valid(0xAAAAUL), "Compile time manchester validity check failed"); + static_assert(etl::manchester_inverted::is_valid(0xAAAAUL), "Compile time manchester validity check failed"); #endif } TEST(valid32) { - CHECK_TRUE(etl::manchester::valid(0xAAAAAAAAUL)); - CHECK_TRUE(etl::manchester_inverted::valid(0xAAAAAAAAUL)); - CHECK_FALSE(etl::manchester::valid(0xAAAAAAA8UL)); - CHECK_FALSE(etl::manchester_inverted::valid(0xAAAAAAA8UL)); + CHECK_TRUE(etl::manchester::is_valid(0xAAAAAAAAUL)); + CHECK_TRUE(etl::manchester_inverted::is_valid(0xAAAAAAAAUL)); + CHECK_FALSE(etl::manchester::is_valid(0xAAAAAAA8UL)); + CHECK_FALSE(etl::manchester_inverted::is_valid(0xAAAAAAA8UL)); #if ETL_USING_CPP14 - static_assert(etl::manchester::valid(0xAAAAAAAAUL), "Compile time manchester validity check failed"); - static_assert(etl::manchester_inverted::valid(0xAAAAAAAAUL), "Compile time manchester validity check failed"); + static_assert(etl::manchester::is_valid(0xAAAAAAAAUL), "Compile time manchester validity check failed"); + static_assert(etl::manchester_inverted::is_valid(0xAAAAAAAAUL), "Compile time manchester validity check failed"); #endif } TEST(valid64) { - CHECK_TRUE(etl::manchester::valid(0xAAAAAAAAAAAAAAAAULL)); - CHECK_TRUE(etl::manchester_inverted::valid(0xAAAAAAAAAAAAAAAAULL)); - CHECK_FALSE(etl::manchester::valid(0xAAAAAAAAAAAAAAA8ULL)); - CHECK_FALSE(etl::manchester_inverted::valid(0xAAAAAAAAAAAAAAA8ULL)); + CHECK_TRUE(etl::manchester::is_valid(0xAAAAAAAAAAAAAAAAULL)); + CHECK_TRUE(etl::manchester_inverted::is_valid(0xAAAAAAAAAAAAAAAAULL)); + CHECK_FALSE(etl::manchester::is_valid(0xAAAAAAAAAAAAAAA8ULL)); + CHECK_FALSE(etl::manchester_inverted::is_valid(0xAAAAAAAAAAAAAAA8ULL)); #if ETL_USING_CPP14 - static_assert(etl::manchester::valid(0xAAAAAAAAAAAAAAAAULL), "Compile time manchester validity check failed"); - static_assert(etl::manchester_inverted::valid(0xAAAAAAAAAAAAAAAAULL), "Compile time manchester validity check failed"); + static_assert(etl::manchester::is_valid(0xAAAAAAAAAAAAAAAAULL), "Compile time manchester validity check failed"); + static_assert(etl::manchester_inverted::is_valid(0xAAAAAAAAAAAAAAAAULL), "Compile time manchester validity check failed"); #endif } @@ -336,12 +336,12 @@ SUITE(test_manchester) constexpr etl::array encoded1{0xAA, 0xAA, 0x55, 0x55, 0xA9, 0xAA, 0XAA, 0x6A}; constexpr etl::array encoded2{0xAA, 0xAA, 0x55, 0x55, 0xA9, 0xAA, 0XAB, 0x6A}; - CHECK_TRUE(etl::manchester::valid_span(encoded1)); - CHECK_FALSE(etl::manchester::valid_span(encoded2)); + CHECK_TRUE(etl::manchester::is_valid_span(encoded1)); + CHECK_FALSE(etl::manchester::is_valid_span(encoded2)); #if ETL_USING_CPP14 - static_assert(etl::manchester::valid_span(encoded1), "Compile time manchester validity check failed"); - static_assert(!etl::manchester::valid_span(encoded2), "Compile time manchester validity check failed"); + static_assert(etl::manchester::is_valid_span(encoded1), "Compile time manchester validity check failed"); + static_assert(!etl::manchester::is_valid_span(encoded2), "Compile time manchester validity check failed"); #endif } }; \ No newline at end of file From ab4092ea84b6e66267c4354b4cdb9ad390586a15 Mon Sep 17 00:00:00 2001 From: Timon Zijnge Date: Tue, 20 Jan 2026 15:19:42 +0100 Subject: [PATCH 22/46] manchester * renamed is_valid_span to is_valid * Using etl exceptions in ETL_ASSERT --- include/etl/manchester.h | 67 +++-- test/test_manchester.cpp | 594 +++++++++++++++++++++------------------ 2 files changed, 370 insertions(+), 291 deletions(-) diff --git a/include/etl/manchester.h b/include/etl/manchester.h index b766cc38c..ff963ff53 100644 --- a/include/etl/manchester.h +++ b/include/etl/manchester.h @@ -158,6 +158,30 @@ namespace etl }; } // namespace private_manchester + //*************************************************************************** + /// Exception for Manchester. + //*************************************************************************** + class manchester_exception : public etl::exception + { + public: + manchester_exception(string_type reason_, string_type file_name_, numeric_type line_number_) + : exception(reason_, file_name_, line_number_) + { + } + }; + + //*************************************************************************** + /// Invalid size exception for Manchester + //*************************************************************************** + class manchester_invalid_size : public etl::manchester_exception + { + public: + manchester_invalid_size(string_type file_name_, numeric_type line_number_) + : etl::manchester_exception("manchester:size", file_name_, line_number_) + { + } + }; + //*************************************************************************** ///\ingroup manchester /// Base template class for Manchester encoding and decoding. @@ -262,11 +286,11 @@ namespace etl static typename etl::enable_if::value, void>::type encode_span(etl::span source, etl::span destination) { - typedef TChunk TDecoded; + typedef TChunk TDecoded; typedef typename etl::private_manchester::manchester_encoded::type TEncoded; - ETL_ASSERT(destination.size() >= source.size() * 2, "Manchester encoding requires destination storage to be at least twice the size of the source storage"); - ETL_ASSERT(source.size() % sizeof(TDecoded) == 0, "Manchester encoding requires the source storage size to be an integer multiple of the encoding chunk size"); + ETL_ASSERT(destination.size() >= source.size() * 2, ETL_ERROR(manchester_invalid_size)); + ETL_ASSERT(source.size() % sizeof(TDecoded) == 0, ETL_ERROR(manchester_invalid_size)); size_t dest_index = 0; size_t source_index = 0; @@ -290,14 +314,13 @@ namespace etl ///\tparam TChunk The chunk size for encoding (default: uint_least8_t). //************************************************************************* template - static typename etl::enable_if::value, void>::type - constexpr encode_span(etl::span source, etl::span destination) + static typename etl::enable_if::value, void>::type constexpr encode_span(etl::span source, etl::span destination) { - typedef TChunk TDecoded; + typedef TChunk TDecoded; typedef typename etl::private_manchester::manchester_encoded::type TEncoded; - ETL_ASSERT(destination.size() >= source.size() * 2, "Manchester encoding requires destination storage to be at least twice the size of the source storage"); - ETL_ASSERT(source.size() % sizeof(TDecoded) == 0, "Manchester encoding requires the source storage size to be an integer multiple of the encoding chunk size"); + ETL_ASSERT(destination.size() >= source.size() * 2, ETL_ERROR(manchester_invalid_size)); + ETL_ASSERT(source.size() % sizeof(TDecoded) == 0, ETL_ERROR(manchester_invalid_size)); size_t dest_index = 0; size_t source_index = 0; @@ -379,7 +402,9 @@ namespace etl ///\return The Manchester decoded value. //************************************************************************* template - ETL_NODISCARD static ETL_CONSTEXPR14 typename private_manchester::manchester_decoded::type decode(TChunk encoded) + ETL_NODISCARD static ETL_CONSTEXPR14 + typename private_manchester::manchester_decoded::type + decode(TChunk encoded) { ETL_STATIC_ASSERT(private_manchester::is_decodable::value, "TChunk must be a decodable type"); @@ -398,10 +423,10 @@ namespace etl ///\return True if the value is valid Manchester encoding. //************************************************************************* template - ETL_NODISCARD static ETL_CONSTEXPR14 bool is_valid(TChunk encoded) + ETL_NODISCARD static ETL_CONSTEXPR14 + typename etl::enable_if::value, bool>::type + is_valid(TChunk encoded) { - ETL_STATIC_ASSERT(private_manchester::is_decodable::value, "TChunk must be a decodable type"); - const TChunk mask = static_cast(0x5555555555555555ULL); return (((encoded ^ (encoded >> 1)) & mask) == mask); } @@ -411,9 +436,9 @@ namespace etl ///\param encoded The span of encoded data to validate. ///\return True if all data is valid Manchester encoding. //************************************************************************* - ETL_NODISCARD static ETL_CONSTEXPR14 bool is_valid_span(etl::span encoded) + ETL_NODISCARD static ETL_CONSTEXPR14 bool is_valid(etl::span encoded) { - ETL_ASSERT(encoded.size() % sizeof(uint16_t) == 0, ""); + ETL_ASSERT(encoded.size() % sizeof(uint16_t) == 0, ETL_ERROR(manchester_invalid_size)); for (size_t i = 0; i < encoded.size(); i += 2) { @@ -442,10 +467,10 @@ namespace etl decode_span(etl::span source, etl::span destination) { typedef typename private_manchester::manchester_decoded::type TDecoded; - typedef TChunk TEncoded; + typedef TChunk TEncoded; - ETL_ASSERT(destination.size() * 2 >= source.size(), "Manchester decoding requires destination storage to be no less than half the source storage"); - ETL_ASSERT(source.size() % sizeof(TChunk) == 0, "Manchester decoding requires the source storage size to be an integer multiple of the decoding chunk size"); + ETL_ASSERT(destination.size() * 2 >= source.size(), ETL_ERROR(manchester_invalid_size)); + ETL_ASSERT(source.size() % sizeof(TChunk) == 0, ETL_ERROR(manchester_invalid_size)); size_t dest_index = 0; size_t source_index = 0; @@ -474,8 +499,8 @@ namespace etl { typedef uint_least8_t TDecoded; - ETL_ASSERT(destination.size() * 2 >= source.size(), "Manchester decoding requires destination storage to be no less than half the source storage"); - ETL_ASSERT(source.size() % sizeof(TChunk) == 0, "Manchester decoding requires the source storage size to be an integer multiple of the decoding chunk size"); + ETL_ASSERT(destination.size() * 2 >= source.size(), ETL_ERROR(manchester_invalid_size)); + ETL_ASSERT(source.size() % sizeof(TChunk) == 0, ETL_ERROR(manchester_invalid_size)); size_t dest_index = 0; size_t source_index = 0; @@ -498,8 +523,8 @@ namespace etl template ::type> static void decode_span_fast(etl::span source, etl::span destination) { - ETL_ASSERT(destination.size() * 2 >= source.size(), "Manchester decoding requires destination storage to be no less than half the source storage"); - ETL_ASSERT(source.size() % sizeof(TChunk) == 0, "Manchester decoding requires the source storage size to be an integer multiple of the decoding chunk size"); + ETL_ASSERT(destination.size() * 2 >= source.size(), ETL_ERROR(manchester_invalid_size)); + ETL_ASSERT(source.size() % sizeof(TChunk) == 0, ETL_ERROR(manchester_invalid_size)); while (!source.empty()) { diff --git a/test/test_manchester.cpp b/test/test_manchester.cpp index 9e74c5140..6c7876ab5 100644 --- a/test/test_manchester.cpp +++ b/test/test_manchester.cpp @@ -5,343 +5,397 @@ #include #include - -SUITE(test_manchester) -{ - TEST(encode_uint8_t) - { +SUITE(test_manchester){ + TEST(encode_uint8_t){ CHECK_EQUAL(0xAAAA, (etl::manchester::encode(0x00U))); - CHECK_EQUAL(0x5555, (etl::manchester::encode(0xFFU))); - CHECK_EQUAL(0xAAA9, (etl::manchester::encode(0x01U))); - CHECK_EQUAL(0x6AAA, (etl::manchester::encode(0x80U))); +CHECK_EQUAL(0x5555, (etl::manchester::encode(0xFFU))); +CHECK_EQUAL(0xAAA9, (etl::manchester::encode(0x01U))); +CHECK_EQUAL(0x6AAA, (etl::manchester::encode(0x80U))); #if ETL_USING_CPP14 - static_assert(0xAAAA == etl::manchester::encode(0x00U), "Compile time manchester encoding failed"); +static_assert(0xAAAA == etl::manchester::encode(0x00U), "Compile time manchester encoding failed"); #endif - } +} - TEST(encode_uint8_t_inverted) - { - CHECK_EQUAL(0x5555, (etl::manchester_inverted::encode(0x00U))); - CHECK_EQUAL(0xAAAA, (etl::manchester_inverted::encode(0xFFU))); - CHECK_EQUAL(0x5556, (etl::manchester_inverted::encode(0x01U))); - CHECK_EQUAL(0x9555, (etl::manchester_inverted::encode(0x80U))); +TEST(encode_uint8_t_inverted) +{ + CHECK_EQUAL(0x5555, (etl::manchester_inverted::encode(0x00U))); + CHECK_EQUAL(0xAAAA, (etl::manchester_inverted::encode(0xFFU))); + CHECK_EQUAL(0x5556, (etl::manchester_inverted::encode(0x01U))); + CHECK_EQUAL(0x9555, (etl::manchester_inverted::encode(0x80U))); #if ETL_USING_CPP14 - static_assert(0x5555 == etl::manchester_inverted::encode(0x00U), "Compile time manchester encoding failed"); + static_assert(0x5555 == etl::manchester_inverted::encode(0x00U), "Compile time manchester encoding failed"); #endif - } +} - TEST(encode_uint16_t) - { - CHECK_EQUAL(0x5555AAAA, (etl::manchester::encode(0xFF00UL))); - CHECK_EQUAL(0x6AAAAAA9, (etl::manchester::encode(0x8001UL))); +TEST(encode_uint16_t) +{ + CHECK_EQUAL(0x5555AAAA, (etl::manchester::encode(0xFF00UL))); + CHECK_EQUAL(0x6AAAAAA9, (etl::manchester::encode(0x8001UL))); #if ETL_USING_CPP14 - static_assert(0x5555AAAA == etl::manchester::encode(0xFF00UL), "Compile time manchester encoding failed"); + static_assert(0x5555AAAA == etl::manchester::encode(0xFF00UL), "Compile time manchester encoding failed"); #endif - } +} - TEST(encode_uint16_t_inverted) - { - CHECK_EQUAL(0xAAAA5555, (etl::manchester_inverted::encode(0xFF00UL))); - CHECK_EQUAL(0x95555556, (etl::manchester_inverted::encode(0x8001UL))); +TEST(encode_uint16_t_inverted) +{ + CHECK_EQUAL(0xAAAA5555, (etl::manchester_inverted::encode(0xFF00UL))); + CHECK_EQUAL(0x95555556, (etl::manchester_inverted::encode(0x8001UL))); #if ETL_USING_CPP14 - static_assert(0xAAAA5555 == etl::manchester_inverted::encode(0xFF00UL), "Compile time manchester encoding failed"); + static_assert(0xAAAA5555 == etl::manchester_inverted::encode(0xFF00UL), "Compile time manchester encoding failed"); #endif - } +} - TEST(encode_uint32_t) - { - CHECK_EQUAL(0x6AAAAAA95555AAAA, (etl::manchester::encode(0x8001FF00ULL))); +TEST(encode_uint32_t) +{ + CHECK_EQUAL(0x6AAAAAA95555AAAA, (etl::manchester::encode(0x8001FF00ULL))); #if ETL_USING_CPP14 - static_assert(0x6AAAAAA95555AAAA == etl::manchester::encode(0x8001FF00ULL), "Compile time manchester encoding failed"); + static_assert(0x6AAAAAA95555AAAA == etl::manchester::encode(0x8001FF00ULL), "Compile time manchester encoding failed"); #endif - } +} - TEST(encode_uint32_t_inverted) - { - CHECK_EQUAL(0x95555556AAAA5555, (etl::manchester_inverted::encode(0x8001FF00ULL))); +TEST(encode_uint32_t_inverted) +{ + CHECK_EQUAL(0x95555556AAAA5555, (etl::manchester_inverted::encode(0x8001FF00ULL))); #if ETL_USING_CPP14 - static_assert(0x95555556AAAA5555 == etl::manchester_inverted::encode(0x8001FF00ULL), "Compile time manchester encoding failed"); + static_assert(0x95555556AAAA5555 == etl::manchester_inverted::encode(0x8001FF00ULL), "Compile time manchester encoding failed"); #endif - } - - constexpr etl::array manchester_encoded(etl::span decoded) - { - etl::array encoded {0, 0, 0, 0, 0, 0, 0, 0}; - etl::manchester::encode_span(decoded, encoded); - return encoded; - } - - TEST(encode_span) - { - constexpr etl::array decoded{0x00, 0xFF, 0x01, 0x80}; - - etl::array encoded0; - etl::array encoded1; - etl::array encoded2; - etl::array encoded3; - - etl::manchester::encode_span(decoded, encoded0); - etl::manchester::encode_span(decoded, encoded1); - etl::manchester::encode_span(decoded, encoded2); - etl::manchester::encode_span(decoded, encoded3); - - CHECK_EQUAL(0xAA, encoded0[0]); - CHECK_EQUAL(0xAA, encoded0[1]); - CHECK_EQUAL(0x55, encoded0[2]); - CHECK_EQUAL(0x55, encoded0[3]); - CHECK_EQUAL(0xA9, encoded0[4]); - CHECK_EQUAL(0xAA, encoded0[5]); - CHECK_EQUAL(0xAA, encoded0[6]); - CHECK_EQUAL(0x6A, encoded0[7]); - - CHECK_TRUE(encoded0 == encoded1); - CHECK_TRUE(encoded0 == encoded2); - CHECK_TRUE(encoded0 == encoded3); +} + +constexpr etl::array manchester_encoded(etl::span decoded) +{ + etl::array encoded{0, 0, 0, 0, 0, 0, 0, 0}; + etl::manchester::encode_span(decoded, encoded); + return encoded; +} + +TEST(encode_span) +{ + constexpr etl::array decoded{0x00, 0xFF, 0x01, 0x80}; + + etl::array encoded0; + etl::array encoded1; + etl::array encoded2; + etl::array encoded3; + + etl::manchester::encode_span(decoded, encoded0); + etl::manchester::encode_span(decoded, encoded1); + etl::manchester::encode_span(decoded, encoded2); + etl::manchester::encode_span(decoded, encoded3); + + CHECK_EQUAL(0xAA, encoded0[0]); + CHECK_EQUAL(0xAA, encoded0[1]); + CHECK_EQUAL(0x55, encoded0[2]); + CHECK_EQUAL(0x55, encoded0[3]); + CHECK_EQUAL(0xA9, encoded0[4]); + CHECK_EQUAL(0xAA, encoded0[5]); + CHECK_EQUAL(0xAA, encoded0[6]); + CHECK_EQUAL(0x6A, encoded0[7]); + + CHECK_TRUE(encoded0 == encoded1); + CHECK_TRUE(encoded0 == encoded2); + CHECK_TRUE(encoded0 == encoded3); #if ETL_USING_CPP14 - static_assert(manchester_encoded(decoded)[0] == 0xAA, "Compile time encoding on range failed"); - static_assert(manchester_encoded(decoded)[1] == 0xAA, "Compile time encoding on range failed"); - static_assert(manchester_encoded(decoded)[2] == 0x55, "Compile time encoding on range failed"); - static_assert(manchester_encoded(decoded)[3] == 0x55, "Compile time encoding on range failed"); - static_assert(manchester_encoded(decoded)[4] == 0xA9, "Compile time encoding on range failed"); - static_assert(manchester_encoded(decoded)[5] == 0xAA, "Compile time encoding on range failed"); - static_assert(manchester_encoded(decoded)[6] == 0xAA, "Compile time encoding on range failed"); - static_assert(manchester_encoded(decoded)[7] == 0x6A, "Compile time encoding on range failed"); + static_assert(manchester_encoded(decoded)[0] == 0xAA, "Compile time encoding on range failed"); + static_assert(manchester_encoded(decoded)[1] == 0xAA, "Compile time encoding on range failed"); + static_assert(manchester_encoded(decoded)[2] == 0x55, "Compile time encoding on range failed"); + static_assert(manchester_encoded(decoded)[3] == 0x55, "Compile time encoding on range failed"); + static_assert(manchester_encoded(decoded)[4] == 0xA9, "Compile time encoding on range failed"); + static_assert(manchester_encoded(decoded)[5] == 0xAA, "Compile time encoding on range failed"); + static_assert(manchester_encoded(decoded)[6] == 0xAA, "Compile time encoding on range failed"); + static_assert(manchester_encoded(decoded)[7] == 0x6A, "Compile time encoding on range failed"); #endif - } - - TEST(encode_span_inverted) - { - etl::array decoded{0x00, 0xFF, 0x01, 0x80}; - - etl::array encoded0; - etl::array encoded1; - etl::array encoded2; - etl::array encoded3; - - etl::manchester_inverted::encode_span(decoded, encoded0); - etl::manchester_inverted::encode_span(decoded, encoded1); - etl::manchester_inverted::encode_span(decoded, encoded2); - etl::manchester_inverted::encode_span(decoded, encoded3); - - CHECK_EQUAL(0x55, encoded0[0]); - CHECK_EQUAL(0x55, encoded0[1]); - CHECK_EQUAL(0xAA, encoded0[2]); - CHECK_EQUAL(0xAA, encoded0[3]); - CHECK_EQUAL(0x56, encoded0[4]); - CHECK_EQUAL(0x55, encoded0[5]); - CHECK_EQUAL(0x55, encoded0[6]); - CHECK_EQUAL(0x95, encoded0[7]); - - CHECK_TRUE(encoded0 == encoded1); - CHECK_TRUE(encoded0 == encoded2); - CHECK_TRUE(encoded0 == encoded3); - } - - TEST(decode_uint16_t) - { - CHECK_EQUAL(0x00, (etl::manchester::decode(0xAAAAUL))); - CHECK_EQUAL(0xFF, (etl::manchester::decode(0x5555UL))); - CHECK_EQUAL(0x01, (etl::manchester::decode(0xAAA9UL))); - CHECK_EQUAL(0x80, (etl::manchester::decode(0x6AAAUL))); +} + +TEST(encode_span_inverted) +{ + etl::array decoded{0x00, 0xFF, 0x01, 0x80}; + + etl::array encoded0; + etl::array encoded1; + etl::array encoded2; + etl::array encoded3; + + etl::manchester_inverted::encode_span(decoded, encoded0); + etl::manchester_inverted::encode_span(decoded, encoded1); + etl::manchester_inverted::encode_span(decoded, encoded2); + etl::manchester_inverted::encode_span(decoded, encoded3); + + CHECK_EQUAL(0x55, encoded0[0]); + CHECK_EQUAL(0x55, encoded0[1]); + CHECK_EQUAL(0xAA, encoded0[2]); + CHECK_EQUAL(0xAA, encoded0[3]); + CHECK_EQUAL(0x56, encoded0[4]); + CHECK_EQUAL(0x55, encoded0[5]); + CHECK_EQUAL(0x55, encoded0[6]); + CHECK_EQUAL(0x95, encoded0[7]); + + CHECK_TRUE(encoded0 == encoded1); + CHECK_TRUE(encoded0 == encoded2); + CHECK_TRUE(encoded0 == encoded3); +} + +TEST(encode_span_invalid_source) +{ + etl::array invalid_source{0x00, 0xFF, 0x01}; + etl::array valid_destination; + + CHECK_THROW({ etl::manchester::encode_span(invalid_source, valid_destination); }, etl::manchester_invalid_size); + CHECK_THROW({ etl::manchester::encode_span(invalid_source, valid_destination); }, etl::manchester_invalid_size); + CHECK_THROW({ etl::manchester_inverted::encode_span(invalid_source, valid_destination); }, etl::manchester_invalid_size); + CHECK_THROW({ etl::manchester_inverted::encode_span(invalid_source, valid_destination); }, etl::manchester_invalid_size); +} + +TEST(encode_span_invalid_destination) +{ + etl::array valid_source{0x00, 0xFF, 0x01, 0x80}; + etl::array invalid_destination; + + CHECK_THROW({ etl::manchester::encode_span(valid_source, invalid_destination); }, etl::manchester_invalid_size); + CHECK_THROW({ etl::manchester::encode_span(valid_source, invalid_destination); }, etl::manchester_invalid_size); + CHECK_THROW({ etl::manchester::encode_span(valid_source, invalid_destination); }, etl::manchester_invalid_size); + CHECK_THROW({ etl::manchester_inverted::encode_span(valid_source, invalid_destination); }, etl::manchester_invalid_size); + CHECK_THROW({ etl::manchester_inverted::encode_span(valid_source, invalid_destination); }, etl::manchester_invalid_size); + CHECK_THROW({ etl::manchester_inverted::encode_span(valid_source, invalid_destination); }, etl::manchester_invalid_size); +} + +TEST(decode_uint16_t) +{ + CHECK_EQUAL(0x00, (etl::manchester::decode(0xAAAAUL))); + CHECK_EQUAL(0xFF, (etl::manchester::decode(0x5555UL))); + CHECK_EQUAL(0x01, (etl::manchester::decode(0xAAA9UL))); + CHECK_EQUAL(0x80, (etl::manchester::decode(0x6AAAUL))); #if ETL_USING_CPP14 - static_assert(0x00 == etl::manchester::decode(0xAAAAUL), "Compile time manchester decoding failed"); + static_assert(0x00 == etl::manchester::decode(0xAAAAUL), "Compile time manchester decoding failed"); #endif - } +} - TEST(decode_uint16_t_inverted) - { - CHECK_EQUAL(0x00, (etl::manchester_inverted::decode(0x5555UL))); - CHECK_EQUAL(0xFF, (etl::manchester_inverted::decode(0xAAAAUL))); - CHECK_EQUAL(0x01, (etl::manchester_inverted::decode(0x5556UL))); - CHECK_EQUAL(0x80, (etl::manchester_inverted::decode(0x9555UL))); +TEST(decode_uint16_t_inverted) +{ + CHECK_EQUAL(0x00, (etl::manchester_inverted::decode(0x5555UL))); + CHECK_EQUAL(0xFF, (etl::manchester_inverted::decode(0xAAAAUL))); + CHECK_EQUAL(0x01, (etl::manchester_inverted::decode(0x5556UL))); + CHECK_EQUAL(0x80, (etl::manchester_inverted::decode(0x9555UL))); #if ETL_USING_CPP14 - static_assert(0x00 == etl::manchester_inverted::decode(0x5555UL), "Compile time manchester decoding failed"); + static_assert(0x00 == etl::manchester_inverted::decode(0x5555UL), "Compile time manchester decoding failed"); #endif - } +} - TEST(decode_uint32_t) - { - CHECK_EQUAL(0xFF00UL, (etl::manchester::decode(0x5555AAAAUL))); - CHECK_EQUAL(0x8001UL, (etl::manchester::decode(0x6AAAAAA9UL))); +TEST(decode_uint32_t) +{ + CHECK_EQUAL(0xFF00UL, (etl::manchester::decode(0x5555AAAAUL))); + CHECK_EQUAL(0x8001UL, (etl::manchester::decode(0x6AAAAAA9UL))); #if ETL_USING_CPP14 - static_assert(0xFF00UL == etl::manchester::decode(0x5555AAAAUL), "Compile time manchester decoding failed"); + static_assert(0xFF00UL == etl::manchester::decode(0x5555AAAAUL), "Compile time manchester decoding failed"); #endif - } +} - TEST(decode_uint32_t_inverted) - { - CHECK_EQUAL(0xFF00UL, (etl::manchester_inverted::decode(0xAAAA5555UL))); - CHECK_EQUAL(0x8001UL, (etl::manchester_inverted::decode(0x95555556UL))); +TEST(decode_uint32_t_inverted) +{ + CHECK_EQUAL(0xFF00UL, (etl::manchester_inverted::decode(0xAAAA5555UL))); + CHECK_EQUAL(0x8001UL, (etl::manchester_inverted::decode(0x95555556UL))); #if ETL_USING_CPP14 - static_assert(0xFF00UL == etl::manchester_inverted::decode(0xAAAA5555UL), "Compile time manchester decoding failed"); + static_assert(0xFF00UL == etl::manchester_inverted::decode(0xAAAA5555UL), "Compile time manchester decoding failed"); #endif - } +} - TEST(decode_uint64_t) - { - CHECK_EQUAL(0x8001FF00ULL, (etl::manchester::decode(0x6AAAAAA95555AAAAULL))); +TEST(decode_uint64_t) +{ + CHECK_EQUAL(0x8001FF00ULL, (etl::manchester::decode(0x6AAAAAA95555AAAAULL))); #if ETL_USING_CPP14 - static_assert(0x8001FF00ULL == etl::manchester::decode(0x6AAAAAA95555AAAAULL), "Compile time manchester decoding failed"); + static_assert(0x8001FF00ULL == etl::manchester::decode(0x6AAAAAA95555AAAAULL), "Compile time manchester decoding failed"); #endif - } +} - TEST(decode_uint64_t_inverted) - { - CHECK_EQUAL(0x8001FF00ULL, (etl::manchester_inverted::decode(0x95555556AAAA5555ULL))); +TEST(decode_uint64_t_inverted) +{ + CHECK_EQUAL(0x8001FF00ULL, (etl::manchester_inverted::decode(0x95555556AAAA5555ULL))); #if ETL_USING_CPP14 - static_assert(0x8001FF00ULL == etl::manchester_inverted::decode(0x95555556AAAA5555ULL), "Compile time manchester decoding failed"); + static_assert(0x8001FF00ULL == etl::manchester_inverted::decode(0x95555556AAAA5555ULL), "Compile time manchester decoding failed"); #endif - } - - constexpr etl::array manchester_decoded(etl::span encoded) - { - etl::array decoded {0, 0, 0, 0}; - etl::manchester::decode_span(encoded, decoded); - return decoded; - } - - TEST(decode_span) - { - constexpr etl::array encoded{0xAA, 0xAA, 0x55, 0x55, 0xA9, 0xAA, 0XAA, 0x6A}; - - etl::array decoded0; - etl::array decoded1; - etl::array decoded2; - etl::array decoded3; - - etl::manchester::decode_span(encoded, decoded0); - etl::manchester::decode_span(encoded, decoded1); - etl::manchester::decode_span(encoded, decoded2); - etl::manchester::decode_span(encoded, decoded3); - - CHECK_EQUAL(0x00, decoded0[0]); - CHECK_EQUAL(0xFF, decoded0[1]); - CHECK_EQUAL(0x01, decoded0[2]); - CHECK_EQUAL(0x80, decoded0[3]); +} + +constexpr etl::array manchester_decoded(etl::span encoded) +{ + etl::array decoded{0, 0, 0, 0}; + etl::manchester::decode_span(encoded, decoded); + return decoded; +} + +TEST(decode_span) +{ + constexpr etl::array encoded{0xAA, 0xAA, 0x55, 0x55, 0xA9, 0xAA, 0XAA, 0x6A}; + + etl::array decoded0; + etl::array decoded1; + etl::array decoded2; + etl::array decoded3; + + etl::manchester::decode_span(encoded, decoded0); + etl::manchester::decode_span(encoded, decoded1); + etl::manchester::decode_span(encoded, decoded2); + etl::manchester::decode_span(encoded, decoded3); + + CHECK_EQUAL(0x00, decoded0[0]); + CHECK_EQUAL(0xFF, decoded0[1]); + CHECK_EQUAL(0x01, decoded0[2]); + CHECK_EQUAL(0x80, decoded0[3]); #if ETL_USING_CPP14 - static_assert(manchester_decoded(encoded)[0] == 0x00, "Compile time decoding on range failed"); - static_assert(manchester_decoded(encoded)[1] == 0xFF, "Compile time decoding on range failed"); - static_assert(manchester_decoded(encoded)[2] == 0x01, "Compile time decoding on range failed"); - static_assert(manchester_decoded(encoded)[3] == 0x80, "Compile time decoding on range failed"); + static_assert(manchester_decoded(encoded)[0] == 0x00, "Compile time decoding on range failed"); + static_assert(manchester_decoded(encoded)[1] == 0xFF, "Compile time decoding on range failed"); + static_assert(manchester_decoded(encoded)[2] == 0x01, "Compile time decoding on range failed"); + static_assert(manchester_decoded(encoded)[3] == 0x80, "Compile time decoding on range failed"); #endif - CHECK_TRUE(decoded0 == decoded1); - CHECK_TRUE(decoded0 == decoded2); - CHECK_TRUE(decoded0 == decoded3); - } - - TEST(decode_span_inverted) - { - etl::array encoded{0x55, 0x55, 0xAA, 0xAA, 0x56, 0x55, 0X55, 0x95}; - - etl::array decoded0; - etl::array decoded1; - etl::array decoded2; - etl::array decoded3; - - etl::manchester_inverted::decode_span(encoded, decoded0); - etl::manchester_inverted::decode_span(encoded, decoded1); - etl::manchester_inverted::decode_span(encoded, decoded2); - etl::manchester_inverted::decode_span(encoded, decoded3); - - CHECK_EQUAL(0x00, decoded0[0]); - CHECK_EQUAL(0xFF, decoded0[1]); - CHECK_EQUAL(0x01, decoded0[2]); - CHECK_EQUAL(0x80, decoded0[3]); - - CHECK_TRUE(decoded0 == decoded1); - CHECK_TRUE(decoded0 == decoded2); - CHECK_TRUE(decoded0 == decoded3); - } - - TEST(decode_span_fast) - { - etl::array encoded{0xAA, 0xAA, 0x55, 0x55, 0xA9, 0xAA, 0XAA, 0x6A}; - - etl::array decoded0; - etl::array decoded1; - etl::array decoded2; - etl::array decoded3; - - etl::manchester::decode_span_fast(encoded, decoded0); - etl::manchester::decode_span_fast(encoded, decoded1); - etl::manchester::decode_span_fast(encoded, decoded2); - etl::manchester::decode_span_fast(encoded, decoded3); - - CHECK_EQUAL(0x00, decoded0[0]); - CHECK_EQUAL(0xFF, decoded0[1]); - CHECK_EQUAL(0x01, decoded0[2]); - CHECK_EQUAL(0x80, decoded0[3]); - - CHECK_TRUE(decoded0 == decoded1); - CHECK_TRUE(decoded0 == decoded2); - CHECK_TRUE(decoded0 == decoded3); - } - - TEST(valid16) - { - CHECK_TRUE(etl::manchester::is_valid(0xAAAAUL)); - CHECK_TRUE(etl::manchester_inverted::is_valid(0xAAAAUL)); - CHECK_FALSE(etl::manchester::is_valid(0xAAA8UL)); - CHECK_FALSE(etl::manchester_inverted::is_valid(0xAAA8UL)); + CHECK_TRUE(decoded0 == decoded1); + CHECK_TRUE(decoded0 == decoded2); + CHECK_TRUE(decoded0 == decoded3); +} + +TEST(decode_span_inverted) +{ + etl::array encoded{0x55, 0x55, 0xAA, 0xAA, 0x56, 0x55, 0X55, 0x95}; + + etl::array decoded0; + etl::array decoded1; + etl::array decoded2; + etl::array decoded3; + + etl::manchester_inverted::decode_span(encoded, decoded0); + etl::manchester_inverted::decode_span(encoded, decoded1); + etl::manchester_inverted::decode_span(encoded, decoded2); + etl::manchester_inverted::decode_span(encoded, decoded3); + + CHECK_EQUAL(0x00, decoded0[0]); + CHECK_EQUAL(0xFF, decoded0[1]); + CHECK_EQUAL(0x01, decoded0[2]); + CHECK_EQUAL(0x80, decoded0[3]); + + CHECK_TRUE(decoded0 == decoded1); + CHECK_TRUE(decoded0 == decoded2); + CHECK_TRUE(decoded0 == decoded3); +} + +TEST(decode_span_invalid_source) +{ + etl::array invalid_source{0x55, 0x55, 0xAA, 0xAA, 0x56, 0x55, 0X55}; + etl::array valid_destination; + + CHECK_THROW({ etl::manchester::decode_span(invalid_source, valid_destination); }, etl::manchester_invalid_size); + CHECK_THROW({ etl::manchester::decode_span(invalid_source, valid_destination); }, etl::manchester_invalid_size); + CHECK_THROW({ etl::manchester::decode_span(invalid_source, valid_destination); }, etl::manchester_invalid_size); + CHECK_THROW({ etl::manchester_inverted::decode_span(invalid_source, valid_destination); }, etl::manchester_invalid_size); + CHECK_THROW({ etl::manchester_inverted::decode_span(invalid_source, valid_destination); }, etl::manchester_invalid_size); + CHECK_THROW({ etl::manchester_inverted::decode_span(invalid_source, valid_destination); }, etl::manchester_invalid_size); +} + +TEST(decode_span_invalid_destination) +{ + etl::array valid_source{0x55, 0x55, 0xAA, 0xAA, 0x56, 0x55, 0X55, 0x95}; + etl::array invalid_destination; + + CHECK_THROW({ etl::manchester::decode_span(valid_source, invalid_destination); }, etl::manchester_invalid_size); + CHECK_THROW({ etl::manchester::decode_span(valid_source, invalid_destination); }, etl::manchester_invalid_size); + CHECK_THROW({ etl::manchester::decode_span(valid_source, invalid_destination); }, etl::manchester_invalid_size); + CHECK_THROW({ etl::manchester_inverted::decode_span(valid_source, invalid_destination); }, etl::manchester_invalid_size); + CHECK_THROW({ etl::manchester_inverted::decode_span(valid_source, invalid_destination); }, etl::manchester_invalid_size); + CHECK_THROW({ etl::manchester_inverted::decode_span(valid_source, invalid_destination); }, etl::manchester_invalid_size); +} + +TEST(decode_span_fast) +{ + etl::array encoded{0xAA, 0xAA, 0x55, 0x55, 0xA9, 0xAA, 0XAA, 0x6A}; + + etl::array decoded0; + etl::array decoded1; + etl::array decoded2; + etl::array decoded3; + + etl::manchester::decode_span_fast(encoded, decoded0); + etl::manchester::decode_span_fast(encoded, decoded1); + etl::manchester::decode_span_fast(encoded, decoded2); + etl::manchester::decode_span_fast(encoded, decoded3); + + CHECK_EQUAL(0x00, decoded0[0]); + CHECK_EQUAL(0xFF, decoded0[1]); + CHECK_EQUAL(0x01, decoded0[2]); + CHECK_EQUAL(0x80, decoded0[3]); + + CHECK_TRUE(decoded0 == decoded1); + CHECK_TRUE(decoded0 == decoded2); + CHECK_TRUE(decoded0 == decoded3); +} + +TEST(valid16) +{ + CHECK_TRUE(etl::manchester::is_valid(0xAAAAUL)); + CHECK_TRUE(etl::manchester_inverted::is_valid(0xAAAAUL)); + CHECK_FALSE(etl::manchester::is_valid(0xAAA8UL)); + CHECK_FALSE(etl::manchester_inverted::is_valid(0xAAA8UL)); #if ETL_USING_CPP14 - static_assert(etl::manchester::is_valid(0xAAAAUL), "Compile time manchester validity check failed"); - static_assert(etl::manchester_inverted::is_valid(0xAAAAUL), "Compile time manchester validity check failed"); + static_assert(etl::manchester::is_valid(0xAAAAUL), "Compile time manchester validity check failed"); + static_assert(etl::manchester_inverted::is_valid(0xAAAAUL), "Compile time manchester validity check failed"); #endif - } +} - TEST(valid32) - { - CHECK_TRUE(etl::manchester::is_valid(0xAAAAAAAAUL)); - CHECK_TRUE(etl::manchester_inverted::is_valid(0xAAAAAAAAUL)); - CHECK_FALSE(etl::manchester::is_valid(0xAAAAAAA8UL)); - CHECK_FALSE(etl::manchester_inverted::is_valid(0xAAAAAAA8UL)); +TEST(valid32) +{ + CHECK_TRUE(etl::manchester::is_valid(0xAAAAAAAAUL)); + CHECK_TRUE(etl::manchester_inverted::is_valid(0xAAAAAAAAUL)); + CHECK_FALSE(etl::manchester::is_valid(0xAAAAAAA8UL)); + CHECK_FALSE(etl::manchester_inverted::is_valid(0xAAAAAAA8UL)); #if ETL_USING_CPP14 - static_assert(etl::manchester::is_valid(0xAAAAAAAAUL), "Compile time manchester validity check failed"); - static_assert(etl::manchester_inverted::is_valid(0xAAAAAAAAUL), "Compile time manchester validity check failed"); + static_assert(etl::manchester::is_valid(0xAAAAAAAAUL), "Compile time manchester validity check failed"); + static_assert(etl::manchester_inverted::is_valid(0xAAAAAAAAUL), "Compile time manchester validity check failed"); #endif - } +} - TEST(valid64) - { - CHECK_TRUE(etl::manchester::is_valid(0xAAAAAAAAAAAAAAAAULL)); - CHECK_TRUE(etl::manchester_inverted::is_valid(0xAAAAAAAAAAAAAAAAULL)); - CHECK_FALSE(etl::manchester::is_valid(0xAAAAAAAAAAAAAAA8ULL)); - CHECK_FALSE(etl::manchester_inverted::is_valid(0xAAAAAAAAAAAAAAA8ULL)); +TEST(valid64) +{ + CHECK_TRUE(etl::manchester::is_valid(0xAAAAAAAAAAAAAAAAULL)); + CHECK_TRUE(etl::manchester_inverted::is_valid(0xAAAAAAAAAAAAAAAAULL)); + CHECK_FALSE(etl::manchester::is_valid(0xAAAAAAAAAAAAAAA8ULL)); + CHECK_FALSE(etl::manchester_inverted::is_valid(0xAAAAAAAAAAAAAAA8ULL)); #if ETL_USING_CPP14 - static_assert(etl::manchester::is_valid(0xAAAAAAAAAAAAAAAAULL), "Compile time manchester validity check failed"); - static_assert(etl::manchester_inverted::is_valid(0xAAAAAAAAAAAAAAAAULL), "Compile time manchester validity check failed"); + static_assert(etl::manchester::is_valid(0xAAAAAAAAAAAAAAAAULL), "Compile time manchester validity check failed"); + static_assert(etl::manchester_inverted::is_valid(0xAAAAAAAAAAAAAAAAULL), "Compile time manchester validity check failed"); #endif - } +} - TEST(valid_span) - { - constexpr etl::array encoded1{0xAA, 0xAA, 0x55, 0x55, 0xA9, 0xAA, 0XAA, 0x6A}; - constexpr etl::array encoded2{0xAA, 0xAA, 0x55, 0x55, 0xA9, 0xAA, 0XAB, 0x6A}; +TEST(valid_span) +{ + constexpr etl::array encoded1{0xAA, 0xAA, 0x55, 0x55, 0xA9, 0xAA, 0XAA, 0x6A}; + constexpr etl::array encoded2{0xAA, 0xAA, 0x55, 0x55, 0xA9, 0xAA, 0XAB, 0x6A}; - CHECK_TRUE(etl::manchester::is_valid_span(encoded1)); - CHECK_FALSE(etl::manchester::is_valid_span(encoded2)); + CHECK_TRUE(etl::manchester::is_valid(encoded1)); + CHECK_FALSE(etl::manchester::is_valid(encoded2)); #if ETL_USING_CPP14 - static_assert(etl::manchester::is_valid_span(encoded1), "Compile time manchester validity check failed"); - static_assert(!etl::manchester::is_valid_span(encoded2), "Compile time manchester validity check failed"); + static_assert(etl::manchester::is_valid(encoded1), "Compile time manchester validity check failed"); + static_assert(!etl::manchester::is_valid(encoded2), "Compile time manchester validity check failed"); #endif - } -}; \ No newline at end of file +} + +TEST(valid_span_on_invalid_source) +{ + constexpr etl::array invalid_source{0xAA, 0xAA, 0x55, 0x55, 0xA9, 0xAA, 0XAA}; + CHECK_THROW({ etl::manchester::is_valid(invalid_source); }, etl::manchester_invalid_size); +} +} +; \ No newline at end of file From 99d3825273f37faf21f321e69b47d3a5802ff120 Mon Sep 17 00:00:00 2001 From: Timon Zijnge Date: Wed, 28 Jan 2026 13:07:51 +0100 Subject: [PATCH 23/46] manchester * Removed _fast functions * merged encode_in_place with encode and decode_in_place with decode * removed _span to create normal overloads of encode and decode for span * Some renaming and minor refactoring --- include/etl/manchester.h | 313 ++++++++++++++++----------------------- test/test_manchester.cpp | 104 +++++-------- 2 files changed, 170 insertions(+), 247 deletions(-) diff --git a/include/etl/manchester.h b/include/etl/manchester.h index ff963ff53..5a1d421b2 100644 --- a/include/etl/manchester.h +++ b/include/etl/manchester.h @@ -85,23 +85,23 @@ namespace etl ///\tparam T The decoded type. //************************************************************************* template - struct manchester_encoded + struct encoded { ETL_STATIC_ASSERT(sizeof(T) == 0, "Manchester encoding type should be one of [uint8_t, uint16_t, uint32_t]"); }; template <> - struct manchester_encoded + struct encoded { typedef uint16_t type; }; template <> - struct manchester_encoded + struct encoded { typedef uint32_t type; }; template <> - struct manchester_encoded + struct encoded { typedef uint64_t type; }; @@ -112,23 +112,23 @@ namespace etl ///\tparam T The encoded type. //************************************************************************* template - struct manchester_decoded + struct decoded { ETL_STATIC_ASSERT(sizeof(T) == 0, "Manchester decoding type should be one of [uint16_t, uint32_t, uint64_t]"); }; template <> - struct manchester_decoded + struct decoded { typedef uint8_t type; }; template <> - struct manchester_decoded + struct decoded { typedef uint16_t type; }; template <> - struct manchester_decoded + struct decoded { typedef uint32_t type; }; @@ -202,51 +202,60 @@ namespace etl #if ETL_USING_8BIT_TYPES //************************************************************************* - /// Encode a uint8_t value in place to a uint16_t. + /// Encode a 8-bit unsigned value and return 16-bit result. ///\param decoded The value to encode. - ///\param encoded The encoded value. + ///\return The Manchester encoded value. //************************************************************************* - template - static ETL_CONSTEXPR14 typename etl::enable_if::value, void>::type - encode_in_place(TChunk decoded, uint16_t& encoded) + template + static ETL_CONSTEXPR14 typename etl::enable_if::value, typename private_manchester::encoded::type>::type + encode(TDecoded decoded) { - encoded = decoded; + typedef typename private_manchester::encoded::type TEncoded; + + TEncoded encoded = decoded; encoded = (encoded | (encoded << 4U)) & 0x0F0FU; encoded = (encoded | (encoded << 2U)) & 0x3333U; encoded = (encoded | (encoded << 1U)) & 0x5555U; - encoded = (encoded | (encoded << 1U)) ^ (0xAAAAU ^ static_cast(TManchesterType::inversion_mask)); + encoded = (encoded | (encoded << 1U)) ^ (0xAAAAU ^ static_cast(TManchesterType::inversion_mask)); + return encoded; } #endif //************************************************************************* - /// Encode a uint16_t value in place to a uint32_t. + /// Encode a 16-bit unsigned value and return the 32-bit result. ///\param decoded The value to encode. - ///\param encoded The encoded value. + ///\return The Manchester encoded value. //************************************************************************* - template - static ETL_CONSTEXPR14 typename etl::enable_if::value, void>::type - encode_in_place(TChunk decoded, uint32_t& encoded) + template + static ETL_CONSTEXPR14 typename etl::enable_if::value, typename private_manchester::encoded::type>::type + encode(TDecoded decoded) { - encoded = decoded; + typedef typename private_manchester::encoded::type TEncoded; + + TEncoded encoded = decoded; encoded = (encoded | (encoded << 8U)) & 0x00FF00FFUL; encoded = (encoded | (encoded << 4U)) & 0x0F0F0F0FUL; encoded = (encoded | (encoded << 2U)) & 0x33333333UL; encoded = (encoded | (encoded << 1U)) & 0x55555555UL; - encoded = (encoded | (encoded << 1U)) ^ (0xAAAAAAAAUL ^ static_cast(TManchesterType::inversion_mask)); + encoded = (encoded | (encoded << 1U)) ^ (0xAAAAAAAAUL ^ static_cast(TManchesterType::inversion_mask)); + return encoded; } +#if ETL_USING_64BIT_TYPES //************************************************************************* - /// Encode a uint32_t value in place to a uint64_t. + /// Encode a 32-bit unsigned value and return the 64-bit result. ///\param decoded The value to encode. - ///\param encoded The encoded value. + ///\return The Manchester encoded value. //************************************************************************* - template - static ETL_CONSTEXPR14 typename etl::enable_if::value, void>::type - encode_in_place(TChunk decoded, uint64_t& encoded) + template + static ETL_CONSTEXPR14 typename etl::enable_if::value, typename private_manchester::encoded::type>::type + encode(TDecoded decoded) { - encoded = decoded; + typedef typename private_manchester::encoded::type TEncoded; + + TEncoded encoded = decoded; encoded = (encoded | (encoded << 16U)) & 0x0000FFFF0000FFFFULL; encoded = (encoded | (encoded << 8U)) & 0x00FF00FF00FF00FFULL; @@ -254,27 +263,9 @@ namespace etl encoded = (encoded | (encoded << 2U)) & 0x3333333333333333ULL; encoded = (encoded | (encoded << 1U)) & 0x5555555555555555ULL; encoded = (encoded | (encoded << 1U)) ^ (0xAAAAAAAAAAAAAAAAULL ^ TManchesterType::inversion_mask); - } -#endif - - template - static typename etl::enable_if::value, void>::type - encode_in_place(TChunk decoded, typename private_manchester::manchester_encoded::type& encoded) ETL_DELETE; - - //************************************************************************* - /// Encode a value and return the Manchester encoded result. - ///\param decoded The value to encode. - ///\return The Manchester encoded value. - //************************************************************************* - template - ETL_NODISCARD static ETL_CONSTEXPR14 typename private_manchester::manchester_encoded::type encode(TChunk decoded) - { - ETL_STATIC_ASSERT(private_manchester::is_encodable::value, "TChunk must be an encodable type"); - - typename private_manchester::manchester_encoded::type encoded = 0; - encode_in_place(decoded, encoded); return encoded; } +#endif //************************************************************************* /// Encode a span of data with the selected chunk size. @@ -284,22 +275,22 @@ namespace etl //************************************************************************* template static typename etl::enable_if::value, void>::type - encode_span(etl::span source, etl::span destination) + encode(etl::span decoded, etl::span encoded) { - typedef TChunk TDecoded; - typedef typename etl::private_manchester::manchester_encoded::type TEncoded; + typedef TChunk TDecoded; + typedef typename etl::private_manchester::encoded::type TEncoded; - ETL_ASSERT(destination.size() >= source.size() * 2, ETL_ERROR(manchester_invalid_size)); - ETL_ASSERT(source.size() % sizeof(TDecoded) == 0, ETL_ERROR(manchester_invalid_size)); + ETL_ASSERT(encoded.size() >= decoded.size() * 2, ETL_ERROR(manchester_invalid_size)); + ETL_ASSERT(decoded.size() % sizeof(TDecoded) == 0, ETL_ERROR(manchester_invalid_size)); size_t dest_index = 0; size_t source_index = 0; - for (size_t i = 0; i < source.size() / sizeof(TDecoded); ++i) + for (size_t i = 0; i < decoded.size() / sizeof(TDecoded); ++i) { TDecoded decoded_value = 0; - memcpy(&decoded_value, &source[source_index], sizeof(TDecoded)); + memcpy(&decoded_value, &decoded[source_index], sizeof(TDecoded)); const TEncoded encoded_value = encode(decoded_value); - memcpy(&destination[dest_index], &encoded_value, sizeof(TEncoded)); + memcpy(&encoded[dest_index], &encoded_value, sizeof(TEncoded)); source_index += sizeof(TDecoded); dest_index += sizeof(TEncoded); @@ -314,21 +305,21 @@ namespace etl ///\tparam TChunk The chunk size for encoding (default: uint_least8_t). //************************************************************************* template - static typename etl::enable_if::value, void>::type constexpr encode_span(etl::span source, etl::span destination) + static ETL_CONSTEXPR14 typename etl::enable_if::value, void>::type encode(etl::span decoded, etl::span encoded) { - typedef TChunk TDecoded; - typedef typename etl::private_manchester::manchester_encoded::type TEncoded; + typedef TChunk TDecoded; + typedef typename etl::private_manchester::encoded::type TEncoded; - ETL_ASSERT(destination.size() >= source.size() * 2, ETL_ERROR(manchester_invalid_size)); - ETL_ASSERT(source.size() % sizeof(TDecoded) == 0, ETL_ERROR(manchester_invalid_size)); + ETL_ASSERT(encoded.size() >= decoded.size() * 2, ETL_ERROR(manchester_invalid_size)); + ETL_ASSERT(decoded.size() % sizeof(TDecoded) == 0, ETL_ERROR(manchester_invalid_size)); size_t dest_index = 0; size_t source_index = 0; - for (size_t i = 0; i < source.size() / sizeof(TDecoded); ++i) + for (size_t i = 0; i < decoded.size() / sizeof(TDecoded); ++i) { - const TEncoded encoded_value = encode(source[source_index]); - destination[dest_index] = static_cast(encoded_value); - destination[dest_index + 1] = static_cast(encoded_value >> CHAR_BIT); + const TEncoded encoded_value = encode(decoded[source_index]); + encoded[dest_index] = static_cast(encoded_value); + encoded[dest_index + 1] = static_cast(encoded_value >> CHAR_BIT); source_index += sizeof(TDecoded); dest_index += sizeof(TEncoded); @@ -339,123 +330,64 @@ namespace etl // Decoding functions //************************************************************************* -#if ETL_USING_8BIT_TYPES #if ETL_USING_8BIT_TYPES //************************************************************************* - /// Decode a uint16_t value in place to a uint8_t. + /// Decode a 16-bit value and return the 8-bit result. ///\param encoded The value to decode. - ///\param decoded The decoded value. + ///\return The Manchester decoded value. //************************************************************************* - template - static ETL_CONSTEXPR14 typename etl::enable_if::value, void>::type - decode_in_place(TChunk encoded, uint8_t& decoded) + template + static ETL_CONSTEXPR14 typename etl::enable_if::value, typename private_manchester::decoded::type>::type + decode(TEncoded encoded) { - encoded = (encoded ^ (0xAAAAU ^ static_cast(TManchesterType::inversion_mask))) & 0x5555U; + typedef typename private_manchester::decoded::type TDecoded; + + encoded = (encoded ^ (0xAAAAU ^ static_cast(TManchesterType::inversion_mask))) & 0x5555U; encoded = (encoded | (encoded >> 1)) & 0x3333U; encoded = (encoded | (encoded >> 2)) & 0x0F0FU; - decoded = static_cast(encoded | (encoded >> 4U)); + return static_cast(encoded | (encoded >> 4U)); } #endif //************************************************************************* - /// Decode a uint32_t value in place to a uint16_t. + /// Decode a 32-bit value and return the 16-bit result. ///\param encoded The value to decode. - ///\param decoded The decoded value. + ///\return The Manchester decoded value. //************************************************************************* - template - static ETL_CONSTEXPR14 typename etl::enable_if::value, void>::type - decode_in_place(TChunk encoded, uint16_t& decoded) + template + static ETL_CONSTEXPR14 typename etl::enable_if::value, typename private_manchester::decoded::type>::type + decode(TEncoded encoded) { - encoded = (encoded ^ (0xAAAAAAAAUL ^ static_cast(TManchesterType::inversion_mask))) & 0x55555555UL; + typedef typename private_manchester::decoded::type TDecoded; + + encoded = (encoded ^ (0xAAAAAAAAUL ^ static_cast(TManchesterType::inversion_mask))) & 0x55555555UL; encoded = (encoded | (encoded >> 1)) & 0x33333333UL; encoded = (encoded | (encoded >> 2)) & 0x0F0F0F0FUL; encoded = (encoded | (encoded >> 4)) & 0x00FF00FFUL; - decoded = static_cast(encoded | (encoded >> 8U)); + return static_cast(encoded | (encoded >> 8U)); } #if ETL_USING_64BIT_TYPES //************************************************************************* - /// Decode a uint64_t value in place to a uint32_t. + /// Decode a 64-bit value and return the 32-bit result. ///\param encoded The value to decode. - ///\param decoded The decoded value. + ///\return The Manchester decoded value. //************************************************************************* - template - static ETL_CONSTEXPR14 typename etl::enable_if::value, void>::type - decode_in_place(TChunk encoded, uint32_t& decoded) + template + static ETL_CONSTEXPR14 typename etl::enable_if::value, typename private_manchester::decoded::type>::type + decode(TEncoded encoded) { + typedef typename private_manchester::decoded::type TDecoded; + encoded = (encoded ^ (0xAAAAAAAAAAAAAAAAULL ^ TManchesterType::inversion_mask)) & 0x5555555555555555ULL; encoded = (encoded | (encoded >> 1)) & 0x3333333333333333ULL; encoded = (encoded | (encoded >> 2)) & 0x0F0F0F0F0F0F0F0FULL; encoded = (encoded | (encoded >> 4)) & 0x00FF00FF00FF00FFULL; encoded = (encoded | (encoded >> 8)) & 0x0000FFFF0000FFFFULL; - decoded = static_cast(encoded | (encoded >> 16U)); + return static_cast(encoded | (encoded >> 16U)); } #endif - template - static typename etl::enable_if::value, void>::type - decode_in_place(TChunk encoded, typename private_manchester::manchester_decoded::type& decoded) ETL_DELETE; - - //************************************************************************* - /// Decode a value and return the Manchester decoded result. - ///\param encoded The value to decode. - ///\return The Manchester decoded value. - //************************************************************************* - template - ETL_NODISCARD static ETL_CONSTEXPR14 - typename private_manchester::manchester_decoded::type - decode(TChunk encoded) - { - ETL_STATIC_ASSERT(private_manchester::is_decodable::value, "TChunk must be a decodable type"); - - typename private_manchester::manchester_decoded::type decoded = 0; - decode_in_place(encoded, decoded); - return decoded; - } - - //************************************************************************* - // Validation functions - //************************************************************************* - - //************************************************************************* - /// Validate that a value contains valid Manchester encoded data. - ///\param encoded The encoded value to validate. - ///\return True if the value is valid Manchester encoding. - //************************************************************************* - template - ETL_NODISCARD static ETL_CONSTEXPR14 - typename etl::enable_if::value, bool>::type - is_valid(TChunk encoded) - { - const TChunk mask = static_cast(0x5555555555555555ULL); - return (((encoded ^ (encoded >> 1)) & mask) == mask); - } - - //************************************************************************* - /// Validate that a span contains valid Manchester encoded data. - ///\param encoded The span of encoded data to validate. - ///\return True if all data is valid Manchester encoding. - //************************************************************************* - ETL_NODISCARD static ETL_CONSTEXPR14 bool is_valid(etl::span encoded) - { - ETL_ASSERT(encoded.size() % sizeof(uint16_t) == 0, ETL_ERROR(manchester_invalid_size)); - - for (size_t i = 0; i < encoded.size(); i += 2) - { - const uint16_t chunk = static_cast((encoded[i + 1] << 8) | encoded[i]); - if (!is_valid(chunk)) - { - return false; - } - } - - return true; - } - - //************************************************************************* - // Span decoding functions - //************************************************************************* - //************************************************************************* /// Decode a span of data using specified chunk type. ///\param source The source encoded data to decode. @@ -463,23 +395,23 @@ namespace etl ///\tparam TChunk The chunk type for decoding. //************************************************************************* template - static typename etl::enable_if::type>::value, void>::type - decode_span(etl::span source, etl::span destination) + static typename etl::enable_if::type>::value, void>::type + decode(etl::span encoded, etl::span decoded) { - typedef typename private_manchester::manchester_decoded::type TDecoded; - typedef TChunk TEncoded; + typedef typename private_manchester::decoded::type TDecoded; + typedef TChunk TEncoded; - ETL_ASSERT(destination.size() * 2 >= source.size(), ETL_ERROR(manchester_invalid_size)); - ETL_ASSERT(source.size() % sizeof(TChunk) == 0, ETL_ERROR(manchester_invalid_size)); + ETL_ASSERT(decoded.size() * 2 >= encoded.size(), ETL_ERROR(manchester_invalid_size)); + ETL_ASSERT(encoded.size() % sizeof(TChunk) == 0, ETL_ERROR(manchester_invalid_size)); size_t dest_index = 0; size_t source_index = 0; - for (size_t i = 0; i < source.size() / sizeof(TEncoded); ++i) + for (size_t i = 0; i < encoded.size() / sizeof(TEncoded); ++i) { TChunk encoded_value = 0; - memcpy(&encoded_value, &source[source_index], sizeof(TEncoded)); + memcpy(&encoded_value, &encoded[source_index], sizeof(TEncoded)); const TDecoded decoded_value = decode(encoded_value); - memcpy(&destination[dest_index], &decoded_value, sizeof(TDecoded)); + memcpy(&decoded[dest_index], &decoded_value, sizeof(TDecoded)); source_index += sizeof(TEncoded); dest_index += sizeof(TDecoded); @@ -487,27 +419,27 @@ namespace etl } //************************************************************************* - /// Decode a span of data using the smalles chunk type. This version is + /// Decode a span of data using the smallest chunk type. This version is /// constexpr so that it can be used to decode data at compile time. ///\param source The source encoded data to decode. ///\param destination The destination buffer for decoded data. ///\tparam TChunk The chunk type for decoding (default type). //************************************************************************* - template ::type> - static ETL_CONSTEXPR14 typename etl::enable_if::type>::value, void>::type - decode_span(etl::span source, etl::span destination) + template ::type> + static ETL_CONSTEXPR14 typename etl::enable_if::type>::value, void>::type + decode(etl::span encoded, etl::span decoded) { typedef uint_least8_t TDecoded; - ETL_ASSERT(destination.size() * 2 >= source.size(), ETL_ERROR(manchester_invalid_size)); - ETL_ASSERT(source.size() % sizeof(TChunk) == 0, ETL_ERROR(manchester_invalid_size)); + ETL_ASSERT(decoded.size() * 2 >= encoded.size(), ETL_ERROR(manchester_invalid_size)); + ETL_ASSERT(encoded.size() % sizeof(TChunk) == 0, ETL_ERROR(manchester_invalid_size)); size_t dest_index = 0; size_t source_index = 0; - for (size_t i = 0; i < source.size() / sizeof(TChunk); ++i) + for (size_t i = 0; i < encoded.size() / sizeof(TChunk); ++i) { - const TChunk encoded_value = static_cast((source[source_index + 1] << CHAR_BIT) | source[source_index]); - destination[dest_index] = decode(encoded_value); + const TChunk encoded_value = static_cast((encoded[source_index + 1] << CHAR_BIT) | encoded[source_index]); + decoded[dest_index] = decode(encoded_value); source_index += sizeof(TChunk); dest_index += sizeof(TDecoded); @@ -515,27 +447,42 @@ namespace etl } //************************************************************************* - /// Fast decode a span of data using pointer arithmetic. - ///\param source The source encoded data to decode. - ///\param destination The destination buffer for decoded data. - ///\tparam TChunk The chunk size for decoding (default: uint16_t). + // Validation functions //************************************************************************* - template ::type> - static void decode_span_fast(etl::span source, etl::span destination) - { - ETL_ASSERT(destination.size() * 2 >= source.size(), ETL_ERROR(manchester_invalid_size)); - ETL_ASSERT(source.size() % sizeof(TChunk) == 0, ETL_ERROR(manchester_invalid_size)); - while (!source.empty()) - { - const TChunk& encoded = *reinterpret_cast(source.data()); - typename etl::private_manchester::manchester_decoded::type& decoded = *reinterpret_cast::type*>(destination.data()); + //************************************************************************* + /// Validate that a value contains valid Manchester encoded data. + ///\param encoded The encoded value to validate. + ///\return True if the value is valid Manchester encoding. + //************************************************************************* + template + ETL_NODISCARD static ETL_CONSTEXPR14 + typename etl::enable_if::value, bool>::type + is_valid(TChunk encoded) + { + const TChunk mask = static_cast(0x5555555555555555ULL); + return (((encoded ^ (encoded >> 1)) & mask) == mask); + } - decode_in_place(encoded, decoded); + //************************************************************************* + /// Validate that a span contains valid Manchester encoded data. + ///\param encoded The span of encoded data to validate. + ///\return True if all data is valid Manchester encoding. + //************************************************************************* + ETL_NODISCARD static ETL_CONSTEXPR14 bool is_valid(etl::span encoded) + { + ETL_ASSERT(encoded.size() % sizeof(uint16_t) == 0, ETL_ERROR(manchester_invalid_size)); - source.advance(sizeof(TChunk)); - destination.advance(sizeof(typename etl::private_manchester::manchester_decoded::type)); + for (size_t i = 0; i < encoded.size(); i += 2) + { + const uint16_t chunk = static_cast((encoded[i + 1] << 8) | encoded[i]); + if (!is_valid(chunk)) + { + return false; + } } + + return true; } }; diff --git a/test/test_manchester.cpp b/test/test_manchester.cpp index 6c7876ab5..bcc28d831 100644 --- a/test/test_manchester.cpp +++ b/test/test_manchester.cpp @@ -70,7 +70,7 @@ TEST(encode_uint32_t_inverted) constexpr etl::array manchester_encoded(etl::span decoded) { etl::array encoded{0, 0, 0, 0, 0, 0, 0, 0}; - etl::manchester::encode_span(decoded, encoded); + etl::manchester::encode(decoded, encoded); return encoded; } @@ -83,10 +83,10 @@ TEST(encode_span) etl::array encoded2; etl::array encoded3; - etl::manchester::encode_span(decoded, encoded0); - etl::manchester::encode_span(decoded, encoded1); - etl::manchester::encode_span(decoded, encoded2); - etl::manchester::encode_span(decoded, encoded3); + etl::manchester::encode(decoded, encoded0); + etl::manchester::encode(decoded, encoded1); + etl::manchester::encode(decoded, encoded2); + etl::manchester::encode(decoded, encoded3); CHECK_EQUAL(0xAA, encoded0[0]); CHECK_EQUAL(0xAA, encoded0[1]); @@ -122,10 +122,10 @@ TEST(encode_span_inverted) etl::array encoded2; etl::array encoded3; - etl::manchester_inverted::encode_span(decoded, encoded0); - etl::manchester_inverted::encode_span(decoded, encoded1); - etl::manchester_inverted::encode_span(decoded, encoded2); - etl::manchester_inverted::encode_span(decoded, encoded3); + etl::manchester_inverted::encode(decoded, encoded0); + etl::manchester_inverted::encode(decoded, encoded1); + etl::manchester_inverted::encode(decoded, encoded2); + etl::manchester_inverted::encode(decoded, encoded3); CHECK_EQUAL(0x55, encoded0[0]); CHECK_EQUAL(0x55, encoded0[1]); @@ -146,10 +146,10 @@ TEST(encode_span_invalid_source) etl::array invalid_source{0x00, 0xFF, 0x01}; etl::array valid_destination; - CHECK_THROW({ etl::manchester::encode_span(invalid_source, valid_destination); }, etl::manchester_invalid_size); - CHECK_THROW({ etl::manchester::encode_span(invalid_source, valid_destination); }, etl::manchester_invalid_size); - CHECK_THROW({ etl::manchester_inverted::encode_span(invalid_source, valid_destination); }, etl::manchester_invalid_size); - CHECK_THROW({ etl::manchester_inverted::encode_span(invalid_source, valid_destination); }, etl::manchester_invalid_size); + CHECK_THROW({ etl::manchester::encode(invalid_source, valid_destination); }, etl::manchester_invalid_size); + CHECK_THROW({ etl::manchester::encode(invalid_source, valid_destination); }, etl::manchester_invalid_size); + CHECK_THROW({ etl::manchester_inverted::encode(invalid_source, valid_destination); }, etl::manchester_invalid_size); + CHECK_THROW({ etl::manchester_inverted::encode(invalid_source, valid_destination); }, etl::manchester_invalid_size); } TEST(encode_span_invalid_destination) @@ -157,12 +157,12 @@ TEST(encode_span_invalid_destination) etl::array valid_source{0x00, 0xFF, 0x01, 0x80}; etl::array invalid_destination; - CHECK_THROW({ etl::manchester::encode_span(valid_source, invalid_destination); }, etl::manchester_invalid_size); - CHECK_THROW({ etl::manchester::encode_span(valid_source, invalid_destination); }, etl::manchester_invalid_size); - CHECK_THROW({ etl::manchester::encode_span(valid_source, invalid_destination); }, etl::manchester_invalid_size); - CHECK_THROW({ etl::manchester_inverted::encode_span(valid_source, invalid_destination); }, etl::manchester_invalid_size); - CHECK_THROW({ etl::manchester_inverted::encode_span(valid_source, invalid_destination); }, etl::manchester_invalid_size); - CHECK_THROW({ etl::manchester_inverted::encode_span(valid_source, invalid_destination); }, etl::manchester_invalid_size); + CHECK_THROW({ etl::manchester::encode(valid_source, invalid_destination); }, etl::manchester_invalid_size); + CHECK_THROW({ etl::manchester::encode(valid_source, invalid_destination); }, etl::manchester_invalid_size); + CHECK_THROW({ etl::manchester::encode(valid_source, invalid_destination); }, etl::manchester_invalid_size); + CHECK_THROW({ etl::manchester_inverted::encode(valid_source, invalid_destination); }, etl::manchester_invalid_size); + CHECK_THROW({ etl::manchester_inverted::encode(valid_source, invalid_destination); }, etl::manchester_invalid_size); + CHECK_THROW({ etl::manchester_inverted::encode(valid_source, invalid_destination); }, etl::manchester_invalid_size); } TEST(decode_uint16_t) @@ -230,7 +230,7 @@ TEST(decode_uint64_t_inverted) constexpr etl::array manchester_decoded(etl::span encoded) { etl::array decoded{0, 0, 0, 0}; - etl::manchester::decode_span(encoded, decoded); + etl::manchester::decode(encoded, decoded); return decoded; } @@ -243,10 +243,10 @@ TEST(decode_span) etl::array decoded2; etl::array decoded3; - etl::manchester::decode_span(encoded, decoded0); - etl::manchester::decode_span(encoded, decoded1); - etl::manchester::decode_span(encoded, decoded2); - etl::manchester::decode_span(encoded, decoded3); + etl::manchester::decode(encoded, decoded0); + etl::manchester::decode(encoded, decoded1); + etl::manchester::decode(encoded, decoded2); + etl::manchester::decode(encoded, decoded3); CHECK_EQUAL(0x00, decoded0[0]); CHECK_EQUAL(0xFF, decoded0[1]); @@ -274,10 +274,10 @@ TEST(decode_span_inverted) etl::array decoded2; etl::array decoded3; - etl::manchester_inverted::decode_span(encoded, decoded0); - etl::manchester_inverted::decode_span(encoded, decoded1); - etl::manchester_inverted::decode_span(encoded, decoded2); - etl::manchester_inverted::decode_span(encoded, decoded3); + etl::manchester_inverted::decode(encoded, decoded0); + etl::manchester_inverted::decode(encoded, decoded1); + etl::manchester_inverted::decode(encoded, decoded2); + etl::manchester_inverted::decode(encoded, decoded3); CHECK_EQUAL(0x00, decoded0[0]); CHECK_EQUAL(0xFF, decoded0[1]); @@ -294,12 +294,12 @@ TEST(decode_span_invalid_source) etl::array invalid_source{0x55, 0x55, 0xAA, 0xAA, 0x56, 0x55, 0X55}; etl::array valid_destination; - CHECK_THROW({ etl::manchester::decode_span(invalid_source, valid_destination); }, etl::manchester_invalid_size); - CHECK_THROW({ etl::manchester::decode_span(invalid_source, valid_destination); }, etl::manchester_invalid_size); - CHECK_THROW({ etl::manchester::decode_span(invalid_source, valid_destination); }, etl::manchester_invalid_size); - CHECK_THROW({ etl::manchester_inverted::decode_span(invalid_source, valid_destination); }, etl::manchester_invalid_size); - CHECK_THROW({ etl::manchester_inverted::decode_span(invalid_source, valid_destination); }, etl::manchester_invalid_size); - CHECK_THROW({ etl::manchester_inverted::decode_span(invalid_source, valid_destination); }, etl::manchester_invalid_size); + CHECK_THROW({ etl::manchester::decode(invalid_source, valid_destination); }, etl::manchester_invalid_size); + CHECK_THROW({ etl::manchester::decode(invalid_source, valid_destination); }, etl::manchester_invalid_size); + CHECK_THROW({ etl::manchester::decode(invalid_source, valid_destination); }, etl::manchester_invalid_size); + CHECK_THROW({ etl::manchester_inverted::decode(invalid_source, valid_destination); }, etl::manchester_invalid_size); + CHECK_THROW({ etl::manchester_inverted::decode(invalid_source, valid_destination); }, etl::manchester_invalid_size); + CHECK_THROW({ etl::manchester_inverted::decode(invalid_source, valid_destination); }, etl::manchester_invalid_size); } TEST(decode_span_invalid_destination) @@ -307,36 +307,12 @@ TEST(decode_span_invalid_destination) etl::array valid_source{0x55, 0x55, 0xAA, 0xAA, 0x56, 0x55, 0X55, 0x95}; etl::array invalid_destination; - CHECK_THROW({ etl::manchester::decode_span(valid_source, invalid_destination); }, etl::manchester_invalid_size); - CHECK_THROW({ etl::manchester::decode_span(valid_source, invalid_destination); }, etl::manchester_invalid_size); - CHECK_THROW({ etl::manchester::decode_span(valid_source, invalid_destination); }, etl::manchester_invalid_size); - CHECK_THROW({ etl::manchester_inverted::decode_span(valid_source, invalid_destination); }, etl::manchester_invalid_size); - CHECK_THROW({ etl::manchester_inverted::decode_span(valid_source, invalid_destination); }, etl::manchester_invalid_size); - CHECK_THROW({ etl::manchester_inverted::decode_span(valid_source, invalid_destination); }, etl::manchester_invalid_size); -} - -TEST(decode_span_fast) -{ - etl::array encoded{0xAA, 0xAA, 0x55, 0x55, 0xA9, 0xAA, 0XAA, 0x6A}; - - etl::array decoded0; - etl::array decoded1; - etl::array decoded2; - etl::array decoded3; - - etl::manchester::decode_span_fast(encoded, decoded0); - etl::manchester::decode_span_fast(encoded, decoded1); - etl::manchester::decode_span_fast(encoded, decoded2); - etl::manchester::decode_span_fast(encoded, decoded3); - - CHECK_EQUAL(0x00, decoded0[0]); - CHECK_EQUAL(0xFF, decoded0[1]); - CHECK_EQUAL(0x01, decoded0[2]); - CHECK_EQUAL(0x80, decoded0[3]); - - CHECK_TRUE(decoded0 == decoded1); - CHECK_TRUE(decoded0 == decoded2); - CHECK_TRUE(decoded0 == decoded3); + CHECK_THROW({ etl::manchester::decode(valid_source, invalid_destination); }, etl::manchester_invalid_size); + CHECK_THROW({ etl::manchester::decode(valid_source, invalid_destination); }, etl::manchester_invalid_size); + CHECK_THROW({ etl::manchester::decode(valid_source, invalid_destination); }, etl::manchester_invalid_size); + CHECK_THROW({ etl::manchester_inverted::decode(valid_source, invalid_destination); }, etl::manchester_invalid_size); + CHECK_THROW({ etl::manchester_inverted::decode(valid_source, invalid_destination); }, etl::manchester_invalid_size); + CHECK_THROW({ etl::manchester_inverted::decode(valid_source, invalid_destination); }, etl::manchester_invalid_size); } TEST(valid16) From 684e7cdd9aed5f517e5b527857756c0e64c78784 Mon Sep 17 00:00:00 2001 From: Timon Zijnge Date: Wed, 28 Jan 2026 13:23:21 +0100 Subject: [PATCH 24/46] manchester * Fix build issues --- test/test_manchester.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/test/test_manchester.cpp b/test/test_manchester.cpp index bcc28d831..f291fa3f5 100644 --- a/test/test_manchester.cpp +++ b/test/test_manchester.cpp @@ -4,6 +4,7 @@ #include #include #include +#include SUITE(test_manchester){ TEST(encode_uint8_t){ @@ -67,12 +68,14 @@ TEST(encode_uint32_t_inverted) #endif } +#if ETL_USING_CPP14 constexpr etl::array manchester_encoded(etl::span decoded) { etl::array encoded{0, 0, 0, 0, 0, 0, 0, 0}; etl::manchester::encode(decoded, encoded); return encoded; } +#endif TEST(encode_span) { @@ -371,7 +374,7 @@ TEST(valid_span) TEST(valid_span_on_invalid_source) { constexpr etl::array invalid_source{0xAA, 0xAA, 0x55, 0x55, 0xA9, 0xAA, 0XAA}; - CHECK_THROW({ etl::manchester::is_valid(invalid_source); }, etl::manchester_invalid_size); + CHECK_THROW({ std::ignore = etl::manchester::is_valid(invalid_source); }, etl::manchester_invalid_size); } } ; \ No newline at end of file From 737c8ef99a5711abb3e75c0f0067ebb384e27847 Mon Sep 17 00:00:00 2001 From: Timon Zijnge Date: Wed, 28 Jan 2026 13:36:38 +0100 Subject: [PATCH 25/46] manchester * Conditionally compile manchester_decoded --- test/test_manchester.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/test/test_manchester.cpp b/test/test_manchester.cpp index f291fa3f5..57b0a9153 100644 --- a/test/test_manchester.cpp +++ b/test/test_manchester.cpp @@ -230,12 +230,14 @@ TEST(decode_uint64_t_inverted) #endif } +#if ETL_USING_CPP14 constexpr etl::array manchester_decoded(etl::span encoded) { etl::array decoded{0, 0, 0, 0}; etl::manchester::decode(encoded, decoded); return decoded; } +#endif TEST(decode_span) { From 521b5dbc034c5a92bc7bffe214d1a2bf215c9c57 Mon Sep 17 00:00:00 2001 From: Timon Zijnge <47081647+tzijnge@users.noreply.github.com> Date: Wed, 28 Jan 2026 14:26:00 +0100 Subject: [PATCH 26/46] Update test_manchester.cpp Removed redundant semicolon --- test/test_manchester.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/test/test_manchester.cpp b/test/test_manchester.cpp index 57b0a9153..1f4837427 100644 --- a/test/test_manchester.cpp +++ b/test/test_manchester.cpp @@ -379,4 +379,3 @@ TEST(valid_span_on_invalid_source) CHECK_THROW({ std::ignore = etl::manchester::is_valid(invalid_source); }, etl::manchester_invalid_size); } } -; \ No newline at end of file From 0dd2ebd40e8a3257c0418a0276a178cac3820a06 Mon Sep 17 00:00:00 2001 From: Timon Zijnge Date: Wed, 28 Jan 2026 14:39:36 +0100 Subject: [PATCH 27/46] #1258 Manchester coding * Formatting * consistency: hex literals with lower case 0x --- test/test_manchester.cpp | 582 ++++++++++++++++++++------------------- 1 file changed, 292 insertions(+), 290 deletions(-) diff --git a/test/test_manchester.cpp b/test/test_manchester.cpp index 1f4837427..0334712fd 100644 --- a/test/test_manchester.cpp +++ b/test/test_manchester.cpp @@ -6,376 +6,378 @@ #include #include -SUITE(test_manchester){ - TEST(encode_uint8_t){ +SUITE(test_manchester) +{ + TEST(encode_uint8_t) + { CHECK_EQUAL(0xAAAA, (etl::manchester::encode(0x00U))); -CHECK_EQUAL(0x5555, (etl::manchester::encode(0xFFU))); -CHECK_EQUAL(0xAAA9, (etl::manchester::encode(0x01U))); -CHECK_EQUAL(0x6AAA, (etl::manchester::encode(0x80U))); + CHECK_EQUAL(0x5555, (etl::manchester::encode(0xFFU))); + CHECK_EQUAL(0xAAA9, (etl::manchester::encode(0x01U))); + CHECK_EQUAL(0x6AAA, (etl::manchester::encode(0x80U))); #if ETL_USING_CPP14 -static_assert(0xAAAA == etl::manchester::encode(0x00U), "Compile time manchester encoding failed"); + static_assert(0xAAAA == etl::manchester::encode(0x00U), "Compile time manchester encoding failed"); #endif -} + } -TEST(encode_uint8_t_inverted) -{ - CHECK_EQUAL(0x5555, (etl::manchester_inverted::encode(0x00U))); - CHECK_EQUAL(0xAAAA, (etl::manchester_inverted::encode(0xFFU))); - CHECK_EQUAL(0x5556, (etl::manchester_inverted::encode(0x01U))); - CHECK_EQUAL(0x9555, (etl::manchester_inverted::encode(0x80U))); + TEST(encode_uint8_t_inverted) + { + CHECK_EQUAL(0x5555, (etl::manchester_inverted::encode(0x00U))); + CHECK_EQUAL(0xAAAA, (etl::manchester_inverted::encode(0xFFU))); + CHECK_EQUAL(0x5556, (etl::manchester_inverted::encode(0x01U))); + CHECK_EQUAL(0x9555, (etl::manchester_inverted::encode(0x80U))); #if ETL_USING_CPP14 - static_assert(0x5555 == etl::manchester_inverted::encode(0x00U), "Compile time manchester encoding failed"); + static_assert(0x5555 == etl::manchester_inverted::encode(0x00U), "Compile time manchester encoding failed"); #endif -} + } -TEST(encode_uint16_t) -{ - CHECK_EQUAL(0x5555AAAA, (etl::manchester::encode(0xFF00UL))); - CHECK_EQUAL(0x6AAAAAA9, (etl::manchester::encode(0x8001UL))); + TEST(encode_uint16_t) + { + CHECK_EQUAL(0x5555AAAA, (etl::manchester::encode(0xFF00UL))); + CHECK_EQUAL(0x6AAAAAA9, (etl::manchester::encode(0x8001UL))); #if ETL_USING_CPP14 - static_assert(0x5555AAAA == etl::manchester::encode(0xFF00UL), "Compile time manchester encoding failed"); + static_assert(0x5555AAAA == etl::manchester::encode(0xFF00UL), "Compile time manchester encoding failed"); #endif -} + } -TEST(encode_uint16_t_inverted) -{ - CHECK_EQUAL(0xAAAA5555, (etl::manchester_inverted::encode(0xFF00UL))); - CHECK_EQUAL(0x95555556, (etl::manchester_inverted::encode(0x8001UL))); + TEST(encode_uint16_t_inverted) + { + CHECK_EQUAL(0xAAAA5555, (etl::manchester_inverted::encode(0xFF00UL))); + CHECK_EQUAL(0x95555556, (etl::manchester_inverted::encode(0x8001UL))); #if ETL_USING_CPP14 - static_assert(0xAAAA5555 == etl::manchester_inverted::encode(0xFF00UL), "Compile time manchester encoding failed"); + static_assert(0xAAAA5555 == etl::manchester_inverted::encode(0xFF00UL), "Compile time manchester encoding failed"); #endif -} + } -TEST(encode_uint32_t) -{ - CHECK_EQUAL(0x6AAAAAA95555AAAA, (etl::manchester::encode(0x8001FF00ULL))); + TEST(encode_uint32_t) + { + CHECK_EQUAL(0x6AAAAAA95555AAAA, (etl::manchester::encode(0x8001FF00ULL))); #if ETL_USING_CPP14 - static_assert(0x6AAAAAA95555AAAA == etl::manchester::encode(0x8001FF00ULL), "Compile time manchester encoding failed"); + static_assert(0x6AAAAAA95555AAAA == etl::manchester::encode(0x8001FF00ULL), "Compile time manchester encoding failed"); #endif -} + } -TEST(encode_uint32_t_inverted) -{ - CHECK_EQUAL(0x95555556AAAA5555, (etl::manchester_inverted::encode(0x8001FF00ULL))); + TEST(encode_uint32_t_inverted) + { + CHECK_EQUAL(0x95555556AAAA5555, (etl::manchester_inverted::encode(0x8001FF00ULL))); #if ETL_USING_CPP14 - static_assert(0x95555556AAAA5555 == etl::manchester_inverted::encode(0x8001FF00ULL), "Compile time manchester encoding failed"); + static_assert(0x95555556AAAA5555 == etl::manchester_inverted::encode(0x8001FF00ULL), "Compile time manchester encoding failed"); #endif -} + } #if ETL_USING_CPP14 -constexpr etl::array manchester_encoded(etl::span decoded) -{ - etl::array encoded{0, 0, 0, 0, 0, 0, 0, 0}; - etl::manchester::encode(decoded, encoded); - return encoded; -} + constexpr etl::array manchester_encoded(etl::span decoded) + { + etl::array encoded{0, 0, 0, 0, 0, 0, 0, 0}; + etl::manchester::encode(decoded, encoded); + return encoded; + } #endif -TEST(encode_span) -{ - constexpr etl::array decoded{0x00, 0xFF, 0x01, 0x80}; - - etl::array encoded0; - etl::array encoded1; - etl::array encoded2; - etl::array encoded3; - - etl::manchester::encode(decoded, encoded0); - etl::manchester::encode(decoded, encoded1); - etl::manchester::encode(decoded, encoded2); - etl::manchester::encode(decoded, encoded3); - - CHECK_EQUAL(0xAA, encoded0[0]); - CHECK_EQUAL(0xAA, encoded0[1]); - CHECK_EQUAL(0x55, encoded0[2]); - CHECK_EQUAL(0x55, encoded0[3]); - CHECK_EQUAL(0xA9, encoded0[4]); - CHECK_EQUAL(0xAA, encoded0[5]); - CHECK_EQUAL(0xAA, encoded0[6]); - CHECK_EQUAL(0x6A, encoded0[7]); - - CHECK_TRUE(encoded0 == encoded1); - CHECK_TRUE(encoded0 == encoded2); - CHECK_TRUE(encoded0 == encoded3); + TEST(encode_span) + { + constexpr etl::array decoded{0x00, 0xFF, 0x01, 0x80}; + + etl::array encoded0; + etl::array encoded1; + etl::array encoded2; + etl::array encoded3; + + etl::manchester::encode(decoded, encoded0); + etl::manchester::encode(decoded, encoded1); + etl::manchester::encode(decoded, encoded2); + etl::manchester::encode(decoded, encoded3); + + CHECK_EQUAL(0xAA, encoded0[0]); + CHECK_EQUAL(0xAA, encoded0[1]); + CHECK_EQUAL(0x55, encoded0[2]); + CHECK_EQUAL(0x55, encoded0[3]); + CHECK_EQUAL(0xA9, encoded0[4]); + CHECK_EQUAL(0xAA, encoded0[5]); + CHECK_EQUAL(0xAA, encoded0[6]); + CHECK_EQUAL(0x6A, encoded0[7]); + + CHECK_TRUE(encoded0 == encoded1); + CHECK_TRUE(encoded0 == encoded2); + CHECK_TRUE(encoded0 == encoded3); #if ETL_USING_CPP14 - static_assert(manchester_encoded(decoded)[0] == 0xAA, "Compile time encoding on range failed"); - static_assert(manchester_encoded(decoded)[1] == 0xAA, "Compile time encoding on range failed"); - static_assert(manchester_encoded(decoded)[2] == 0x55, "Compile time encoding on range failed"); - static_assert(manchester_encoded(decoded)[3] == 0x55, "Compile time encoding on range failed"); - static_assert(manchester_encoded(decoded)[4] == 0xA9, "Compile time encoding on range failed"); - static_assert(manchester_encoded(decoded)[5] == 0xAA, "Compile time encoding on range failed"); - static_assert(manchester_encoded(decoded)[6] == 0xAA, "Compile time encoding on range failed"); - static_assert(manchester_encoded(decoded)[7] == 0x6A, "Compile time encoding on range failed"); + static_assert(manchester_encoded(decoded)[0] == 0xAA, "Compile time encoding on range failed"); + static_assert(manchester_encoded(decoded)[1] == 0xAA, "Compile time encoding on range failed"); + static_assert(manchester_encoded(decoded)[2] == 0x55, "Compile time encoding on range failed"); + static_assert(manchester_encoded(decoded)[3] == 0x55, "Compile time encoding on range failed"); + static_assert(manchester_encoded(decoded)[4] == 0xA9, "Compile time encoding on range failed"); + static_assert(manchester_encoded(decoded)[5] == 0xAA, "Compile time encoding on range failed"); + static_assert(manchester_encoded(decoded)[6] == 0xAA, "Compile time encoding on range failed"); + static_assert(manchester_encoded(decoded)[7] == 0x6A, "Compile time encoding on range failed"); #endif -} - -TEST(encode_span_inverted) -{ - etl::array decoded{0x00, 0xFF, 0x01, 0x80}; - - etl::array encoded0; - etl::array encoded1; - etl::array encoded2; - etl::array encoded3; - - etl::manchester_inverted::encode(decoded, encoded0); - etl::manchester_inverted::encode(decoded, encoded1); - etl::manchester_inverted::encode(decoded, encoded2); - etl::manchester_inverted::encode(decoded, encoded3); - - CHECK_EQUAL(0x55, encoded0[0]); - CHECK_EQUAL(0x55, encoded0[1]); - CHECK_EQUAL(0xAA, encoded0[2]); - CHECK_EQUAL(0xAA, encoded0[3]); - CHECK_EQUAL(0x56, encoded0[4]); - CHECK_EQUAL(0x55, encoded0[5]); - CHECK_EQUAL(0x55, encoded0[6]); - CHECK_EQUAL(0x95, encoded0[7]); - - CHECK_TRUE(encoded0 == encoded1); - CHECK_TRUE(encoded0 == encoded2); - CHECK_TRUE(encoded0 == encoded3); -} - -TEST(encode_span_invalid_source) -{ - etl::array invalid_source{0x00, 0xFF, 0x01}; - etl::array valid_destination; - - CHECK_THROW({ etl::manchester::encode(invalid_source, valid_destination); }, etl::manchester_invalid_size); - CHECK_THROW({ etl::manchester::encode(invalid_source, valid_destination); }, etl::manchester_invalid_size); - CHECK_THROW({ etl::manchester_inverted::encode(invalid_source, valid_destination); }, etl::manchester_invalid_size); - CHECK_THROW({ etl::manchester_inverted::encode(invalid_source, valid_destination); }, etl::manchester_invalid_size); -} - -TEST(encode_span_invalid_destination) -{ - etl::array valid_source{0x00, 0xFF, 0x01, 0x80}; - etl::array invalid_destination; - - CHECK_THROW({ etl::manchester::encode(valid_source, invalid_destination); }, etl::manchester_invalid_size); - CHECK_THROW({ etl::manchester::encode(valid_source, invalid_destination); }, etl::manchester_invalid_size); - CHECK_THROW({ etl::manchester::encode(valid_source, invalid_destination); }, etl::manchester_invalid_size); - CHECK_THROW({ etl::manchester_inverted::encode(valid_source, invalid_destination); }, etl::manchester_invalid_size); - CHECK_THROW({ etl::manchester_inverted::encode(valid_source, invalid_destination); }, etl::manchester_invalid_size); - CHECK_THROW({ etl::manchester_inverted::encode(valid_source, invalid_destination); }, etl::manchester_invalid_size); -} - -TEST(decode_uint16_t) -{ - CHECK_EQUAL(0x00, (etl::manchester::decode(0xAAAAUL))); - CHECK_EQUAL(0xFF, (etl::manchester::decode(0x5555UL))); - CHECK_EQUAL(0x01, (etl::manchester::decode(0xAAA9UL))); - CHECK_EQUAL(0x80, (etl::manchester::decode(0x6AAAUL))); + } + + TEST(encode_span_inverted) + { + etl::array decoded{0x00, 0xFF, 0x01, 0x80}; + + etl::array encoded0; + etl::array encoded1; + etl::array encoded2; + etl::array encoded3; + + etl::manchester_inverted::encode(decoded, encoded0); + etl::manchester_inverted::encode(decoded, encoded1); + etl::manchester_inverted::encode(decoded, encoded2); + etl::manchester_inverted::encode(decoded, encoded3); + + CHECK_EQUAL(0x55, encoded0[0]); + CHECK_EQUAL(0x55, encoded0[1]); + CHECK_EQUAL(0xAA, encoded0[2]); + CHECK_EQUAL(0xAA, encoded0[3]); + CHECK_EQUAL(0x56, encoded0[4]); + CHECK_EQUAL(0x55, encoded0[5]); + CHECK_EQUAL(0x55, encoded0[6]); + CHECK_EQUAL(0x95, encoded0[7]); + + CHECK_TRUE(encoded0 == encoded1); + CHECK_TRUE(encoded0 == encoded2); + CHECK_TRUE(encoded0 == encoded3); + } + + TEST(encode_span_invalid_source) + { + etl::array invalid_source{0x00, 0xFF, 0x01}; + etl::array valid_destination; + + CHECK_THROW({ etl::manchester::encode(invalid_source, valid_destination); }, etl::manchester_invalid_size); + CHECK_THROW({ etl::manchester::encode(invalid_source, valid_destination); }, etl::manchester_invalid_size); + CHECK_THROW({ etl::manchester_inverted::encode(invalid_source, valid_destination); }, etl::manchester_invalid_size); + CHECK_THROW({ etl::manchester_inverted::encode(invalid_source, valid_destination); }, etl::manchester_invalid_size); + } + + TEST(encode_span_invalid_destination) + { + etl::array valid_source{0x00, 0xFF, 0x01, 0x80}; + etl::array invalid_destination; + + CHECK_THROW({ etl::manchester::encode(valid_source, invalid_destination); }, etl::manchester_invalid_size); + CHECK_THROW({ etl::manchester::encode(valid_source, invalid_destination); }, etl::manchester_invalid_size); + CHECK_THROW({ etl::manchester::encode(valid_source, invalid_destination); }, etl::manchester_invalid_size); + CHECK_THROW({ etl::manchester_inverted::encode(valid_source, invalid_destination); }, etl::manchester_invalid_size); + CHECK_THROW({ etl::manchester_inverted::encode(valid_source, invalid_destination); }, etl::manchester_invalid_size); + CHECK_THROW({ etl::manchester_inverted::encode(valid_source, invalid_destination); }, etl::manchester_invalid_size); + } + + TEST(decode_uint16_t) + { + CHECK_EQUAL(0x00, (etl::manchester::decode(0xAAAAUL))); + CHECK_EQUAL(0xFF, (etl::manchester::decode(0x5555UL))); + CHECK_EQUAL(0x01, (etl::manchester::decode(0xAAA9UL))); + CHECK_EQUAL(0x80, (etl::manchester::decode(0x6AAAUL))); #if ETL_USING_CPP14 - static_assert(0x00 == etl::manchester::decode(0xAAAAUL), "Compile time manchester decoding failed"); + static_assert(0x00 == etl::manchester::decode(0xAAAAUL), "Compile time manchester decoding failed"); #endif -} + } -TEST(decode_uint16_t_inverted) -{ - CHECK_EQUAL(0x00, (etl::manchester_inverted::decode(0x5555UL))); - CHECK_EQUAL(0xFF, (etl::manchester_inverted::decode(0xAAAAUL))); - CHECK_EQUAL(0x01, (etl::manchester_inverted::decode(0x5556UL))); - CHECK_EQUAL(0x80, (etl::manchester_inverted::decode(0x9555UL))); + TEST(decode_uint16_t_inverted) + { + CHECK_EQUAL(0x00, (etl::manchester_inverted::decode(0x5555UL))); + CHECK_EQUAL(0xFF, (etl::manchester_inverted::decode(0xAAAAUL))); + CHECK_EQUAL(0x01, (etl::manchester_inverted::decode(0x5556UL))); + CHECK_EQUAL(0x80, (etl::manchester_inverted::decode(0x9555UL))); #if ETL_USING_CPP14 - static_assert(0x00 == etl::manchester_inverted::decode(0x5555UL), "Compile time manchester decoding failed"); + static_assert(0x00 == etl::manchester_inverted::decode(0x5555UL), "Compile time manchester decoding failed"); #endif -} + } -TEST(decode_uint32_t) -{ - CHECK_EQUAL(0xFF00UL, (etl::manchester::decode(0x5555AAAAUL))); - CHECK_EQUAL(0x8001UL, (etl::manchester::decode(0x6AAAAAA9UL))); + TEST(decode_uint32_t) + { + CHECK_EQUAL(0xFF00UL, (etl::manchester::decode(0x5555AAAAUL))); + CHECK_EQUAL(0x8001UL, (etl::manchester::decode(0x6AAAAAA9UL))); #if ETL_USING_CPP14 - static_assert(0xFF00UL == etl::manchester::decode(0x5555AAAAUL), "Compile time manchester decoding failed"); + static_assert(0xFF00UL == etl::manchester::decode(0x5555AAAAUL), "Compile time manchester decoding failed"); #endif -} + } -TEST(decode_uint32_t_inverted) -{ - CHECK_EQUAL(0xFF00UL, (etl::manchester_inverted::decode(0xAAAA5555UL))); - CHECK_EQUAL(0x8001UL, (etl::manchester_inverted::decode(0x95555556UL))); + TEST(decode_uint32_t_inverted) + { + CHECK_EQUAL(0xFF00UL, (etl::manchester_inverted::decode(0xAAAA5555UL))); + CHECK_EQUAL(0x8001UL, (etl::manchester_inverted::decode(0x95555556UL))); #if ETL_USING_CPP14 - static_assert(0xFF00UL == etl::manchester_inverted::decode(0xAAAA5555UL), "Compile time manchester decoding failed"); + static_assert(0xFF00UL == etl::manchester_inverted::decode(0xAAAA5555UL), "Compile time manchester decoding failed"); #endif -} + } -TEST(decode_uint64_t) -{ - CHECK_EQUAL(0x8001FF00ULL, (etl::manchester::decode(0x6AAAAAA95555AAAAULL))); + TEST(decode_uint64_t) + { + CHECK_EQUAL(0x8001FF00ULL, (etl::manchester::decode(0x6AAAAAA95555AAAAULL))); #if ETL_USING_CPP14 - static_assert(0x8001FF00ULL == etl::manchester::decode(0x6AAAAAA95555AAAAULL), "Compile time manchester decoding failed"); + static_assert(0x8001FF00ULL == etl::manchester::decode(0x6AAAAAA95555AAAAULL), "Compile time manchester decoding failed"); #endif -} + } -TEST(decode_uint64_t_inverted) -{ - CHECK_EQUAL(0x8001FF00ULL, (etl::manchester_inverted::decode(0x95555556AAAA5555ULL))); + TEST(decode_uint64_t_inverted) + { + CHECK_EQUAL(0x8001FF00ULL, (etl::manchester_inverted::decode(0x95555556AAAA5555ULL))); #if ETL_USING_CPP14 - static_assert(0x8001FF00ULL == etl::manchester_inverted::decode(0x95555556AAAA5555ULL), "Compile time manchester decoding failed"); + static_assert(0x8001FF00ULL == etl::manchester_inverted::decode(0x95555556AAAA5555ULL), "Compile time manchester decoding failed"); #endif -} + } #if ETL_USING_CPP14 -constexpr etl::array manchester_decoded(etl::span encoded) -{ - etl::array decoded{0, 0, 0, 0}; - etl::manchester::decode(encoded, decoded); - return decoded; -} + constexpr etl::array manchester_decoded(etl::span encoded) + { + etl::array decoded{0, 0, 0, 0}; + etl::manchester::decode(encoded, decoded); + return decoded; + } #endif -TEST(decode_span) -{ - constexpr etl::array encoded{0xAA, 0xAA, 0x55, 0x55, 0xA9, 0xAA, 0XAA, 0x6A}; + TEST(decode_span) + { + constexpr etl::array encoded{0xAA, 0xAA, 0x55, 0x55, 0xA9, 0xAA, 0xAA, 0x6A}; - etl::array decoded0; - etl::array decoded1; - etl::array decoded2; - etl::array decoded3; + etl::array decoded0; + etl::array decoded1; + etl::array decoded2; + etl::array decoded3; - etl::manchester::decode(encoded, decoded0); - etl::manchester::decode(encoded, decoded1); - etl::manchester::decode(encoded, decoded2); - etl::manchester::decode(encoded, decoded3); + etl::manchester::decode(encoded, decoded0); + etl::manchester::decode(encoded, decoded1); + etl::manchester::decode(encoded, decoded2); + etl::manchester::decode(encoded, decoded3); - CHECK_EQUAL(0x00, decoded0[0]); - CHECK_EQUAL(0xFF, decoded0[1]); - CHECK_EQUAL(0x01, decoded0[2]); - CHECK_EQUAL(0x80, decoded0[3]); + CHECK_EQUAL(0x00, decoded0[0]); + CHECK_EQUAL(0xFF, decoded0[1]); + CHECK_EQUAL(0x01, decoded0[2]); + CHECK_EQUAL(0x80, decoded0[3]); #if ETL_USING_CPP14 - static_assert(manchester_decoded(encoded)[0] == 0x00, "Compile time decoding on range failed"); - static_assert(manchester_decoded(encoded)[1] == 0xFF, "Compile time decoding on range failed"); - static_assert(manchester_decoded(encoded)[2] == 0x01, "Compile time decoding on range failed"); - static_assert(manchester_decoded(encoded)[3] == 0x80, "Compile time decoding on range failed"); + static_assert(manchester_decoded(encoded)[0] == 0x00, "Compile time decoding on range failed"); + static_assert(manchester_decoded(encoded)[1] == 0xFF, "Compile time decoding on range failed"); + static_assert(manchester_decoded(encoded)[2] == 0x01, "Compile time decoding on range failed"); + static_assert(manchester_decoded(encoded)[3] == 0x80, "Compile time decoding on range failed"); #endif - CHECK_TRUE(decoded0 == decoded1); - CHECK_TRUE(decoded0 == decoded2); - CHECK_TRUE(decoded0 == decoded3); -} - -TEST(decode_span_inverted) -{ - etl::array encoded{0x55, 0x55, 0xAA, 0xAA, 0x56, 0x55, 0X55, 0x95}; - - etl::array decoded0; - etl::array decoded1; - etl::array decoded2; - etl::array decoded3; - - etl::manchester_inverted::decode(encoded, decoded0); - etl::manchester_inverted::decode(encoded, decoded1); - etl::manchester_inverted::decode(encoded, decoded2); - etl::manchester_inverted::decode(encoded, decoded3); - - CHECK_EQUAL(0x00, decoded0[0]); - CHECK_EQUAL(0xFF, decoded0[1]); - CHECK_EQUAL(0x01, decoded0[2]); - CHECK_EQUAL(0x80, decoded0[3]); - - CHECK_TRUE(decoded0 == decoded1); - CHECK_TRUE(decoded0 == decoded2); - CHECK_TRUE(decoded0 == decoded3); -} - -TEST(decode_span_invalid_source) -{ - etl::array invalid_source{0x55, 0x55, 0xAA, 0xAA, 0x56, 0x55, 0X55}; - etl::array valid_destination; - - CHECK_THROW({ etl::manchester::decode(invalid_source, valid_destination); }, etl::manchester_invalid_size); - CHECK_THROW({ etl::manchester::decode(invalid_source, valid_destination); }, etl::manchester_invalid_size); - CHECK_THROW({ etl::manchester::decode(invalid_source, valid_destination); }, etl::manchester_invalid_size); - CHECK_THROW({ etl::manchester_inverted::decode(invalid_source, valid_destination); }, etl::manchester_invalid_size); - CHECK_THROW({ etl::manchester_inverted::decode(invalid_source, valid_destination); }, etl::manchester_invalid_size); - CHECK_THROW({ etl::manchester_inverted::decode(invalid_source, valid_destination); }, etl::manchester_invalid_size); -} - -TEST(decode_span_invalid_destination) -{ - etl::array valid_source{0x55, 0x55, 0xAA, 0xAA, 0x56, 0x55, 0X55, 0x95}; - etl::array invalid_destination; - - CHECK_THROW({ etl::manchester::decode(valid_source, invalid_destination); }, etl::manchester_invalid_size); - CHECK_THROW({ etl::manchester::decode(valid_source, invalid_destination); }, etl::manchester_invalid_size); - CHECK_THROW({ etl::manchester::decode(valid_source, invalid_destination); }, etl::manchester_invalid_size); - CHECK_THROW({ etl::manchester_inverted::decode(valid_source, invalid_destination); }, etl::manchester_invalid_size); - CHECK_THROW({ etl::manchester_inverted::decode(valid_source, invalid_destination); }, etl::manchester_invalid_size); - CHECK_THROW({ etl::manchester_inverted::decode(valid_source, invalid_destination); }, etl::manchester_invalid_size); -} - -TEST(valid16) -{ - CHECK_TRUE(etl::manchester::is_valid(0xAAAAUL)); - CHECK_TRUE(etl::manchester_inverted::is_valid(0xAAAAUL)); - CHECK_FALSE(etl::manchester::is_valid(0xAAA8UL)); - CHECK_FALSE(etl::manchester_inverted::is_valid(0xAAA8UL)); + CHECK_TRUE(decoded0 == decoded1); + CHECK_TRUE(decoded0 == decoded2); + CHECK_TRUE(decoded0 == decoded3); + } + + TEST(decode_span_inverted) + { + etl::array encoded{0x55, 0x55, 0xAA, 0xAA, 0x56, 0x55, 0x55, 0x95}; + + etl::array decoded0; + etl::array decoded1; + etl::array decoded2; + etl::array decoded3; + + etl::manchester_inverted::decode(encoded, decoded0); + etl::manchester_inverted::decode(encoded, decoded1); + etl::manchester_inverted::decode(encoded, decoded2); + etl::manchester_inverted::decode(encoded, decoded3); + + CHECK_EQUAL(0x00, decoded0[0]); + CHECK_EQUAL(0xFF, decoded0[1]); + CHECK_EQUAL(0x01, decoded0[2]); + CHECK_EQUAL(0x80, decoded0[3]); + + CHECK_TRUE(decoded0 == decoded1); + CHECK_TRUE(decoded0 == decoded2); + CHECK_TRUE(decoded0 == decoded3); + } + + TEST(decode_span_invalid_source) + { + etl::array invalid_source{0x55, 0x55, 0xAA, 0xAA, 0x56, 0x55, 0x55}; + etl::array valid_destination; + + CHECK_THROW({ etl::manchester::decode(invalid_source, valid_destination); }, etl::manchester_invalid_size); + CHECK_THROW({ etl::manchester::decode(invalid_source, valid_destination); }, etl::manchester_invalid_size); + CHECK_THROW({ etl::manchester::decode(invalid_source, valid_destination); }, etl::manchester_invalid_size); + CHECK_THROW({ etl::manchester_inverted::decode(invalid_source, valid_destination); }, etl::manchester_invalid_size); + CHECK_THROW({ etl::manchester_inverted::decode(invalid_source, valid_destination); }, etl::manchester_invalid_size); + CHECK_THROW({ etl::manchester_inverted::decode(invalid_source, valid_destination); }, etl::manchester_invalid_size); + } + + TEST(decode_span_invalid_destination) + { + etl::array valid_source{0x55, 0x55, 0xAA, 0xAA, 0x56, 0x55, 0x55, 0x95}; + etl::array invalid_destination; + + CHECK_THROW({ etl::manchester::decode(valid_source, invalid_destination); }, etl::manchester_invalid_size); + CHECK_THROW({ etl::manchester::decode(valid_source, invalid_destination); }, etl::manchester_invalid_size); + CHECK_THROW({ etl::manchester::decode(valid_source, invalid_destination); }, etl::manchester_invalid_size); + CHECK_THROW({ etl::manchester_inverted::decode(valid_source, invalid_destination); }, etl::manchester_invalid_size); + CHECK_THROW({ etl::manchester_inverted::decode(valid_source, invalid_destination); }, etl::manchester_invalid_size); + CHECK_THROW({ etl::manchester_inverted::decode(valid_source, invalid_destination); }, etl::manchester_invalid_size); + } + + TEST(valid16) + { + CHECK_TRUE(etl::manchester::is_valid(0xAAAAUL)); + CHECK_TRUE(etl::manchester_inverted::is_valid(0xAAAAUL)); + CHECK_FALSE(etl::manchester::is_valid(0xAAA8UL)); + CHECK_FALSE(etl::manchester_inverted::is_valid(0xAAA8UL)); #if ETL_USING_CPP14 - static_assert(etl::manchester::is_valid(0xAAAAUL), "Compile time manchester validity check failed"); - static_assert(etl::manchester_inverted::is_valid(0xAAAAUL), "Compile time manchester validity check failed"); + static_assert(etl::manchester::is_valid(0xAAAAUL), "Compile time manchester validity check failed"); + static_assert(etl::manchester_inverted::is_valid(0xAAAAUL), "Compile time manchester validity check failed"); #endif -} + } -TEST(valid32) -{ - CHECK_TRUE(etl::manchester::is_valid(0xAAAAAAAAUL)); - CHECK_TRUE(etl::manchester_inverted::is_valid(0xAAAAAAAAUL)); - CHECK_FALSE(etl::manchester::is_valid(0xAAAAAAA8UL)); - CHECK_FALSE(etl::manchester_inverted::is_valid(0xAAAAAAA8UL)); + TEST(valid32) + { + CHECK_TRUE(etl::manchester::is_valid(0xAAAAAAAAUL)); + CHECK_TRUE(etl::manchester_inverted::is_valid(0xAAAAAAAAUL)); + CHECK_FALSE(etl::manchester::is_valid(0xAAAAAAA8UL)); + CHECK_FALSE(etl::manchester_inverted::is_valid(0xAAAAAAA8UL)); #if ETL_USING_CPP14 - static_assert(etl::manchester::is_valid(0xAAAAAAAAUL), "Compile time manchester validity check failed"); - static_assert(etl::manchester_inverted::is_valid(0xAAAAAAAAUL), "Compile time manchester validity check failed"); + static_assert(etl::manchester::is_valid(0xAAAAAAAAUL), "Compile time manchester validity check failed"); + static_assert(etl::manchester_inverted::is_valid(0xAAAAAAAAUL), "Compile time manchester validity check failed"); #endif -} + } -TEST(valid64) -{ - CHECK_TRUE(etl::manchester::is_valid(0xAAAAAAAAAAAAAAAAULL)); - CHECK_TRUE(etl::manchester_inverted::is_valid(0xAAAAAAAAAAAAAAAAULL)); - CHECK_FALSE(etl::manchester::is_valid(0xAAAAAAAAAAAAAAA8ULL)); - CHECK_FALSE(etl::manchester_inverted::is_valid(0xAAAAAAAAAAAAAAA8ULL)); + TEST(valid64) + { + CHECK_TRUE(etl::manchester::is_valid(0xAAAAAAAAAAAAAAAAULL)); + CHECK_TRUE(etl::manchester_inverted::is_valid(0xAAAAAAAAAAAAAAAAULL)); + CHECK_FALSE(etl::manchester::is_valid(0xAAAAAAAAAAAAAAA8ULL)); + CHECK_FALSE(etl::manchester_inverted::is_valid(0xAAAAAAAAAAAAAAA8ULL)); #if ETL_USING_CPP14 - static_assert(etl::manchester::is_valid(0xAAAAAAAAAAAAAAAAULL), "Compile time manchester validity check failed"); - static_assert(etl::manchester_inverted::is_valid(0xAAAAAAAAAAAAAAAAULL), "Compile time manchester validity check failed"); + static_assert(etl::manchester::is_valid(0xAAAAAAAAAAAAAAAAULL), "Compile time manchester validity check failed"); + static_assert(etl::manchester_inverted::is_valid(0xAAAAAAAAAAAAAAAAULL), "Compile time manchester validity check failed"); #endif -} + } -TEST(valid_span) -{ - constexpr etl::array encoded1{0xAA, 0xAA, 0x55, 0x55, 0xA9, 0xAA, 0XAA, 0x6A}; - constexpr etl::array encoded2{0xAA, 0xAA, 0x55, 0x55, 0xA9, 0xAA, 0XAB, 0x6A}; + TEST(valid_span) + { + constexpr etl::array encoded1{0xAA, 0xAA, 0x55, 0x55, 0xA9, 0xAA, 0xAA, 0x6A}; + constexpr etl::array encoded2{0xAA, 0xAA, 0x55, 0x55, 0xA9, 0xAA, 0xAB, 0x6A}; - CHECK_TRUE(etl::manchester::is_valid(encoded1)); - CHECK_FALSE(etl::manchester::is_valid(encoded2)); + CHECK_TRUE(etl::manchester::is_valid(encoded1)); + CHECK_FALSE(etl::manchester::is_valid(encoded2)); #if ETL_USING_CPP14 - static_assert(etl::manchester::is_valid(encoded1), "Compile time manchester validity check failed"); - static_assert(!etl::manchester::is_valid(encoded2), "Compile time manchester validity check failed"); + static_assert(etl::manchester::is_valid(encoded1), "Compile time manchester validity check failed"); + static_assert(!etl::manchester::is_valid(encoded2), "Compile time manchester validity check failed"); #endif -} + } -TEST(valid_span_on_invalid_source) -{ - constexpr etl::array invalid_source{0xAA, 0xAA, 0x55, 0x55, 0xA9, 0xAA, 0XAA}; - CHECK_THROW({ std::ignore = etl::manchester::is_valid(invalid_source); }, etl::manchester_invalid_size); -} + TEST(valid_span_on_invalid_source) + { + constexpr etl::array invalid_source{0xAA, 0xAA, 0x55, 0x55, 0xA9, 0xAA, 0xAA}; + CHECK_THROW({ std::ignore = etl::manchester::is_valid(invalid_source); }, etl::manchester_invalid_size); + } } From 482246f6f521b79532d0d7aab0a3710840007299 Mon Sep 17 00:00:00 2001 From: Timon Zijnge Date: Wed, 4 Feb 2026 17:22:40 +0100 Subject: [PATCH 28/46] #1258 Manchester coding * Moved copyright to top of file * Make constexpr encode/decode span functions equal for little and big endian platforms --- include/etl/manchester.h | 38 ++++++++++++++++++++++++++++---------- 1 file changed, 28 insertions(+), 10 deletions(-) diff --git a/include/etl/manchester.h b/include/etl/manchester.h index 5a1d421b2..de7998454 100644 --- a/include/etl/manchester.h +++ b/include/etl/manchester.h @@ -1,6 +1,3 @@ -#ifndef ETL_MANCHESTER_INCLUDED -#define ETL_MANCHESTER_INCLUDED - ///\file /****************************************************************************** @@ -10,7 +7,7 @@ Embedded Template Library. https://github.com/ETLCPP/etl https://www.etlcpp.com -Copyright(c) 2021 John Wellbelove +Copyright(c) 2026 John Wellbelove Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files(the "Software"), to deal @@ -31,9 +28,13 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ******************************************************************************/ -#include -#include -#include +#ifndef ETL_MANCHESTER_INCLUDED +#define ETL_MANCHESTER_INCLUDED + +#include "platform.h" +#include "endianness.h" +#include "span.h" +#include "static_assert.h" ///\defgroup manchester manchester /// Manchester encoding and decoding @@ -318,8 +319,16 @@ namespace etl for (size_t i = 0; i < decoded.size() / sizeof(TDecoded); ++i) { const TEncoded encoded_value = encode(decoded[source_index]); - encoded[dest_index] = static_cast(encoded_value); - encoded[dest_index + 1] = static_cast(encoded_value >> CHAR_BIT); + if (etl::endianness::value() == etl::endian::little) + { + encoded[dest_index] = static_cast(encoded_value); + encoded[dest_index + 1] = static_cast(encoded_value >> CHAR_BIT); + } + else + { + encoded[dest_index] = static_cast(encoded_value >> CHAR_BIT); + encoded[dest_index + 1] = static_cast(encoded_value); + } source_index += sizeof(TDecoded); dest_index += sizeof(TEncoded); @@ -438,7 +447,16 @@ namespace etl size_t source_index = 0; for (size_t i = 0; i < encoded.size() / sizeof(TChunk); ++i) { - const TChunk encoded_value = static_cast((encoded[source_index + 1] << CHAR_BIT) | encoded[source_index]); + TChunk encoded_value{}; + if (etl::endianness::value() == etl::endian::little) + { + encoded_value = static_cast((encoded[source_index + 1] << CHAR_BIT) | encoded[source_index]); + } + else + { + encoded_value = static_cast((encoded[source_index] << CHAR_BIT) | encoded[source_index + 1]); + } + decoded[dest_index] = decode(encoded_value); source_index += sizeof(TChunk); From 0d2f4480e84cc15b73258068f4504674c71edf41 Mon Sep 17 00:00:00 2001 From: Timon Zijnge Date: Wed, 4 Feb 2026 17:50:52 +0100 Subject: [PATCH 29/46] #1258 Manchester coding * Added missing include * Added missing 8bit/64bit guards * Fixed is_valid for big endian platforms --- include/etl/manchester.h | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/include/etl/manchester.h b/include/etl/manchester.h index de7998454..68e17fbd3 100644 --- a/include/etl/manchester.h +++ b/include/etl/manchester.h @@ -35,6 +35,7 @@ SOFTWARE. #include "endianness.h" #include "span.h" #include "static_assert.h" +#include ///\defgroup manchester manchester /// Manchester encoding and decoding @@ -91,21 +92,27 @@ namespace etl ETL_STATIC_ASSERT(sizeof(T) == 0, "Manchester encoding type should be one of [uint8_t, uint16_t, uint32_t]"); }; +#if ETL_USING_8BIT_TYPES template <> struct encoded { typedef uint16_t type; }; +#endif + template <> struct encoded { typedef uint32_t type; }; + +#if ETL_USING_64BIT_TYPES template <> struct encoded { typedef uint64_t type; }; +#endif //************************************************************************* /// Type trait to determine the decoded type for a given encoded type. @@ -491,9 +498,18 @@ namespace etl { ETL_ASSERT(encoded.size() % sizeof(uint16_t) == 0, ETL_ERROR(manchester_invalid_size)); - for (size_t i = 0; i < encoded.size(); i += 2) + for (size_t i = 0; i < encoded.size(); i += sizeof(uint16_t)) { - const uint16_t chunk = static_cast((encoded[i + 1] << 8) | encoded[i]); + uint16_t chunk{}; + if (etl::endianness::value() == etl::endian::little) + { + chunk = static_cast((encoded[i + 1] << 8) | encoded[i]); + } + else + { + chunk = static_cast((encoded[i] << 8) | encoded[i + 1]); + } + if (!is_valid(chunk)) { return false; From c742792d03521abebd9e5cfbd910ee580fd5300a Mon Sep 17 00:00:00 2001 From: Timon Zijnge Date: Mon, 23 Feb 2026 10:50:10 +0100 Subject: [PATCH 30/46] #1258 Manchester coding * private memcpy alias --- include/etl/manchester.h | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/include/etl/manchester.h b/include/etl/manchester.h index 68e17fbd3..86dbb4c69 100644 --- a/include/etl/manchester.h +++ b/include/etl/manchester.h @@ -164,6 +164,19 @@ namespace etl static const uint32_t inversion_mask = 0xFFFFFFFFUL; #endif }; + + //************************************************************************* + /// Alias for memcpy. etl::mem_copy is not suitable for the Manchester + /// algorithm. This is an alternative way to respect ETL_USING_BUILTIN_MEMCPY + //************************************************************************* + inline void* memcpy(void* dest, const void* src, std::size_t count) ETL_NOEXCEPT + { +#if ETL_USING_BUILTIN_MEMCPY + return __builtin_memcpy(dest, src, count); +#else + return ::memcpy(dest, src, count); +#endif + } } // namespace private_manchester //*************************************************************************** @@ -296,9 +309,9 @@ namespace etl for (size_t i = 0; i < decoded.size() / sizeof(TDecoded); ++i) { TDecoded decoded_value = 0; - memcpy(&decoded_value, &decoded[source_index], sizeof(TDecoded)); + etl::private_manchester::memcpy(&decoded_value, &decoded[source_index], sizeof(TDecoded)); const TEncoded encoded_value = encode(decoded_value); - memcpy(&encoded[dest_index], &encoded_value, sizeof(TEncoded)); + etl::private_manchester::memcpy(&encoded[dest_index], &encoded_value, sizeof(TEncoded)); source_index += sizeof(TDecoded); dest_index += sizeof(TEncoded); @@ -425,9 +438,9 @@ namespace etl for (size_t i = 0; i < encoded.size() / sizeof(TEncoded); ++i) { TChunk encoded_value = 0; - memcpy(&encoded_value, &encoded[source_index], sizeof(TEncoded)); + etl::private_manchester::memcpy(&encoded_value, &encoded[source_index], sizeof(TEncoded)); const TDecoded decoded_value = decode(encoded_value); - memcpy(&decoded[dest_index], &decoded_value, sizeof(TDecoded)); + etl::private_manchester::memcpy(&decoded[dest_index], &decoded_value, sizeof(TDecoded)); source_index += sizeof(TEncoded); dest_index += sizeof(TDecoded); From 777f7856306c2b3100b4e1990524981db5ccde80 Mon Sep 17 00:00:00 2001 From: Timon Zijnge Date: Mon, 23 Feb 2026 11:32:37 +0100 Subject: [PATCH 31/46] #1258 Manchester coding * Review comments --- include/etl/manchester.h | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/include/etl/manchester.h b/include/etl/manchester.h index 86dbb4c69..b019a799f 100644 --- a/include/etl/manchester.h +++ b/include/etl/manchester.h @@ -125,21 +125,27 @@ namespace etl ETL_STATIC_ASSERT(sizeof(T) == 0, "Manchester decoding type should be one of [uint16_t, uint32_t, uint64_t]"); }; +#if ETL_USING_64BIT_TYPES template <> struct decoded { typedef uint8_t type; }; +#endif + template <> struct decoded { typedef uint16_t type; }; + +#if ETL_USING_64BIT_TYPES template <> struct decoded { typedef uint32_t type; }; +#endif //************************************************************************* /// Normal Manchester encoding type (no inversion). @@ -167,7 +173,9 @@ namespace etl //************************************************************************* /// Alias for memcpy. etl::mem_copy is not suitable for the Manchester - /// algorithm. This is an alternative way to respect ETL_USING_BUILTIN_MEMCPY + /// algorithm because all memory copies are between different types. This + /// alias is a way to respect ETL_USING_BUILTIN_MEMCPY while using the + /// memcpy function signature //************************************************************************* inline void* memcpy(void* dest, const void* src, std::size_t count) ETL_NOEXCEPT { @@ -320,7 +328,7 @@ namespace etl //************************************************************************* /// Encode a span of data with the minimum chunk size. This version is - /// constexpr so that it can be used to decode data at compile time. + /// constexpr so that it can be used to encode data at compile time. ///\param source The source data to encode. ///\param destination The destination buffer for encoded data. ///\tparam TChunk The chunk size for encoding (default: uint_least8_t). @@ -516,11 +524,11 @@ namespace etl uint16_t chunk{}; if (etl::endianness::value() == etl::endian::little) { - chunk = static_cast((encoded[i + 1] << 8) | encoded[i]); + chunk = static_cast((encoded[i + 1] << CHAR_BIT | encoded[i]); } else { - chunk = static_cast((encoded[i] << 8) | encoded[i + 1]); + chunk = static_cast((encoded[i] << CHAR_BIT) | encoded[i + 1]); } if (!is_valid(chunk)) From d56a586ad31bd2686e9902ce0ed82efb079a5ca6 Mon Sep 17 00:00:00 2001 From: Timon Zijnge Date: Mon, 23 Feb 2026 11:42:35 +0100 Subject: [PATCH 32/46] #1258 Manchester coding * Cleanup * Fix build error --- include/etl/manchester.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/etl/manchester.h b/include/etl/manchester.h index b019a799f..4c35deb86 100644 --- a/include/etl/manchester.h +++ b/include/etl/manchester.h @@ -174,7 +174,7 @@ namespace etl //************************************************************************* /// Alias for memcpy. etl::mem_copy is not suitable for the Manchester /// algorithm because all memory copies are between different types. This - /// alias is a way to respect ETL_USING_BUILTIN_MEMCPY while using the + /// alias is a way to respect ETL_USING_BUILTIN_MEMCPY while using the /// memcpy function signature //************************************************************************* inline void* memcpy(void* dest, const void* src, std::size_t count) ETL_NOEXCEPT @@ -524,7 +524,7 @@ namespace etl uint16_t chunk{}; if (etl::endianness::value() == etl::endian::little) { - chunk = static_cast((encoded[i + 1] << CHAR_BIT | encoded[i]); + chunk = static_cast((encoded[i + 1] << CHAR_BIT) | encoded[i]); } else { From 71ab73415214a4cf43fdda61ebd5fe211fdb8eed Mon Sep 17 00:00:00 2001 From: Timon Zijnge Date: Fri, 27 Feb 2026 12:04:01 +0100 Subject: [PATCH 33/46] #1258 Manchester coding * Add manchester documentation --- docs/manchester.md | 256 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 256 insertions(+) create mode 100644 docs/manchester.md diff --git a/docs/manchester.md b/docs/manchester.md new file mode 100644 index 000000000..adc6a6faa --- /dev/null +++ b/docs/manchester.md @@ -0,0 +1,256 @@ +# Manchester encoding and decoding + +Efficient Manchester encoding and decoding of data. The Manchester code represents a data bit as a sequence of a 'high' and a 'low' value. In software this translates to a conversion from one to two bits, or in a practical situation, from `n` bytes to `n*2` bytes. + +## See also + +[Manchester code](https://en.wikipedia.org/wiki/Manchester_code) + +## Features + +- Normal and inverted Manchester encoding +- Support for multiple encoding chunk sizes: 8-bit, 16-bit and 32-bit +- Span-based operations or chunk based operations +- Constexpr functions for compile-time encoding/decoding (8-bit chunk size only) +- Validation of encoded data + +## Algorithm background + +To encode the value `0b11001100` we must first duplicate all bits to create the value `0b1111000011110000`. We then perform an XOR of this value with the constant `0b1010101010101010` (`0xAAAA`) to obtain the Manchester coded value of `0b1010010110100101`. We have now replace each `1` bit with the sequence `10` and each `0` bit with the sequence `01`. + +### 2. Bit duplication + +Bit duplication is achieved with the following steps. This is also called binary interleaving. The example shows encoding of an 8-bit value. + +| Step | High Byte | Low Byte | Operation | +|------|--------------------|--------------------|----------------------------| +| 0 | `_ _ _ _ _ _ _ _` | `A B C D E F G H` | input value (i) | +| 1 | `_ _ _ _ A B C D` | `_ _ _ _ E F G H` | `(i \| (i << 4)) & 0x0F0F` | +| 2 | `_ _ A B _ _ C D` | `_ _ E F _ _ G H` | `(i \| (i << 2)) & 0x3333` | +| 3 | `_ A _ B _ C _ D` | `_ A _ B _ C _ D` | `(i \| (i << 1)) & 0x5555` | +| 4 | `A A B B C C D D` | `A A B B C C D D` | `(i \| (i << 1))` | + +This process can be easily extended to 16-bit or 32-bit values by adding additional steps to the bit duplication. + +### 3. Manchester Decoding + +Manchester decoding is done in a similar, but reversed way. + +### 4. Error Detection + +Error detection in Manchester coded data is done by comparing 2 neighboring bits. If they are +equal, then there is an error in the encoded input data. + +Comparing all 8 bit-pairs in a 16-bit word is done as follows. + +| Step | Binary Value | Operation | Description | +|------|--------------|-------------------|-----------------------------------------------------------------------------------------------| +| 1 | `11011000` | Original | First bit pair (lsb, 00) is invalid. Last bit pair is also invalid. Other bit pairs are valid | +| 2 | `01101100` | Shift right by 1 | Shift the original value right by one bit | +| 3 | `10110100` | XOR | XOR the original with the shifted value | +| 4 | `01010101` | Mask with 0x55 | Apply mask to isolate bit pairs | +| 5 | `00010100` | Result | If result is not equal to 0x55, there was an error in the input | + +## Analysis + +Most traditional ways to Manchester encode data consist of a loop over all bits and a nested if-statement to check the value of the current bit. This approach does not scale well to increasing number of bits. The algorithm implemented here contains no conditional code and scales well. Doubling the number of processed bit per step (the chunk size) adds a single row to the bit duplication table. Because of the lack of loops and conditional code, this algorithm is likely to perform better than traditional ones on simple processors or when compiler optimization is disabled. On modern, powerful processors with caches and advanced optimization possibilities this algorithm may not show much benefit. In any case, the performance of the algorithm depends heavily on the processor type, compiler and compiler (optimization) settings. + +## API Reference + +### Classes + +Classes `etl::manchester` and `etl::manchester_inverted` contain static functions for encoding, decoding and validity checking. It is not necessary to instantiate objects of these classes. + +#### etl::manchester + +```cpp +typedef manchester_base manchester; +``` + +Manchester encoder using normal encoding (no inversion). + +#### etl::manchester_inverted + +```cpp +typedef manchester_base manchester_inverted; +``` + +Manchester encoder using inverted encoding. + +### Encoding Functions + +#### Encode single value + +```cpp +template +static ETL_CONSTEXPR14 typename encoded::type encode(TDecoded decoded) +``` + +Encodes a single value using Manchester encoding. + +**Parameters:** + +- `decoded`: The value to encode (`uint8_t`, `uint16_t`, or `uint32_t`) + +**Returns:** + +- The Manchester encoded value (twice the bit width of input) + +**Example:** + +```cpp +uint16_t encoded = etl::manchester::encode(0x55); +``` + +#### Encode range + +```cpp +template +static ETL_CONSTEXPR14 void encode(etl::span decoded, + etl::span encoded) +``` + +Encodes a span of data using the specified chunk size. + +**Parameters:** + +- `decoded`: Source data to encode +- `encoded`: Destination for encoded data (must be twice the size of `decoded`) + +**Template Parameters:** + +- `TChunk`: Chunk size for encoding (`uint8_t`, `uint16_t` or `uint32_t`) + +**Example:** + +```cpp +std::array data = {0x12, 0x34, 0x56, 0x78}; +std::array encoded_data1{}; +std::array encoded_data2{}; + +// Encode with TChunk == uint8_t +etl::manchester::encode(data, encoded_data1); + +// Encode with TChunk == uint32_t +etl::manchester::encode(data, encoded_data2); +``` + +### Decoding Functions + +#### Decode single value + +```cpp +template +static ETL_CONSTEXPR14 typename decoded::type decode(TEncoded encoded) +``` + +Decodes a single Manchester encoded value. + +**Parameters:** + +- `encoded`: The encoded value to decode (`uint16_t`, `uint32_t`, or `uint64_t`) + +**Returns:** + +- The Manchester decoded value (half the bit width of input) + +**Example:** + +```cpp +uint8_t decoded = etl::manchester::decode(0x5A5A); +``` + +#### Decode range + +```cpp +template ::type> +static ETL_CONSTEXPR14 void decode(etl::span encoded, + etl::span decoded) +``` + +Decodes a span of Manchester encoded data. + +**Parameters:** + +- `encoded`: Source data to decode +- `decoded`: Destination for decoded data (must be half the size of `encoded`) + +**Template Parameters:** + +- `TChunk`: Chunk type for decoding (`uint16_t`, `uint32_t`, or `uint64_t`) + +**Example:** + +```cpp +std::array encoded = {/* ... */}; +std::array decoded1 {}; +std::array decoded2 {}; + +// Decode with TChunk == uint16_t +etl::manchester::decode(encoded, decoded1); + +// Decode with TChunk == uint64_t +etl::manchester::decode(encoded, decoded2); +``` + +### Validation Functions + +#### Single value + +```cpp +template +static ETL_CONSTEXPR14 bool is_valid(TChunk encoded) +``` + +Validates that a single value contains valid Manchester encoded data. + +**Parameters:** + +- `encoded`: The encoded value to validate + +**Returns:** + +- `true` if the value contains valid Manchester encoded data, `false` otherwise + +**Example:** + +```cpp +bool valid = etl::manchester::is_valid(0x5A5A); +``` + +#### Range + +```cpp +static ETL_CONSTEXPR14 bool is_valid(etl::span encoded) +``` + +Validates that a range contains valid Manchester encoded data. + +**Parameters:** + +- `encoded`: The range of encoded data to validate + +**Returns:** + +- `true` if all data is valid Manchester encoding, `false` otherwise + +**Example:** + +```cpp +std::array encoded_data = {/* ... */}; +bool valid = etl::manchester::is_valid(encoded_data); +``` + +## Supported Types + +### Input/chunk types for encoding + +- `uint8_t` → `uint16_t` (if 8-bit types are supported) +- `uint16_t` → `uint32_t` +- `uint32_t` → `uint64_t` (if 64-bit types are supported) + +### Input/chunk types for decoding + +- `uint16_t` → `uint8_t` (if 8-bit types are supported) +- `uint32_t` → `uint16_t` +- `uint64_t` → `uint32_t` (if 64-bit types are supported) From 69c730907b2f2453902f990ff9345e06014ae99a Mon Sep 17 00:00:00 2001 From: Timon Zijnge Date: Fri, 27 Feb 2026 12:44:33 +0100 Subject: [PATCH 34/46] #1258 Manchester coding * Preparation for GitHub pages --- docs/_config.yml | 6 ++++++ docs/index.md | 7 +++++++ docs/manchester.md | 4 +++- 3 files changed, 16 insertions(+), 1 deletion(-) create mode 100644 docs/_config.yml create mode 100644 docs/index.md diff --git a/docs/_config.yml b/docs/_config.yml new file mode 100644 index 000000000..6fac68f05 --- /dev/null +++ b/docs/_config.yml @@ -0,0 +1,6 @@ +plugins: + - jekyll-relative-links +relative_links: + enabled: true +include: + - manchester.md diff --git a/docs/index.md b/docs/index.md new file mode 100644 index 000000000..23e43ac59 --- /dev/null +++ b/docs/index.md @@ -0,0 +1,7 @@ +--- +title: ETL documentation +--- + +## Pages + +* [Manchester](manchester.md) diff --git a/docs/manchester.md b/docs/manchester.md index adc6a6faa..78f016119 100644 --- a/docs/manchester.md +++ b/docs/manchester.md @@ -1,4 +1,6 @@ -# Manchester encoding and decoding +--- +title: Manchester encoding and decoding +--- Efficient Manchester encoding and decoding of data. The Manchester code represents a data bit as a sequence of a 'high' and a 'low' value. In software this translates to a conversion from one to two bits, or in a practical situation, from `n` bytes to `n*2` bytes. From f514725683b9dd2b183bc1ffd17b92cb8b570817 Mon Sep 17 00:00:00 2001 From: Timon Zijnge Date: Tue, 3 Mar 2026 15:41:43 +0100 Subject: [PATCH 35/46] #1324 Manchester documentation * Some small fixes --- docs/manchester.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/docs/manchester.md b/docs/manchester.md index 78f016119..06c0cf7d4 100644 --- a/docs/manchester.md +++ b/docs/manchester.md @@ -12,13 +12,13 @@ Efficient Manchester encoding and decoding of data. The Manchester code represen - Normal and inverted Manchester encoding - Support for multiple encoding chunk sizes: 8-bit, 16-bit and 32-bit -- Span-based operations or chunk based operations +- Span-based operations or chunk-based operations - Constexpr functions for compile-time encoding/decoding (8-bit chunk size only) - Validation of encoded data ## Algorithm background -To encode the value `0b11001100` we must first duplicate all bits to create the value `0b1111000011110000`. We then perform an XOR of this value with the constant `0b1010101010101010` (`0xAAAA`) to obtain the Manchester coded value of `0b1010010110100101`. We have now replace each `1` bit with the sequence `10` and each `0` bit with the sequence `01`. +To encode the value `0b11001100` we must first duplicate all bits to create the value `0b1111000011110000`. We then perform an XOR of this value with the constant `0b1010101010101010` (`0xAAAA`) to obtain the Manchester coded value of `0b1010010110100101`. We have now replaced each `1` bit with the sequence `10` and each `0` bit with the sequence `01`. ### 2. Bit duplication @@ -29,8 +29,8 @@ Bit duplication is achieved with the following steps. This is also called binary | 0 | `_ _ _ _ _ _ _ _` | `A B C D E F G H` | input value (i) | | 1 | `_ _ _ _ A B C D` | `_ _ _ _ E F G H` | `(i \| (i << 4)) & 0x0F0F` | | 2 | `_ _ A B _ _ C D` | `_ _ E F _ _ G H` | `(i \| (i << 2)) & 0x3333` | -| 3 | `_ A _ B _ C _ D` | `_ A _ B _ C _ D` | `(i \| (i << 1)) & 0x5555` | -| 4 | `A A B B C C D D` | `A A B B C C D D` | `(i \| (i << 1))` | +| 3 | `_ A _ B _ C _ D` | `_ E _ F _ G _ H` | `(i \| (i << 1)) & 0x5555` | +| 4 | `A A B B C C D D` | `E E F F G G H H` | `(i \| (i << 1))` | This process can be easily extended to 16-bit or 32-bit values by adding additional steps to the bit duplication. @@ -43,7 +43,7 @@ Manchester decoding is done in a similar, but reversed way. Error detection in Manchester coded data is done by comparing 2 neighboring bits. If they are equal, then there is an error in the encoded input data. -Comparing all 8 bit-pairs in a 16-bit word is done as follows. +Comparing all 8 bit pairs in a 16-bit word is done as follows. | Step | Binary Value | Operation | Description | |------|--------------|-------------------|-----------------------------------------------------------------------------------------------| @@ -55,7 +55,7 @@ Comparing all 8 bit-pairs in a 16-bit word is done as follows. ## Analysis -Most traditional ways to Manchester encode data consist of a loop over all bits and a nested if-statement to check the value of the current bit. This approach does not scale well to increasing number of bits. The algorithm implemented here contains no conditional code and scales well. Doubling the number of processed bit per step (the chunk size) adds a single row to the bit duplication table. Because of the lack of loops and conditional code, this algorithm is likely to perform better than traditional ones on simple processors or when compiler optimization is disabled. On modern, powerful processors with caches and advanced optimization possibilities this algorithm may not show much benefit. In any case, the performance of the algorithm depends heavily on the processor type, compiler and compiler (optimization) settings. +Most traditional ways to Manchester encode data consist of a loop over all bits and a nested if-statement to check the value of the current bit. This approach does not scale well to increasing number of bits. The algorithm implemented here contains no conditional code and scales well. Doubling the number of processed bits per step (the chunk size) adds a single row to the bit duplication table. Because of the lack of loops and conditional code, this algorithm is likely to perform better than traditional ones on simple processors or when compiler optimization is disabled. On modern, powerful processors with caches and advanced optimization possibilities this algorithm may not show much benefit. In any case, the performance of the algorithm depends heavily on the processor type, compiler and compiler (optimization) settings. ## API Reference From a0c98662ca62682e915549002dd6681b54addb6a Mon Sep 17 00:00:00 2001 From: Roland Reichwein Date: Thu, 12 Mar 2026 20:55:16 +0100 Subject: [PATCH 36/46] Print test names at test time (#1343) --- .github/workflows/clang-c++11.yml | 4 +- .github/workflows/clang-c++14.yml | 4 +- .github/workflows/clang-c++17.yml | 4 +- .github/workflows/clang-c++20.yml | 14 ++--- .github/workflows/clang-c++23.yml | 14 ++--- .github/workflows/gcc-c++11.yml | 4 +- .github/workflows/gcc-c++14.yml | 4 +- .github/workflows/gcc-c++17.yml | 4 +- .github/workflows/gcc-c++20.yml | 8 +-- .github/workflows/gcc-c++23.yml | 8 +-- .github/workflows/msvc.yml | 8 +-- test/main.cpp | 85 ++++++++++++++++++++++++++++++- test/run-tests.sh | 33 ++++++++---- 13 files changed, 144 insertions(+), 50 deletions(-) diff --git a/.github/workflows/clang-c++11.yml b/.github/workflows/clang-c++11.yml index 1d6976eb7..d511f5b7e 100644 --- a/.github/workflows/clang-c++11.yml +++ b/.github/workflows/clang-c++11.yml @@ -28,7 +28,7 @@ jobs: make -j $(getconf _NPROCESSORS_ONLN) - name: Run tests - run: ./test/etl_tests + run: ./test/etl_tests -v build-clang-cpp11-linux-no-stl: name: Clang C++11 Linux - No STL @@ -50,4 +50,4 @@ jobs: make -j $(getconf _NPROCESSORS_ONLN) - name: Run tests - run: ./test/etl_tests \ No newline at end of file + run: ./test/etl_tests -v \ No newline at end of file diff --git a/.github/workflows/clang-c++14.yml b/.github/workflows/clang-c++14.yml index dd6c2aad1..d06778b12 100644 --- a/.github/workflows/clang-c++14.yml +++ b/.github/workflows/clang-c++14.yml @@ -28,7 +28,7 @@ jobs: make -j $(getconf _NPROCESSORS_ONLN) - name: Run tests - run: ./test/etl_tests + run: ./test/etl_tests -v build-clang-cpp14-linux-no-stl: name: Clang C++14 Linux - No STL @@ -50,4 +50,4 @@ jobs: make -j $(getconf _NPROCESSORS_ONLN) - name: Run tests - run: ./test/etl_tests \ No newline at end of file + run: ./test/etl_tests -v \ No newline at end of file diff --git a/.github/workflows/clang-c++17.yml b/.github/workflows/clang-c++17.yml index bc54989d0..9fb4611f3 100644 --- a/.github/workflows/clang-c++17.yml +++ b/.github/workflows/clang-c++17.yml @@ -28,7 +28,7 @@ jobs: make -j $(getconf _NPROCESSORS_ONLN) - name: Run tests - run: ./test/etl_tests + run: ./test/etl_tests -v build-clang-cpp17-linux-no-stl: name: Clang C++17 Linux - No STL @@ -50,4 +50,4 @@ jobs: make -j $(getconf _NPROCESSORS_ONLN) - name: Run tests - run: ./test/etl_tests \ No newline at end of file + run: ./test/etl_tests -v \ No newline at end of file diff --git a/.github/workflows/clang-c++20.yml b/.github/workflows/clang-c++20.yml index bfd886658..c68f9870a 100644 --- a/.github/workflows/clang-c++20.yml +++ b/.github/workflows/clang-c++20.yml @@ -35,7 +35,7 @@ jobs: make -j $(getconf _NPROCESSORS_ONLN) - name: Run tests - run: ./test/etl_tests + run: ./test/etl_tests -v build-clang-cpp20-linux-stl-force-cpp03: name: Clang C++20 Linux - STL - Force C++03 @@ -64,7 +64,7 @@ jobs: make -j $(getconf _NPROCESSORS_ONLN) - name: Run tests - run: ./test/etl_tests + run: ./test/etl_tests -v build-clang-cpp20-linux-no-stl-force-cpp03: name: Clang C++20 Linux - No STL - Force C++03 @@ -93,7 +93,7 @@ jobs: make -j $(getconf _NPROCESSORS_ONLN) - name: Run tests - run: ./test/etl_tests + run: ./test/etl_tests -v build-clang-cpp20-osx-stl: name: Clang C++20 OSX - STL @@ -115,7 +115,7 @@ jobs: make -j $(getconf _NPROCESSORS_ONLN) - name: Run tests - run: ./test/etl_tests + run: ./test/etl_tests -v build-clang-cpp20-osx-no-stl: name: Clang C++20 OSX - No STL @@ -137,7 +137,7 @@ jobs: make -j $(getconf _NPROCESSORS_ONLN) - name: Run tests - run: ./test/etl_tests + run: ./test/etl_tests -v build-clang-cpp20-osx-stl-force-cpp03: name: Clang C++20 OSX - STL - Force C++03 @@ -159,7 +159,7 @@ jobs: make -j $(getconf _NPROCESSORS_ONLN) - name: Run tests - run: ./test/etl_tests + run: ./test/etl_tests -v build-clang-cpp20-osx-no-stl-force-cpp03: name: Clang C++20 OSX - No STL - Force C++03 @@ -181,5 +181,5 @@ jobs: make -j $(getconf _NPROCESSORS_ONLN) - name: Run tests - run: ./test/etl_tests + run: ./test/etl_tests -v diff --git a/.github/workflows/clang-c++23.yml b/.github/workflows/clang-c++23.yml index 3e1f5a670..ffa88744d 100644 --- a/.github/workflows/clang-c++23.yml +++ b/.github/workflows/clang-c++23.yml @@ -35,7 +35,7 @@ jobs: make -j $(getconf _NPROCESSORS_ONLN) - name: Run tests - run: ./test/etl_tests + run: ./test/etl_tests -v build-clang-cpp23-linux-stl-force-cpp03: name: Clang C++23 Linux - STL - Force C++03 @@ -64,7 +64,7 @@ jobs: make -j $(getconf _NPROCESSORS_ONLN) - name: Run tests - run: ./test/etl_tests + run: ./test/etl_tests -v build-clang-cpp2-linux-no-stl-force-cpp03: name: Clang C++23 Linux - No STL - Force C++03 @@ -93,7 +93,7 @@ jobs: make -j $(getconf _NPROCESSORS_ONLN) - name: Run tests - run: ./test/etl_tests + run: ./test/etl_tests -v build-clang-cpp23-osx-stl: name: Clang C++23 OSX - STL @@ -115,7 +115,7 @@ jobs: make -j $(getconf _NPROCESSORS_ONLN) - name: Run tests - run: ./test/etl_tests + run: ./test/etl_tests -v build-clang-cpp23-osx-no-stl: name: Clang C++23 OSX - No STL @@ -137,7 +137,7 @@ jobs: make -j $(getconf _NPROCESSORS_ONLN) - name: Run tests - run: ./test/etl_tests + run: ./test/etl_tests -v build-clang-cpp23-osx-stl-force-cpp03: name: Clang C++23 OSX - STL - Force C++03 @@ -159,7 +159,7 @@ jobs: make -j $(getconf _NPROCESSORS_ONLN) - name: Run tests - run: ./test/etl_tests + run: ./test/etl_tests -v build-clang-cpp23-osx-no-stl-force-cpp03: name: Clang C++23 OSX - No STL - Force C++03 @@ -181,5 +181,5 @@ jobs: make -j $(getconf _NPROCESSORS_ONLN) - name: Run tests - run: ./test/etl_tests + run: ./test/etl_tests -v diff --git a/.github/workflows/gcc-c++11.yml b/.github/workflows/gcc-c++11.yml index 938402c16..571c6d6e8 100644 --- a/.github/workflows/gcc-c++11.yml +++ b/.github/workflows/gcc-c++11.yml @@ -29,7 +29,7 @@ jobs: make -j $(getconf _NPROCESSORS_ONLN) - name: Run tests - run: ./test/etl_tests + run: ./test/etl_tests -v build-gcc-cpp11-linux-no-stl: name: GCC C++11 Linux - No STL @@ -52,4 +52,4 @@ jobs: make -j $(getconf _NPROCESSORS_ONLN) - name: Run tests - run: ./test/etl_tests + run: ./test/etl_tests -v diff --git a/.github/workflows/gcc-c++14.yml b/.github/workflows/gcc-c++14.yml index 59a06efc5..f623af08c 100644 --- a/.github/workflows/gcc-c++14.yml +++ b/.github/workflows/gcc-c++14.yml @@ -28,7 +28,7 @@ jobs: make -j $(getconf _NPROCESSORS_ONLN) - name: Run tests - run: ./test/etl_tests + run: ./test/etl_tests -v build-gcc-cpp14-linux-no-stl: name: GCC C++14 Linux - No STL @@ -50,4 +50,4 @@ jobs: make -j $(getconf _NPROCESSORS_ONLN) - name: Run tests - run: ./test/etl_tests \ No newline at end of file + run: ./test/etl_tests -v \ No newline at end of file diff --git a/.github/workflows/gcc-c++17.yml b/.github/workflows/gcc-c++17.yml index 90f6ced53..fc0ddd974 100644 --- a/.github/workflows/gcc-c++17.yml +++ b/.github/workflows/gcc-c++17.yml @@ -28,7 +28,7 @@ jobs: make -j $(getconf _NPROCESSORS_ONLN) - name: Run tests - run: ./test/etl_tests + run: ./test/etl_tests -v build-gcc-cpp17-linux-no-stl: name: GCC C++17 Linux - No STL @@ -50,4 +50,4 @@ jobs: make -j $(getconf _NPROCESSORS_ONLN) - name: Run tests - run: ./test/etl_tests + run: ./test/etl_tests -v diff --git a/.github/workflows/gcc-c++20.yml b/.github/workflows/gcc-c++20.yml index 62833fbfd..5965e05e3 100644 --- a/.github/workflows/gcc-c++20.yml +++ b/.github/workflows/gcc-c++20.yml @@ -28,7 +28,7 @@ jobs: make -j $(getconf _NPROCESSORS_ONLN) - name: Run tests - run: ./test/etl_tests + run: ./test/etl_tests -v build-gcc-cpp20-linux-no-stl: name: GCC C++20 Linux - No STL @@ -50,7 +50,7 @@ jobs: make -j $(getconf _NPROCESSORS_ONLN) - name: Run tests - run: ./test/etl_tests + run: ./test/etl_tests -v build-gcc-cpp20-linux-stl-force-cpp03: name: GCC C++20 Linux - STL - Force C++03 @@ -72,7 +72,7 @@ jobs: make -j $(getconf _NPROCESSORS_ONLN) - name: Run tests - run: ./test/etl_tests + run: ./test/etl_tests -v build-gcc-cpp20-linux-no-stl-force-cpp03: name: GCC C++20 Linux - No STL - Force C++03 @@ -94,4 +94,4 @@ jobs: make -j $(getconf _NPROCESSORS_ONLN) - name: Run tests - run: ./test/etl_tests \ No newline at end of file + run: ./test/etl_tests -v \ No newline at end of file diff --git a/.github/workflows/gcc-c++23.yml b/.github/workflows/gcc-c++23.yml index 4b2efa3d5..f91924bde 100644 --- a/.github/workflows/gcc-c++23.yml +++ b/.github/workflows/gcc-c++23.yml @@ -28,7 +28,7 @@ jobs: make -j $(getconf _NPROCESSORS_ONLN) - name: Run tests - run: ./test/etl_tests + run: ./test/etl_tests -v build-gcc-cpp23-linux-no-stl: name: GCC C++23 Linux - No STL @@ -50,7 +50,7 @@ jobs: make -j $(getconf _NPROCESSORS_ONLN) - name: Run tests - run: ./test/etl_tests + run: ./test/etl_tests -v build-gcc-cpp23-linux-stl-force-cpp03: name: GCC C++23 Linux - STL - Force C++03 @@ -72,7 +72,7 @@ jobs: make -j $(getconf _NPROCESSORS_ONLN) - name: Run tests - run: ./test/etl_tests + run: ./test/etl_tests -v build-gcc-cpp23-linux-no-stl-force-cpp03: name: GCC C++23 Linux - No STL - Force C++03 @@ -94,4 +94,4 @@ jobs: make -j $(getconf _NPROCESSORS_ONLN) - name: Run tests - run: ./test/etl_tests \ No newline at end of file + run: ./test/etl_tests -v \ No newline at end of file diff --git a/.github/workflows/msvc.yml b/.github/workflows/msvc.yml index 9f28f025f..32d7aee82 100644 --- a/.github/workflows/msvc.yml +++ b/.github/workflows/msvc.yml @@ -27,7 +27,7 @@ jobs: MSBuild.exe .\etl.sln - name: Run tests - run: test/Debug/etl_tests.exe + run: test/Debug/etl_tests.exe -v build-windows-msvc-no-stl: name: Windows - No STL @@ -48,7 +48,7 @@ jobs: MSBuild.exe .\etl.sln - name: Run tests - run: test/Debug/etl_tests.exe + run: test/Debug/etl_tests.exe -v build-windows-msvc-stl-force-cpp03: name: Windows - STL - Force C++03 @@ -70,7 +70,7 @@ jobs: MSBuild.exe .\etl.sln - name: Run tests - run: test/Debug/etl_tests.exe + run: test/Debug/etl_tests.exe -v build-windows-msvc-no-stl-force-cpp03: name: Windows - No STL - Force C++03 @@ -92,5 +92,5 @@ jobs: MSBuild.exe .\etl.sln - name: Run tests - run: test/Debug/etl_tests.exe + run: test/Debug/etl_tests.exe -v diff --git a/test/main.cpp b/test/main.cpp index fd6aaf87d..68b745819 100644 --- a/test/main.cpp +++ b/test/main.cpp @@ -27,7 +27,88 @@ SOFTWARE. #include "unit_test_framework.h" -int main() +#include "UnitTest++/TestReporter.h" +#include "UnitTest++/TestReporterStdout.h" +#include "UnitTest++/TestRunner.h" +#include "UnitTest++/TestDetails.h" + +#include +#include +#include + +class VerboseTestReporter : public UnitTest::TestReporter { - return UnitTest::RunAllTests(); +public: + VerboseTestReporter() : m_testIndex(0), m_currentTestFailed(false) {} + + void ReportTestStart(UnitTest::TestDetails const& test) override + { + ++m_testIndex; + m_currentTestFailed = false; + std::cout << "[START #" << m_testIndex << "] " + << test.suiteName << "::" << test.testName << std::endl; + std::cout.flush(); + std::cerr.flush(); + } + + void ReportTestFinish(UnitTest::TestDetails const& test, float secondsElapsed) override + { + std::cout.flush(); + std::cerr.flush(); + std::cout << "[" << (m_currentTestFailed ? "FAILED" : "PASSED") + << " #" << m_testIndex << "] " + << test.suiteName << "::" << test.testName + << " (" << std::fixed << std::setprecision(4) << secondsElapsed << " s)" + << std::endl; + } + + void ReportFailure(UnitTest::TestDetails const& details, char const* failure) override + { + m_currentTestFailed = true; +#if defined(__APPLE__) || defined(__GNUG__) + std::cerr << details.filename << ":" << details.lineNumber << ":1: error: Failure in " + << details.testName << ": " << failure << std::endl; +#else + std::cerr << details.filename << "(" << details.lineNumber << "): error: Failure in " + << details.testName << ": " << failure << std::endl; +#endif + } + + void ReportSummary(int totalTestCount, int failedTestCount, + int failureCount, float secondsElapsed) override + { + if (failureCount > 0) + std::cout << "FAILURE: " << failedTestCount << " out of " << totalTestCount + << " tests failed (" << failureCount << " failures)." << std::endl; + else + std::cout << "Success: " << totalTestCount << " tests passed." << std::endl; + + std::cout << "Test time: " << std::fixed << std::setprecision(2) + << secondsElapsed << " seconds." << std::endl; + } + +private: + int m_testIndex; + bool m_currentTestFailed; +}; + +int main(int argc, char* argv[]) +{ + bool verbose = false; + for (int i = 1; i < argc; ++i) + { + if (strcmp(argv[i], "-v") == 0 || strcmp(argv[i], "--verbose") == 0) + verbose = true; + } + + if (verbose) + { + VerboseTestReporter reporter; + UnitTest::TestRunner runner(reporter); + return runner.RunTestsIf(UnitTest::Test::GetTestList(), NULL, UnitTest::True(), 0); + } + else + { + return UnitTest::RunAllTests(); + } } diff --git a/test/run-tests.sh b/test/run-tests.sh index e914114be..06e394001 100755 --- a/test/run-tests.sh +++ b/test/run-tests.sh @@ -38,9 +38,10 @@ PrintHeader() echo " Configuration : $configuration_name" | tee -a log.txt echo " Compiler : $compiler " | tee -a log.txt echo " Language : C++$cxx_standard " | tee -a log.txt - echo " Optimisation : $opt " | tee -a log.txt + echo " Optimisation : $opt " | tee -a log.txt echo " Sanitizer : $sanitize " | tee -a log.txt echo " Compiler select : $compiler_enabled " | tee -a log.txt + echo " Verbose : $verbose " | tee -a log.txt echo " ETL version : $etl_version " | tee -a log.txt echo " Git branch : $(ParseGitBranch) " | tee -a log.txt echo " Processes : ${CMAKE_BUILD_PARALLEL_LEVEL}" | tee -a log.txt @@ -51,14 +52,15 @@ PrintHeader() PrintHelp() { echo "$HelpColour" - echo "------------------------------------------------------------------------------------------------" - echo " Syntax : ./run-tests.sh " - echo " C++ Standard : 11, 14, 17, 20 or 23 " - echo " Optimisation : 0, 1, 2 or 3. Default = 0 " - echo " Threads : Number of threads to use. Default = 4 " - echo " Sanitizer : s enables sanitizer checks, n disables. Default disabled " - echo " Compiler select : gcc or clang. Default All compilers " - echo "------------------------------------------------------------------------------------------------" + echo "----------------------------------------------------------------------------------------------------------" + echo " Syntax : ./run-tests.sh " + echo " C++ Standard : 11, 14, 17, 20 or 23 " + echo " Optimisation : 0, 1, 2 or 3. Default = 0 " + echo " Threads : Number of threads to use. Default = 4 " + echo " Sanitizer : s enables sanitizer checks, n disables. Default disabled " + echo " Compiler select : gcc or clang. Default All compilers " + echo " Verbose : v enables verbose log, n disables. Default disabled " + echo "----------------------------------------------------------------------------------------------------------" echo "$NoColour" } @@ -173,6 +175,17 @@ else compiler_enabled="All compilers" fi +#****************************************************************************** +# Set the verbose enable. Default OFF +#****************************************************************************** +if [ "$6" = "v" ]; then + verbose="On" + verbose_flag="-v" +else + verbose="Off" + verbose_flag="" +fi + #****************************************************************************** # Get the ETL version #****************************************************************************** @@ -210,7 +223,7 @@ while read i ; do FailedCompilation exit $? fi - ./etl_tests + ./etl_tests $verbose_flag if [ $? -eq 0 ]; then PassedTests else From fd96291b35a349430f516ef8905da2f47f3dbdb2 Mon Sep 17 00:00:00 2001 From: Timon Zijnge Date: Tue, 17 Mar 2026 10:28:09 +0100 Subject: [PATCH 37/46] IGN-280 biphasic amplitude as float * Add big-endian devcontainer --- .devcontainer/s390x/Dockerfile | 29 +++++++++++ .devcontainer/s390x/build-and-test.sh | 72 +++++++++++++++++++++++++++ .devcontainer/s390x/devcontainer.json | 19 +++++++ 3 files changed, 120 insertions(+) create mode 100644 .devcontainer/s390x/Dockerfile create mode 100644 .devcontainer/s390x/build-and-test.sh create mode 100644 .devcontainer/s390x/devcontainer.json diff --git a/.devcontainer/s390x/Dockerfile b/.devcontainer/s390x/Dockerfile new file mode 100644 index 000000000..a6a2f4658 --- /dev/null +++ b/.devcontainer/s390x/Dockerfile @@ -0,0 +1,29 @@ +# s390x Big-Endian Test Environment for ETL +# Based on Debian 12 (Bookworm) for s390x architecture +FROM s390x/debian:bookworm + +# Avoid prompts from apt +ENV DEBIAN_FRONTEND=noninteractive + +# Install build dependencies +RUN apt-get update && apt-get install -y \ + build-essential \ + cmake \ + g++ \ + make \ + git \ + wget \ + util-linux \ + && rm -rf /var/lib/apt/lists/* + +# Set working directory +WORKDIR /workspaces/etl + +# Verify architecture and endianness +RUN echo "=== System Information ===" && \ + uname -m && \ + lscpu | grep -E "Architecture|Byte Order" && \ + echo "==========================" + +# Default command +CMD ["/bin/bash"] diff --git a/.devcontainer/s390x/build-and-test.sh b/.devcontainer/s390x/build-and-test.sh new file mode 100644 index 000000000..889af58d3 --- /dev/null +++ b/.devcontainer/s390x/build-and-test.sh @@ -0,0 +1,72 @@ +#!/bin/bash + +# ETL s390x Big-Endian Build and Test Script +# This script verifies the environment is big-endian, builds the ETL tests, and runs them + +set -e # Exit on error + +echo "==========================================" +echo "ETL s390x Big-Endian Test Environment" +echo "==========================================" +echo "" + +# Verify architecture +echo "=== System Architecture ===" +uname -m +echo "" + +# Verify endianness - this is critical for Manchester encoding tests +echo "=== Endianness Verification ===" +BYTE_ORDER=$(lscpu | grep "Byte Order" | awk '{print $3, $4}') +echo "Byte Order: $BYTE_ORDER" + +if [[ "$BYTE_ORDER" != "Big Endian" ]]; then + echo "ERROR: Expected Big Endian but found: $BYTE_ORDER" + echo "Manchester encoding tests require big-endian architecture!" + exit 1 +fi +echo "✓ Big-endian confirmed" +echo "" + +# Navigate to project root +cd /workspaces/etl + +# Create build directory +echo "=== Creating Build Directory ===" +rm -rf build-s390x +mkdir -p build-s390x +cd build-s390x +echo "" + +# Configure with CMake +echo "=== Configuring CMake ===" +cmake -DBUILD_TESTS=ON \ + -DNO_STL=OFF \ + -DETL_CXX_STANDARD=17 \ + /workspaces/etl/test +echo "" + +# Build tests +echo "=== Building Tests ===" +make -j$(nproc) +echo "" + +# Run all tests +echo "=== Running ETL Test Suite ===" +echo "This includes Manchester encoding tests which verify big-endian handling" +echo "" +./etl_tests + +# Capture test result +TEST_RESULT=$? + +echo "" +echo "==========================================" +if [ $TEST_RESULT -eq 0 ]; then + echo "✓ All tests PASSED on s390x big-endian!" +else + echo "✗ Tests FAILED with exit code: $TEST_RESULT" +fi +echo "==========================================" + +exit $TEST_RESULT diff --git a/.devcontainer/s390x/devcontainer.json b/.devcontainer/s390x/devcontainer.json new file mode 100644 index 000000000..5407f9668 --- /dev/null +++ b/.devcontainer/s390x/devcontainer.json @@ -0,0 +1,19 @@ +// For format details, see https://aka.ms/devcontainer.json. For config options, see the +// README at: https://github.com/devcontainers/templates/tree/main/src/cpp +{ + "name": "s390x Big Endian (Debian)", + "build": { + "dockerfile": "./Dockerfile", + "context": "." + }, + "customizations": { + "vscode": { + "extensions": [ + "ms-vscode.cpptools", + "ms-vscode.cmake-tools" + ] + } + }, + "postCreateCommand": "chmod +x /workspaces/etl/.devcontainer/s390x/build-and-test.sh", + "remoteUser": "root" +} From ac6f3a437cde235544069ba50bba9e250fba0224 Mon Sep 17 00:00:00 2001 From: Timon Zijnge Date: Tue, 17 Mar 2026 11:40:47 +0100 Subject: [PATCH 38/46] manchester * fixed the configuration to work with GitHub Codespaces. The changes use cross-compilation with QEMU emulation instead of trying to use a native s390x container. --- .devcontainer/s390x/Dockerfile | 41 +++++++++---- .devcontainer/s390x/build-and-test.sh | 71 ++++++++++++++++------- .devcontainer/s390x/toolchain-s390x.cmake | 21 +++++++ 3 files changed, 100 insertions(+), 33 deletions(-) create mode 100644 .devcontainer/s390x/toolchain-s390x.cmake diff --git a/.devcontainer/s390x/Dockerfile b/.devcontainer/s390x/Dockerfile index a6a2f4658..d082598eb 100644 --- a/.devcontainer/s390x/Dockerfile +++ b/.devcontainer/s390x/Dockerfile @@ -1,29 +1,48 @@ # s390x Big-Endian Test Environment for ETL -# Based on Debian 12 (Bookworm) for s390x architecture -FROM s390x/debian:bookworm +# Uses QEMU user-mode emulation to run s390x binaries on x64 host +FROM debian:bookworm # Avoid prompts from apt ENV DEBIAN_FRONTEND=noninteractive -# Install build dependencies -RUN apt-get update && apt-get install -y \ - build-essential \ +# Install QEMU user-mode emulation and s390x cross-compilation tools +RUN dpkg --add-architecture s390x && \ + apt-get update && apt-get install -y \ + qemu-user-static \ + qemu-user \ + binfmt-support \ + gcc-s390x-linux-gnu \ + g++-s390x-linux-gnu \ cmake \ - g++ \ make \ git \ wget \ - util-linux \ + file \ + libc6:s390x \ + libstdc++6:s390x \ && rm -rf /var/lib/apt/lists/* +# Set up s390x as default cross-compilation target +ENV CROSS_COMPILE=s390x-linux-gnu- +ENV CC=s390x-linux-gnu-gcc +ENV CXX=s390x-linux-gnu-g++ +ENV AR=s390x-linux-gnu-ar +ENV AS=s390x-linux-gnu-as +ENV LD=s390x-linux-gnu-ld +ENV STRIP=s390x-linux-gnu-strip + # Set working directory WORKDIR /workspaces/etl -# Verify architecture and endianness -RUN echo "=== System Information ===" && \ +# Verify QEMU and cross-compilation setup +RUN echo "=== Host Architecture ===" && \ uname -m && \ - lscpu | grep -E "Architecture|Byte Order" && \ - echo "==========================" + echo "" && \ + echo "=== s390x Cross Compiler ===" && \ + s390x-linux-gnu-gcc --version && \ + echo "" && \ + echo "=== QEMU s390x ===" && \ + qemu-s390x-static --version | head -n1 # Default command CMD ["/bin/bash"] diff --git a/.devcontainer/s390x/build-and-test.sh b/.devcontainer/s390x/build-and-test.sh index 889af58d3..e4232ce1c 100644 --- a/.devcontainer/s390x/build-and-test.sh +++ b/.devcontainer/s390x/build-and-test.sh @@ -1,7 +1,7 @@ #!/bin/bash # ETL s390x Big-Endian Build and Test Script -# This script verifies the environment is big-endian, builds the ETL tests, and runs them +# Cross-compiles for s390x and runs tests under QEMU emulation set -e # Exit on error @@ -10,22 +10,20 @@ echo "ETL s390x Big-Endian Test Environment" echo "==========================================" echo "" -# Verify architecture -echo "=== System Architecture ===" -uname -m +# Verify host architecture +echo "=== Host Architecture ===" +echo "Host: $(uname -m)" echo "" -# Verify endianness - this is critical for Manchester encoding tests -echo "=== Endianness Verification ===" -BYTE_ORDER=$(lscpu | grep "Byte Order" | awk '{print $3, $4}') -echo "Byte Order: $BYTE_ORDER" +# Verify cross-compilation tools +echo "=== Cross-Compilation Tools ===" +s390x-linux-gnu-gcc --version | head -n1 +s390x-linux-gnu-g++ --version | head -n1 +echo "" -if [[ "$BYTE_ORDER" != "Big Endian" ]]; then - echo "ERROR: Expected Big Endian but found: $BYTE_ORDER" - echo "Manchester encoding tests require big-endian architecture!" - exit 1 -fi -echo "✓ Big-endian confirmed" +# Verify QEMU availability +echo "=== QEMU s390x Emulator ===" +qemu-s390x-static --version | head -n1 echo "" # Navigate to project root @@ -38,24 +36,50 @@ mkdir -p build-s390x cd build-s390x echo "" -# Configure with CMake -echo "=== Configuring CMake ===" -cmake -DBUILD_TESTS=ON \ +# Configure with CMake using s390x toolchain +echo "=== Configuring CMake for s390x Cross-Compilation ===" +cmake -DCMAKE_TOOLCHAIN_FILE=/workspaces/etl/.devcontainer/s390x/toolchain-s390x.cmake \ + -DBUILD_TESTS=ON \ -DNO_STL=OFF \ -DETL_CXX_STANDARD=17 \ /workspaces/etl/test echo "" # Build tests -echo "=== Building Tests ===" +echo "=== Building Tests for s390x ===" make -j$(nproc) echo "" -# Run all tests -echo "=== Running ETL Test Suite ===" -echo "This includes Manchester encoding tests which verify big-endian handling" +# Verify the binary is s390x +echo "=== Verifying Binary Architecture ===" +TEST_BINARY="./etl_tests" +if [ -f "$TEST_BINARY" ]; then + FILE_OUTPUT=$(file "$TEST_BINARY") + echo "$FILE_OUTPUT" + + if echo "$FILE_OUTPUT" | grep -q "s390x"; then + echo "✓ Binary is s390x architecture" + else + echo "✗ ERROR: Binary is not s390x!" + exit 1 + fi + + if echo "$FILE_OUTPUT" | grep -q "MSB"; then + echo "✓ Binary is big-endian (MSB)" + else + echo "⚠ Warning: Could not confirm big-endian from file output" + fi +else + echo "✗ ERROR: Test binary not found!" + exit 1 +fi +echo "" + +# Run all tests using QEMU +echo "=== Running ETL Test Suite under QEMU s390x Emulation ===" +echo "This runs s390x big-endian binaries, testing Manchester encoding" echo "" -./etl_tests +qemu-s390x-static "$TEST_BINARY" # Capture test result TEST_RESULT=$? @@ -64,9 +88,12 @@ echo "" echo "==========================================" if [ $TEST_RESULT -eq 0 ]; then echo "✓ All tests PASSED on s390x big-endian!" + echo "✓ Manchester encoding verified on big-endian architecture" else echo "✗ Tests FAILED with exit code: $TEST_RESULT" fi echo "==========================================" exit $TEST_RESULT + +exit $TEST_RESULT diff --git a/.devcontainer/s390x/toolchain-s390x.cmake b/.devcontainer/s390x/toolchain-s390x.cmake new file mode 100644 index 000000000..93d3abb03 --- /dev/null +++ b/.devcontainer/s390x/toolchain-s390x.cmake @@ -0,0 +1,21 @@ +# CMake toolchain file for s390x cross-compilation +set(CMAKE_SYSTEM_NAME Linux) +set(CMAKE_SYSTEM_PROCESSOR s390x) + +# Specify the cross compiler +set(CMAKE_C_COMPILER s390x-linux-gnu-gcc) +set(CMAKE_CXX_COMPILER s390x-linux-gnu-g++) +set(CMAKE_AR s390x-linux-gnu-ar) +set(CMAKE_RANLIB s390x-linux-gnu-ranlib) +set(CMAKE_STRIP s390x-linux-gnu-strip) + +# Search for programs in the build host directories +set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) + +# For libraries and headers in the target directories +set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) +set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) +set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY) + +# Set QEMU for running tests +set(CMAKE_CROSSCOMPILING_EMULATOR /usr/bin/qemu-s390x-static) From 758128768b52f75a6c8df9bdd2794add10387aa6 Mon Sep 17 00:00:00 2001 From: Timon Zijnge Date: Tue, 17 Mar 2026 17:32:23 +0100 Subject: [PATCH 39/46] manchester * Made manchester work for big-endian * Some updates to the container --- .devcontainer/s390x/Dockerfile | 29 +++++ .devcontainer/s390x/build-and-test.sh | 4 +- include/etl/manchester.h | 149 +++++++------------------- test/test_manchester.cpp | 103 ++++++++++++++---- 4 files changed, 156 insertions(+), 129 deletions(-) diff --git a/.devcontainer/s390x/Dockerfile b/.devcontainer/s390x/Dockerfile index d082598eb..57010a706 100644 --- a/.devcontainer/s390x/Dockerfile +++ b/.devcontainer/s390x/Dockerfile @@ -1,4 +1,18 @@ # s390x Big-Endian Test Environment for ETL +# Based on Debian 12 (Bookworm) for s390x architecture +FROM s390x/debian:bookworm + +# Avoid prompts from apt +ENV DEBIAN_FRONTEND=noninteractive + +# Install build dependencies +RUN apt-get update && apt-get install -y \ + build-essential \ + cmake \ + g++ \ + make \ + git \ + wget \# s390x Big-Endian Test Environment for ETL # Uses QEMU user-mode emulation to run s390x binaries on x64 host FROM debian:bookworm @@ -46,3 +60,18 @@ RUN echo "=== Host Architecture ===" && \ # Default command CMD ["/bin/bash"] + +util-linux \ + && rm -rf /var/lib/apt/lists/* + +# Set working directory +WORKDIR /workspaces/etl + +# Verify architecture and endianness +RUN echo "=== System Information ===" && \ + uname -m && \ + lscpu | grep -E "Architecture|Byte Order" && \ + echo "==========================" + +# Default command +CMD ["/bin/bash"] diff --git a/.devcontainer/s390x/build-and-test.sh b/.devcontainer/s390x/build-and-test.sh index e4232ce1c..9ed15ccb1 100644 --- a/.devcontainer/s390x/build-and-test.sh +++ b/.devcontainer/s390x/build-and-test.sh @@ -57,7 +57,7 @@ if [ -f "$TEST_BINARY" ]; then FILE_OUTPUT=$(file "$TEST_BINARY") echo "$FILE_OUTPUT" - if echo "$FILE_OUTPUT" | grep -q "s390x"; then + if echo "$FILE_OUTPUT" | grep -qi "S/390\|s390"; then echo "✓ Binary is s390x architecture" else echo "✗ ERROR: Binary is not s390x!" @@ -77,7 +77,6 @@ echo "" # Run all tests using QEMU echo "=== Running ETL Test Suite under QEMU s390x Emulation ===" -echo "This runs s390x big-endian binaries, testing Manchester encoding" echo "" qemu-s390x-static "$TEST_BINARY" @@ -88,7 +87,6 @@ echo "" echo "==========================================" if [ $TEST_RESULT -eq 0 ]; then echo "✓ All tests PASSED on s390x big-endian!" - echo "✓ Manchester encoding verified on big-endian architecture" else echo "✗ Tests FAILED with exit code: $TEST_RESULT" fi diff --git a/include/etl/manchester.h b/include/etl/manchester.h index 4c35deb86..f89141d3e 100644 --- a/include/etl/manchester.h +++ b/include/etl/manchester.h @@ -172,18 +172,37 @@ namespace etl }; //************************************************************************* - /// Alias for memcpy. etl::mem_copy is not suitable for the Manchester - /// algorithm because all memory copies are between different types. This - /// alias is a way to respect ETL_USING_BUILTIN_MEMCPY while using the - /// memcpy function signature + /// Read a multi-byte value from a span in little-endian byte order. + ///\tparam T The type to read. + ///\param bytes The span to read from. + ///\param index The starting index in the span. + ///\return The value read from the span. //************************************************************************* - inline void* memcpy(void* dest, const void* src, std::size_t count) ETL_NOEXCEPT + template + static ETL_CONSTEXPR14 T read_little_endian(etl::span bytes, size_t index) { -#if ETL_USING_BUILTIN_MEMCPY - return __builtin_memcpy(dest, src, count); -#else - return ::memcpy(dest, src, count); -#endif + T value = 0; + for (size_t j = 0; j < sizeof(T); ++j) + { + value |= static_cast(bytes[index + j]) << (j * CHAR_BIT); + } + return value; + } + + //************************************************************************* + /// Write a multi-byte value to a span in little-endian byte order. + ///\tparam T The type to write. + ///\param bytes The span to write to. + ///\param index The starting index in the span. + ///\param value The value to write. + //************************************************************************* + template + static ETL_CONSTEXPR14 void write_little_endian(etl::span bytes, size_t index, T value) + { + for (size_t j = 0; j < sizeof(T); ++j) + { + bytes[index + j] = static_cast(value >> (j * CHAR_BIT)); + } } } // namespace private_manchester @@ -297,44 +316,13 @@ namespace etl #endif //************************************************************************* - /// Encode a span of data with the selected chunk size. - ///\param source The source data to encode. - ///\param destination The destination buffer for encoded data. - ///\tparam TChunk The chunk size for encoding (default: uint_least8_t). - //************************************************************************* - template - static typename etl::enable_if::value, void>::type - encode(etl::span decoded, etl::span encoded) - { - typedef TChunk TDecoded; - typedef typename etl::private_manchester::encoded::type TEncoded; - - ETL_ASSERT(encoded.size() >= decoded.size() * 2, ETL_ERROR(manchester_invalid_size)); - ETL_ASSERT(decoded.size() % sizeof(TDecoded) == 0, ETL_ERROR(manchester_invalid_size)); - - size_t dest_index = 0; - size_t source_index = 0; - for (size_t i = 0; i < decoded.size() / sizeof(TDecoded); ++i) - { - TDecoded decoded_value = 0; - etl::private_manchester::memcpy(&decoded_value, &decoded[source_index], sizeof(TDecoded)); - const TEncoded encoded_value = encode(decoded_value); - etl::private_manchester::memcpy(&encoded[dest_index], &encoded_value, sizeof(TEncoded)); - - source_index += sizeof(TDecoded); - dest_index += sizeof(TEncoded); - } - } - - //************************************************************************* - /// Encode a span of data with the minimum chunk size. This version is - /// constexpr so that it can be used to encode data at compile time. + /// Encode a span of data with the specified chunk size. ///\param source The source data to encode. ///\param destination The destination buffer for encoded data. ///\tparam TChunk The chunk size for encoding (default: uint_least8_t). //************************************************************************* template - static ETL_CONSTEXPR14 typename etl::enable_if::value, void>::type encode(etl::span decoded, etl::span encoded) + static ETL_CONSTEXPR14 void encode(etl::span decoded, etl::span encoded) { typedef TChunk TDecoded; typedef typename etl::private_manchester::encoded::type TEncoded; @@ -346,17 +334,9 @@ namespace etl size_t source_index = 0; for (size_t i = 0; i < decoded.size() / sizeof(TDecoded); ++i) { - const TEncoded encoded_value = encode(decoded[source_index]); - if (etl::endianness::value() == etl::endian::little) - { - encoded[dest_index] = static_cast(encoded_value); - encoded[dest_index + 1] = static_cast(encoded_value >> CHAR_BIT); - } - else - { - encoded[dest_index] = static_cast(encoded_value >> CHAR_BIT); - encoded[dest_index + 1] = static_cast(encoded_value); - } + const TDecoded decoded_value = private_manchester::read_little_endian(decoded, source_index); + const TEncoded encoded_value = encode(decoded_value); + private_manchester::write_little_endian(encoded, dest_index, encoded_value); source_index += sizeof(TDecoded); dest_index += sizeof(TEncoded); @@ -426,14 +406,13 @@ namespace etl #endif //************************************************************************* - /// Decode a span of data using specified chunk type. + /// Decode a span of data using the specified chunk type. ///\param source The source encoded data to decode. ///\param destination The destination buffer for decoded data. - ///\tparam TChunk The chunk type for decoding. + ///\tparam TChunk The chunk type for decoding (default: uint16_t). //************************************************************************* - template - static typename etl::enable_if::type>::value, void>::type - decode(etl::span encoded, etl::span decoded) + template ::type> + static ETL_CONSTEXPR14 void decode(etl::span encoded, etl::span decoded) { typedef typename private_manchester::decoded::type TDecoded; typedef TChunk TEncoded; @@ -445,53 +424,15 @@ namespace etl size_t source_index = 0; for (size_t i = 0; i < encoded.size() / sizeof(TEncoded); ++i) { - TChunk encoded_value = 0; - etl::private_manchester::memcpy(&encoded_value, &encoded[source_index], sizeof(TEncoded)); + const TEncoded encoded_value = private_manchester::read_little_endian(encoded, source_index); const TDecoded decoded_value = decode(encoded_value); - etl::private_manchester::memcpy(&decoded[dest_index], &decoded_value, sizeof(TDecoded)); + private_manchester::write_little_endian(decoded, dest_index, decoded_value); source_index += sizeof(TEncoded); dest_index += sizeof(TDecoded); } } - //************************************************************************* - /// Decode a span of data using the smallest chunk type. This version is - /// constexpr so that it can be used to decode data at compile time. - ///\param source The source encoded data to decode. - ///\param destination The destination buffer for decoded data. - ///\tparam TChunk The chunk type for decoding (default type). - //************************************************************************* - template ::type> - static ETL_CONSTEXPR14 typename etl::enable_if::type>::value, void>::type - decode(etl::span encoded, etl::span decoded) - { - typedef uint_least8_t TDecoded; - - ETL_ASSERT(decoded.size() * 2 >= encoded.size(), ETL_ERROR(manchester_invalid_size)); - ETL_ASSERT(encoded.size() % sizeof(TChunk) == 0, ETL_ERROR(manchester_invalid_size)); - - size_t dest_index = 0; - size_t source_index = 0; - for (size_t i = 0; i < encoded.size() / sizeof(TChunk); ++i) - { - TChunk encoded_value{}; - if (etl::endianness::value() == etl::endian::little) - { - encoded_value = static_cast((encoded[source_index + 1] << CHAR_BIT) | encoded[source_index]); - } - else - { - encoded_value = static_cast((encoded[source_index] << CHAR_BIT) | encoded[source_index + 1]); - } - - decoded[dest_index] = decode(encoded_value); - - source_index += sizeof(TChunk); - dest_index += sizeof(TDecoded); - } - } - //************************************************************************* // Validation functions //************************************************************************* @@ -521,15 +462,7 @@ namespace etl for (size_t i = 0; i < encoded.size(); i += sizeof(uint16_t)) { - uint16_t chunk{}; - if (etl::endianness::value() == etl::endian::little) - { - chunk = static_cast((encoded[i + 1] << CHAR_BIT) | encoded[i]); - } - else - { - chunk = static_cast((encoded[i] << CHAR_BIT) | encoded[i + 1]); - } + const uint16_t chunk = private_manchester::read_little_endian(encoded, i); if (!is_valid(chunk)) { diff --git a/test/test_manchester.cpp b/test/test_manchester.cpp index 0334712fd..29fe9acb7 100644 --- a/test/test_manchester.cpp +++ b/test/test_manchester.cpp @@ -4,6 +4,7 @@ #include #include #include +#include #include SUITE(test_manchester) @@ -71,12 +72,26 @@ SUITE(test_manchester) } #if ETL_USING_CPP14 - constexpr etl::array manchester_encoded(etl::span decoded) + constexpr etl::array manchester_encoded_uint8(etl::span decoded) { etl::array encoded{0, 0, 0, 0, 0, 0, 0, 0}; etl::manchester::encode(decoded, encoded); return encoded; } + + constexpr etl::array manchester_encoded_uint16(etl::span decoded) + { + etl::array encoded{0, 0, 0, 0, 0, 0, 0, 0}; + etl::manchester::encode(decoded, encoded); + return encoded; + } + + constexpr etl::array manchester_encoded_uint32(etl::span decoded) + { + etl::array encoded{0, 0, 0, 0, 0, 0, 0, 0}; + etl::manchester::encode(decoded, encoded); + return encoded; + } #endif TEST(encode_span) @@ -105,18 +120,41 @@ SUITE(test_manchester) CHECK_TRUE(encoded0 == encoded1); CHECK_TRUE(encoded0 == encoded2); CHECK_TRUE(encoded0 == encoded3); + } #if ETL_USING_CPP14 - static_assert(manchester_encoded(decoded)[0] == 0xAA, "Compile time encoding on range failed"); - static_assert(manchester_encoded(decoded)[1] == 0xAA, "Compile time encoding on range failed"); - static_assert(manchester_encoded(decoded)[2] == 0x55, "Compile time encoding on range failed"); - static_assert(manchester_encoded(decoded)[3] == 0x55, "Compile time encoding on range failed"); - static_assert(manchester_encoded(decoded)[4] == 0xA9, "Compile time encoding on range failed"); - static_assert(manchester_encoded(decoded)[5] == 0xAA, "Compile time encoding on range failed"); - static_assert(manchester_encoded(decoded)[6] == 0xAA, "Compile time encoding on range failed"); - static_assert(manchester_encoded(decoded)[7] == 0x6A, "Compile time encoding on range failed"); -#endif + TEST(encode_span_constexpr) + { + constexpr etl::array decoded{0x00, 0xFF, 0x01, 0x80}; + + static_assert(manchester_encoded_uint8(decoded)[0] == 0xAA, "Compile time encoding with uint8_t failed"); + static_assert(manchester_encoded_uint8(decoded)[1] == 0xAA, "Compile time encoding with uint8_t failed"); + static_assert(manchester_encoded_uint8(decoded)[2] == 0x55, "Compile time encoding with uint8_t failed"); + static_assert(manchester_encoded_uint8(decoded)[3] == 0x55, "Compile time encoding with uint8_t failed"); + static_assert(manchester_encoded_uint8(decoded)[4] == 0xA9, "Compile time encoding with uint8_t failed"); + static_assert(manchester_encoded_uint8(decoded)[5] == 0xAA, "Compile time encoding with uint8_t failed"); + static_assert(manchester_encoded_uint8(decoded)[6] == 0xAA, "Compile time encoding with uint8_t failed"); + static_assert(manchester_encoded_uint8(decoded)[7] == 0x6A, "Compile time encoding with uint8_t failed"); + + static_assert(manchester_encoded_uint16(decoded)[0] == 0xAA, "Compile time encoding with uint16_t failed"); + static_assert(manchester_encoded_uint16(decoded)[1] == 0xAA, "Compile time encoding with uint16_t failed"); + static_assert(manchester_encoded_uint16(decoded)[2] == 0x55, "Compile time encoding with uint16_t failed"); + static_assert(manchester_encoded_uint16(decoded)[3] == 0x55, "Compile time encoding with uint16_t failed"); + static_assert(manchester_encoded_uint16(decoded)[4] == 0xA9, "Compile time encoding with uint16_t failed"); + static_assert(manchester_encoded_uint16(decoded)[5] == 0xAA, "Compile time encoding with uint16_t failed"); + static_assert(manchester_encoded_uint16(decoded)[6] == 0xAA, "Compile time encoding with uint16_t failed"); + static_assert(manchester_encoded_uint16(decoded)[7] == 0x6A, "Compile time encoding with uint16_t failed"); + + static_assert(manchester_encoded_uint32(decoded)[0] == 0xAA, "Compile time encoding with uint32_t failed"); + static_assert(manchester_encoded_uint32(decoded)[1] == 0xAA, "Compile time encoding with uint32_t failed"); + static_assert(manchester_encoded_uint32(decoded)[2] == 0x55, "Compile time encoding with uint32_t failed"); + static_assert(manchester_encoded_uint32(decoded)[3] == 0x55, "Compile time encoding with uint32_t failed"); + static_assert(manchester_encoded_uint32(decoded)[4] == 0xA9, "Compile time encoding with uint32_t failed"); + static_assert(manchester_encoded_uint32(decoded)[5] == 0xAA, "Compile time encoding with uint32_t failed"); + static_assert(manchester_encoded_uint32(decoded)[6] == 0xAA, "Compile time encoding with uint32_t failed"); + static_assert(manchester_encoded_uint32(decoded)[7] == 0x6A, "Compile time encoding with uint32_t failed"); } +#endif TEST(encode_span_inverted) { @@ -233,12 +271,26 @@ SUITE(test_manchester) } #if ETL_USING_CPP14 - constexpr etl::array manchester_decoded(etl::span encoded) + constexpr etl::array manchester_decoded_uint16(etl::span encoded) { etl::array decoded{0, 0, 0, 0}; etl::manchester::decode(encoded, decoded); return decoded; } + + constexpr etl::array manchester_decoded_uint32(etl::span encoded) + { + etl::array decoded{0, 0, 0, 0}; + etl::manchester::decode(encoded, decoded); + return decoded; + } + + constexpr etl::array manchester_decoded_uint64(etl::span encoded) + { + etl::array decoded{0, 0, 0, 0}; + etl::manchester::decode(encoded, decoded); + return decoded; + } #endif TEST(decode_span) @@ -260,18 +312,33 @@ SUITE(test_manchester) CHECK_EQUAL(0x01, decoded0[2]); CHECK_EQUAL(0x80, decoded0[3]); -#if ETL_USING_CPP14 - static_assert(manchester_decoded(encoded)[0] == 0x00, "Compile time decoding on range failed"); - static_assert(manchester_decoded(encoded)[1] == 0xFF, "Compile time decoding on range failed"); - static_assert(manchester_decoded(encoded)[2] == 0x01, "Compile time decoding on range failed"); - static_assert(manchester_decoded(encoded)[3] == 0x80, "Compile time decoding on range failed"); -#endif - CHECK_TRUE(decoded0 == decoded1); CHECK_TRUE(decoded0 == decoded2); CHECK_TRUE(decoded0 == decoded3); } +#if ETL_USING_CPP14 + TEST(decode_span_constexpr) + { + constexpr etl::array encoded{0xAA, 0xAA, 0x55, 0x55, 0xA9, 0xAA, 0xAA, 0x6A}; + + static_assert(manchester_decoded_uint16(encoded)[0] == 0x00, "Compile time decoding with uint16_t failed"); + static_assert(manchester_decoded_uint16(encoded)[1] == 0xFF, "Compile time decoding with uint16_t failed"); + static_assert(manchester_decoded_uint16(encoded)[2] == 0x01, "Compile time decoding with uint16_t failed"); + static_assert(manchester_decoded_uint16(encoded)[3] == 0x80, "Compile time decoding with uint16_t failed"); + + static_assert(manchester_decoded_uint32(encoded)[0] == 0x00, "Compile time decoding with uint32_t failed"); + static_assert(manchester_decoded_uint32(encoded)[1] == 0xFF, "Compile time decoding with uint32_t failed"); + static_assert(manchester_decoded_uint32(encoded)[2] == 0x01, "Compile time decoding with uint32_t failed"); + static_assert(manchester_decoded_uint32(encoded)[3] == 0x80, "Compile time decoding with uint32_t failed"); + + static_assert(manchester_decoded_uint64(encoded)[0] == 0x00, "Compile time decoding with uint64_t failed"); + static_assert(manchester_decoded_uint64(encoded)[1] == 0xFF, "Compile time decoding with uint64_t failed"); + static_assert(manchester_decoded_uint64(encoded)[2] == 0x01, "Compile time decoding with uint64_t failed"); + static_assert(manchester_decoded_uint64(encoded)[3] == 0x80, "Compile time decoding with uint64_t failed"); + } +#endif + TEST(decode_span_inverted) { etl::array encoded{0x55, 0x55, 0xAA, 0xAA, 0x56, 0x55, 0x55, 0x95}; From 88efa65c870c64baeba16c57262b7afe6a6ef278 Mon Sep 17 00:00:00 2001 From: Timon Zijnge Date: Wed, 18 Mar 2026 13:12:44 +0100 Subject: [PATCH 40/46] Manchester big-endian support * Cleanup --- .devcontainer/s390x/Dockerfile | 41 +---------- .devcontainer/s390x/build-and-test.sh | 97 --------------------------- .devcontainer/s390x/devcontainer.json | 13 +++- 3 files changed, 13 insertions(+), 138 deletions(-) delete mode 100644 .devcontainer/s390x/build-and-test.sh diff --git a/.devcontainer/s390x/Dockerfile b/.devcontainer/s390x/Dockerfile index 57010a706..a4d643c5f 100644 --- a/.devcontainer/s390x/Dockerfile +++ b/.devcontainer/s390x/Dockerfile @@ -1,20 +1,6 @@ # s390x Big-Endian Test Environment for ETL -# Based on Debian 12 (Bookworm) for s390x architecture -FROM s390x/debian:bookworm - -# Avoid prompts from apt -ENV DEBIAN_FRONTEND=noninteractive - -# Install build dependencies -RUN apt-get update && apt-get install -y \ - build-essential \ - cmake \ - g++ \ - make \ - git \ - wget \# s390x Big-Endian Test Environment for ETL # Uses QEMU user-mode emulation to run s390x binaries on x64 host -FROM debian:bookworm +FROM debian:trixie # Avoid prompts from apt ENV DEBIAN_FRONTEND=noninteractive @@ -29,6 +15,7 @@ RUN dpkg --add-architecture s390x && \ g++-s390x-linux-gnu \ cmake \ make \ + ninja-build \ git \ wget \ file \ @@ -36,15 +23,6 @@ RUN dpkg --add-architecture s390x && \ libstdc++6:s390x \ && rm -rf /var/lib/apt/lists/* -# Set up s390x as default cross-compilation target -ENV CROSS_COMPILE=s390x-linux-gnu- -ENV CC=s390x-linux-gnu-gcc -ENV CXX=s390x-linux-gnu-g++ -ENV AR=s390x-linux-gnu-ar -ENV AS=s390x-linux-gnu-as -ENV LD=s390x-linux-gnu-ld -ENV STRIP=s390x-linux-gnu-strip - # Set working directory WORKDIR /workspaces/etl @@ -60,18 +38,3 @@ RUN echo "=== Host Architecture ===" && \ # Default command CMD ["/bin/bash"] - -util-linux \ - && rm -rf /var/lib/apt/lists/* - -# Set working directory -WORKDIR /workspaces/etl - -# Verify architecture and endianness -RUN echo "=== System Information ===" && \ - uname -m && \ - lscpu | grep -E "Architecture|Byte Order" && \ - echo "==========================" - -# Default command -CMD ["/bin/bash"] diff --git a/.devcontainer/s390x/build-and-test.sh b/.devcontainer/s390x/build-and-test.sh deleted file mode 100644 index 9ed15ccb1..000000000 --- a/.devcontainer/s390x/build-and-test.sh +++ /dev/null @@ -1,97 +0,0 @@ -#!/bin/bash - -# ETL s390x Big-Endian Build and Test Script -# Cross-compiles for s390x and runs tests under QEMU emulation - -set -e # Exit on error - -echo "==========================================" -echo "ETL s390x Big-Endian Test Environment" -echo "==========================================" -echo "" - -# Verify host architecture -echo "=== Host Architecture ===" -echo "Host: $(uname -m)" -echo "" - -# Verify cross-compilation tools -echo "=== Cross-Compilation Tools ===" -s390x-linux-gnu-gcc --version | head -n1 -s390x-linux-gnu-g++ --version | head -n1 -echo "" - -# Verify QEMU availability -echo "=== QEMU s390x Emulator ===" -qemu-s390x-static --version | head -n1 -echo "" - -# Navigate to project root -cd /workspaces/etl - -# Create build directory -echo "=== Creating Build Directory ===" -rm -rf build-s390x -mkdir -p build-s390x -cd build-s390x -echo "" - -# Configure with CMake using s390x toolchain -echo "=== Configuring CMake for s390x Cross-Compilation ===" -cmake -DCMAKE_TOOLCHAIN_FILE=/workspaces/etl/.devcontainer/s390x/toolchain-s390x.cmake \ - -DBUILD_TESTS=ON \ - -DNO_STL=OFF \ - -DETL_CXX_STANDARD=17 \ - /workspaces/etl/test -echo "" - -# Build tests -echo "=== Building Tests for s390x ===" -make -j$(nproc) -echo "" - -# Verify the binary is s390x -echo "=== Verifying Binary Architecture ===" -TEST_BINARY="./etl_tests" -if [ -f "$TEST_BINARY" ]; then - FILE_OUTPUT=$(file "$TEST_BINARY") - echo "$FILE_OUTPUT" - - if echo "$FILE_OUTPUT" | grep -qi "S/390\|s390"; then - echo "✓ Binary is s390x architecture" - else - echo "✗ ERROR: Binary is not s390x!" - exit 1 - fi - - if echo "$FILE_OUTPUT" | grep -q "MSB"; then - echo "✓ Binary is big-endian (MSB)" - else - echo "⚠ Warning: Could not confirm big-endian from file output" - fi -else - echo "✗ ERROR: Test binary not found!" - exit 1 -fi -echo "" - -# Run all tests using QEMU -echo "=== Running ETL Test Suite under QEMU s390x Emulation ===" -echo "" -qemu-s390x-static "$TEST_BINARY" - -# Capture test result -TEST_RESULT=$? - -echo "" -echo "==========================================" -if [ $TEST_RESULT -eq 0 ]; then - echo "✓ All tests PASSED on s390x big-endian!" -else - echo "✗ Tests FAILED with exit code: $TEST_RESULT" -fi -echo "==========================================" - -exit $TEST_RESULT - -exit $TEST_RESULT diff --git a/.devcontainer/s390x/devcontainer.json b/.devcontainer/s390x/devcontainer.json index 5407f9668..8ee21079a 100644 --- a/.devcontainer/s390x/devcontainer.json +++ b/.devcontainer/s390x/devcontainer.json @@ -11,9 +11,18 @@ "extensions": [ "ms-vscode.cpptools", "ms-vscode.cmake-tools" - ] + ], + "settings": { + "cmake.configureArgs": [ + "-DCMAKE_TOOLCHAIN_FILE=/workspaces/etl/.devcontainer/s390x/toolchain-s390x.cmake", + "-DBUILD_TESTS=ON", + "-DNO_STL=OFF", + "-DETL_CXX_STANDARD=17" + ], + "cmake.buildDirectory": "${workspaceFolder}/build-s390x", + "cmake.generator": "Ninja" + } } }, - "postCreateCommand": "chmod +x /workspaces/etl/.devcontainer/s390x/build-and-test.sh", "remoteUser": "root" } From c2c19545196902ef2fc6b10863afd25a1b90567c Mon Sep 17 00:00:00 2001 From: Timon Zijnge Date: Wed, 18 Mar 2026 13:59:55 +0100 Subject: [PATCH 41/46] Manchester big-endian support * add sourcedirectory --- .devcontainer/s390x/devcontainer.json | 1 + 1 file changed, 1 insertion(+) diff --git a/.devcontainer/s390x/devcontainer.json b/.devcontainer/s390x/devcontainer.json index 8ee21079a..5abf76b0a 100644 --- a/.devcontainer/s390x/devcontainer.json +++ b/.devcontainer/s390x/devcontainer.json @@ -13,6 +13,7 @@ "ms-vscode.cmake-tools" ], "settings": { + "cmake.sourceDirectory": "${workspaceFolder}/test", "cmake.configureArgs": [ "-DCMAKE_TOOLCHAIN_FILE=/workspaces/etl/.devcontainer/s390x/toolchain-s390x.cmake", "-DBUILD_TESTS=ON", From dd89b307834b68b557080b0ccbfeea2344c3fdbb Mon Sep 17 00:00:00 2001 From: Timon Zijnge <47081647+tzijnge@users.noreply.github.com> Date: Wed, 18 Mar 2026 13:30:27 +0000 Subject: [PATCH 42/46] Enable running with ctest --- .devcontainer/s390x/toolchain-s390x.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.devcontainer/s390x/toolchain-s390x.cmake b/.devcontainer/s390x/toolchain-s390x.cmake index 93d3abb03..706884d98 100644 --- a/.devcontainer/s390x/toolchain-s390x.cmake +++ b/.devcontainer/s390x/toolchain-s390x.cmake @@ -18,4 +18,4 @@ set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY) # Set QEMU for running tests -set(CMAKE_CROSSCOMPILING_EMULATOR /usr/bin/qemu-s390x-static) +set(CMAKE_CROSSCOMPILING_EMULATOR /usr/bin/qemu-s390x-static CACHE FILEPATH "Path to the emulator for cross-compiled binaries") From 396a3def5c06f14a7963e3cb74c04ad2393c127a Mon Sep 17 00:00:00 2001 From: Timon Zijnge Date: Wed, 18 Mar 2026 14:52:13 +0100 Subject: [PATCH 43/46] Manchester big-endian support * Update documentation --- docs/manchester.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/manchester.md b/docs/manchester.md index 06c0cf7d4..15fc6ee9b 100644 --- a/docs/manchester.md +++ b/docs/manchester.md @@ -13,8 +13,9 @@ Efficient Manchester encoding and decoding of data. The Manchester code represen - Normal and inverted Manchester encoding - Support for multiple encoding chunk sizes: 8-bit, 16-bit and 32-bit - Span-based operations or chunk-based operations -- Constexpr functions for compile-time encoding/decoding (8-bit chunk size only) +- Constexpr functions for compile-time encoding/decoding - Validation of encoded data +- Support for little-endian and big-endian platforms ## Algorithm background From 763a181fc14b40518fcb484bc3ee3a5175970ed7 Mon Sep 17 00:00:00 2001 From: Timon Zijnge Date: Wed, 18 Mar 2026 17:36:32 +0100 Subject: [PATCH 44/46] Manchester big-endian support * QA --- .devcontainer/s390x/devcontainer.json | 2 +- docs/manchester.md | 2 +- test/test_manchester.cpp | 1 - 3 files changed, 2 insertions(+), 3 deletions(-) diff --git a/.devcontainer/s390x/devcontainer.json b/.devcontainer/s390x/devcontainer.json index 5abf76b0a..8b7f82355 100644 --- a/.devcontainer/s390x/devcontainer.json +++ b/.devcontainer/s390x/devcontainer.json @@ -15,7 +15,7 @@ "settings": { "cmake.sourceDirectory": "${workspaceFolder}/test", "cmake.configureArgs": [ - "-DCMAKE_TOOLCHAIN_FILE=/workspaces/etl/.devcontainer/s390x/toolchain-s390x.cmake", + "-DCMAKE_TOOLCHAIN_FILE=${workspaceFolder}/.devcontainer/s390x/toolchain-s390x.cmake", "-DBUILD_TESTS=ON", "-DNO_STL=OFF", "-DETL_CXX_STANDARD=17" diff --git a/docs/manchester.md b/docs/manchester.md index 15fc6ee9b..d73cb9581 100644 --- a/docs/manchester.md +++ b/docs/manchester.md @@ -15,7 +15,7 @@ Efficient Manchester encoding and decoding of data. The Manchester code represen - Span-based operations or chunk-based operations - Constexpr functions for compile-time encoding/decoding - Validation of encoded data -- Support for little-endian and big-endian platforms +- Chunked span I/O uses little-endian byte order for multi-byte chunks, independent of host platform endianness ## Algorithm background diff --git a/test/test_manchester.cpp b/test/test_manchester.cpp index 29fe9acb7..bd3574354 100644 --- a/test/test_manchester.cpp +++ b/test/test_manchester.cpp @@ -4,7 +4,6 @@ #include #include #include -#include #include SUITE(test_manchester) From 78eeb38ee0dc68c4c048a869f0705f8a4e556bfb Mon Sep 17 00:00:00 2001 From: Timon Zijnge Date: Wed, 18 Mar 2026 18:09:51 +0100 Subject: [PATCH 45/46] Manchester big-endian support * QA --- .devcontainer/s390x/Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.devcontainer/s390x/Dockerfile b/.devcontainer/s390x/Dockerfile index a4d643c5f..21a6289c9 100644 --- a/.devcontainer/s390x/Dockerfile +++ b/.devcontainer/s390x/Dockerfile @@ -7,7 +7,7 @@ ENV DEBIAN_FRONTEND=noninteractive # Install QEMU user-mode emulation and s390x cross-compilation tools RUN dpkg --add-architecture s390x && \ - apt-get update && apt-get install -y \ + apt-get update && apt-get install -y --no-install-recommends\ qemu-user-static \ qemu-user \ binfmt-support \ From 704563d69985ad1e513dd81c84237b57b81cd276 Mon Sep 17 00:00:00 2001 From: Timon Zijnge <47081647+tzijnge@users.noreply.github.com> Date: Fri, 20 Mar 2026 09:47:34 +0100 Subject: [PATCH 46/46] Enable testing with ctest with cross-compiler (#5) * Enable testing with ctest and with cross-compiler * Clean up includes in manchester.h --------- Co-authored-by: Timon Zijnge --- include/etl/manchester.h | 2 -- test/CMakeLists.txt | 3 ++- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/include/etl/manchester.h b/include/etl/manchester.h index f89141d3e..fd6e83b4d 100644 --- a/include/etl/manchester.h +++ b/include/etl/manchester.h @@ -32,10 +32,8 @@ SOFTWARE. #define ETL_MANCHESTER_INCLUDED #include "platform.h" -#include "endianness.h" #include "span.h" #include "static_assert.h" -#include ///\defgroup manchester manchester /// Manchester encoding and decoding diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 2bec78478..9a3bc89b8 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -524,8 +524,9 @@ target_include_directories(etl_tests add_subdirectory(UnitTest++) target_link_libraries(etl_tests PRIVATE UnitTestpp) +enable_testing() # Enable the 'make test' CMake target using the executable defined above -add_test(etl_unit_tests etl_tests) +add_test(NAME etl_unit_tests COMMAND etl_tests) # Since ctest will only show you the results of the single executable # define a target that will output all of the failing or passing tests