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
This commit is contained in:
parent
785476901c
commit
eb995b4a7e
|
@ -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
|
|
@ -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.
|
|
@ -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);
|
|
@ -0,0 +1,208 @@
|
||||||
|
/* (C) 2019 by Harald Welte <laforge@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);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,183 @@
|
||||||
|
/* (C) 2019 by Harald Welte <laforge@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)));
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,106 @@
|
||||||
|
/* (C) 2019 by Harald Welte <laforge@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;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,47 @@
|
||||||
|
/* (C) 2019 by Harald Welte <laforge@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);
|
||||||
|
}
|
|
@ -0,0 +1,66 @@
|
||||||
|
/* (C) 2019 by Harald Welte <laforge@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(¶m, 0, sizeof(param));
|
||||||
|
param.sched_priority = rt_prio;
|
||||||
|
rc = sched_setscheduler(getpid(), SCHED_RR, ¶m);
|
||||||
|
OSMO_ASSERT(rc == 0);
|
||||||
|
}
|
Loading…
Reference in New Issue