Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
50 commits
Select commit Hold shift + click to select a range
9d56214
manchester
Dec 17, 2025
c4f211a
manchester
Dec 17, 2025
724c5c9
manchester
Dec 17, 2025
fcc7c2f
manchester
Jan 6, 2026
718f15f
manchester
Jan 6, 2026
451fc1d
manchester
Jan 6, 2026
076fe5d
manchester
Jan 6, 2026
eefe86b
manchester
Jan 6, 2026
f224fbc
manchester
Jan 6, 2026
16f9bb8
manchester
Jan 6, 2026
0a6e349
manchester
Jan 6, 2026
49a9205
manchester
Jan 7, 2026
cfb93a0
manchester
Jan 7, 2026
ef6f408
manchester
Jan 7, 2026
53b28cc
manchester
Jan 7, 2026
1e42a5a
manchester
Jan 7, 2026
2746b11
manchester
Jan 7, 2026
fd391c4
manchester
Jan 7, 2026
bb6f6aa
manchester
Jan 7, 2026
eebf60c
manchester
Jan 8, 2026
5280502
manchester
Jan 12, 2026
ab4092e
manchester
Jan 20, 2026
99d3825
manchester
Jan 28, 2026
684e7cd
manchester
Jan 28, 2026
737c8ef
manchester
Jan 28, 2026
521b5db
Update test_manchester.cpp
tzijnge Jan 28, 2026
0dd2ebd
#1258 Manchester coding
Jan 28, 2026
f98283d
Merge branch 'master' into manchester
tzijnge Jan 28, 2026
482246f
#1258 Manchester coding
Feb 4, 2026
0d2f448
#1258 Manchester coding
Feb 4, 2026
c742792
#1258 Manchester coding
Feb 23, 2026
777f785
#1258 Manchester coding
Feb 23, 2026
d56a586
#1258 Manchester coding
Feb 23, 2026
71ab734
#1258 Manchester coding
Feb 27, 2026
69c7309
#1258 Manchester coding
Feb 27, 2026
fe34052
Merge branch 'master' into manchester
tzijnge Mar 3, 2026
f514725
#1324 Manchester documentation
Mar 3, 2026
a0c9866
Print test names at test time (#1343)
rolandreichweinbmw Mar 12, 2026
7469ed1
Merge branch 'ETLCPP:master' into manchester
tzijnge Mar 17, 2026
fd96291
IGN-280 biphasic amplitude as float
Mar 17, 2026
ac6f3a4
manchester
Mar 17, 2026
7581287
manchester
Mar 17, 2026
805dc2f
Merge branch 'development' into manchester-big-endian-support
Mar 18, 2026
88efa65
Manchester big-endian support
Mar 18, 2026
c2c1954
Manchester big-endian support
Mar 18, 2026
dd89b30
Enable running with ctest
tzijnge Mar 18, 2026
396a3de
Manchester big-endian support
Mar 18, 2026
763a181
Manchester big-endian support
Mar 18, 2026
78eeb38
Manchester big-endian support
Mar 18, 2026
704563d
Enable testing with ctest with cross-compiler (#5)
tzijnge Mar 20, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 40 additions & 0 deletions .devcontainer/s390x/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
# s390x Big-Endian Test Environment for ETL
# Uses QEMU user-mode emulation to run s390x binaries on x64 host
FROM debian:trixie

# Avoid prompts from apt
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 --no-install-recommends\
qemu-user-static \
qemu-user \
binfmt-support \
gcc-s390x-linux-gnu \
g++-s390x-linux-gnu \
cmake \
make \
ninja-build \
git \
wget \
file \
libc6:s390x \
libstdc++6:s390x \
&& rm -rf /var/lib/apt/lists/*

# Set working directory
WORKDIR /workspaces/etl

# Verify QEMU and cross-compilation setup
RUN echo "=== Host Architecture ===" && \
uname -m && \
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"]
29 changes: 29 additions & 0 deletions .devcontainer/s390x/devcontainer.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
// 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"
],
"settings": {
"cmake.sourceDirectory": "${workspaceFolder}/test",
"cmake.configureArgs": [
"-DCMAKE_TOOLCHAIN_FILE=${workspaceFolder}/.devcontainer/s390x/toolchain-s390x.cmake",
"-DBUILD_TESTS=ON",
"-DNO_STL=OFF",
"-DETL_CXX_STANDARD=17"
],
"cmake.buildDirectory": "${workspaceFolder}/build-s390x",
"cmake.generator": "Ninja"
}
}
},
"remoteUser": "root"
}
21 changes: 21 additions & 0 deletions .devcontainer/s390x/toolchain-s390x.cmake
Original file line number Diff line number Diff line change
@@ -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 CACHE FILEPATH "Path to the emulator for cross-compiled binaries")
3 changes: 2 additions & 1 deletion docs/manchester.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
- Chunked span I/O uses little-endian byte order for multi-byte chunks, independent of host platform endianness

## Algorithm background

Expand Down
151 changes: 41 additions & 110 deletions include/etl/manchester.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,10 +32,8 @@ SOFTWARE.
#define ETL_MANCHESTER_INCLUDED

#include "platform.h"
#include "endianness.h"
#include "span.h"
#include "static_assert.h"
#include <cstring>

///\defgroup manchester manchester
/// Manchester encoding and decoding
Expand Down Expand Up @@ -172,18 +170,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 <typename T>
static ETL_CONSTEXPR14 T read_little_endian(etl::span<const uint_least8_t> 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<T>(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 <typename T>
static ETL_CONSTEXPR14 void write_little_endian(etl::span<uint_least8_t> bytes, size_t index, T value)
{
for (size_t j = 0; j < sizeof(T); ++j)
{
bytes[index + j] = static_cast<uint_least8_t>(value >> (j * CHAR_BIT));
}
}
} // namespace private_manchester

Expand Down Expand Up @@ -297,44 +314,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 <typename TChunk>
static typename etl::enable_if<!etl::is_same<TChunk, uint_least8_t>::value, void>::type
encode(etl::span<const uint_least8_t> decoded, etl::span<uint_least8_t> encoded)
{
typedef TChunk TDecoded;
typedef typename etl::private_manchester::encoded<TChunk>::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 <typename TChunk = uint_least8_t>
static ETL_CONSTEXPR14 typename etl::enable_if<etl::is_same<TChunk, uint_least8_t>::value, void>::type encode(etl::span<const uint_least8_t> decoded, etl::span<uint_least8_t> encoded)
static ETL_CONSTEXPR14 void encode(etl::span<const uint_least8_t> decoded, etl::span<uint_least8_t> encoded)
{
typedef TChunk TDecoded;
typedef typename etl::private_manchester::encoded<TChunk>::type TEncoded;
Expand All @@ -346,17 +332,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<uint_least8_t>(encoded_value);
encoded[dest_index + 1] = static_cast<uint_least8_t>(encoded_value >> CHAR_BIT);
}
else
{
encoded[dest_index] = static_cast<uint_least8_t>(encoded_value >> CHAR_BIT);
encoded[dest_index + 1] = static_cast<uint_least8_t>(encoded_value);
}
const TDecoded decoded_value = private_manchester::read_little_endian<TDecoded>(decoded, source_index);
const TEncoded encoded_value = encode(decoded_value);
private_manchester::write_little_endian<TEncoded>(encoded, dest_index, encoded_value);

source_index += sizeof(TDecoded);
dest_index += sizeof(TEncoded);
Expand Down Expand Up @@ -426,14 +404,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 <typename TChunk>
static typename etl::enable_if<!etl::is_same<TChunk, typename private_manchester::encoded<uint_least8_t>::type>::value, void>::type
decode(etl::span<const uint_least8_t> encoded, etl::span<uint_least8_t> decoded)
template <typename TChunk = typename private_manchester::encoded<uint_least8_t>::type>
static ETL_CONSTEXPR14 void decode(etl::span<const uint_least8_t> encoded, etl::span<uint_least8_t> decoded)
{
typedef typename private_manchester::decoded<TChunk>::type TDecoded;
typedef TChunk TEncoded;
Expand All @@ -445,53 +422,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<TEncoded>(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<TDecoded>(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 <typename TChunk = typename private_manchester::encoded<uint_least8_t>::type>
static ETL_CONSTEXPR14 typename etl::enable_if<etl::is_same<TChunk, typename private_manchester::encoded<uint_least8_t>::type>::value, void>::type
decode(etl::span<const uint_least8_t> encoded, etl::span<uint_least8_t> 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<TChunk>((encoded[source_index + 1] << CHAR_BIT) | encoded[source_index]);
}
else
{
encoded_value = static_cast<TChunk>((encoded[source_index] << CHAR_BIT) | encoded[source_index + 1]);
}

decoded[dest_index] = decode<TChunk>(encoded_value);

source_index += sizeof(TChunk);
dest_index += sizeof(TDecoded);
}
}

//*************************************************************************
// Validation functions
//*************************************************************************
Expand Down Expand Up @@ -521,15 +460,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<uint16_t>((encoded[i + 1] << CHAR_BIT) | encoded[i]);
}
else
{
chunk = static_cast<uint16_t>((encoded[i] << CHAR_BIT) | encoded[i + 1]);
}
const uint16_t chunk = private_manchester::read_little_endian<uint16_t>(encoded, i);

if (!is_valid<uint16_t>(chunk))
{
Expand Down
3 changes: 2 additions & 1 deletion test/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Loading
Loading