changeset 30:5dd30224b70a

abis: starting new program
author Mychaela Falconia <falcon@freecalypso.org>
date Tue, 13 Aug 2024 21:38:55 +0000
parents 1dda11905e85
children cd7448724d74
files .hgignore abis/Makefile abis/dl_frames.c abis/dl_frames.h abis/globals.h abis/main.c abis/read_ts.c abis/record_ctrl.c abis/submux.h abis/subslot_rx.c abis/tx_func.c abis/user_cmd.c
diffstat 12 files changed, 459 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- a/.hgignore	Mon Jun 24 20:42:23 2024 +0000
+++ b/.hgignore	Tue Aug 13 21:38:55 2024 +0000
@@ -3,5 +3,6 @@
 \.[oa]$
 ^config\.defs$
 
+^abis/itt-abis-16$
 ^ater/itt-ater-16$
 ^pcm/itt-pcm-one$
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/abis/Makefile	Tue Aug 13 21:38:55 2024 +0000
@@ -0,0 +1,24 @@
+PROG=	itt-abis-16
+OBJS=	dl_frames.o main.o read_ts.o record_ctrl.o subslot_rx.o tx_func.o \
+	user_cmd.o
+HDRS=	dl_frames.h globals.h submux.h
+LIBUTIL=../libutil/libutil.a
+
+include ../config.defs
+
+CPPFLAGS=${OSMO_INCLUDE}
+OSMO_LINK=${OSMO_LPATH} ${OSMO_RPATH} ${OSMO_LIBS}
+
+all:	${PROG}
+
+${OBJS}:	${HDRS}
+
+${PROG}: ${OBJS} ${LIBUTIL}
+	${CC} -o $@ ${OBJS} ${LIBUTIL} ${OSMO_LINK}
+
+install:
+	mkdir -p ${DESTDIR}${bindir}
+	install -c -m 755 ${PROG} ${DESTDIR}${bindir}
+
+clean:
+	rm -f *.o ${PROG} errs
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/abis/dl_frames.c	Tue Aug 13 21:38:55 2024 +0000
@@ -0,0 +1,70 @@
+/*
+ * In this module we generate canned TRAU-DL frames for FR and EFR,
+ * which will later be transmitted on Abis when individual subslots
+ * come alive.
+ */
+
+#include <stdint.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <osmocom/core/bits.h>
+#include <osmocom/core/utils.h>
+#include <osmocom/trau/trau_frame.h>
+#include <osmocom/trau/trau_rtp.h>
+
+#include "dl_frames.h"
+
+ubit_t dl_frame_fr[DL_OUTPUT_BUFLEN];
+ubit_t dl_frame_efr[DL_OUTPUT_BUFLEN];
+
+static const uint8_t gsmfr_silence_frame[33] = {
+	0xDA, 0xA7, 0xAA, 0xA5, 0x1A,
+	0x50, 0x20, 0x38, 0xE4, 0x6D, 0xB9, 0x1B,
+	0x50, 0x20, 0x38, 0xE4, 0x6D, 0xB9, 0x1B,
+	0x50, 0x20, 0x38, 0xE4, 0x6D, 0xB9, 0x1B,
+	0x50, 0x20, 0x38, 0xE4, 0x6D, 0xB9, 0x1B,
+};
+
+static const uint8_t efr_dhf_rtp[31] = {
+	0xC0, 0x85, 0xEB, 0x49, 0x0F, 0xAA, 0xD6, 0x03,
+	0xE3, 0xA1, 0x86, 0x07, 0xB0, 0xC4, 0x2C, 0x08,
+	0x04, 0x80, 0x55, 0x80, 0x00, 0x00, 0x00, 0x00,
+	0x03, 0x6B, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+
+static void gen_dl_fr(void)
+{
+	struct osmo_trau_frame tf;
+	struct osmo_trau2rtp_state st;
+	int rc;
+
+	tf.dir = OSMO_TRAU_DIR_DL;
+	st.type = OSMO_TRAU16_FT_FR;
+	rc = osmo_rtp2trau(&tf, gsmfr_silence_frame, 33, &st);
+	OSMO_ASSERT(rc == 0);
+	rc = osmo_trau_frame_encode(dl_frame_fr, DL_OUTPUT_BUFLEN, &tf);
+	OSMO_ASSERT(rc == DL_OUTPUT_LEN);
+}
+
+static void gen_dl_efr(void)
+{
+	struct osmo_trau_frame tf;
+	struct osmo_trau2rtp_state st;
+	int rc;
+
+	tf.dir = OSMO_TRAU_DIR_DL;
+	st.type = OSMO_TRAU16_FT_EFR;
+	rc = osmo_rtp2trau(&tf, efr_dhf_rtp, 31, &st);
+	OSMO_ASSERT(rc == 0);
+	rc = osmo_trau_frame_encode(dl_frame_efr, DL_OUTPUT_BUFLEN, &tf);
+	OSMO_ASSERT(rc == DL_OUTPUT_LEN);
+}
+
+void init_canned_dl_frames(void)
+{
+	gen_dl_fr();
+	gen_dl_efr();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/abis/dl_frames.h	Tue Aug 13 21:38:55 2024 +0000
@@ -0,0 +1,16 @@
+/*
+ * This header file defines the interface to the module that provides
+ * canned TRAU-DL frames to be transmitted on Abis as needed.
+ */
+
+#pragma once
+
+#include <osmocom/core/bits.h>
+
+#define	DL_OUTPUT_LEN		320
+#define	DL_OUTPUT_BUFLEN	640
+
+extern ubit_t dl_frame_fr[DL_OUTPUT_BUFLEN];
+extern ubit_t dl_frame_efr[DL_OUTPUT_BUFLEN];
+
+void init_canned_dl_frames(void);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/abis/globals.h	Tue Aug 13 21:38:55 2024 +0000
@@ -0,0 +1,18 @@
+/* global vars and intermodule-linkage functions in itt-abis-16 */
+
+#pragma once
+
+extern void *g_ctx;
+extern struct osmo_e1dp_client *g_client;
+extern int ts_fd;
+extern struct osmo_i460_timeslot i460_ts;
+extern uint8_t readbuf[160];
+extern FILE *record_file;
+
+int ts_fd_cb(struct osmo_fd *ofd, unsigned int what);
+void transmit_e1_ts(void);
+
+void handle_user_cmd(int argc, char **argv);
+void cmd_record_start(int argc, char **argv);
+void cmd_record_stop(int argc, char **argv);
+void cmd_print_rx(int argc, char **argv);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/abis/main.c	Tue Aug 13 21:38:55 2024 +0000
@@ -0,0 +1,113 @@
+/*
+ * This C module is the main for itt-abis-16, a test program for collecting
+ * TRAU-UL captures from an E1 BTS.  This program operates on a single E1
+ * timeslot on Abis and treats it as consisting of four 16 kbit/s subslots.
+ *
+ * This code is based on osmo-e1d-pipe,
+ * (C) 2020-2022 by Harald Welte <laforge@osmocom.org>,
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <stdint.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <osmocom/core/talloc.h>
+#include <osmocom/core/select.h>
+#include <osmocom/core/application.h>
+#include <osmocom/e1d/proto_clnt.h>
+#include <osmocom/isdn/i460_mux.h>
+
+#include "../libutil/open_ts.h"
+#include "../libutil/stdin_handler.h"
+#include "globals.h"
+#include "submux.h"
+#include "dl_frames.h"
+
+void *g_ctx;
+struct osmo_e1dp_client *g_client;
+int ts_fd;
+struct osmo_i460_timeslot i460_ts;
+struct abis_subslot subslots[ABIS_SUBSLOTS];
+
+static const char *e1d_socket_path = E1DP_DEFAULT_SOCKET;
+static const char *timeslot_spec;
+static struct osmo_fd ts_ofd, stdin_ofd;
+
+static void process_cmdline(int argc, char **argv)
+{
+	extern int optind;
+	extern char *optarg;
+	int c;
+
+	while ((c = getopt(argc, argv, "p:")) != EOF) {
+		switch (c) {
+		case 'p':
+			e1d_socket_path = optarg;
+			continue;
+		default:
+		usage:
+			fprintf(stderr, "usage: %s [-p socket] intf:line:ts\n",
+				argv[0]);
+			exit(1);
+		}
+	}
+	if (argc != optind + 1)
+		goto usage;
+	timeslot_spec = argv[optind];
+}
+
+static void register_subslots(void)
+{
+	int nr;
+	struct osmo_i460_schan_desc chd;
+
+	memset(&chd, 0, sizeof chd);
+	chd.rate = OSMO_I460_RATE_16k;
+	chd.demux.num_bits = 320;
+	chd.demux.out_cb_bits = i460_rx_func;
+
+	for (nr = 0; nr < ABIS_SUBSLOTS; nr++) {
+		subslots[nr].nr = nr;
+		chd.demux.user_data = subslots + nr;
+		chd.mux.user_data = subslots + nr;
+		subslots[nr].schan =
+				osmo_i460_subchan_add(g_ctx, &i460_ts, &chd);
+		OSMO_ASSERT(subslots[nr].schan);
+		chd.bit_offset += 2;
+	}
+}
+
+int main(int argc, char **argv)
+{
+	process_cmdline(argc, argv);
+	g_ctx = talloc_named_const(NULL, 0, "g_ctx");
+	OSMO_ASSERT(g_ctx);
+	osmo_init_logging2(g_ctx, NULL);
+
+	g_client = osmo_e1dp_client_create(g_ctx, e1d_socket_path);
+	if (!g_client) {
+		fprintf(stderr, "error: cannot connect to osmo-e1d at %s\n",
+			e1d_socket_path);
+		exit(1);
+	}
+	ts_fd = open_e1d_ts(g_client, timeslot_spec);
+
+	osmo_i460_ts_init(&i460_ts);
+	register_subslots();
+	init_canned_dl_frames();
+
+	osmo_fd_setup(&ts_ofd, ts_fd, OSMO_FD_READ, ts_fd_cb, NULL, 0);
+	OSMO_ASSERT(osmo_fd_register(&ts_ofd) == 0);
+
+	osmo_fd_setup(&stdin_ofd, 0, OSMO_FD_READ, stdin_select_cb,
+			handle_user_cmd, 0);
+	OSMO_ASSERT(osmo_fd_register(&stdin_ofd) == 0);
+
+	while (1) {
+		osmo_select_main(0);
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/abis/read_ts.c	Tue Aug 13 21:38:55 2024 +0000
@@ -0,0 +1,36 @@
+/*
+ * The function in this module gets called from Osmocom select loop
+ * whenever the data socket to osmo-e1d is ready for reading.
+ */
+
+#include <stdint.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include <osmocom/core/select.h>
+#include <osmocom/isdn/i460_mux.h>
+
+#include "globals.h"
+
+uint8_t readbuf[160];
+FILE *record_file;
+
+int ts_fd_cb(struct osmo_fd *ofd, unsigned int what)
+{
+	int rc;
+
+	rc = read(ts_fd, readbuf, 160);
+	if (rc != 160) {
+		fprintf(stderr,
+			"error: read from ts returned %d instead of 160\n",
+			rc);
+		exit(1);
+	}
+	if (record_file)
+		fwrite(readbuf, 1, 160, record_file);
+	osmo_i460_demux_in(&i460_ts, readbuf, 160);
+	transmit_e1_ts();
+	return 0;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/abis/record_ctrl.c	Tue Aug 13 21:38:55 2024 +0000
@@ -0,0 +1,50 @@
+/*
+ * Here we implement stdin commands that control recording of E1 timeslot
+ * read stream.
+ */
+
+#include <stdint.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <osmocom/core/select.h>
+
+#include "globals.h"
+
+void cmd_record_start(int argc, char **argv)
+{
+	if (argc != 2) {
+		printf("error: record command needs 1 argument\n");
+		return;
+	}
+	if (record_file) {
+		printf("error: recording already in progress\n");
+		return;
+	}
+	record_file = fopen(argv[1], "w");
+	if (!record_file)
+		perror(argv[1]);
+}
+
+void cmd_record_stop(int argc, char **argv)
+{
+	if (!record_file) {
+		printf("error: no recording in progress\n");
+		return;
+	}
+	fclose(record_file);
+	record_file = NULL;
+}
+
+void cmd_print_rx(int argc, char **argv)
+{
+	int i, j, off;
+
+	off = 0;
+	for (i = 0; i < 10; i++) {
+		for (j = 0; j < 16; j++)
+			printf(" %02X", readbuf[off++]);
+		putchar('\n');
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/abis/submux.h	Tue Aug 13 21:38:55 2024 +0000
@@ -0,0 +1,26 @@
+/*
+ * The structures and functions defined in this header file deal with
+ * submultiplexing on the Abis interface.
+ */
+
+#pragma once
+
+#include <stdint.h>
+#include <stdbool.h>
+
+#include <osmocom/core/bits.h>
+#include <osmocom/isdn/i460_mux.h>
+
+#define	ABIS_SUBSLOTS	4
+
+struct abis_subslot {
+	struct osmo_i460_subchan *schan;
+	int nr;
+	bool is_active;
+	bool is_efr;
+};
+
+extern struct abis_subslot subslots[ABIS_SUBSLOTS];
+
+void i460_rx_func(struct osmo_i460_subchan *schan, void *user_data,
+		  const ubit_t *bits, unsigned int num_bits);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/abis/subslot_rx.c	Tue Aug 13 21:38:55 2024 +0000
@@ -0,0 +1,21 @@
+/*
+ * Here we are going to implement Abis subslot Rx.
+ */
+
+#include <stdint.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <osmocom/core/select.h>
+#include <osmocom/isdn/i460_mux.h>
+
+#include "globals.h"
+#include "submux.h"
+
+void i460_rx_func(struct osmo_i460_subchan *schan, void *user_data,
+		  const ubit_t *bits, unsigned int num_bits)
+{
+	/* to be filled */
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/abis/tx_func.c	Tue Aug 13 21:38:55 2024 +0000
@@ -0,0 +1,45 @@
+/*
+ * Here we are going to implement Tx on Abis toward the BTS.
+ */
+
+#include <stdint.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <osmocom/core/msgb.h>
+#include <osmocom/core/select.h>
+#include <osmocom/isdn/i460_mux.h>
+
+#include "globals.h"
+#include "submux.h"
+#include "dl_frames.h"
+
+static void tx_service_subslot(int nr)
+{
+	struct abis_subslot *ab = &subslots[nr];
+	struct msgb *msg;
+	uint8_t *outbuf;
+
+	if (!ab->is_active)
+		return;
+	msg = msgb_alloc_c(g_ctx, DL_OUTPUT_LEN, "TRAU-DL-frame");
+	if (!msg)
+		return;
+	outbuf = msgb_put(msg, DL_OUTPUT_LEN);
+	memcpy(outbuf, ab->is_efr ? dl_frame_efr : dl_frame_fr, DL_OUTPUT_LEN);
+	osmo_i460_mux_enqueue(ab->schan, msg);
+}
+
+void transmit_e1_ts(void)
+{
+	uint8_t buf[160];
+	int nr;
+
+	for (nr = 0; nr < ABIS_SUBSLOTS; nr++)
+		tx_service_subslot(nr);
+	osmo_i460_mux_out(&i460_ts, buf, 160);
+	write(ts_fd, buf, 160);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/abis/user_cmd.c	Tue Aug 13 21:38:55 2024 +0000
@@ -0,0 +1,39 @@
+/*
+ * In this module we handle user-issued stdin commands during
+ * itt-abis-16 running session.
+ */
+
+#include <stdint.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <osmocom/core/select.h>
+
+#include "globals.h"
+
+static struct cmdtab {
+	char	*cmd;
+	void	(*func)(int argc, char **argv);
+} cmdtab[] = {
+	{"print-rx", cmd_print_rx},
+	{"record", cmd_record_start},
+	{"record-stop", cmd_record_stop},
+	/* table search terminator */
+	{NULL, NULL}
+};
+
+void handle_user_cmd(int argc, char **argv)
+{
+	struct cmdtab *tp;
+
+	for (tp = cmdtab; tp->cmd; tp++)
+		if (!strcmp(tp->cmd, argv[0]))
+			break;
+	if (!tp->func) {
+		printf("error: unknown or unimplemented command\n");
+		return;
+	}
+	tp->func(argc, argv);
+}