comparison spandsp-0.0.3/spandsp-0.0.3/src/bert.c @ 5:f762bf195c4b

import spandsp-0.0.3
author Peter Meerwald <pmeerw@cosy.sbg.ac.at>
date Fri, 25 Jun 2010 16:00:21 +0200
parents
children
comparison
equal deleted inserted replaced
4:26cd8f1ef0b1 5:f762bf195c4b
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 General Public License version 2, as
14 * 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 General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License
22 * 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.21 2006/11/19 14:07:24 steveu Exp $
26 */
27
28 #ifdef 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 static const char *qbf = "VoyeZ Le BricK GeanT QuE J'ExaminE PreS Du WharF 123 456 7890 + - * : = $ % ( )"
45 "ThE QuicK BrowN FoX JumpS OveR ThE LazY DoG 123 456 7890 + - * : = $ % ( )";
46
47 int bert_get_bit(bert_state_t *s)
48 {
49 int bit;
50
51 if (s->limit && s->tx_bits >= s->limit)
52 return PUTBIT_END_OF_DATA;
53 bit = 0;
54 switch (s->pattern_class)
55 {
56 case 0:
57 bit = s->tx_reg & 1;
58 s->tx_reg = (s->tx_reg >> 1) | ((s->tx_reg & 1) << s->shift2);
59 break;
60 case 1:
61 bit = s->tx_reg & 1;
62 s->tx_reg = (s->tx_reg >> 1) | (((s->tx_reg ^ (s->tx_reg >> s->shift)) & 1) << s->shift2);
63 if (s->max_zeros)
64 {
65 /* This generator suppresses runs >s->max_zeros */
66 if (bit)
67 {
68 if (++s->tx_zeros > s->max_zeros)
69 {
70 s->tx_zeros = 0;
71 bit ^= 1;
72 }
73 }
74 else
75 {
76 s->tx_zeros = 0;
77 }
78 }
79 bit ^= s->invert;
80 break;
81 case 2:
82 if (s->tx_step_bit == 0)
83 {
84 s->tx_step_bit = 7;
85 s->tx_reg = qbf[s->tx_step++];
86 if (s->tx_reg == 0)
87 {
88 s->tx_reg = 'V';
89 s->tx_step = 1;
90 }
91 }
92 bit = s->tx_reg & 1;
93 s->tx_reg >>= 1;
94 s->tx_step_bit--;
95 break;
96 }
97 s->tx_bits++;
98 return bit;
99 }
100 /*- End of function --------------------------------------------------------*/
101
102 void bert_put_bit(bert_state_t *s, int bit)
103 {
104 int i;
105 int j;
106 int sum;
107 int test;
108
109 if (bit < 0)
110 {
111 /* Special conditions */
112 switch (bit)
113 {
114 case PUTBIT_TRAINING_FAILED:
115 span_log(&s->logging, SPAN_LOG_FLOW, "Training failed\n");
116 break;
117 case PUTBIT_TRAINING_SUCCEEDED:
118 span_log(&s->logging, SPAN_LOG_FLOW, "Training succeeded\n");
119 break;
120 case PUTBIT_CARRIER_UP:
121 span_log(&s->logging, SPAN_LOG_FLOW, "Carrier up\n");
122 break;
123 case PUTBIT_CARRIER_DOWN:
124 span_log(&s->logging, SPAN_LOG_FLOW, "Carrier down\n");
125 break;
126 default:
127 span_log(&s->logging, SPAN_LOG_FLOW, "Eh!\n");
128 break;
129 }
130 return;
131 }
132 bit = (bit & 1) ^ s->invert;
133 s->rx_bits++;
134 switch (s->pattern_class)
135 {
136 case 0:
137 if (s->resync)
138 {
139 s->rx_reg = (s->rx_reg >> 1) | (bit << s->shift2);
140 s->ref_reg = (s->ref_reg >> 1) | ((s->ref_reg & 1) << s->shift2);
141 if (s->rx_reg == s->ref_reg)
142 {
143 if (++s->resync > s->resync_time)
144 {
145 s->resync = 0;
146 if (s->reporter)
147 s->reporter(s->user_data, BERT_REPORT_SYNCED, &s->results);
148 }
149 }
150 else
151 {
152 s->resync = 2;
153 s->ref_reg = s->master_reg;
154 }
155 }
156 else
157 {
158 s->results.total_bits++;
159 if ((bit ^ s->ref_reg) & 1)
160 s->results.bad_bits++;
161 s->ref_reg = (s->ref_reg >> 1) | ((s->ref_reg & 1) << s->shift2);
162 }
163 break;
164 case 1:
165 if (s->resync)
166 {
167 /* If we get a reasonable period for which we correctly predict the
168 next bit, we must be in sync. */
169 /* Don't worry about max. zeros tests when resyncing.
170 It might just extend the resync time a little. Trying
171 to include the test might affect robustness. */
172 if (bit == (int) ((s->rx_reg >> s->shift) & 1))
173 {
174 if (++s->resync > s->resync_time)
175 {
176 s->resync = 0;
177 if (s->reporter)
178 s->reporter(s->user_data, BERT_REPORT_SYNCED, &s->results);
179 }
180 }
181 else
182 {
183 s->resync = 2;
184 s->rx_reg ^= s->mask;
185 }
186 }
187 else
188 {
189 if (s->max_zeros)
190 {
191 if ((s->rx_reg & s->mask))
192 {
193 if (++s->rx_zeros > s->max_zeros)
194 {
195 s->rx_zeros = 0;
196 bit ^= 1;
197 }
198 }
199 else
200 {
201 s->rx_zeros = 0;
202 }
203 }
204 s->results.total_bits++;
205 if (bit != (int) ((s->rx_reg >> s->shift) & 1))
206 {
207 s->results.bad_bits++;
208 s->resync_bad_bits++;
209 s->decade_bad[2][s->decade_ptr[2]]++;
210 }
211 if (--s->step <= 0)
212 {
213 s->step = 100;
214 test = TRUE;
215 for (i = 2; i <= 7; i++)
216 {
217 if (++s->decade_ptr[i] < 10)
218 break;
219 s->decade_ptr[i] = 0;
220 for (sum = 0, j = 0; j < 10; j++)
221 sum += s->decade_bad[i][j];
222 if (test && sum > 10)
223 {
224 test = FALSE;
225 if (s->error_rate != i && s->reporter)
226 s->reporter(s->user_data, BERT_REPORT_GT_10_2 + i - 2, &s->results);
227 s->error_rate = i;
228 }
229 s->decade_bad[i][0] = 0;
230 if (i < 7)
231 s->decade_bad[i + 1][s->decade_ptr[i + 1]] = sum;
232 }
233 if (i > 7)
234 {
235 if (s->decade_ptr[i] >= 10)
236 s->decade_ptr[i] = 0;
237 if (test)
238 {
239 if (s->error_rate != i && s->reporter)
240 s->reporter(s->user_data, BERT_REPORT_GT_10_2 + i - 2, &s->results);
241 s->error_rate = i;
242 }
243 }
244 else
245 {
246 s->decade_bad[i][s->decade_ptr[i]] = 0;
247 }
248 }
249 if (--s->resync_cnt <= 0)
250 {
251 /* Check if there were enough bad bits during this period to
252 justify a resync. */
253 if (s->resync_bad_bits >= (s->resync_len*s->resync_percent)/100)
254 {
255 s->resync = 1;
256 s->results.resyncs++;
257 if (s->reporter)
258 s->reporter(s->user_data, BERT_REPORT_UNSYNCED, &s->results);
259 }
260 s->resync_cnt = s->resync_len;
261 s->resync_bad_bits = 0;
262 }
263 }
264 s->rx_reg = (s->rx_reg >> 1) | (((s->rx_reg ^ (s->rx_reg >> s->shift)) & 1) << s->shift2);
265 break;
266 case 2:
267 s->rx_reg = (s->rx_reg >> 1) | (bit << 6);
268 /* TODO: There is no mechanism for synching yet. This only works if things start in sync. */
269 if (++s->rx_step_bit == 7)
270 {
271 s->rx_step_bit = 0;
272 if ((int) s->rx_reg != qbf[s->rx_step])
273 {
274 /* We need to work out the number of actual bad bits here. We need to look at the
275 error rate, and see it a resync is needed. etc. */
276 s->results.bad_bits++;
277 }
278 if (qbf[++s->rx_step] == '\0')
279 s->rx_step = 0;
280 }
281 s->results.total_bits++;
282 break;
283 }
284 if (s->report_frequency > 0)
285 {
286 if (--s->report_countdown <= 0)
287 {
288 if (s->reporter)
289 s->reporter(s->user_data, BERT_REPORT_REGULAR, &s->results);
290 s->report_countdown = s->report_frequency;
291 }
292 }
293 }
294 /*- End of function --------------------------------------------------------*/
295
296 int bert_result(bert_state_t *s, bert_results_t *results)
297 {
298 results->total_bits = s->results.total_bits;
299 results->bad_bits = s->results.bad_bits;
300 results->resyncs = s->results.resyncs;
301 return sizeof(*results);
302 }
303 /*- End of function --------------------------------------------------------*/
304
305 void bert_set_report(bert_state_t *s, int freq, bert_report_func_t reporter, void *user_data)
306 {
307 s->report_frequency = freq;
308 s->reporter = reporter;
309 s->user_data = user_data;
310
311 s->report_countdown = s->report_frequency;
312 }
313 /*- End of function --------------------------------------------------------*/
314
315 bert_state_t *bert_init(bert_state_t *s, int limit, int pattern, int resync_len, int resync_percent)
316 {
317 int i;
318 int j;
319
320 memset(s, 0, sizeof(*s));
321
322 s->pattern = pattern;
323 s->limit = limit;
324 s->reporter = NULL;
325 s->user_data = NULL;
326 s->report_frequency = 0;
327
328 s->resync_time = 72;
329 s->invert = 0;
330 switch (s->pattern)
331 {
332 case BERT_PATTERN_ZEROS:
333 s->tx_reg = 0;
334 s->shift2 = 31;
335 s->pattern_class = 0;
336 break;
337 case BERT_PATTERN_ONES:
338 s->tx_reg = ~((uint32_t) 0);
339 s->shift2 = 31;
340 s->pattern_class = 0;
341 break;
342 case BERT_PATTERN_7_TO_1:
343 s->tx_reg = 0xFEFEFEFE;
344 s->shift2 = 31;
345 s->pattern_class = 0;
346 break;
347 case BERT_PATTERN_3_TO_1:
348 s->tx_reg = 0xEEEEEEEE;
349 s->shift2 = 31;
350 s->pattern_class = 0;
351 break;
352 case BERT_PATTERN_1_TO_1:
353 s->tx_reg = 0xAAAAAAAA;
354 s->shift2 = 31;
355 s->pattern_class = 0;
356 break;
357 case BERT_PATTERN_1_TO_3:
358 s->tx_reg = 0x11111111;
359 s->shift2 = 31;
360 s->pattern_class = 0;
361 break;
362 case BERT_PATTERN_1_TO_7:
363 s->tx_reg = 0x01010101;
364 s->shift2 = 31;
365 s->pattern_class = 0;
366 break;
367 case BERT_PATTERN_QBF:
368 s->tx_reg = 0;
369 s->pattern_class = 2;
370 break;
371 case BERT_PATTERN_ITU_O151_23:
372 s->pattern_class = 1;
373 s->tx_reg = 0x7FFFFF;
374 s->mask = 0x20;
375 s->shift = 5;
376 s->shift2 = 22;
377 s->invert = 1;
378 s->resync_time = 56;
379 s->max_zeros = 0;
380 break;
381 case BERT_PATTERN_ITU_O151_20:
382 s->pattern_class = 1;
383 s->tx_reg = 0xFFFFF;
384 s->mask = 0x8;
385 s->shift = 3;
386 s->shift2 = 19;
387 s->invert = 1;
388 s->resync_time = 50;
389 s->max_zeros = 14;
390 break;
391 case BERT_PATTERN_ITU_O151_15:
392 s->pattern_class = 1;
393 s->tx_reg = 0x7FFF;
394 s->mask = 0x2;
395 s->shift = 1;
396 s->shift2 = 14;
397 s->invert = 1;
398 s->resync_time = 40;
399 s->max_zeros = 0;
400 break;
401 case BERT_PATTERN_ITU_O152_11:
402 s->pattern_class = 1;
403 s->tx_reg = 0x7FF;
404 s->mask = 0x4;
405 s->shift = 2;
406 s->shift2 = 10;
407 s->invert = 0;
408 s->resync_time = 32;
409 s->max_zeros = 0;
410 break;
411 case BERT_PATTERN_ITU_O153_9:
412 s->pattern_class = 1;
413 s->tx_reg = 0x1FF;
414 s->mask = 0x10;
415 s->shift = 4;
416 s->shift2 = 8;
417 s->invert = 0;
418 s->resync_time = 28;
419 s->max_zeros = 0;
420 break;
421 }
422 s->tx_bits = 0;
423 s->tx_step = 0;
424 s->tx_step_bit = 0;
425 s->tx_zeros = 0;
426
427 s->rx_reg = s->tx_reg;
428 s->ref_reg = s->rx_reg;
429 s->master_reg = s->ref_reg;
430 s->rx_bits = 0;
431 s->rx_step = 0;
432 s->rx_step_bit = 0;
433
434 s->resync = 1;
435 s->resync_cnt = resync_len;
436 s->resync_bad_bits = 0;
437 s->resync_len = resync_len;
438 s->resync_percent = resync_percent;
439 s->results.total_bits = 0;
440 s->results.bad_bits = 0;
441 s->results.resyncs = 0;
442
443 s->report_countdown = 0;
444
445 for (i = 0; i < 8; i++)
446 {
447 for (j = 0; j < 10; j++)
448 s->decade_bad[i][j] = 0;
449 s->decade_ptr[i] = 0;
450 }
451 s->error_rate = 8;
452 s->step = 100;
453
454 span_log_init(&s->logging, SPAN_LOG_NONE, NULL);
455 span_log_set_protocol(&s->logging, "BERT");
456
457 return s;
458 }
459 /*- End of function --------------------------------------------------------*/
460 /*- End of file ------------------------------------------------------------*/

Repositories maintained by Peter Meerwald, pmeerw@pmeerw.net.