| 
									
										
										
										
											2022-07-20 07:07:00 +00:00
										 |  |  | // Copyright 2020 Mobilinkd LLC.
 | 
					
						
							| 
									
										
										
										
											2022-06-07 01:22:18 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | #pragma once
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include <algorithm>
 | 
					
						
							|  |  |  | #include <cstdlib>
 | 
					
						
							| 
									
										
										
										
											2022-07-31 02:24:03 +00:00
										 |  |  | #include <cstdint>
 | 
					
						
							| 
									
										
										
										
											2022-06-07 01:22:18 +00:00
										 |  |  | #include <cassert>
 | 
					
						
							|  |  |  | #include <array>
 | 
					
						
							|  |  |  | #include <bitset>
 | 
					
						
							|  |  |  | #include <tuple>
 | 
					
						
							|  |  |  | #include <limits>
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-07-04 21:03:07 +00:00
										 |  |  | namespace modemm17 | 
					
						
							| 
									
										
										
										
											2022-06-07 01:22:18 +00:00
										 |  |  | { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // The make_bitset stuff only works as expected in GCC10 and later.
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | namespace detail { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /**
 | 
					
						
							|  |  |  |  * This is the max value for the LLR based on size N. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | template <size_t N> | 
					
						
							|  |  |  | constexpr size_t llr_limit() | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     return (1 << (N - 1)) - 1; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /**
 | 
					
						
							|  |  |  |  * There are (2^(N-1)-1) elements (E) per segment (e.g. N=4, E=7; N=3, E=3). | 
					
						
							|  |  |  |  * These contain the LLR values 1..E. There are 6 segments in the LLR map: | 
					
						
							|  |  |  |  *  1. (-Inf,-2] | 
					
						
							|  |  |  |  *  2. (-2, -1] | 
					
						
							|  |  |  |  *  3. (-1, 0] | 
					
						
							|  |  |  |  *  4. (0, 1] | 
					
						
							|  |  |  |  *  5. (1, 2] | 
					
						
							|  |  |  |  *  6. (2, Inf) | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * Note the slight asymmetry.  This is OK as we are dealing with floats and | 
					
						
							|  |  |  |  * it only matters to an epsilon of the float type. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | template <size_t N> | 
					
						
							|  |  |  | constexpr size_t llr_size() | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     return llr_limit<N>() * 6 + 1; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-06-09 18:12:35 +00:00
										 |  |  | template<size_t LLR> | 
					
						
							|  |  |  | constexpr std::array<std::tuple<float, std::tuple<int8_t, int8_t>>, llr_size<LLR>()> make_llr_map() | 
					
						
							| 
									
										
										
										
											2022-06-07 01:22:18 +00:00
										 |  |  | { | 
					
						
							|  |  |  |     constexpr size_t size = llr_size<LLR>(); | 
					
						
							| 
									
										
										
										
											2022-06-09 18:12:35 +00:00
										 |  |  |     std::array<std::tuple<float, std::tuple<int8_t, int8_t>>, size> result; | 
					
						
							| 
									
										
										
										
											2022-06-07 01:22:18 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     constexpr int8_t limit = llr_limit<LLR>(); | 
					
						
							| 
									
										
										
										
											2022-06-09 18:12:35 +00:00
										 |  |  |     constexpr float inc = 1.0 / float(limit); | 
					
						
							| 
									
										
										
										
											2022-06-07 01:22:18 +00:00
										 |  |  |     int8_t i = limit; | 
					
						
							|  |  |  |     int8_t j = limit; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // Output must be ordered by k, ascending.
 | 
					
						
							| 
									
										
										
										
											2022-06-09 18:12:35 +00:00
										 |  |  |     float k = -3.0 + inc; | 
					
						
							| 
									
										
										
										
											2022-06-07 01:22:18 +00:00
										 |  |  |     for (size_t index = 0; index != size; ++index) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         auto& a = result[index]; | 
					
						
							|  |  |  |         std::get<0>(a) = k; | 
					
						
							|  |  |  |         std::get<0>(std::get<1>(a)) = i; | 
					
						
							|  |  |  |         std::get<1>(std::get<1>(a)) = j; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if (k + 1.0 < 0) | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |             j--; | 
					
						
							|  |  |  |             if (j == 0) j = -1; | 
					
						
							|  |  |  |             if (j < -limit) j = -limit; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         else if (k - 1.0 < 0) | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |             i--; | 
					
						
							|  |  |  |             if (i == 0) i = -1; | 
					
						
							|  |  |  |             if (i < -limit) i = -limit; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         else | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |             j++; | 
					
						
							|  |  |  |             if (j == 0) j = 1; | 
					
						
							|  |  |  |             if (j > limit) j = limit; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         k += inc; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     return result; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-07-20 07:57:59 +00:00
										 |  |  | // template<class...Bools>
 | 
					
						
							|  |  |  | // constexpr auto make_bitset(Bools&&...bools)
 | 
					
						
							|  |  |  | // {
 | 
					
						
							|  |  |  | //     return detail::make_bitset(std::make_index_sequence<sizeof...(Bools)>(),
 | 
					
						
							|  |  |  | //         std::make_tuple(bool(bools)...));
 | 
					
						
							|  |  |  | // }
 | 
					
						
							| 
									
										
										
										
											2022-06-07 01:22:18 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | inline int from_4fsk(int symbol) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     // Convert a 4-FSK symbol to a pair of bits.
 | 
					
						
							|  |  |  |     switch (symbol) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         case 1: return 0; | 
					
						
							|  |  |  |         case 3: return 1; | 
					
						
							|  |  |  |         case -1: return 2; | 
					
						
							|  |  |  |         case -3: return 3; | 
					
						
							|  |  |  |         default: abort(); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-06-09 18:12:35 +00:00
										 |  |  | template <size_t LLR> | 
					
						
							|  |  |  | auto llr(float sample) | 
					
						
							| 
									
										
										
										
											2022-06-07 01:22:18 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2022-06-09 18:12:35 +00:00
										 |  |  |     static auto symbol_map = detail::make_llr_map<LLR>(); | 
					
						
							|  |  |  |     static constexpr float MAX_VALUE = 3.0; | 
					
						
							|  |  |  |     static constexpr float MIN_VALUE = -3.0; | 
					
						
							| 
									
										
										
										
											2022-06-07 01:22:18 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-06-09 18:12:35 +00:00
										 |  |  |     float s = std::min(MAX_VALUE, std::max(MIN_VALUE, sample)); | 
					
						
							| 
									
										
										
										
											2022-06-07 01:22:18 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     auto it = std::lower_bound(symbol_map.begin(), symbol_map.end(), s, | 
					
						
							| 
									
										
										
										
											2022-06-09 18:12:35 +00:00
										 |  |  |         [](std::tuple<float, std::tuple<int8_t, int8_t>> const& e, float s){ | 
					
						
							| 
									
										
										
										
											2022-06-07 01:22:18 +00:00
										 |  |  |             return std::get<0>(e) < s; | 
					
						
							|  |  |  |         }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (it == symbol_map.end()) return std::get<1>(*symbol_map.rbegin()); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return std::get<1>(*it); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-09-06 20:10:25 +00:00
										 |  |  | template <size_t IN1, size_t OUT1, size_t P> | 
					
						
							|  |  |  | size_t depuncture( // FIXED: MSVC (MULTIPLE DEFINITIONS SAME TEMPLATE)
 | 
					
						
							|  |  |  |     const std::array<int8_t, IN1>& in, | 
					
						
							|  |  |  |     std::array<int8_t, OUT1>& out, | 
					
						
							| 
									
										
										
										
											2022-08-02 21:42:50 +00:00
										 |  |  |     const std::array<int8_t, P>& p | 
					
						
							|  |  |  | ) | 
					
						
							| 
									
										
										
										
											2022-06-07 01:22:18 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2022-08-02 21:42:50 +00:00
										 |  |  |     size_t index = 0; | 
					
						
							|  |  |  |     size_t pindex = 0; | 
					
						
							|  |  |  |     size_t bit_count = 0; | 
					
						
							| 
									
										
										
										
											2022-09-06 20:10:25 +00:00
										 |  |  |     for (size_t i = 0; i != OUT1 && index < IN1; ++i) | 
					
						
							| 
									
										
										
										
											2022-06-07 01:22:18 +00:00
										 |  |  |     { | 
					
						
							| 
									
										
										
										
											2022-08-02 21:42:50 +00:00
										 |  |  |         if (!p[pindex++]) | 
					
						
							| 
									
										
										
										
											2022-06-07 01:22:18 +00:00
										 |  |  |         { | 
					
						
							| 
									
										
										
										
											2022-08-02 21:42:50 +00:00
										 |  |  |             out[i] = 0; | 
					
						
							|  |  |  |             bit_count++; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         else | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |             out[i] = in[index++]; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         if (pindex == P) { | 
					
						
							|  |  |  |             pindex = 0; | 
					
						
							| 
									
										
										
										
											2022-07-31 02:24:03 +00:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2022-06-07 01:22:18 +00:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2022-08-02 21:42:50 +00:00
										 |  |  |     return bit_count; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-06-07 01:22:18 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-09-06 20:10:25 +00:00
										 |  |  | template <size_t IN0, size_t OUT0, size_t P> | 
					
						
							|  |  |  | size_t puncture( // FIXED::MSVC (MULTIPLE DEFINITIONS OF THE SAME TEMPLATE)
 | 
					
						
							|  |  |  |     const std::array<uint8_t, IN0>& in, | 
					
						
							|  |  |  |     std::array<int8_t, OUT0>& out, | 
					
						
							| 
									
										
										
										
											2022-08-02 21:42:50 +00:00
										 |  |  |     const std::array<int8_t, P>& p | 
					
						
							|  |  |  | ) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     size_t index = 0; | 
					
						
							|  |  |  |     size_t pindex = 0; | 
					
						
							|  |  |  |     size_t bit_count = 0; | 
					
						
							| 
									
										
										
										
											2022-09-06 20:10:25 +00:00
										 |  |  |     for (size_t i = 0; i != IN0 && index != OUT0; ++i) | 
					
						
							| 
									
										
										
										
											2022-06-07 01:22:18 +00:00
										 |  |  |     { | 
					
						
							| 
									
										
										
										
											2022-08-02 21:42:50 +00:00
										 |  |  |         if (p[pindex++]) | 
					
						
							| 
									
										
										
										
											2022-06-07 01:22:18 +00:00
										 |  |  |         { | 
					
						
							| 
									
										
										
										
											2022-08-02 21:42:50 +00:00
										 |  |  |             out[index++] = in[i]; | 
					
						
							|  |  |  |             bit_count++; | 
					
						
							| 
									
										
										
										
											2022-08-02 03:56:40 +00:00
										 |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-08-02 21:42:50 +00:00
										 |  |  |         if (pindex == P) pindex = 0; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     return bit_count; | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2022-06-07 01:22:18 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | template <size_t N> | 
					
						
							| 
									
										
										
										
											2022-07-20 07:57:59 +00:00
										 |  |  | constexpr bool get_bit_index( | 
					
						
							|  |  |  |     const std::array<uint8_t, N>& input, | 
					
						
							|  |  |  |     size_t index | 
					
						
							|  |  |  | ) | 
					
						
							| 
									
										
										
										
											2022-06-07 01:22:18 +00:00
										 |  |  | { | 
					
						
							|  |  |  |     auto byte_index = index >> 3; | 
					
						
							|  |  |  |     assert(byte_index < N); | 
					
						
							|  |  |  |     auto bit_index = 7 - (index & 7); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return (input[byte_index] & (1 << bit_index)) >> bit_index; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | template <size_t N> | 
					
						
							| 
									
										
										
										
											2022-07-20 07:57:59 +00:00
										 |  |  | void set_bit_index( | 
					
						
							|  |  |  |     std::array<uint8_t, N>& input, | 
					
						
							|  |  |  |     size_t index | 
					
						
							|  |  |  | ) | 
					
						
							| 
									
										
										
										
											2022-06-07 01:22:18 +00:00
										 |  |  | { | 
					
						
							|  |  |  |     auto byte_index = index >> 3; | 
					
						
							|  |  |  |     assert(byte_index < N); | 
					
						
							|  |  |  |     auto bit_index = 7 - (index & 7); | 
					
						
							|  |  |  |     input[byte_index] |= (1 << bit_index); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | template <size_t N> | 
					
						
							| 
									
										
										
										
											2022-07-20 07:57:59 +00:00
										 |  |  | void reset_bit_index( | 
					
						
							|  |  |  |     std::array<uint8_t, N>& input, | 
					
						
							|  |  |  |     size_t index | 
					
						
							|  |  |  | ) | 
					
						
							| 
									
										
										
										
											2022-06-07 01:22:18 +00:00
										 |  |  | { | 
					
						
							|  |  |  |     auto byte_index = index >> 3; | 
					
						
							|  |  |  |     assert(byte_index < N); | 
					
						
							|  |  |  |     auto bit_index = 7 - (index & 7); | 
					
						
							|  |  |  |     input[byte_index] &= ~(1 << bit_index); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | template <size_t N> | 
					
						
							| 
									
										
										
										
											2022-07-20 07:57:59 +00:00
										 |  |  | void assign_bit_index( | 
					
						
							|  |  |  |     std::array<uint8_t, N>& input, | 
					
						
							|  |  |  |     size_t index, | 
					
						
							|  |  |  |     bool value | 
					
						
							|  |  |  | ) | 
					
						
							| 
									
										
										
										
											2022-06-07 01:22:18 +00:00
										 |  |  | { | 
					
						
							|  |  |  |     if (value) set_bit_index(input, index); | 
					
						
							|  |  |  |     else reset_bit_index(input, index); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /**
 | 
					
						
							|  |  |  |  * Sign-extend an n-bit value to a specific signed integer type. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | template <typename T, size_t n> | 
					
						
							|  |  |  | constexpr T to_int(uint8_t v) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     constexpr auto MAX_LOCAL_INPUT = (1 << (n - 1)); | 
					
						
							|  |  |  |     constexpr auto NEGATIVE_OFFSET = std::numeric_limits<typename std::make_unsigned<T>::type>::max() - (MAX_LOCAL_INPUT - 1); | 
					
						
							|  |  |  |     T r = v & (1 << (n - 1)) ? NEGATIVE_OFFSET : 0; | 
					
						
							|  |  |  |     return r + (v & (MAX_LOCAL_INPUT - 1)); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | template <typename T, size_t N> | 
					
						
							|  |  |  | constexpr auto to_byte_array(std::array<T, N> in) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     std::array<uint8_t, (N + 7) / 8> out{}; | 
					
						
							|  |  |  |     out.fill(0); | 
					
						
							|  |  |  |     size_t i = 0; | 
					
						
							|  |  |  |     size_t b = 0; | 
					
						
							|  |  |  |     for (auto c : in) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         out[i] |= (c << (7 - b)); | 
					
						
							|  |  |  |         if (++b == 8) | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |             ++i; | 
					
						
							|  |  |  |             b = 0; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     return out; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | template <typename T, size_t N> | 
					
						
							| 
									
										
										
										
											2022-07-20 07:57:59 +00:00
										 |  |  | constexpr void to_byte_array( | 
					
						
							|  |  |  |     std::array<T, N> in, | 
					
						
							|  |  |  |     std::array<uint8_t, (N + 7) / 8>& out | 
					
						
							|  |  |  | ) | 
					
						
							| 
									
										
										
										
											2022-06-07 01:22:18 +00:00
										 |  |  | { | 
					
						
							|  |  |  |     size_t i = 0; | 
					
						
							|  |  |  |     size_t b = 0; | 
					
						
							|  |  |  |     uint8_t tmp = 0; | 
					
						
							|  |  |  |     for (auto c : in) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         tmp |= (c << (7 - b)); | 
					
						
							|  |  |  |         if (++b == 8) | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |             out[i] = tmp; | 
					
						
							|  |  |  |             tmp = 0; | 
					
						
							|  |  |  |             ++i; | 
					
						
							|  |  |  |             b = 0; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     if (i < out.size()) out[i] = tmp; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | struct PRBS9 | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	static constexpr uint16_t MASK = 0x1FF; | 
					
						
							|  |  |  | 	static constexpr uint8_t TAP_1 = 8;		    // Bit 9
 | 
					
						
							|  |  |  | 	static constexpr uint8_t TAP_2 = 4;		    // Bit 5
 | 
					
						
							|  |  |  |     static constexpr uint8_t LOCK_COUNT = 18;   // 18 consecutive good bits.
 | 
					
						
							|  |  |  |     static constexpr uint8_t UNLOCK_COUNT = 25; // bad bits in history required to unlock.
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     uint16_t state = 1; | 
					
						
							|  |  |  |     bool synced = false; | 
					
						
							|  |  |  |     uint8_t sync_count = 0; | 
					
						
							|  |  |  |     uint32_t bit_count = 0; | 
					
						
							|  |  |  |     uint32_t err_count = 0; | 
					
						
							|  |  |  |     std::array<uint8_t, 16> history; | 
					
						
							|  |  |  |     size_t hist_count = 0; | 
					
						
							|  |  |  |     size_t hist_pos = 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     void count_errors(bool error) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         bit_count += 1; | 
					
						
							|  |  |  |         hist_count -= (history[hist_pos >> 3] & (1 << (hist_pos & 7))) != 0; | 
					
						
							|  |  |  |         if (error) { | 
					
						
							|  |  |  |             err_count += 1; | 
					
						
							|  |  |  |             hist_count += 1; | 
					
						
							|  |  |  |             history[hist_pos >> 3] |= (1 << (hist_pos & 7)); | 
					
						
							|  |  |  |             if (hist_count >= UNLOCK_COUNT) synced = false; | 
					
						
							|  |  |  |         } else { | 
					
						
							|  |  |  |             history[hist_pos >> 3] &= ~(1 << (hist_pos & 7)); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         if (++hist_pos == 128) hist_pos = 0; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // PRBS generator.
 | 
					
						
							|  |  |  |     bool generate() | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         bool result = ((state >> TAP_1) ^ (state >> TAP_2)) & 1; | 
					
						
							|  |  |  |         state = ((state << 1) | result) & MASK; | 
					
						
							|  |  |  |         return result; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // PRBS Syncronizer. Returns 0 if the bit matches the PRBS, otherwise 1.
 | 
					
						
							|  |  |  |     // When synchronizing the LFSR used in the PRBS, a single bad input bit will
 | 
					
						
							|  |  |  |     // result in 3 error bits being emitted.
 | 
					
						
							|  |  |  |     bool synchronize(bool bit) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         bool result = (bit ^ (state >> TAP_1) ^ (state >> TAP_2)) & 1; | 
					
						
							|  |  |  |         state = ((state << 1) | bit) & MASK; | 
					
						
							|  |  |  |         if (result) { | 
					
						
							|  |  |  |             sync_count = 0; // error
 | 
					
						
							|  |  |  |         } else { | 
					
						
							|  |  |  |             if (++sync_count == LOCK_COUNT) { | 
					
						
							|  |  |  |                 synced = true; | 
					
						
							|  |  |  |                 bit_count += LOCK_COUNT; | 
					
						
							|  |  |  |                 history.fill(0); | 
					
						
							|  |  |  |                 hist_count = 0; | 
					
						
							|  |  |  |                 hist_pos = 0; | 
					
						
							|  |  |  |                 sync_count = 0; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         return result; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // PRBS validator.  Returns 0 if the bit matches the PRBS, otherwise 1.
 | 
					
						
							|  |  |  |     // The results are only valid when sync() returns true;
 | 
					
						
							|  |  |  |     bool validate(bool bit) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         bool result; | 
					
						
							|  |  |  |         if (!synced) { | 
					
						
							|  |  |  |             result = synchronize(bit); | 
					
						
							|  |  |  |         } else { | 
					
						
							|  |  |  |             // PRBS is now free-running.
 | 
					
						
							|  |  |  |             result = bit ^ generate(); | 
					
						
							|  |  |  |             count_errors(result); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         return result; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     bool sync() const { return synced; } | 
					
						
							|  |  |  |     uint32_t errors() const { assert(synced); return err_count; } | 
					
						
							|  |  |  |     uint32_t bits() const { assert(synced); return bit_count; } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // Reset the state.
 | 
					
						
							|  |  |  |     void reset() | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         state = 1; | 
					
						
							|  |  |  |         synced = false; | 
					
						
							|  |  |  |         sync_count = 0; | 
					
						
							|  |  |  |         bit_count = 0; | 
					
						
							|  |  |  |         err_count = 0; | 
					
						
							|  |  |  |         history.fill(0); | 
					
						
							|  |  |  |         hist_count = 0; | 
					
						
							|  |  |  |         hist_pos = 0; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | template< class T > | 
					
						
							|  |  |  | constexpr int popcount( T x ) noexcept | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     int count = 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     while (x) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         count += x & 1; | 
					
						
							|  |  |  |         x >>= 1; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return count; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-07-04 21:03:07 +00:00
										 |  |  | } // modemm17
 |