1use std;
7
8use binfield_matrix::matrix_mul_systematic;
9
10use crate::coding::bmcf;
11use crate::coding::galois::{GaloisField, P25Codeword, P25Field, Polynomial, PolynomialCoefs};
12
13pub fn encode(word: u16) -> u64 {
15 matrix_mul_systematic(word, GEN)
16}
17
18pub fn decode(bits: u64) -> Option<(u16, usize)> {
25 let word = bits >> 1;
27
28 bmcf::Errors::new(syndromes(word)).map(|(nerr, errs)| {
29 let fixed = errs.fold(word, |w, (loc, pat)| {
31 assert!(pat.power().unwrap() == 0);
32 w ^ 1 << loc
33 });
34
35 ((fixed >> 47) as u16, nerr)
37 })
38}
39
40const GEN: &[u16] = &[
42 0b1110110001000111,
43 0b1001101001100100,
44 0b0100110100110010,
45 0b0010011010011001,
46 0b1111111100001011,
47 0b1001001111000010,
48 0b0100100111100001,
49 0b1100100010110111,
50 0b1000100000011100,
51 0b0100010000001110,
52 0b0010001000000111,
53 0b1111110101000100,
54 0b0111111010100010,
55 0b0011111101010001,
56 0b1111001111101111,
57 0b1001010110110000,
58 0b0100101011011000,
59 0b0010010101101100,
60 0b0001001010110110,
61 0b0000100101011011,
62 0b1110100011101010,
63 0b0111010001110101,
64 0b1101011001111101,
65 0b1000011101111001,
66 0b1010111111111011,
67 0b1011101110111010,
68 0b0101110111011101,
69 0b1100001010101001,
70 0b1000110100010011,
71 0b1010101011001110,
72 0b0101010101100111,
73 0b1100011011110100,
74 0b0110001101111010,
75 0b0011000110111101,
76 0b1111010010011001,
77 0b1001011000001011,
78 0b1010011101000010,
79 0b0101001110100001,
80 0b1100010110010111,
81 0b1000111010001100,
82 0b0100011101000110,
83 0b0010001110100011,
84 0b1111110110010110,
85 0b0111111011001011,
86 0b1101001100100010,
87 0b0110100110010001,
88 0b1101100010001111,
89 0b0000000000000011,
90];
91
92impl_polynomial_coefs!(BchCoefs, 23);
93
94type BchPolynomial = Polynomial<BchCoefs>;
96
97fn syndromes(word: u64) -> BchPolynomial {
102 BchPolynomial::new((1..=BchCoefs::syndromes()).map(|p| {
103 (0..P25Field::size()).fold(P25Codeword::default(), |s, b| {
106 if word >> b & 1 == 0 {
107 s
108 } else {
109 s + P25Codeword::for_power(b * p)
110 }
111 })
112 }))
113}
114
115#[cfg(test)]
116mod test {
117 use super::*;
118 use super::{syndromes, BchCoefs};
119 use crate::coding::galois::{P25Codeword, Polynomial, PolynomialCoefs};
120 use std;
121
122 impl_polynomial_coefs!(TestCoefs, 23, 50);
123
124 #[test]
125 fn validate_coefs() {
126 BchCoefs::default().validate();
127 }
128
129 #[test]
130 fn verify_gen() {
131 let p = Polynomial::<TestCoefs>::new(
134 [
135 P25Codeword::for_power(0),
136 P25Codeword::for_power(0),
137 P25Codeword::for_power(0),
138 ]
139 .iter()
140 .cloned(),
141 ) * Polynomial::new(
142 [
143 P25Codeword::for_power(0),
144 P25Codeword::default(),
145 P25Codeword::for_power(0),
146 P25Codeword::default(),
147 P25Codeword::for_power(0),
148 P25Codeword::for_power(0),
149 P25Codeword::for_power(0),
150 ]
151 .iter()
152 .cloned(),
153 ) * Polynomial::new(
154 [
155 P25Codeword::for_power(0),
156 P25Codeword::for_power(0),
157 P25Codeword::default(),
158 P25Codeword::for_power(0),
159 P25Codeword::for_power(0),
160 P25Codeword::default(),
161 P25Codeword::for_power(0),
162 ]
163 .iter()
164 .cloned(),
165 ) * Polynomial::new(
166 [
167 P25Codeword::for_power(0),
168 P25Codeword::default(),
169 P25Codeword::for_power(0),
170 P25Codeword::for_power(0),
171 P25Codeword::default(),
172 P25Codeword::for_power(0),
173 P25Codeword::for_power(0),
174 ]
175 .iter()
176 .cloned(),
177 ) * Polynomial::new(
178 [
179 P25Codeword::for_power(0),
180 P25Codeword::default(),
181 P25Codeword::for_power(0),
182 P25Codeword::for_power(0),
183 ]
184 .iter()
185 .cloned(),
186 ) * Polynomial::new(
187 [
188 P25Codeword::for_power(0),
189 P25Codeword::default(),
190 P25Codeword::default(),
191 P25Codeword::for_power(0),
192 P25Codeword::default(),
193 P25Codeword::default(),
194 P25Codeword::for_power(0),
195 ]
196 .iter()
197 .cloned(),
198 ) * Polynomial::new(
199 [
200 P25Codeword::for_power(0),
201 P25Codeword::for_power(0),
202 P25Codeword::for_power(0),
203 P25Codeword::default(),
204 P25Codeword::default(),
205 P25Codeword::for_power(0),
206 P25Codeword::for_power(0),
207 ]
208 .iter()
209 .cloned(),
210 ) * Polynomial::new(
211 [
212 P25Codeword::for_power(0),
213 P25Codeword::for_power(0),
214 P25Codeword::for_power(0),
215 P25Codeword::default(),
216 P25Codeword::for_power(0),
217 P25Codeword::default(),
218 P25Codeword::for_power(0),
219 ]
220 .iter()
221 .cloned(),
222 ) * Polynomial::new(
223 [
224 P25Codeword::for_power(0),
225 P25Codeword::for_power(0),
226 P25Codeword::default(),
227 P25Codeword::default(),
228 P25Codeword::default(),
229 P25Codeword::default(),
230 P25Codeword::for_power(0),
231 ]
232 .iter()
233 .cloned(),
234 );
235
236 assert_eq!(p.degree().unwrap(), 47);
237
238 let gen = 0o6331_1413_6723_5453u64;
239
240 for i in 0..=47 {
241 let coef = gen >> i & 1;
242
243 assert_eq!(p[i].power(), if coef == 0 { None } else { Some(0) });
244 }
245 }
246
247 #[test]
248 fn test_encode() {
249 assert_eq!(
250 encode(0b1111111100000000),
251 0b1111111100000000100100110001000011000010001100000110100001101000
252 );
253 assert_eq!(encode(0b0011) & 1, 0);
254 assert_eq!(encode(0b0101) & 1, 1);
255 assert_eq!(encode(0b1010) & 1, 1);
256 assert_eq!(encode(0b1100) & 1, 0);
257 assert_eq!(encode(0b1111) & 1, 0);
258 }
259
260 #[test]
261 fn test_syndromes() {
262 let w = encode(0b1111111100000000) >> 1;
263
264 assert_eq!(syndromes(w).degree(), None);
265 assert_eq!(syndromes(w ^ 1 << 60).degree().unwrap(), 21);
266 }
267
268 #[test]
269 fn test_decode() {
270 assert!(decode(encode(0b0000111100001111) ^ 1 << 63).unwrap() == (0b0000111100001111, 1));
271
272 assert!(decode(encode(0b1100011111111111) ^ 1).unwrap() == (0b1100011111111111, 0));
273
274 assert!(
275 decode(encode(0b1111111100000000) ^ 0b11010011 << 30).unwrap()
276 == (0b1111111100000000, 5)
277 );
278
279 assert!(
280 decode(encode(0b1101101101010001) ^ (1 << 63 | 1)).unwrap() == (0b1101101101010001, 1)
281 );
282
283 assert!(
284 decode(encode(0b1111111111111111) ^ 0b11111111111).unwrap() == (0b1111111111111111, 10)
285 );
286
287 assert!(
288 decode(encode(0b0000000000000000) ^ 0b11111111111).unwrap() == (0b0000000000000000, 10)
289 );
290
291 assert!(
292 decode(encode(0b0000111110000000) ^ 0b111111111110).unwrap()
293 == (0b0000111110000000, 11)
294 );
295
296 assert!(
297 decode(encode(0b0000111110000000) ^ 0b111111111110).unwrap()
298 == (0b0000111110000000, 11)
299 );
300
301 assert!(decode(encode(0b0000111110001010) ^ 0b1111111111110).is_none());
302 assert!(decode(encode(0b0000001111111111) ^ 0b11111111111111111111110).is_none());
303 assert!(decode(
304 encode(0b0000001111111111) ^ 0b00100101010101000010001100100010011111111110
305 )
306 .is_none());
307
308 for i in 0..1u32 << 17 {
309 assert_eq!(decode(encode(i as u16)).unwrap().0, i as u16);
310 }
311 }
312}