31#ifndef ETL_MANCHESTER_INCLUDED
32#define ETL_MANCHESTER_INCLUDED
36#include "static_assert.h"
46 namespace private_manchester
52 template <
typename TChunk>
55 static const bool value =
56 #if ETL_USING_8BIT_TYPES
57 etl::is_same<TChunk, uint8_t>::value ||
59 etl::is_same<TChunk, uint16_t>::value
60 #if ETL_USING_64BIT_TYPES
61 || etl::is_same<TChunk, uint32_t>::value
70 template <
typename TChunk>
73 static const bool value =
74 #if ETL_USING_8BIT_TYPES
75 etl::is_same<TChunk, uint16_t>::value ||
77 etl::is_same<TChunk, uint32_t>::value
78 #if ETL_USING_64BIT_TYPES
79 || etl::is_same<TChunk, uint64_t>::value
93 ETL_STATIC_ASSERT(
sizeof(T) == 0,
"Manchester encoding type should be one of [uint8_t, uint16_t, uint32_t]");
96 #if ETL_USING_8BIT_TYPES
98 struct encoded<uint8_t>
100 typedef uint16_t type;
105 struct encoded<uint16_t>
107 typedef uint32_t type;
110 #if ETL_USING_64BIT_TYPES
112 struct encoded<uint32_t>
114 typedef uint64_t type;
124 template <
typename T>
127 ETL_STATIC_ASSERT(
sizeof(T) == 0,
"Manchester decoding type should be one of [uint16_t, uint32_t, uint64_t]");
130 #if ETL_USING_64BIT_TYPES
132 struct decoded<uint16_t>
134 typedef uint8_t type;
139 struct decoded<uint32_t>
141 typedef uint16_t type;
144 #if ETL_USING_64BIT_TYPES
146 struct decoded<uint64_t>
148 typedef uint32_t type;
155 struct manchester_type_normal
157 #if ETL_USING_64BIT_TYPES
158 static const uint64_t inversion_mask = 0x0000000000000000ULL;
160 static const uint32_t inversion_mask = 0x00000000UL;
167 struct manchester_type_inverted
169 #if ETL_USING_64BIT_TYPES
170 static const uint64_t inversion_mask = 0xFFFFFFFFFFFFFFFFULL;
172 static const uint32_t inversion_mask = 0xFFFFFFFFUL;
183 template <
typename T>
184 static ETL_CONSTEXPR14 T read_little_endian(etl::span<const uint_least8_t> bytes,
size_t index)
187 for (
size_t j = 0; j <
sizeof(T); ++j)
189 value |=
static_cast<T
>(bytes[index + j]) << (j * CHAR_BIT);
201 template <
typename T>
202 static ETL_CONSTEXPR14
void write_little_endian(etl::span<uint_least8_t> bytes,
size_t index, T value)
204 for (
size_t j = 0; j <
sizeof(T); ++j)
206 bytes[index + j] =
static_cast<uint_least8_t
>(value >> (j * CHAR_BIT));
214 class manchester_exception :
public etl::exception
218 manchester_exception(string_type reason_, string_type file_name_, numeric_type line_number_)
219 : exception(reason_, file_name_, line_number_)
227 class manchester_invalid_size :
public etl::manchester_exception
231 manchester_invalid_size(string_type file_name_, numeric_type line_number_)
232 : etl::manchester_exception(
"manchester:size", file_name_, line_number_)
242 template <
typename TManchesterType>
243 struct manchester_base
245 ETL_STATIC_ASSERT((etl::is_same<TManchesterType, private_manchester::manchester_type_normal>::value
246 || etl::is_same<TManchesterType, private_manchester::manchester_type_inverted>::value),
247 "TManchesterType must be manchester_type_normal or manchester_type_inverted");
249 ETL_STATIC_ASSERT(CHAR_BIT == etl::numeric_limits<uint_least8_t>::digits,
250 "Manchester requires uint_least8_t to have the same number of bits as CHAR (CHAR_BITS)");
256 #if ETL_USING_8BIT_TYPES
262 template <
typename TDecoded>
264 ETL_CONSTEXPR14
typename etl::enable_if< etl::is_same<TDecoded, uint8_t>::value,
typename private_manchester::encoded<TDecoded>::type>::type
265 encode(TDecoded decoded)
267 typedef typename private_manchester::encoded<TDecoded>::type TEncoded;
269 TEncoded encoded = decoded;
271 encoded =
static_cast<TEncoded
>((
static_cast<unsigned int>(encoded) | (
static_cast<unsigned int>(encoded) << 4U)) & 0x0F0FU);
272 encoded =
static_cast<TEncoded
>((
static_cast<unsigned int>(encoded) | (
static_cast<unsigned int>(encoded) << 2U)) & 0x3333U);
273 encoded =
static_cast<TEncoded
>((
static_cast<unsigned int>(encoded) | (
static_cast<unsigned int>(encoded) << 1U)) & 0x5555U);
274 encoded =
static_cast<TEncoded
>((
static_cast<unsigned int>(encoded) | (
static_cast<unsigned int>(encoded) << 1U))
275 ^ (0xAAAAU ^
static_cast<unsigned int>(TManchesterType::inversion_mask)));
285 template <
typename TDecoded>
287 ETL_CONSTEXPR14
typename etl::enable_if< etl::is_same<TDecoded, uint16_t>::value,
typename private_manchester::encoded<TDecoded>::type>::type
288 encode(TDecoded decoded)
290 typedef typename private_manchester::encoded<TDecoded>::type TEncoded;
292 TEncoded encoded = decoded;
294 encoded = (encoded | (encoded << 8U)) & 0x00FF00FFUL;
295 encoded = (encoded | (encoded << 4U)) & 0x0F0F0F0FUL;
296 encoded = (encoded | (encoded << 2U)) & 0x33333333UL;
297 encoded = (encoded | (encoded << 1U)) & 0x55555555UL;
298 encoded = (encoded | (encoded << 1U)) ^ (0xAAAAAAAAUL ^ static_cast<TEncoded>(TManchesterType::inversion_mask));
302 #if ETL_USING_64BIT_TYPES
308 template <
typename TDecoded>
310 ETL_CONSTEXPR14
typename etl::enable_if< etl::is_same<TDecoded, uint32_t>::value,
typename private_manchester::encoded<TDecoded>::type>::type
311 encode(TDecoded decoded)
313 typedef typename private_manchester::encoded<TDecoded>::type TEncoded;
315 TEncoded encoded = decoded;
317 encoded = (encoded | (encoded << 16U)) & 0x0000FFFF0000FFFFULL;
318 encoded = (encoded | (encoded << 8U)) & 0x00FF00FF00FF00FFULL;
319 encoded = (encoded | (encoded << 4U)) & 0x0F0F0F0F0F0F0F0FULL;
320 encoded = (encoded | (encoded << 2U)) & 0x3333333333333333ULL;
321 encoded = (encoded | (encoded << 1U)) & 0x5555555555555555ULL;
322 encoded = (encoded | (encoded << 1U)) ^ (0xAAAAAAAAAAAAAAAAULL ^ TManchesterType::inversion_mask);
333 template <
typename TChunk = u
int_least8_t>
334 static ETL_CONSTEXPR14
void encode(etl::span<const uint_least8_t> decoded, etl::span<uint_least8_t> encoded)
336 typedef TChunk TDecoded;
337 typedef typename etl::private_manchester::encoded<TChunk>::type TEncoded;
340 ETL_ASSERT(decoded.
size() %
sizeof(TDecoded) == 0, ETL_ERROR(manchester_invalid_size));
342 size_t dest_index = 0;
343 size_t source_index = 0;
344 for (
size_t i = 0; i < decoded.
size() /
sizeof(TDecoded); ++i)
346 const TDecoded decoded_value = private_manchester::read_little_endian<TDecoded>(decoded, source_index);
347 const TEncoded encoded_value = encode(decoded_value);
348 private_manchester::write_little_endian<TEncoded>(encoded, dest_index, encoded_value);
350 source_index +=
sizeof(TDecoded);
351 dest_index +=
sizeof(TEncoded);
359 #if ETL_USING_8BIT_TYPES
365 template <
typename TEncoded>
367 ETL_CONSTEXPR14
typename etl::enable_if< etl::is_same<TEncoded, uint16_t>::value,
typename private_manchester::decoded<TEncoded>::type>::type
368 decode(TEncoded encoded)
370 typedef typename private_manchester::decoded<TEncoded>::type TDecoded;
372 encoded =
static_cast<TEncoded
>((
static_cast<unsigned int>(encoded) ^ (0xAAAAU ^
static_cast<unsigned int>(TManchesterType::inversion_mask)))
374 encoded =
static_cast<TEncoded
>((
static_cast<unsigned int>(encoded) | (
static_cast<unsigned int>(encoded) >> 1)) & 0x3333U);
375 encoded =
static_cast<TEncoded
>((
static_cast<unsigned int>(encoded) | (
static_cast<unsigned int>(encoded) >> 2)) & 0x0F0FU);
376 return static_cast<TDecoded
>(
static_cast<unsigned int>(encoded) | (
static_cast<unsigned int>(encoded) >> 4U));
385 template <
typename TEncoded>
387 ETL_CONSTEXPR14
typename etl::enable_if< etl::is_same<TEncoded, uint32_t>::value,
typename private_manchester::decoded<TEncoded>::type>::type
388 decode(TEncoded encoded)
390 typedef typename private_manchester::decoded<TEncoded>::type TDecoded;
392 encoded = (encoded ^ (0xAAAAAAAAUL ^
static_cast<TEncoded
>(TManchesterType::inversion_mask))) & 0x55555555UL;
393 encoded = (encoded | (encoded >> 1)) & 0x33333333UL;
394 encoded = (encoded | (encoded >> 2)) & 0x0F0F0F0FUL;
395 encoded = (encoded | (encoded >> 4)) & 0x00FF00FFUL;
396 return static_cast<TDecoded
>(encoded | (encoded >> 8U));
399 #if ETL_USING_64BIT_TYPES
405 template <
typename TEncoded>
407 ETL_CONSTEXPR14
typename etl::enable_if< etl::is_same<TEncoded, uint64_t>::value,
typename private_manchester::decoded<TEncoded>::type>::type
408 decode(TEncoded encoded)
410 typedef typename private_manchester::decoded<TEncoded>::type TDecoded;
412 encoded = (encoded ^ (0xAAAAAAAAAAAAAAAAULL ^ TManchesterType::inversion_mask)) & 0x5555555555555555ULL;
413 encoded = (encoded | (encoded >> 1)) & 0x3333333333333333ULL;
414 encoded = (encoded | (encoded >> 2)) & 0x0F0F0F0F0F0F0F0FULL;
415 encoded = (encoded | (encoded >> 4)) & 0x00FF00FF00FF00FFULL;
416 encoded = (encoded | (encoded >> 8)) & 0x0000FFFF0000FFFFULL;
417 return static_cast<TDecoded
>(encoded | (encoded >> 16U));
427 template <typename TChunk = typename private_manchester::encoded<uint_least8_t>::type>
428 static ETL_CONSTEXPR14
void decode(etl::span<const uint_least8_t> encoded, etl::span<uint_least8_t> decoded)
430 typedef typename private_manchester::decoded<TChunk>::type TDecoded;
431 typedef TChunk TEncoded;
434 ETL_ASSERT(encoded.
size() %
sizeof(TChunk) == 0, ETL_ERROR(manchester_invalid_size));
436 size_t dest_index = 0;
437 size_t source_index = 0;
438 for (
size_t i = 0; i < encoded.
size() /
sizeof(TEncoded); ++i)
440 const TEncoded encoded_value = private_manchester::read_little_endian<TEncoded>(encoded, source_index);
441 const TDecoded decoded_value = decode(encoded_value);
442 private_manchester::write_little_endian<TDecoded>(decoded, dest_index, decoded_value);
444 source_index +=
sizeof(TEncoded);
445 dest_index +=
sizeof(TDecoded);
458 template <
typename TChunk>
460 static ETL_CONSTEXPR14
typename etl::enable_if<private_manchester::is_decodable<TChunk>::value,
bool>::type is_valid(TChunk encoded)
462 const TChunk mask =
static_cast<TChunk
>(0x5555555555555555ULL);
463 return (((encoded ^ (encoded >> 1)) & mask) == mask);
472 static ETL_CONSTEXPR14
bool is_valid(etl::span<const uint_least8_t> encoded)
474 ETL_ASSERT(encoded.
size() %
sizeof(uint16_t) == 0, ETL_ERROR(manchester_invalid_size));
476 for (
size_t i = 0; i < encoded.
size(); i +=
sizeof(uint16_t))
478 const uint16_t chunk = private_manchester::read_little_endian<uint16_t>(encoded, i);
480 if (!is_valid<uint16_t>(chunk))
494 typedef manchester_base<private_manchester::manchester_type_normal> manchester;
500 typedef manchester_base<private_manchester::manchester_type_inverted> manchester_inverted;
ETL_NODISCARD ETL_CONSTEXPR size_t size() const ETL_NOEXCEPT
Returns the size of the span.
Definition span.h:564
#define ETL_ASSERT(b, e)
Definition error_handler.h:511