Embedded Template Library 1.0
Loading...
Searching...
No Matches
manchester.h
Go to the documentation of this file.
1
2
3/******************************************************************************
4The MIT License(MIT)
5
6Embedded Template Library.
7https://github.com/ETLCPP/etl
8https://www.etlcpp.com
9
10Copyright(c) 2026 John Wellbelove
11
12Permission is hereby granted, free of charge, to any person obtaining a copy
13of this software and associated documentation files(the "Software"), to deal
14in the Software without restriction, including without limitation the rights
15to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
16copies of the Software, and to permit persons to whom the Software is
17furnished to do so, subject to the following conditions :
18
19The above copyright notice and this permission notice shall be included in all
20copies or substantial portions of the Software.
21
22THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
23IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
24FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
25AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
26LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
27OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
28SOFTWARE.
29******************************************************************************/
30
31#ifndef ETL_MANCHESTER_INCLUDED
32#define ETL_MANCHESTER_INCLUDED
33
34#include "platform.h"
35#include "span.h"
36#include "static_assert.h"
37
38#if ETL_USING_CPP11
39
43
44namespace etl
45{
46 namespace private_manchester
47 {
48 //*************************************************************************
51 //*************************************************************************
52 template <typename TChunk>
53 struct is_encodable
54 {
55 static const bool value =
56 #if ETL_USING_8BIT_TYPES
57 etl::is_same<TChunk, uint8_t>::value ||
58 #endif
59 etl::is_same<TChunk, uint16_t>::value
60 #if ETL_USING_64BIT_TYPES
61 || etl::is_same<TChunk, uint32_t>::value
62 #endif
63 ;
64 };
65
66 //*************************************************************************
69 //*************************************************************************
70 template <typename TChunk>
71 struct is_decodable
72 {
73 static const bool value =
74 #if ETL_USING_8BIT_TYPES
75 etl::is_same<TChunk, uint16_t>::value ||
76 #endif
77 etl::is_same<TChunk, uint32_t>::value
78 #if ETL_USING_64BIT_TYPES
79 || etl::is_same<TChunk, uint64_t>::value
80 #endif
81 ;
82 };
83
84 //*************************************************************************
89 //*************************************************************************
90 template <typename T>
91 struct encoded
92 {
93 ETL_STATIC_ASSERT(sizeof(T) == 0, "Manchester encoding type should be one of [uint8_t, uint16_t, uint32_t]");
94 };
95
96 #if ETL_USING_8BIT_TYPES
97 template <>
98 struct encoded<uint8_t>
99 {
100 typedef uint16_t type;
101 };
102 #endif
103
104 template <>
105 struct encoded<uint16_t>
106 {
107 typedef uint32_t type;
108 };
109
110 #if ETL_USING_64BIT_TYPES
111 template <>
112 struct encoded<uint32_t>
113 {
114 typedef uint64_t type;
115 };
116 #endif
117
118 //*************************************************************************
123 //*************************************************************************
124 template <typename T>
125 struct decoded
126 {
127 ETL_STATIC_ASSERT(sizeof(T) == 0, "Manchester decoding type should be one of [uint16_t, uint32_t, uint64_t]");
128 };
129
130 #if ETL_USING_64BIT_TYPES
131 template <>
132 struct decoded<uint16_t>
133 {
134 typedef uint8_t type;
135 };
136 #endif
137
138 template <>
139 struct decoded<uint32_t>
140 {
141 typedef uint16_t type;
142 };
143
144 #if ETL_USING_64BIT_TYPES
145 template <>
146 struct decoded<uint64_t>
147 {
148 typedef uint32_t type;
149 };
150 #endif
151
152 //*************************************************************************
154 //*************************************************************************
155 struct manchester_type_normal
156 {
157 #if ETL_USING_64BIT_TYPES
158 static const uint64_t inversion_mask = 0x0000000000000000ULL;
159 #else
160 static const uint32_t inversion_mask = 0x00000000UL;
161 #endif
162 };
163
164 //*************************************************************************
166 //*************************************************************************
167 struct manchester_type_inverted
168 {
169 #if ETL_USING_64BIT_TYPES
170 static const uint64_t inversion_mask = 0xFFFFFFFFFFFFFFFFULL;
171 #else
172 static const uint32_t inversion_mask = 0xFFFFFFFFUL;
173 #endif
174 };
175
176 //*************************************************************************
182 //*************************************************************************
183 template <typename T>
184 static ETL_CONSTEXPR14 T read_little_endian(etl::span<const uint_least8_t> bytes, size_t index)
185 {
186 T value = 0;
187 for (size_t j = 0; j < sizeof(T); ++j)
188 {
189 value |= static_cast<T>(bytes[index + j]) << (j * CHAR_BIT);
190 }
191 return value;
192 }
193
194 //*************************************************************************
200 //*************************************************************************
201 template <typename T>
202 static ETL_CONSTEXPR14 void write_little_endian(etl::span<uint_least8_t> bytes, size_t index, T value)
203 {
204 for (size_t j = 0; j < sizeof(T); ++j)
205 {
206 bytes[index + j] = static_cast<uint_least8_t>(value >> (j * CHAR_BIT));
207 }
208 }
209 } // namespace private_manchester
210
211 //***************************************************************************
213 //***************************************************************************
214 class manchester_exception : public etl::exception
215 {
216 public:
217
218 manchester_exception(string_type reason_, string_type file_name_, numeric_type line_number_)
219 : exception(reason_, file_name_, line_number_)
220 {
221 }
222 };
223
224 //***************************************************************************
226 //***************************************************************************
227 class manchester_invalid_size : public etl::manchester_exception
228 {
229 public:
230
231 manchester_invalid_size(string_type file_name_, numeric_type line_number_)
232 : etl::manchester_exception("manchester:size", file_name_, line_number_)
233 {
234 }
235 };
236
237 //***************************************************************************
241 //***************************************************************************
242 template <typename TManchesterType>
243 struct manchester_base
244 {
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");
248
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)");
251
252 //*************************************************************************
253 // Encoding functions
254 //*************************************************************************
255
256 #if ETL_USING_8BIT_TYPES
257 //*************************************************************************
261 //*************************************************************************
262 template <typename TDecoded>
263 static
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)
266 {
267 typedef typename private_manchester::encoded<TDecoded>::type TEncoded;
268
269 TEncoded encoded = decoded;
270
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)));
276 return encoded;
277 }
278 #endif
279
280 //*************************************************************************
284 //*************************************************************************
285 template <typename TDecoded>
286 static
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)
289 {
290 typedef typename private_manchester::encoded<TDecoded>::type TEncoded;
291
292 TEncoded encoded = decoded;
293
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));
299 return encoded;
300 }
301
302 #if ETL_USING_64BIT_TYPES
303 //*************************************************************************
307 //*************************************************************************
308 template <typename TDecoded>
309 static
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)
312 {
313 typedef typename private_manchester::encoded<TDecoded>::type TEncoded;
314
315 TEncoded encoded = decoded;
316
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);
323 return encoded;
324 }
325 #endif
326
327 //*************************************************************************
332 //*************************************************************************
333 template <typename TChunk = uint_least8_t>
334 static ETL_CONSTEXPR14 void encode(etl::span<const uint_least8_t> decoded, etl::span<uint_least8_t> encoded)
335 {
336 typedef TChunk TDecoded;
337 typedef typename etl::private_manchester::encoded<TChunk>::type TEncoded;
338
339 ETL_ASSERT(encoded.size() >= decoded.size() * 2, ETL_ERROR(manchester_invalid_size));
340 ETL_ASSERT(decoded.size() % sizeof(TDecoded) == 0, ETL_ERROR(manchester_invalid_size));
341
342 size_t dest_index = 0;
343 size_t source_index = 0;
344 for (size_t i = 0; i < decoded.size() / sizeof(TDecoded); ++i)
345 {
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);
349
350 source_index += sizeof(TDecoded);
351 dest_index += sizeof(TEncoded);
352 }
353 }
354
355 //*************************************************************************
356 // Decoding functions
357 //*************************************************************************
358
359 #if ETL_USING_8BIT_TYPES
360 //*************************************************************************
364 //*************************************************************************
365 template <typename TEncoded>
366 static
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)
369 {
370 typedef typename private_manchester::decoded<TEncoded>::type TDecoded;
371
372 encoded = static_cast<TEncoded>((static_cast<unsigned int>(encoded) ^ (0xAAAAU ^ static_cast<unsigned int>(TManchesterType::inversion_mask)))
373 & 0x5555U);
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));
377 }
378 #endif
379
380 //*************************************************************************
384 //*************************************************************************
385 template <typename TEncoded>
386 static
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)
389 {
390 typedef typename private_manchester::decoded<TEncoded>::type TDecoded;
391
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));
397 }
398
399 #if ETL_USING_64BIT_TYPES
400 //*************************************************************************
404 //*************************************************************************
405 template <typename TEncoded>
406 static
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)
409 {
410 typedef typename private_manchester::decoded<TEncoded>::type TDecoded;
411
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));
418 }
419 #endif
420
421 //*************************************************************************
426 //*************************************************************************
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)
429 {
430 typedef typename private_manchester::decoded<TChunk>::type TDecoded;
431 typedef TChunk TEncoded;
432
433 ETL_ASSERT(decoded.size() * 2 >= encoded.size(), ETL_ERROR(manchester_invalid_size));
434 ETL_ASSERT(encoded.size() % sizeof(TChunk) == 0, ETL_ERROR(manchester_invalid_size));
435
436 size_t dest_index = 0;
437 size_t source_index = 0;
438 for (size_t i = 0; i < encoded.size() / sizeof(TEncoded); ++i)
439 {
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);
443
444 source_index += sizeof(TEncoded);
445 dest_index += sizeof(TDecoded);
446 }
447 }
448
449 //*************************************************************************
450 // Validation functions
451 //*************************************************************************
452
453 //*************************************************************************
457 //*************************************************************************
458 template <typename TChunk>
459 ETL_NODISCARD
460 static ETL_CONSTEXPR14 typename etl::enable_if<private_manchester::is_decodable<TChunk>::value, bool>::type is_valid(TChunk encoded)
461 {
462 const TChunk mask = static_cast<TChunk>(0x5555555555555555ULL);
463 return (((encoded ^ (encoded >> 1)) & mask) == mask);
464 }
465
466 //*************************************************************************
470 //*************************************************************************
471 ETL_NODISCARD
472 static ETL_CONSTEXPR14 bool is_valid(etl::span<const uint_least8_t> encoded)
473 {
474 ETL_ASSERT(encoded.size() % sizeof(uint16_t) == 0, ETL_ERROR(manchester_invalid_size));
475
476 for (size_t i = 0; i < encoded.size(); i += sizeof(uint16_t))
477 {
478 const uint16_t chunk = private_manchester::read_little_endian<uint16_t>(encoded, i);
479
480 if (!is_valid<uint16_t>(chunk))
481 {
482 return false;
483 }
484 }
485
486 return true;
487 }
488 };
489
490 //***************************************************************************
493 //***************************************************************************
494 typedef manchester_base<private_manchester::manchester_type_normal> manchester;
495
496 //***************************************************************************
499 //***************************************************************************
500 typedef manchester_base<private_manchester::manchester_type_inverted> manchester_inverted;
501
502} // namespace etl
503
504#endif
505#endif
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
Definition absolute.h:40