This is merely a historical archive of years 2008-2021, before the migration to mailman3.
A maintained and still updated list archive can be found at https://lists.osmocom.org/hyperkitty/list/gerrit-log@lists.osmocom.org/.
laforge gerrit-no-reply at lists.osmocom.orglaforge has uploaded this change for review. ( https://gerrit.osmocom.org/c/osmo-e1d/+/16735 ) Change subject: add e1-prbs-test ...................................................................... add e1-prbs-test 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/prbs.c A contrib/e1-prbs-test/rx.c A contrib/e1-prbs-test/tx.c A contrib/e1-prbs-test/utils.c 7 files changed, 668 insertions(+), 0 deletions(-) git pull ssh://gerrit.osmocom.org:29418/osmo-e1d refs/changes/35/16735/1 diff --git a/contrib/e1-prbs-test/Makefile b/contrib/e1-prbs-test/Makefile new file mode 100644 index 0000000..e692880 --- /dev/null +++ b/contrib/e1-prbs-test/Makefile @@ -0,0 +1,19 @@ +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-tx e1-prbs-test-rx + +e1-prbs-test-tx: tx.o prbs.o utils.o + $(CC) $(LDFLAGS) -o $@ $^ $(LIBS) + +e1-prbs-test-rx: rx.o prbs.o utils.o + $(CC) $(LDFLAGS) -o $@ $^ $(LIBS) + +%.o: %.c + $(CC) $(CFLAGS) -o $@ -c $^ + +clean: + @rm -f e1-prbs-test-tx e1-prbs-test-rx *.o diff --git a/contrib/e1-prbs-test/README b/contrib/e1-prbs-test/README new file mode 100644 index 0000000..c2f78df --- /dev/null +++ b/contrib/e1-prbs-test/README @@ -0,0 +1,32 @@ +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 (e1-prbs-test-tx) and a receiver +(e1-prbs-test-rx), 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 transmit side, assuming you would want to use DAHDI span 1: + e1-prbs-test-tx /dev/dahdi/chan/001 + +For the transmit side, assuming you would want to use DAHDI span 2: + e1-prbs-test-rx /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-rx. If you'd like to stop, simply press ctrl+c on +e1-prbs-test-rx. Make sure you terminate e1-prbs-test-rx first. If you +terminate e1-prbs-test-tx before e1-prbs-test-rx, it will negatively +affect your test results. diff --git a/contrib/e1-prbs-test/internal.h b/contrib/e1-prbs-test/internal.h new file mode 100644 index 0000000..b3f1874 --- /dev/null +++ b/contrib/e1-prbs-test/internal.h @@ -0,0 +1,18 @@ +#pragma once + +#define PRBS_LEN 512 + +struct prbs_precomp { + uint8_t bytes[PRBS_LEN/8]; +}; + +/* prbs.c */ +#include <osmocom/core/prbs.h> +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); + +/* utils.c */ +uint8_t bits_set_in_byte(uint8_t byte); +void cfg_dahdi_buffer(int fd); +void set_realtime(int rt_prio); diff --git a/contrib/e1-prbs-test/prbs.c b/contrib/e1-prbs-test/prbs.c new file mode 100644 index 0000000..1a2c3d3 --- /dev/null +++ b/contrib/e1-prbs-test/prbs.c @@ -0,0 +1,103 @@ +/* (C) 2019 by Harald Welte <laforge at 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 <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 9bit (512) length */ + +const uint32_t prbs9_coeff[] = { + 0x108, + 0x10D, + 0x110, + 0x116, + 0x119, + 0x12C, + 0x12F, + 0x134, + 0x137, + 0x13B, + 0x13E, + 0x143, + 0x14A, + 0x151, + 0x152, + 0x157, + 0x15B, + 0x15E, + 0x167, + 0x168, + 0x16D, + 0x17A, + 0x17C, + 0x189, + 0x18A, + 0x18F, + 0x191, + 0x198, + 0x19D, + 0x1A7, + 0x1AD, + 0x1B0, + 0x1B5, + 0x1B6, + 0x1B9, + 0x1BF, + 0x1C2, + 0x1C7, + 0x1DA, + 0x1DC, + 0x1E3, + 0x1E5, + 0x1E6, + 0x1EA, + 0x1EC, + 0x1F1, + 0x1F4, + 0x1FD +}; + +/* 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(prbs9_coeff)); + + prbs->name = "custom"; + prbs->len = 9; + prbs->coeff = prbs9_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)); + } +} diff --git a/contrib/e1-prbs-test/rx.c b/contrib/e1-prbs-test/rx.c new file mode 100644 index 0000000..29fbcbe --- /dev/null +++ b/contrib/e1-prbs-test/rx.c @@ -0,0 +1,261 @@ +/* (C) 2019 by Harald Welte <laforge at 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 <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" + +#define MAX_NR_TS 31 + +struct timeslot_state { + struct osmo_fd ofd; + 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 test_state { + struct timeslot_state ts[MAX_NR_TS]; + unsigned int next_unused_ts; +}; +static struct test_state g_tst; + +static uint8_t next_prbs_pc_byte(struct timeslot_state *ts) +{ + const struct prbs_precomp *pc = &ts->prbs_pc[ts->sync_state.prbs_pc_num]; + uint8_t ret = pc->bytes[ts->sync_state.prbs_pc_offset]; + ts->sync_state.prbs_pc_offset = (ts->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 *ts, 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(ts); + 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 */ +static void process_rx(struct timeslot_state *ts, const uint8_t *data, unsigned int len) +{ + if (!ts->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(ts->prbs_pc); pc_num++) { + const struct prbs_precomp *pc = &ts->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->ofd.priv_nr, + pc_num, offset); + clock_gettime(CLOCK_MONOTONIC, &ts->sync_state.ts_sync); + ts->sync_state.has_sync = true; + ts->sync_state.prbs_pc_num = pc_num; + ts->sync_state.prbs_pc_offset = (sizeof(pc->bytes) - offset) % sizeof(pc->bytes); + ts->sync_state.num_bit_err = 0; + /* we will compare the full buffer below in the 'has_sync' path */ + break; + } + } + if (ts->sync_state.has_sync) { + unsigned int num_wrong_bits; + /* we already have sync */ + num_wrong_bits = compare_buf(ts, 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->ofd.priv_nr, num_wrong_bits, len*8, ts->sync_state.num_bit_err, + ts_now.tv_sec - ts->sync_state.ts_sync.tv_sec); + ts->sync_state.has_sync = false; + ts->sync_state.num_sync_loss++; + } + ts->sync_state.num_bit_err += num_wrong_bits; + } +} + +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, buf, 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); + + /* initialize the PRNG for this slot */ + ubit_t ubit[PRBS_LEN*2]; + prbs_for_ts_nr(&ts->prbs, ts->ofd.priv_nr); + prbs_precomp(&ts->prbs_pc[0], &ts->prbs); + osmo_pbit2ubit(ubit, ts->prbs_pc[0].bytes, PRBS_LEN); + /* copy buffer twice back-to-back */ + memcpy(ubit+PRBS_LEN, ubit, PRBS_LEN); + + 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); + /* pre-compute bit-shifted versions */ + for (int i = 1; i < ARRAY_SIZE(ts->prbs_pc); i++) { + osmo_ubit2pbit_ext(ts->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))); + } + 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->sync_state.num_sync_loss, ts->sync_state.num_bit_err, + ts_now.tv_sec - ts->sync_state.ts_sync.tv_sec); + } +} + +static void sig_handler(int signal) +{ + switch (signal) { + case SIGINT: + print_report(); + exit(0); + break; + case SIGHUP: + print_report(); + break; + } +} + +int main(int argc, char **argv) +{ + char *basedir; + int rc; + + if (argc < 2) + exit(1); + basedir = argv[1]; + + 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/tx.c b/contrib/e1-prbs-test/tx.c new file mode 100644 index 0000000..5848e76 --- /dev/null +++ b/contrib/e1-prbs-test/tx.c @@ -0,0 +1,169 @@ +/* (C) 2019 by Harald Welte <laforge at 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 <dirent.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 <osmocom/core/bits.h> +#include <osmocom/core/prbs.h> + +#include "internal.h" + +#define MAX_NR_TS 31 + +/* pre-compute the PRBS sequences only once at startup */ +#define PRBS_PRECOMP + +struct timeslot_state { + struct osmo_fd ofd; + struct osmo_prbs prbs; +#ifdef PRBS_PRECOMP + struct prbs_precomp prbs_pc; + unsigned int prbs_pc_idx; +#else + struct osmo_prbs_state prbs_s; +#endif +}; + +struct test_state { + struct timeslot_state ts[MAX_NR_TS]; + unsigned int next_unused_ts; +}; +static struct test_state g_tst; + + +static void e1_fd_write(struct timeslot_state *ts, int len) +{ + uint8_t buf[4096]; + int i, rc; + + for (i = 0; i < len; i++) { +#ifdef PRBS_PRECOMP + buf[i] = ts->prbs_pc.bytes[ts->prbs_pc_idx]; + ts->prbs_pc_idx = (ts->prbs_pc_idx + 1) % sizeof(ts->prbs_pc); +#else + ubit_t ubit[8]; + osmo_prbs_get_ubits(ubit, sizeof(ubit), &ts->prbs_s); + osmo_ubit2pbit(&buf[i], ubit, sizeof(ubit)); +#endif + } + 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); +} + +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(%02u) read: %d (%s)\n", ofd->priv_nr, rc, strerror(errno)); + return rc; + } + len = rc; + + /* generate as many bytes as were read */ + e1_fd_write(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); + + /* start to put something into the transmit queue, before we get read-triggered + * later on */ + e1_fd_write(ts, 1024); + + /* initialize the PRNG for this slot */ + prbs_for_ts_nr(&ts->prbs, ts->ofd.priv_nr); +#ifdef PRBS_PRECOMP + prbs_precomp(&ts->prbs_pc, &ts->prbs); +#else + osmo_prbs_state_init(&ts->prbs_s, &ts->prbs); +#endif + + num_slots++; + } + closedir(dir); + return num_slots; +} + +int main(int argc, char **argv) +{ + char *basedir; + int rc; + + if (argc < 2) + exit(1); + basedir = argv[1]; + + set_realtime(11); + rc = open_slots(&g_tst, basedir); + printf("opened a total of %d slots\n", rc); + + while (1) { + osmo_select_main(0); + } +} 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 <laforge at 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); +} -- 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: 1 Gerrit-Owner: laforge <laforge at osmocom.org> Gerrit-MessageType: newchange -------------- next part -------------- An HTML attachment was scrubbed... URL: <http://lists.osmocom.org/pipermail/gerrit-log/attachments/20200104/d935d200/attachment.htm>