diff 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
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/spandsp-0.0.3/spandsp-0.0.3/src/bert.c	Fri Jun 25 16:00:21 2010 +0200
@@ -0,0 +1,460 @@
+/*
+ * SpanDSP - a series of DSP components for telephony
+ *
+ * bert.c - Bit error rate tests.
+ *
+ * Written by Steve Underwood <steveu@coppice.org>
+ *
+ * Copyright (C) 2004 Steve Underwood
+ *
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2, as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id: bert.c,v 1.21 2006/11/19 14:07:24 steveu Exp $
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <inttypes.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <assert.h>
+#include <time.h>
+
+#include "spandsp/telephony.h"
+#include "spandsp/logging.h"
+#include "spandsp/async.h"
+#include "spandsp/bert.h"
+
+static const char *qbf = "VoyeZ Le BricK GeanT QuE J'ExaminE PreS Du WharF 123 456 7890 + - * : = $ % ( )"
+                         "ThE QuicK BrowN FoX JumpS OveR ThE LazY DoG 123 456 7890 + - * : = $ % ( )";
+
+int bert_get_bit(bert_state_t *s)
+{
+    int bit;
+
+    if (s->limit  &&  s->tx_bits >= s->limit)
+        return PUTBIT_END_OF_DATA;
+    bit = 0;
+    switch (s->pattern_class)
+    {
+    case 0:
+        bit = s->tx_reg & 1;
+        s->tx_reg = (s->tx_reg >> 1) | ((s->tx_reg & 1) << s->shift2);
+        break;
+    case 1:
+        bit = s->tx_reg & 1;
+        s->tx_reg = (s->tx_reg >> 1) | (((s->tx_reg ^ (s->tx_reg >> s->shift)) & 1) << s->shift2);
+        if (s->max_zeros)
+        {
+            /* This generator suppresses runs >s->max_zeros */
+            if (bit)
+            {
+                if (++s->tx_zeros > s->max_zeros)
+                {
+                    s->tx_zeros = 0;
+                    bit ^= 1;
+                }
+            }
+            else
+            {
+                s->tx_zeros = 0;
+            }
+        }
+        bit ^= s->invert;
+        break;
+    case 2:
+        if (s->tx_step_bit == 0)
+        {
+            s->tx_step_bit = 7;
+            s->tx_reg = qbf[s->tx_step++];
+            if (s->tx_reg == 0)
+            {
+                s->tx_reg = 'V';
+                s->tx_step = 1;
+            }
+        }
+        bit = s->tx_reg & 1;
+        s->tx_reg >>= 1;
+        s->tx_step_bit--;
+        break;
+    }
+    s->tx_bits++;
+    return bit;
+}
+/*- End of function --------------------------------------------------------*/
+
+void bert_put_bit(bert_state_t *s, int bit)
+{
+    int i;
+    int j;
+    int sum;
+    int test;
+
+    if (bit < 0)
+    {
+        /* Special conditions */
+        switch (bit)
+        {
+        case PUTBIT_TRAINING_FAILED:
+            span_log(&s->logging, SPAN_LOG_FLOW, "Training failed\n");
+            break;
+        case PUTBIT_TRAINING_SUCCEEDED:
+            span_log(&s->logging, SPAN_LOG_FLOW, "Training succeeded\n");
+            break;
+        case PUTBIT_CARRIER_UP:
+            span_log(&s->logging, SPAN_LOG_FLOW, "Carrier up\n");
+            break;
+        case PUTBIT_CARRIER_DOWN:
+            span_log(&s->logging, SPAN_LOG_FLOW, "Carrier down\n");
+            break;
+        default:
+            span_log(&s->logging, SPAN_LOG_FLOW, "Eh!\n");
+            break;
+        }
+        return;
+    }
+    bit = (bit & 1) ^ s->invert;
+    s->rx_bits++;
+    switch (s->pattern_class)
+    {
+    case 0:
+        if (s->resync)
+        {
+            s->rx_reg = (s->rx_reg >> 1) | (bit << s->shift2);
+            s->ref_reg = (s->ref_reg >> 1) | ((s->ref_reg & 1) << s->shift2);
+            if (s->rx_reg == s->ref_reg)
+            {
+                if (++s->resync > s->resync_time)
+                {
+                    s->resync = 0;
+                    if (s->reporter)
+                        s->reporter(s->user_data, BERT_REPORT_SYNCED, &s->results);
+                }
+            }
+            else
+            {
+                s->resync = 2;
+                s->ref_reg = s->master_reg;
+            }
+        }
+        else
+        {
+            s->results.total_bits++;
+            if ((bit ^ s->ref_reg) & 1)
+                s->results.bad_bits++;
+            s->ref_reg = (s->ref_reg >> 1) | ((s->ref_reg & 1) << s->shift2);
+        }
+        break;
+    case 1:
+        if (s->resync)
+        {
+            /* If we get a reasonable period for which we correctly predict the
+               next bit, we must be in sync. */
+            /* Don't worry about max. zeros tests when resyncing.
+               It might just extend the resync time a little. Trying
+               to include the test might affect robustness. */
+            if (bit == (int) ((s->rx_reg >> s->shift) & 1))
+            {
+                if (++s->resync > s->resync_time)
+                {
+                    s->resync = 0;
+                    if (s->reporter)
+                        s->reporter(s->user_data, BERT_REPORT_SYNCED, &s->results);
+                }
+            }
+            else
+            {
+                s->resync = 2;
+                s->rx_reg ^= s->mask;
+            }
+        }
+        else
+        {
+            if (s->max_zeros)
+            {
+                if ((s->rx_reg & s->mask))
+                {
+                    if (++s->rx_zeros > s->max_zeros)
+                    {
+                        s->rx_zeros = 0;
+                        bit ^= 1;
+                    }
+                }
+                else
+                {
+                    s->rx_zeros = 0;
+                }
+            }
+            s->results.total_bits++;
+            if (bit != (int) ((s->rx_reg >> s->shift) & 1))
+            {
+                s->results.bad_bits++;
+                s->resync_bad_bits++;
+                s->decade_bad[2][s->decade_ptr[2]]++;
+            }
+            if (--s->step <= 0)
+            {
+                s->step = 100;
+                test = TRUE;
+                for (i = 2;  i <= 7;  i++)
+                {
+                    if (++s->decade_ptr[i] < 10)
+                        break;
+                    s->decade_ptr[i] = 0;
+                    for (sum = 0, j = 0;  j < 10;  j++)
+                        sum += s->decade_bad[i][j];
+                    if (test  &&  sum > 10)
+                    {
+                        test = FALSE;
+                        if (s->error_rate != i  &&  s->reporter)
+                            s->reporter(s->user_data, BERT_REPORT_GT_10_2 + i - 2, &s->results);
+                        s->error_rate = i;
+                    }
+                    s->decade_bad[i][0] = 0;
+                    if (i < 7)
+                        s->decade_bad[i + 1][s->decade_ptr[i + 1]] = sum;
+                }
+                if (i > 7)
+                {
+                    if (s->decade_ptr[i] >= 10)
+                        s->decade_ptr[i] = 0;
+                    if (test)
+                    {
+                        if (s->error_rate != i  &&  s->reporter)
+                            s->reporter(s->user_data, BERT_REPORT_GT_10_2 + i - 2, &s->results);
+                        s->error_rate = i;
+                    }
+                }
+                else
+                {
+                    s->decade_bad[i][s->decade_ptr[i]] = 0;
+                }
+            }
+            if (--s->resync_cnt <= 0)
+            {
+                /* Check if there were enough bad bits during this period to
+                   justify a resync. */
+                if (s->resync_bad_bits >= (s->resync_len*s->resync_percent)/100)
+                {
+                    s->resync = 1;
+                    s->results.resyncs++;
+                    if (s->reporter)
+                        s->reporter(s->user_data, BERT_REPORT_UNSYNCED, &s->results);
+                }
+                s->resync_cnt = s->resync_len;
+                s->resync_bad_bits = 0;
+            }
+        }
+        s->rx_reg = (s->rx_reg >> 1) | (((s->rx_reg ^ (s->rx_reg >> s->shift)) & 1) << s->shift2);
+        break;
+    case 2:
+        s->rx_reg = (s->rx_reg >> 1) | (bit << 6);
+        /* TODO: There is no mechanism for synching yet. This only works if things start in sync. */
+        if (++s->rx_step_bit == 7)
+        {
+            s->rx_step_bit = 0;
+            if ((int) s->rx_reg != qbf[s->rx_step])
+            {
+                /* We need to work out the number of actual bad bits here. We need to look at the
+                   error rate, and see it a resync is needed. etc. */
+                s->results.bad_bits++;
+            }
+            if (qbf[++s->rx_step] == '\0')
+                s->rx_step = 0;
+        }
+        s->results.total_bits++;
+        break;
+    }
+    if (s->report_frequency > 0)
+    {
+        if (--s->report_countdown <= 0)
+        {
+            if (s->reporter)
+                s->reporter(s->user_data, BERT_REPORT_REGULAR, &s->results);
+            s->report_countdown = s->report_frequency;
+        }
+    }
+}
+/*- End of function --------------------------------------------------------*/
+
+int bert_result(bert_state_t *s, bert_results_t *results)
+{
+    results->total_bits = s->results.total_bits;
+    results->bad_bits = s->results.bad_bits;
+    results->resyncs = s->results.resyncs;
+    return sizeof(*results);
+}
+/*- End of function --------------------------------------------------------*/
+
+void bert_set_report(bert_state_t *s, int freq, bert_report_func_t reporter, void *user_data)
+{
+    s->report_frequency = freq;
+    s->reporter = reporter;
+    s->user_data = user_data;
+    
+    s->report_countdown = s->report_frequency;
+}
+/*- End of function --------------------------------------------------------*/
+
+bert_state_t *bert_init(bert_state_t *s, int limit, int pattern, int resync_len, int resync_percent)
+{
+    int i;
+    int j;
+
+    memset(s, 0, sizeof(*s));
+
+    s->pattern = pattern;
+    s->limit = limit;
+    s->reporter = NULL;
+    s->user_data = NULL;
+    s->report_frequency = 0;
+
+    s->resync_time = 72;
+    s->invert = 0;
+    switch (s->pattern)
+    {
+    case BERT_PATTERN_ZEROS:
+        s->tx_reg = 0;
+        s->shift2 = 31;
+        s->pattern_class = 0;
+        break;
+    case BERT_PATTERN_ONES:
+        s->tx_reg = ~((uint32_t) 0);
+        s->shift2 = 31;
+        s->pattern_class = 0;
+        break;
+    case BERT_PATTERN_7_TO_1:
+        s->tx_reg = 0xFEFEFEFE;
+        s->shift2 = 31;
+        s->pattern_class = 0;
+        break;
+    case BERT_PATTERN_3_TO_1:
+        s->tx_reg = 0xEEEEEEEE;
+        s->shift2 = 31;
+        s->pattern_class = 0;
+        break;
+    case BERT_PATTERN_1_TO_1:
+        s->tx_reg = 0xAAAAAAAA;
+        s->shift2 = 31;
+        s->pattern_class = 0;
+        break;
+    case BERT_PATTERN_1_TO_3:
+        s->tx_reg = 0x11111111;
+        s->shift2 = 31;
+        s->pattern_class = 0;
+        break;
+    case BERT_PATTERN_1_TO_7:
+        s->tx_reg = 0x01010101;
+        s->shift2 = 31;
+        s->pattern_class = 0;
+        break;
+    case BERT_PATTERN_QBF:
+        s->tx_reg = 0;
+        s->pattern_class = 2;
+        break;
+    case BERT_PATTERN_ITU_O151_23:
+        s->pattern_class = 1;
+        s->tx_reg = 0x7FFFFF;
+        s->mask = 0x20;
+        s->shift = 5;
+        s->shift2 = 22;
+        s->invert = 1;
+        s->resync_time = 56;
+        s->max_zeros = 0;
+        break;
+    case BERT_PATTERN_ITU_O151_20:
+        s->pattern_class = 1;
+        s->tx_reg = 0xFFFFF;
+        s->mask = 0x8;
+        s->shift = 3;
+        s->shift2 = 19;
+        s->invert = 1;
+        s->resync_time = 50;
+        s->max_zeros = 14;
+        break;
+    case BERT_PATTERN_ITU_O151_15:
+        s->pattern_class = 1;
+        s->tx_reg = 0x7FFF;
+        s->mask = 0x2;
+        s->shift = 1;
+        s->shift2 = 14;
+        s->invert = 1;
+        s->resync_time = 40;
+        s->max_zeros = 0;
+        break;
+    case BERT_PATTERN_ITU_O152_11:
+        s->pattern_class = 1;
+        s->tx_reg = 0x7FF;
+        s->mask = 0x4;
+        s->shift = 2;
+        s->shift2 = 10;
+        s->invert = 0;
+        s->resync_time = 32;
+        s->max_zeros = 0;
+        break;
+    case BERT_PATTERN_ITU_O153_9:
+        s->pattern_class = 1;
+        s->tx_reg = 0x1FF;
+        s->mask = 0x10;
+        s->shift = 4;
+        s->shift2 = 8;
+        s->invert = 0;
+        s->resync_time = 28;
+        s->max_zeros = 0;
+        break;
+    }
+    s->tx_bits = 0;
+    s->tx_step = 0;
+    s->tx_step_bit = 0;
+    s->tx_zeros = 0;
+
+    s->rx_reg = s->tx_reg;
+    s->ref_reg = s->rx_reg;
+    s->master_reg = s->ref_reg;
+    s->rx_bits = 0;
+    s->rx_step = 0;
+    s->rx_step_bit = 0;
+
+    s->resync = 1;
+    s->resync_cnt = resync_len;
+    s->resync_bad_bits = 0;
+    s->resync_len = resync_len;
+    s->resync_percent = resync_percent;
+    s->results.total_bits = 0;
+    s->results.bad_bits = 0;
+    s->results.resyncs = 0;
+
+    s->report_countdown = 0;
+
+    for (i = 0;  i < 8;  i++)
+    {
+        for (j = 0;  j < 10;  j++)
+            s->decade_bad[i][j] = 0;
+        s->decade_ptr[i] = 0;
+    }
+    s->error_rate = 8;
+    s->step = 100;
+    
+    span_log_init(&s->logging, SPAN_LOG_NONE, NULL);
+    span_log_set_protocol(&s->logging, "BERT");
+
+    return  s;
+}
+/*- End of function --------------------------------------------------------*/
+/*- End of file ------------------------------------------------------------*/

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