Mercurial > hg > audiostuff
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 ------------------------------------------------------------*/ |