laforge has submitted this change. ( 
https://gerrit.osmocom.org/c/osmo-e1d/+/16735 )

Change subject: contrib: add e1-prbs-test
......................................................................

contrib: add e1-prbs-test

e1-prbs-test is a small utility that can be used to do PRBS testing
on E1/T1 lines using DAHDI cards.  A transmiter and receiver are
exchanging timeslot-specific PRBS sequences.

Change-Id: Ib25d266e61e0d70919cc4e65d5b1bf0bc9ec7d00
---
A contrib/e1-prbs-test/Makefile
A contrib/e1-prbs-test/README
A contrib/e1-prbs-test/internal.h
A contrib/e1-prbs-test/main.c
A contrib/e1-prbs-test/prbs.c
A contrib/e1-prbs-test/rx.c
A contrib/e1-prbs-test/tx.c
A contrib/e1-prbs-test/utils.c
8 files changed, 727 insertions(+), 0 deletions(-)

Approvals:
  Jenkins Builder: Verified
  laforge: Looks good to me, approved



diff --git a/contrib/e1-prbs-test/Makefile b/contrib/e1-prbs-test/Makefile
new file mode 100644
index 0000000..726befc
--- /dev/null
+++ b/contrib/e1-prbs-test/Makefile
@@ -0,0 +1,16 @@
+LIBOSMO_CFLAGS:=$(shell pkg-config --cflags libosmocore)
+LIBOSMO_LIBS:=$(shell pkg-config --libs libosmocore)
+
+CFLAGS=-O2 -g -Wall -Werror $(LIBOSMO_CFLAGS)
+LIBS=$(LIBOSMO_LIBS)
+
+all: e1-prbs-test
+
+e1-prbs-test: main.o rx.o tx.o prbs.o utils.o
+       $(CC) $(LDFLAGS) -o $@ $^ $(LIBS)
+
+%.o: %.c
+       $(CC) $(CFLAGS) -o $@ -c $^
+
+clean:
+       @rm -f e1-prbs-test e1-prbs-test *.o
diff --git a/contrib/e1-prbs-test/README b/contrib/e1-prbs-test/README
new file mode 100644
index 0000000..903cc39
--- /dev/null
+++ b/contrib/e1-prbs-test/README
@@ -0,0 +1,36 @@
+e1-prbs-test - Utility to test for bit errors on E1 lines using DAHDI
+======================================================================
+
+e1-prbs-test can be used to test for bit errors in E1 transmission
+lines. It consists of a sender and a receiver, which should be used
+on either end of the E1 line.
+
+Transmitter and receiver can be on the same machine, or on different
+machines.
+
+The code currently works directly on DAHDI, so only DAHDI-supported E1
+cards are supported at this point.
+
+The test works by sending timeslot-specific PRBS sequences of 512 bit
+(64byte) length on the transmit side, and by correlating to those PRBS
+sequences on the receiver side.
+
+The use is relatively simple:
+
+For the A-side, assuming you would want to use DAHDI span 1:
+  e1-prbs-test /dev/dahdi/chan/001
+
+For the B-side, assuming you would want to use DAHDI span 2:
+  e1-prbs-test /dev/dahdi/chan/002
+
+The test will run indefinitely.
+
+If you'd like to get an interim report, send a SIGHUP to
+e1-prbs-test.
+
+If you'd like to stop, simply press Ctrl+C.
+There is a two-stage shut-down process.  When you press Ctrl+C for
+the first time, the report is printed, but transmission continues. At
+the second Ctrl+C, the process terminates.   You must press Ctrl+C for
+the first time on both A and B side, before pressing it the second time
+on the A-side in order to get correct results.
diff --git a/contrib/e1-prbs-test/internal.h b/contrib/e1-prbs-test/internal.h
new file mode 100644
index 0000000..681648a
--- /dev/null
+++ b/contrib/e1-prbs-test/internal.h
@@ -0,0 +1,65 @@
+#pragma once
+
+#include <stdint.h>
+#include <osmocom/core/prbs.h>
+#include <osmocom/core/select.h>
+
+#define MAX_NR_TS      31
+#define PRBS_LEN       2048
+
+/* prbs.c */
+
+struct timeslot_state;
+struct prbs_precomp {
+       uint8_t bytes[PRBS_LEN/8];
+};
+
+void prbs_for_ts_nr(struct osmo_prbs *prbs, uint8_t ts_nr);
+
+void prbs_precomp(struct prbs_precomp *out, const struct osmo_prbs *prbs);
+void ts_init_prbs_tx(struct timeslot_state *ts, unsigned int prbs_offs_tx);
+void ts_init_prbs_rx(struct timeslot_state *ts, unsigned int prbs_offs_rx);
+
+/* utils.c */
+uint8_t bits_set_in_byte(uint8_t byte);
+void cfg_dahdi_buffer(int fd);
+void set_realtime(int rt_prio);
+
+
+struct timeslot_state_tx {
+       struct osmo_prbs prbs;                  /* PRBS definition */
+       struct prbs_precomp prbs_pc;            /* pre-computed PRBS bytes */
+       unsigned int prbs_pc_idx;               /* next to-be-transmitted byte 
offset in prbs_pc */
+};
+
+struct timeslot_state_rx {
+       struct osmo_prbs prbs;                  /* PRBS definition */
+       struct prbs_precomp prbs_pc[8];         /* bit-shifted pre-computed 
PRBS sequences */
+       struct {
+               bool has_sync;                  /* do we have a PRBS sync? */
+               struct timespec ts_sync;        /* time at which sync was 
established */
+               unsigned int prbs_pc_num;       /* index to prbs_pc[] array */
+               unsigned int prbs_pc_offset;    /* offset of next byte into 
prbs_pc[pc_num].bytes[] */
+
+               unsigned int num_bit_err;       /* bit errors since last sync */
+               unsigned int num_sync_loss;     /* number of sync losses since 
start */
+       } sync_state;
+};
+
+
+struct timeslot_state {
+       struct osmo_fd ofd;
+       struct timeslot_state_tx tx;
+       struct timeslot_state_rx rx;
+};
+
+struct test_state {
+       struct timeslot_state ts[MAX_NR_TS];
+       unsigned int next_unused_ts;
+};
+
+/* rx.c */
+void process_rx(struct timeslot_state_rx *tsr, unsigned int ts_nr, const 
uint8_t *data, unsigned int len);
+
+/* tx.c */
+void process_tx(struct timeslot_state *ts, int len);
diff --git a/contrib/e1-prbs-test/main.c b/contrib/e1-prbs-test/main.c
new file mode 100644
index 0000000..4fe0e84
--- /dev/null
+++ b/contrib/e1-prbs-test/main.c
@@ -0,0 +1,208 @@
+/* (C) 2019 by Harald Welte <lafo...@gnumonks.org>
+ * All Rights Reserved
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#define _GNU_SOURCE
+#include <string.h>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <dirent.h>
+#include <fcntl.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <getopt.h>
+#include <unistd.h>
+#include <errno.h>
+#include <time.h>
+#include <signal.h>
+#include <dahdi/user.h>
+
+#include <osmocom/core/select.h>
+#include <osmocom/core/utils.h>
+#include <osmocom/core/bits.h>
+#include <osmocom/core/prbs.h>
+
+#include "internal.h"
+
+static struct test_state g_tst;
+static int g_prbs_offs_rx;
+static int g_prbs_offs_tx;
+
+static int e1_fd_cb(struct osmo_fd *ofd, unsigned int what)
+{
+       struct timeslot_state *ts = ofd->data;
+       uint8_t buf[4096];
+       int rc, len;
+
+       OSMO_ASSERT(what & OSMO_FD_READ);
+
+       /* read whatever data */
+       rc = read(ofd->fd, buf, sizeof(buf));
+       if (rc < 0) {
+               fprintf(stderr, "E1TS(%d) read: %d (%s)\n", ofd->priv_nr, rc, 
strerror(errno));
+               return rc;
+       }
+       len = rc;
+       process_rx(&ts->rx, ofd->priv_nr, buf, len);
+
+       /* generate as many bytes as were read */
+       process_tx(ts, len);
+
+       return 0;
+}
+
+static int open_slots(struct test_state *tst, const char *basedir)
+{
+       DIR *dir = opendir(basedir);
+       struct dirent *ent;
+       int rc, num_slots = 0;
+
+       if (!dir)
+               return -ENOENT;
+
+       while ((ent = readdir(dir))) {
+               struct timeslot_state *ts;
+               switch (ent->d_type) {
+               case DT_CHR:
+               case DT_FIFO:
+               case DT_SOCK:
+                       break;
+               default:
+                       printf("%s: skipping\n", ent->d_name);
+                       continue;
+               }
+
+               rc = openat(dirfd(dir), ent->d_name, O_RDWR);
+               if (rc < 0) {
+                       fprintf(stderr, "Error opening %s: %d (%s)\n", 
ent->d_name, rc, strerror(errno));
+                       return -1;
+               }
+               ts = &tst->ts[tst->next_unused_ts++];
+
+               /* open the respective file descriptor */
+               osmo_fd_setup(&ts->ofd, rc, BSC_FD_READ, e1_fd_cb, ts, 
atoi(ent->d_name));
+               osmo_fd_register(&ts->ofd);
+               printf("E1TS(%02u) opened\n", ts->ofd.priv_nr);
+
+               ts_init_prbs_tx(ts, g_prbs_offs_tx);
+               ts_init_prbs_rx(ts, g_prbs_offs_rx);
+
+               /* start to put something into the transmit queue, before we 
get read-triggered
+                * later on */
+               process_tx(ts, 1024);
+
+               cfg_dahdi_buffer(ts->ofd.fd);
+               struct dahdi_bufferinfo bi;
+               rc = ioctl(ts->ofd.fd, DAHDI_GET_BUFINFO, &bi);
+               OSMO_ASSERT(rc == 0);
+               printf("tx_pol=%d, rx_pol=%d, num=%d, size=%d, nread=%d, 
nwrite=%d\n",
+                       bi.txbufpolicy, bi.rxbufpolicy, bi.numbufs, bi.bufsize, 
bi.readbufs, bi.writebufs);
+               num_slots++;
+       }
+       closedir(dir);
+       return num_slots;
+}
+
+static void print_report(void)
+{
+       struct timespec ts_now;
+       int i;
+
+       clock_gettime(CLOCK_MONOTONIC, &ts_now);
+
+       for (i = 0; i < ARRAY_SIZE(g_tst.ts); i++) {
+               const struct timeslot_state *ts = &g_tst.ts[i];
+               printf("E1TS(%02u) STATS: sync_losses=%u, bit_errs=%u in %lu 
seconds\n",
+                       ts->ofd.priv_nr, ts->rx.sync_state.num_sync_loss, 
ts->rx.sync_state.num_bit_err,
+                       ts_now.tv_sec - ts->rx.sync_state.ts_sync.tv_sec);
+       }
+}
+
+static int g_ctrlc_count = 0;
+
+static void sig_handler(int signal)
+{
+       switch (signal) {
+       case SIGINT:
+               g_ctrlc_count++;
+               if (g_ctrlc_count == 1) {
+                       print_report();
+                       printf("\nPlease stop remote end before pressing Ctrl+C 
another time\n");
+               }
+               if (g_ctrlc_count > 1)
+                       exit(0);
+               break;
+       case SIGHUP:
+               print_report();
+               break;
+       }
+}
+
+static void handle_options(int argc, char **argv)
+{
+       while (1) {
+               int c;
+               static const struct option long_opts[] = {
+                       { "rx-prbs-offset", 1, 0, 'r' },
+                       { "tx-prbs-offset", 1, 0, 't' },
+                       { 0, 0, 0, 0 }
+               };
+               c = getopt_long(argc, argv, "r:t:", long_opts, NULL);
+               if (c == -1)
+                       break;
+
+               switch (c) {
+               case 'r':
+                       g_prbs_offs_rx = atoi(optarg);
+                       break;
+               case 't':
+                       g_prbs_offs_tx = atoi(optarg);
+                       break;
+               default:
+                       exit(1);
+               }
+       }
+}
+
+int main(int argc, char **argv)
+{
+       char *basedir;
+       int rc;
+
+       handle_options(argc, argv);
+
+       if (argc <= optind) {
+               fprintf(stderr, "You must specify the base-path of your DAHDI 
span "
+                       "like /dev/dahdi/chan/001\n");
+               exit(1);
+       }
+       basedir = argv[optind];
+
+       set_realtime(10);
+       rc = open_slots(&g_tst, basedir);
+       printf("==> opened a total of %d slots\n", rc);
+
+       signal(SIGINT, sig_handler);
+       signal(SIGHUP, sig_handler);
+       while (1) {
+               osmo_select_main(0);
+       }
+}
diff --git a/contrib/e1-prbs-test/prbs.c b/contrib/e1-prbs-test/prbs.c
new file mode 100644
index 0000000..ed8a80a
--- /dev/null
+++ b/contrib/e1-prbs-test/prbs.c
@@ -0,0 +1,183 @@
+/* (C) 2019 by Harald Welte <lafo...@gnumonks.org>
+ * All Rights Reserved
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <stdint.h>
+#include <string.h>
+#include <osmocom/core/utils.h>
+#include <osmocom/core/prbs.h>
+
+#include "internal.h"
+
+/* according to https://users.ece.cmu.edu/~koopman/lfsr/index.html all below
+ * coefficients should render maximal length LFSRs of 11bit (2048) length */
+static const uint32_t prbs11_coeff[] = {
+       0x402,
+       0x40B,
+       0x415,
+       0x416,
+       0x423,
+       0x431,
+       0x432,
+       0x438,
+       0x43D,
+       0x446,
+       0x44A,
+       0x44F,
+       0x454,
+       0x458,
+       0x467,
+       0x468,
+       0x470,
+       0x473,
+       0x475,
+       0x47A,
+       0x486,
+       0x489,
+       0x492,
+       0x494,
+       0x49D,
+       0x49E,
+       0x4A2,
+       0x4A4,
+       0x4A8,
+       0x4AD,
+       0x4B9,
+       0x4BA,
+       0x4BF,
+       0x4C1,
+       0x4C7,
+       0x4D5,
+       0x4D6,
+       0x4DC,
+       0x4E3,
+       0x4EC,
+       0x4F2,
+       0x4FB,
+       0x500,
+       0x503,
+       0x509,
+       0x50A,
+       0x514,
+       0x524,
+       0x530,
+       0x536,
+       0x53C,
+       0x53F,
+       0x542,
+       0x548,
+       0x54E,
+       0x553,
+       0x555,
+       0x559,
+       0x55A,
+       0x56A,
+       0x56F,
+       0x574,
+       0x577,
+       0x578,
+       0x57D,
+       0x581,
+       0x584,
+       0x588,
+       0x599,
+       0x59F,
+       0x5A0,
+       0x5A5,
+       0x5AC,
+       0x5AF,
+       0x5B2,
+       0x5B7,
+       0x5BE,
+       0x5C3,
+       0x5C5,
+       0x5C9,
+       0x5CA,
+       0x5D7,
+       0x5DB,
+       0x5DE,
+       0x5E4,
+       0x5ED,
+       0x5EE,
+       0x5F3,
+       0x5F6,
+       0x605,
+       0x606,
+       0x60C,
+       0x60F,
+       0x62B,
+       0x630,
+       0x635,
+       0x639,
+       0x642,
+       0x644,
+       0x64B
+};
+
+/* build the PRBS description for a given timeslot number */
+void prbs_for_ts_nr(struct osmo_prbs *prbs, uint8_t ts_nr)
+{
+
+       OSMO_ASSERT(ts_nr < ARRAY_SIZE(prbs11_coeff));
+       prbs->name = "custom";
+       prbs->len = 11;
+       prbs->coeff = prbs11_coeff[ts_nr];
+}
+
+/* compute one full sequence of the given PRBS */
+void prbs_precomp(struct prbs_precomp *out, const struct osmo_prbs *prbs)
+{
+       struct osmo_prbs_state prbs_s;
+       int i;
+
+       osmo_prbs_state_init(&prbs_s, prbs);
+       for (i = 0; i < sizeof(out->bytes); i++) {
+               ubit_t ubit[8];
+               osmo_prbs_get_ubits(ubit, sizeof(ubit), &prbs_s);
+               osmo_ubit2pbit(&out->bytes[i], ubit, sizeof(ubit));
+       }
+}
+
+void ts_init_prbs_tx(struct timeslot_state *ts, unsigned int prbs_offs_tx)
+{
+       unsigned int prbs_nr = prbs_offs_tx + ts->ofd.priv_nr;
+       /* initialize the transmit-side PRNG for this slot */
+       printf("Selecting PRBS11 #%02u for Tx of TS%02u\n", prbs_nr, 
ts->ofd.priv_nr);
+       prbs_for_ts_nr(&ts->tx.prbs, prbs_nr);
+       prbs_precomp(&ts->tx.prbs_pc, &ts->tx.prbs);
+}
+
+void ts_init_prbs_rx(struct timeslot_state *ts, unsigned int prbs_offs_rx)
+{
+       unsigned int prbs_nr = prbs_offs_rx + ts->ofd.priv_nr;
+       /* initialize the receive-side PRNG for this slot */
+       ubit_t ubit[PRBS_LEN*2];
+       printf("Selecting PRBS11 #%02u for Rx of TS%02u\n", prbs_nr, 
ts->ofd.priv_nr);
+       prbs_for_ts_nr(&ts->rx.prbs, prbs_nr);
+       prbs_precomp(&ts->rx.prbs_pc[0], &ts->rx.prbs);
+       osmo_pbit2ubit(ubit, ts->rx.prbs_pc[0].bytes, PRBS_LEN);
+       /* copy buffer twice back-to-back */
+       memcpy(ubit+PRBS_LEN, ubit, PRBS_LEN);
+
+       /* pre-compute bit-shifted versions */
+       for (int i = 1; i < ARRAY_SIZE(ts->rx.prbs_pc); i++) {
+               osmo_ubit2pbit_ext(ts->rx.prbs_pc[i].bytes, 0, ubit, i, 
PRBS_LEN, 0);
+               //printf("%d: %s\n", i, 
osmo_hexdump_nospc(ts->prbs_pc[i].bytes, sizeof(ts->prbs_pc[i].bytes)));
+       }
+}
diff --git a/contrib/e1-prbs-test/rx.c b/contrib/e1-prbs-test/rx.c
new file mode 100644
index 0000000..bb6967d
--- /dev/null
+++ b/contrib/e1-prbs-test/rx.c
@@ -0,0 +1,106 @@
+/* (C) 2019 by Harald Welte <lafo...@gnumonks.org>
+ * All Rights Reserved
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#define _GNU_SOURCE
+#include <string.h>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <errno.h>
+#include <time.h>
+
+#include <osmocom/core/select.h>
+#include <osmocom/core/utils.h>
+
+#include "internal.h"
+
+static uint8_t next_prbs_pc_byte(struct timeslot_state_rx *tsr)
+{
+       const struct prbs_precomp *pc = 
&tsr->prbs_pc[tsr->sync_state.prbs_pc_num];
+       uint8_t ret = pc->bytes[tsr->sync_state.prbs_pc_offset];
+       tsr->sync_state.prbs_pc_offset = (tsr->sync_state.prbs_pc_offset + 1) % 
sizeof(pc->bytes);
+       return ret;
+}
+
+/* compare if received buffer matches PRBS; count number of different bits */
+static unsigned int compare_buf(struct timeslot_state_rx *tsr, const uint8_t 
*data, unsigned int len)
+{
+       unsigned int i, num_wrong_bits = 0;
+
+       for (i = 0; i < len; i++) {
+               uint8_t bt = next_prbs_pc_byte(tsr);
+               if (data[i] != bt) {
+                       uint8_t x = data[i] ^ bt;
+                       num_wrong_bits += bits_set_in_byte(x);
+               }
+       }
+       return num_wrong_bits;
+}
+
+/* process incoming received data; try to correlate with prbs sequence */
+void process_rx(struct timeslot_state_rx *tsr, unsigned int ts_nr, const 
uint8_t *data, unsigned int len)
+{
+       if (!tsr->sync_state.has_sync) {
+               unsigned int pc_num;
+               /* we haven't synced yet and must attempt to sync to the 
pattern.  We will try
+                * to match each pattern */
+               for (pc_num = 0; pc_num < ARRAY_SIZE(tsr->prbs_pc); pc_num++) {
+                       const struct prbs_precomp *pc = &tsr->prbs_pc[pc_num];
+                       uint8_t *found;
+                       long int offset;
+
+                       OSMO_ASSERT(len > sizeof(pc->bytes));
+                       found = memmem(data, len, pc->bytes, sizeof(pc->bytes));
+                       if (!found)
+                               continue;
+
+                       offset = (found - data);
+                       printf("E1TS(%02u) FOUND SYNC (pc_num=%u, 
offset=%li)\n", ts_nr,
+                               pc_num, offset);
+                       clock_gettime(CLOCK_MONOTONIC, 
&tsr->sync_state.ts_sync);
+                       tsr->sync_state.has_sync = true;
+                       tsr->sync_state.prbs_pc_num = pc_num;
+                       tsr->sync_state.prbs_pc_offset = (sizeof(pc->bytes) - 
offset) % sizeof(pc->bytes);
+                       tsr->sync_state.num_bit_err = 0;
+                       /* FIXME: compare the remainder of the buffer */
+                       return;
+               }
+       }
+       if (tsr->sync_state.has_sync) {
+               unsigned int num_wrong_bits;
+               /* we already have sync */
+               num_wrong_bits = compare_buf(tsr, data, len);
+               if (num_wrong_bits >= len*8/4) { /* more than 25% of wrong bits 
*/
+                       struct timespec ts_now;
+                       clock_gettime(CLOCK_MONOTONIC, &ts_now);
+                       printf("E1TS(%02u) LOST SYNC after %u of %u wrong bits 
in one buffer; "
+                               "until now, total bit errors %u in %lu 
seconds\n", ts_nr,
+                               num_wrong_bits, len*8, 
tsr->sync_state.num_bit_err,
+                               ts_now.tv_sec - tsr->sync_state.ts_sync.tv_sec);
+                       tsr->sync_state.has_sync = false;
+                       tsr->sync_state.num_sync_loss++;
+               }
+               tsr->sync_state.num_bit_err += num_wrong_bits;
+       }
+}
diff --git a/contrib/e1-prbs-test/tx.c b/contrib/e1-prbs-test/tx.c
new file mode 100644
index 0000000..6d775d7
--- /dev/null
+++ b/contrib/e1-prbs-test/tx.c
@@ -0,0 +1,47 @@
+/* (C) 2019 by Harald Welte <lafo...@gnumonks.org>
+ * All Rights Reserved
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <errno.h>
+#include <string.h>
+
+#include <osmocom/core/select.h>
+#include <osmocom/core/utils.h>
+
+#include "internal.h"
+
+void process_tx(struct timeslot_state *ts, int len)
+{
+       uint8_t buf[4096];
+       int i, rc;
+
+       for (i = 0; i < len; i++) {
+               buf[i] = ts->tx.prbs_pc.bytes[ts->tx.prbs_pc_idx];
+               ts->tx.prbs_pc_idx = (ts->tx.prbs_pc_idx + 1) % 
sizeof(ts->tx.prbs_pc);
+       }
+       rc = write(ts->ofd.fd, buf, len);
+       if (rc != len)
+               fprintf(stderr, "E1TS(%02u) write: %d bytes less than %d\n", 
ts->ofd.priv_nr, rc, len);
+}
diff --git a/contrib/e1-prbs-test/utils.c b/contrib/e1-prbs-test/utils.c
new file mode 100644
index 0000000..5610e80
--- /dev/null
+++ b/contrib/e1-prbs-test/utils.c
@@ -0,0 +1,66 @@
+/* (C) 2019 by Harald Welte <lafo...@gnumonks.org>
+ * All Rights Reserved
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <stdint.h>
+#include <string.h>
+#include <sched.h>
+#include <unistd.h>
+#include <sys/ioctl.h>
+#include <sys/types.h>
+#include <dahdi/user.h>
+
+#include <osmocom/core/utils.h>
+
+/* we could generate a lookup table at start ... */
+uint8_t bits_set_in_byte(uint8_t byte)
+{
+       uint8_t ret = 0;
+       int i;
+
+       for (i = 0; i < 8; i++) {
+               if (byte & (1 << i))
+                       ret += 1;
+       }
+       return ret;
+}
+
+void cfg_dahdi_buffer(int fd)
+{
+       struct dahdi_bufferinfo bi = {
+               .txbufpolicy = DAHDI_POLICY_WHEN_FULL, /* default is immediate 
*/
+               .rxbufpolicy = DAHDI_POLICY_WHEN_FULL, /* default is immediate 
*/
+               .numbufs = 8, /* default is 2 */
+               .bufsize = 1024, /* default is 1024 */
+               .readbufs = -1,
+               .writebufs = -1,
+       };
+       OSMO_ASSERT(ioctl(fd, DAHDI_SET_BUFINFO, &bi) == 0);
+}
+
+void set_realtime(int rt_prio)
+{
+       struct sched_param param;
+       int rc;
+
+       memset(&param, 0, sizeof(param));
+       param.sched_priority = rt_prio;
+       rc = sched_setscheduler(getpid(), SCHED_RR, &param);
+       OSMO_ASSERT(rc == 0);
+}

--
To view, visit https://gerrit.osmocom.org/c/osmo-e1d/+/16735
To unsubscribe, or for help writing mail filters, visit 
https://gerrit.osmocom.org/settings

Gerrit-Project: osmo-e1d
Gerrit-Branch: master
Gerrit-Change-Id: Ib25d266e61e0d70919cc4e65d5b1bf0bc9ec7d00
Gerrit-Change-Number: 16735
Gerrit-PatchSet: 3
Gerrit-Owner: laforge <lafo...@osmocom.org>
Gerrit-Reviewer: Jenkins Builder
Gerrit-Reviewer: laforge <lafo...@osmocom.org>
Gerrit-MessageType: merged

Reply via email to