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 ------------------------------------------------------------*/ |
