Mercurial > hg > audiostuff
comparison spandsp-0.0.6pre17/src/bert.c @ 4:26cd8f1ef0b1
import spandsp-0.0.6pre17
author | Peter Meerwald <pmeerw@cosy.sbg.ac.at> |
---|---|
date | Fri, 25 Jun 2010 15:50:58 +0200 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
3:c6c5a16ce2f2 | 4:26cd8f1ef0b1 |
---|---|
1 /* | |
2 * SpanDSP - a series of DSP components for telephony | |
3 * | |
4 * bert.c - Bit error rate tests. | |
5 * | |
6 * Written by Steve Underwood <steveu@coppice.org> | |
7 * | |
8 * Copyright (C) 2004 Steve Underwood | |
9 * | |
10 * All rights reserved. | |
11 * | |
12 * This program is free software; you can redistribute it and/or modify | |
13 * it under the terms of the GNU Lesser General Public License version 2.1, | |
14 * as published by the Free Software Foundation. | |
15 * | |
16 * This program is distributed in the hope that it will be useful, | |
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
19 * GNU Lesser General Public License for more details. | |
20 * | |
21 * You should have received a copy of the GNU Lesser General Public | |
22 * License along with this program; if not, write to the Free Software | |
23 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | |
24 * | |
25 * $Id: bert.c,v 1.33 2009/04/14 16:04:53 steveu Exp $ | |
26 */ | |
27 | |
28 #if defined(HAVE_CONFIG_H) | |
29 #include "config.h" | |
30 #endif | |
31 | |
32 #include <inttypes.h> | |
33 #include <stdlib.h> | |
34 #include <stdio.h> | |
35 #include <string.h> | |
36 #include <assert.h> | |
37 #include <time.h> | |
38 | |
39 #include "spandsp/telephony.h" | |
40 #include "spandsp/logging.h" | |
41 #include "spandsp/async.h" | |
42 #include "spandsp/bert.h" | |
43 | |
44 #include "spandsp/private/logging.h" | |
45 #include "spandsp/private/bert.h" | |
46 | |
47 #define MEASUREMENT_STEP 100 | |
48 | |
49 static const char *qbf = "VoyeZ Le BricK GeanT QuE J'ExaminE PreS Du WharF 123 456 7890 + - * : = $ % ( )" | |
50 "ThE QuicK BrowN FoX JumpS OveR ThE LazY DoG 123 456 7890 + - * : = $ % ( )"; | |
51 | |
52 SPAN_DECLARE(const char *) bert_event_to_str(int event) | |
53 { | |
54 switch (event) | |
55 { | |
56 case BERT_REPORT_SYNCED: | |
57 return "synced"; | |
58 case BERT_REPORT_UNSYNCED: | |
59 return "unsync'ed"; | |
60 case BERT_REPORT_REGULAR: | |
61 return "regular"; | |
62 case BERT_REPORT_GT_10_2: | |
63 return "error rate > 1 in 10^2"; | |
64 case BERT_REPORT_LT_10_2: | |
65 return "error rate < 1 in 10^2"; | |
66 case BERT_REPORT_LT_10_3: | |
67 return "error rate < 1 in 10^3"; | |
68 case BERT_REPORT_LT_10_4: | |
69 return "error rate < 1 in 10^4"; | |
70 case BERT_REPORT_LT_10_5: | |
71 return "error rate < 1 in 10^5"; | |
72 case BERT_REPORT_LT_10_6: | |
73 return "error rate < 1 in 10^6"; | |
74 case BERT_REPORT_LT_10_7: | |
75 return "error rate < 1 in 10^7"; | |
76 } | |
77 return "???"; | |
78 } | |
79 /*- End of function --------------------------------------------------------*/ | |
80 | |
81 SPAN_DECLARE(int) bert_get_bit(bert_state_t *s) | |
82 { | |
83 int bit; | |
84 | |
85 if (s->limit && s->tx.bits >= s->limit) | |
86 return SIG_STATUS_END_OF_DATA; | |
87 bit = 0; | |
88 switch (s->pattern_class) | |
89 { | |
90 case 0: | |
91 bit = s->tx.reg & 1; | |
92 s->tx.reg = (s->tx.reg >> 1) | ((s->tx.reg & 1) << s->shift2); | |
93 break; | |
94 case 1: | |
95 bit = s->tx.reg & 1; | |
96 s->tx.reg = (s->tx.reg >> 1) | (((s->tx.reg ^ (s->tx.reg >> s->shift)) & 1) << s->shift2); | |
97 if (s->max_zeros) | |
98 { | |
99 /* This generator suppresses runs >s->max_zeros */ | |
100 if (bit) | |
101 { | |
102 if (++s->tx.zeros > s->max_zeros) | |
103 { | |
104 s->tx.zeros = 0; | |
105 bit ^= 1; | |
106 } | |
107 } | |
108 else | |
109 { | |
110 s->tx.zeros = 0; | |
111 } | |
112 } | |
113 bit ^= s->invert; | |
114 break; | |
115 case 2: | |
116 if (s->tx.step_bit == 0) | |
117 { | |
118 s->tx.step_bit = 7; | |
119 s->tx.reg = qbf[s->tx.step++]; | |
120 if (s->tx.reg == 0) | |
121 { | |
122 s->tx.reg = 'V'; | |
123 s->tx.step = 1; | |
124 } | |
125 } | |
126 bit = s->tx.reg & 1; | |
127 s->tx.reg >>= 1; | |
128 s->tx.step_bit--; | |
129 break; | |
130 } | |
131 s->tx.bits++; | |
132 return bit; | |
133 } | |
134 /*- End of function --------------------------------------------------------*/ | |
135 | |
136 static void assess_error_rate(bert_state_t *s) | |
137 { | |
138 int i; | |
139 int j; | |
140 int sum; | |
141 int test; | |
142 | |
143 /* We assess the error rate in decadic steps. For each decade we assess the error over 10 times | |
144 the number of bits, to smooth the result. This means we assess the 1 in 100 rate based on 1000 bits | |
145 (i.e. we look for >=10 errors in 1000 bits). We make an assessment every 100 bits, using a sliding | |
146 window over the last 1000 bits. We assess the 1 in 1000 rate over 10000 bits in a similar way, and | |
147 so on for the lower error rates. */ | |
148 test = TRUE; | |
149 for (i = 2; i <= 7; i++) | |
150 { | |
151 if (++s->decade_ptr[i] < 10) | |
152 break; | |
153 /* This decade has reached 10 snapshots, so we need to touch the next decade */ | |
154 s->decade_ptr[i] = 0; | |
155 /* Sum the last 10 snapshots from this decade, to see if we overflow into the next decade */ | |
156 for (sum = 0, j = 0; j < 10; j++) | |
157 sum += s->decade_bad[i][j]; | |
158 if (test && sum > 10) | |
159 { | |
160 /* We overflow into the next decade */ | |
161 test = FALSE; | |
162 if (s->error_rate != i && s->reporter) | |
163 s->reporter(s->user_data, BERT_REPORT_GT_10_2 + i - 2, &s->results); | |
164 s->error_rate = i; | |
165 } | |
166 s->decade_bad[i][0] = 0; | |
167 if (i < 7) | |
168 s->decade_bad[i + 1][s->decade_ptr[i + 1]] = sum; | |
169 } | |
170 if (i > 7) | |
171 { | |
172 if (s->decade_ptr[i] >= 10) | |
173 s->decade_ptr[i] = 0; | |
174 if (test) | |
175 { | |
176 if (s->error_rate != i && s->reporter) | |
177 s->reporter(s->user_data, BERT_REPORT_GT_10_2 + i - 2, &s->results); | |
178 s->error_rate = i; | |
179 } | |
180 } | |
181 else | |
182 { | |
183 s->decade_bad[i][s->decade_ptr[i]] = 0; | |
184 } | |
185 } | |
186 /*- End of function --------------------------------------------------------*/ | |
187 | |
188 SPAN_DECLARE(void) bert_put_bit(bert_state_t *s, int bit) | |
189 { | |
190 if (bit < 0) | |
191 { | |
192 /* Special conditions */ | |
193 printf("Status is %s (%d)\n", signal_status_to_str(bit), bit); | |
194 return; | |
195 } | |
196 bit = (bit & 1) ^ s->invert; | |
197 s->rx.bits++; | |
198 switch (s->pattern_class) | |
199 { | |
200 case 0: | |
201 if (s->rx.resync) | |
202 { | |
203 s->rx.reg = (s->rx.reg >> 1) | (bit << s->shift2); | |
204 s->rx.ref_reg = (s->rx.ref_reg >> 1) | ((s->rx.ref_reg & 1) << s->shift2); | |
205 if (s->rx.reg == s->rx.ref_reg) | |
206 { | |
207 if (++s->rx.resync > s->resync_time) | |
208 { | |
209 s->rx.resync = 0; | |
210 if (s->reporter) | |
211 s->reporter(s->user_data, BERT_REPORT_SYNCED, &s->results); | |
212 } | |
213 } | |
214 else | |
215 { | |
216 s->rx.resync = 2; | |
217 s->rx.ref_reg = s->rx.master_reg; | |
218 } | |
219 } | |
220 else | |
221 { | |
222 s->results.total_bits++; | |
223 if ((bit ^ s->rx.ref_reg) & 1) | |
224 s->results.bad_bits++; | |
225 s->rx.ref_reg = (s->rx.ref_reg >> 1) | ((s->rx.ref_reg & 1) << s->shift2); | |
226 } | |
227 break; | |
228 case 1: | |
229 if (s->rx.resync) | |
230 { | |
231 /* If we get a reasonable period for which we correctly predict the | |
232 next bit, we must be in sync. */ | |
233 /* Don't worry about max. zeros tests when resyncing. | |
234 It might just extend the resync time a little. Trying | |
235 to include the test might affect robustness. */ | |
236 if (bit == (int) ((s->rx.reg >> s->shift) & 1)) | |
237 { | |
238 if (++s->rx.resync > s->resync_time) | |
239 { | |
240 s->rx.resync = 0; | |
241 if (s->reporter) | |
242 s->reporter(s->user_data, BERT_REPORT_SYNCED, &s->results); | |
243 } | |
244 } | |
245 else | |
246 { | |
247 s->rx.resync = 2; | |
248 s->rx.reg ^= s->mask; | |
249 } | |
250 } | |
251 else | |
252 { | |
253 s->results.total_bits++; | |
254 if (s->max_zeros) | |
255 { | |
256 /* This generator suppresses runs >s->max_zeros */ | |
257 if ((s->rx.reg & s->mask)) | |
258 { | |
259 if (++s->rx.zeros > s->max_zeros) | |
260 { | |
261 s->rx.zeros = 0; | |
262 bit ^= 1; | |
263 } | |
264 } | |
265 else | |
266 { | |
267 s->rx.zeros = 0; | |
268 } | |
269 } | |
270 if (bit != (int) ((s->rx.reg >> s->shift) & 1)) | |
271 { | |
272 s->results.bad_bits++; | |
273 s->rx.resync_bad_bits++; | |
274 s->decade_bad[2][s->decade_ptr[2]]++; | |
275 } | |
276 if (--s->rx.measurement_step <= 0) | |
277 { | |
278 /* Every hundred bits we need to do the error rate measurement */ | |
279 s->rx.measurement_step = MEASUREMENT_STEP; | |
280 assess_error_rate(s); | |
281 } | |
282 if (--s->rx.resync_cnt <= 0) | |
283 { | |
284 /* Check if there were enough bad bits during this period to | |
285 justify a resync. */ | |
286 if (s->rx.resync_bad_bits >= (s->rx.resync_len*s->rx.resync_percent)/100) | |
287 { | |
288 s->rx.resync = 1; | |
289 s->results.resyncs++; | |
290 if (s->reporter) | |
291 s->reporter(s->user_data, BERT_REPORT_UNSYNCED, &s->results); | |
292 } | |
293 s->rx.resync_cnt = s->rx.resync_len; | |
294 s->rx.resync_bad_bits = 0; | |
295 } | |
296 } | |
297 s->rx.reg = (s->rx.reg >> 1) | (((s->rx.reg ^ (s->rx.reg >> s->shift)) & 1) << s->shift2); | |
298 break; | |
299 case 2: | |
300 s->rx.reg = (s->rx.reg >> 1) | (bit << 6); | |
301 /* TODO: There is no mechanism for synching yet. This only works if things start in sync. */ | |
302 if (++s->rx.step_bit == 7) | |
303 { | |
304 s->rx.step_bit = 0; | |
305 if ((int) s->rx.reg != qbf[s->rx.step]) | |
306 { | |
307 /* We need to work out the number of actual bad bits here. We need to look at the | |
308 error rate, and see it a resync is needed. etc. */ | |
309 s->results.bad_bits++; | |
310 } | |
311 if (qbf[++s->rx.step] == '\0') | |
312 s->rx.step = 0; | |
313 } | |
314 s->results.total_bits++; | |
315 break; | |
316 } | |
317 if (s->report_frequency > 0) | |
318 { | |
319 if (--s->rx.report_countdown <= 0) | |
320 { | |
321 if (s->reporter) | |
322 s->reporter(s->user_data, BERT_REPORT_REGULAR, &s->results); | |
323 s->rx.report_countdown = s->report_frequency; | |
324 } | |
325 } | |
326 } | |
327 /*- End of function --------------------------------------------------------*/ | |
328 | |
329 SPAN_DECLARE(int) bert_result(bert_state_t *s, bert_results_t *results) | |
330 { | |
331 results->total_bits = s->results.total_bits; | |
332 results->bad_bits = s->results.bad_bits; | |
333 results->resyncs = s->results.resyncs; | |
334 return sizeof(*results); | |
335 } | |
336 /*- End of function --------------------------------------------------------*/ | |
337 | |
338 SPAN_DECLARE(void) bert_set_report(bert_state_t *s, int freq, bert_report_func_t reporter, void *user_data) | |
339 { | |
340 s->report_frequency = freq; | |
341 s->reporter = reporter; | |
342 s->user_data = user_data; | |
343 | |
344 s->rx.report_countdown = s->report_frequency; | |
345 } | |
346 /*- End of function --------------------------------------------------------*/ | |
347 | |
348 SPAN_DECLARE(bert_state_t *) bert_init(bert_state_t *s, int limit, int pattern, int resync_len, int resync_percent) | |
349 { | |
350 int i; | |
351 int j; | |
352 | |
353 if (s == NULL) | |
354 { | |
355 if ((s = (bert_state_t *) malloc(sizeof(*s))) == NULL) | |
356 return NULL; | |
357 } | |
358 memset(s, 0, sizeof(*s)); | |
359 | |
360 s->pattern = pattern; | |
361 s->limit = limit; | |
362 s->reporter = NULL; | |
363 s->user_data = NULL; | |
364 s->report_frequency = 0; | |
365 | |
366 s->resync_time = 72; | |
367 s->invert = 0; | |
368 switch (s->pattern) | |
369 { | |
370 case BERT_PATTERN_ZEROS: | |
371 s->tx.reg = 0; | |
372 s->shift2 = 31; | |
373 s->pattern_class = 0; | |
374 break; | |
375 case BERT_PATTERN_ONES: | |
376 s->tx.reg = ~((uint32_t) 0); | |
377 s->shift2 = 31; | |
378 s->pattern_class = 0; | |
379 break; | |
380 case BERT_PATTERN_7_TO_1: | |
381 s->tx.reg = 0xFEFEFEFE; | |
382 s->shift2 = 31; | |
383 s->pattern_class = 0; | |
384 break; | |
385 case BERT_PATTERN_3_TO_1: | |
386 s->tx.reg = 0xEEEEEEEE; | |
387 s->shift2 = 31; | |
388 s->pattern_class = 0; | |
389 break; | |
390 case BERT_PATTERN_1_TO_1: | |
391 s->tx.reg = 0xAAAAAAAA; | |
392 s->shift2 = 31; | |
393 s->pattern_class = 0; | |
394 break; | |
395 case BERT_PATTERN_1_TO_3: | |
396 s->tx.reg = 0x11111111; | |
397 s->shift2 = 31; | |
398 s->pattern_class = 0; | |
399 break; | |
400 case BERT_PATTERN_1_TO_7: | |
401 s->tx.reg = 0x01010101; | |
402 s->shift2 = 31; | |
403 s->pattern_class = 0; | |
404 break; | |
405 case BERT_PATTERN_QBF: | |
406 s->tx.reg = 0; | |
407 s->pattern_class = 2; | |
408 break; | |
409 case BERT_PATTERN_ITU_O151_23: | |
410 s->pattern_class = 1; | |
411 s->tx.reg = 0x7FFFFF; | |
412 s->mask = 0x20; | |
413 s->shift = 5; | |
414 s->shift2 = 22; | |
415 s->invert = 1; | |
416 s->resync_time = 56; | |
417 s->max_zeros = 0; | |
418 break; | |
419 case BERT_PATTERN_ITU_O151_20: | |
420 s->pattern_class = 1; | |
421 s->tx.reg = 0xFFFFF; | |
422 s->mask = 0x8; | |
423 s->shift = 3; | |
424 s->shift2 = 19; | |
425 s->invert = 1; | |
426 s->resync_time = 50; | |
427 s->max_zeros = 14; | |
428 break; | |
429 case BERT_PATTERN_ITU_O151_15: | |
430 s->pattern_class = 1; | |
431 s->tx.reg = 0x7FFF; | |
432 s->mask = 0x2; | |
433 s->shift = 1; | |
434 s->shift2 = 14; | |
435 s->invert = 1; | |
436 s->resync_time = 40; | |
437 s->max_zeros = 0; | |
438 break; | |
439 case BERT_PATTERN_ITU_O152_11: | |
440 s->pattern_class = 1; | |
441 s->tx.reg = 0x7FF; | |
442 s->mask = 0x4; | |
443 s->shift = 2; | |
444 s->shift2 = 10; | |
445 s->invert = 0; | |
446 s->resync_time = 32; | |
447 s->max_zeros = 0; | |
448 break; | |
449 case BERT_PATTERN_ITU_O153_9: | |
450 s->pattern_class = 1; | |
451 s->tx.reg = 0x1FF; | |
452 s->mask = 0x10; | |
453 s->shift = 4; | |
454 s->shift2 = 8; | |
455 s->invert = 0; | |
456 s->resync_time = 28; | |
457 s->max_zeros = 0; | |
458 break; | |
459 } | |
460 s->tx.bits = 0; | |
461 s->tx.step = 0; | |
462 s->tx.step_bit = 0; | |
463 s->tx.zeros = 0; | |
464 | |
465 s->rx.reg = s->tx.reg; | |
466 s->rx.ref_reg = s->rx.reg; | |
467 s->rx.master_reg = s->rx.ref_reg; | |
468 s->rx.bits = 0; | |
469 s->rx.step = 0; | |
470 s->rx.step_bit = 0; | |
471 | |
472 s->rx.resync = 1; | |
473 s->rx.resync_cnt = resync_len; | |
474 s->rx.resync_bad_bits = 0; | |
475 s->rx.resync_len = resync_len; | |
476 s->rx.resync_percent = resync_percent; | |
477 | |
478 s->results.total_bits = 0; | |
479 s->results.bad_bits = 0; | |
480 s->results.resyncs = 0; | |
481 | |
482 s->rx.report_countdown = 0; | |
483 | |
484 for (i = 0; i < 8; i++) | |
485 { | |
486 for (j = 0; j < 10; j++) | |
487 s->decade_bad[i][j] = 0; | |
488 s->decade_ptr[i] = 0; | |
489 } | |
490 s->error_rate = 8; | |
491 s->rx.measurement_step = MEASUREMENT_STEP; | |
492 | |
493 span_log_init(&s->logging, SPAN_LOG_NONE, NULL); | |
494 span_log_set_protocol(&s->logging, "BERT"); | |
495 | |
496 return s; | |
497 } | |
498 /*- End of function --------------------------------------------------------*/ | |
499 | |
500 SPAN_DECLARE(int) bert_release(bert_state_t *s) | |
501 { | |
502 return 0; | |
503 } | |
504 /*- End of function --------------------------------------------------------*/ | |
505 | |
506 SPAN_DECLARE(int) bert_free(bert_state_t *s) | |
507 { | |
508 free(s); | |
509 return 0; | |
510 } | |
511 /*- End of function --------------------------------------------------------*/ | |
512 /*- End of file ------------------------------------------------------------*/ |