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