[PATCH] osmocom-bb[master]: host/trxcon: initial release of transceiver interface

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/.

Harald Welte gerrit-no-reply at lists.osmocom.org
Thu Feb 22 15:32:27 UTC 2018


Review at  https://gerrit.osmocom.org/6683

host/trxcon: initial release of transceiver interface

This is the second side of the 'OsmocomBB <-> SDR' bridge.
Most of source code taken from the OsmoBTS project.

Change-Id: I96fa3ada05d010f31af419a4950fd8ae2b62ef34
---
M src/host/trxcon/Makefile.am
M src/host/trxcon/configure.ac
M src/host/trxcon/logging.c
M src/host/trxcon/logging.h
A src/host/trxcon/trx_if.c
A src/host/trxcon/trx_if.h
M src/host/trxcon/trxcon.c
7 files changed, 666 insertions(+), 1 deletion(-)


  git pull ssh://gerrit.osmocom.org:29418/osmocom-bb refs/changes/83/6683/1

diff --git a/src/host/trxcon/Makefile.am b/src/host/trxcon/Makefile.am
index d7c26d4..9da2199 100644
--- a/src/host/trxcon/Makefile.am
+++ b/src/host/trxcon/Makefile.am
@@ -15,16 +15,19 @@
 AM_CFLAGS = \
 	-Wall \
 	$(LIBOSMOCORE_CFLAGS) \
+	$(LIBOSMOGSM_CFLAGS) \
 	$(NULL)
 
 bin_PROGRAMS = trxcon
 
 trxcon_SOURCES = \
 	l1ctl_link.c \
+	trx_if.c \
 	logging.c \
 	trxcon.c \
 	$(NULL)
 
 trxcon_LDADD = \
 	$(LIBOSMOCORE_LIBS) \
+	$(LIBOSMOGSM_LIBS) \
 	$(NULL)
diff --git a/src/host/trxcon/configure.ac b/src/host/trxcon/configure.ac
index c411d04..a94859b 100644
--- a/src/host/trxcon/configure.ac
+++ b/src/host/trxcon/configure.ac
@@ -13,6 +13,7 @@
 dnl checks for libraries
 PKG_CHECK_MODULES(LIBOSMOCORE, libosmocore)
 PKG_CHECK_MODULES(LIBOSMOCODING, libosmocoding)
+PKG_CHECK_MODULES(LIBOSMOGSM, libosmogsm)
 
 dnl checks for header files
 AC_HEADER_STDC
diff --git a/src/host/trxcon/logging.c b/src/host/trxcon/logging.c
index 734d138..28e6776 100644
--- a/src/host/trxcon/logging.c
+++ b/src/host/trxcon/logging.c
@@ -40,6 +40,12 @@
 		.color = "\033[1;31m",
 		.enabled = 1, .loglevel = LOGL_NOTICE,
 	},
+	[DTRX] = {
+		.name = "DTRX",
+		.description = "Transceiver interface",
+		.color = "\033[1;33m",
+		.enabled = 1, .loglevel = LOGL_NOTICE,
+	},
 };
 
 static const struct log_info trx_log_info = {
diff --git a/src/host/trxcon/logging.h b/src/host/trxcon/logging.h
index 049f322..4d7cea0 100644
--- a/src/host/trxcon/logging.h
+++ b/src/host/trxcon/logging.h
@@ -2,11 +2,12 @@
 
 #include <osmocom/core/logging.h>
 
-#define DEBUG_DEFAULT "DAPP:DL1C"
+#define DEBUG_DEFAULT "DAPP:DL1C:DTRX"
 
 enum {
 	DAPP,
 	DL1C,
+	DTRX,
 };
 
 int trx_log_init(const char *category_mask);
diff --git a/src/host/trxcon/trx_if.c b/src/host/trxcon/trx_if.c
new file mode 100644
index 0000000..0607167
--- /dev/null
+++ b/src/host/trxcon/trx_if.c
@@ -0,0 +1,607 @@
+/*
+ * OsmocomBB <-> SDR connection bridge
+ * Transceiver interface handlers
+ *
+ * Copyright (C) 2013 by Andreas Eversberg <jolly at eversberg.eu>
+ * Copyright (C) 2016-2017 by Vadim Yanitskiy <axilirator at gmail.com>
+ *
+ * All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation; either version 3 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 Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <stdio.h>
+#include <errno.h>
+#include <stdint.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <netinet/in.h>
+
+#include <osmocom/core/logging.h>
+#include <osmocom/core/select.h>
+#include <osmocom/core/socket.h>
+#include <osmocom/core/talloc.h>
+#include <osmocom/core/bits.h>
+
+#include <osmocom/gsm/gsm_utils.h>
+
+#include "trx_if.h"
+#include "logging.h"
+
+extern void *tall_trx_ctx;
+
+static int trx_udp_open(void *priv, struct osmo_fd *ofd, const char *host,
+	uint16_t port_local, uint16_t port_remote,
+	int (*cb)(struct osmo_fd *fd, unsigned int what))
+{
+	struct sockaddr_storage sas;
+	struct sockaddr *sa = (struct sockaddr *) &sas;
+	socklen_t sa_len;
+	int rc;
+
+	ofd->data = priv;
+	ofd->fd = -1;
+	ofd->cb = cb;
+
+	/* Init RX side for UDP connection */
+	rc = osmo_sock_init_ofd(ofd, AF_UNSPEC, SOCK_DGRAM,
+		0, host, port_local, OSMO_SOCK_F_BIND);
+	if (rc < 0)
+		return rc;
+
+	/* Init TX side for UDP connection */
+	sa_len = sizeof(sas);
+	rc = getsockname(ofd->fd, sa, &sa_len);
+	if (rc)
+		return rc;
+
+	if (sa->sa_family == AF_INET) {
+		struct sockaddr_in *sin = (struct sockaddr_in *) sa;
+		sin->sin_port = htons(port_remote);
+	} else if (sa->sa_family == AF_INET6) {
+		struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *) sa;
+		sin6->sin6_port = htons(port_remote);
+	} else {
+		return -EINVAL;
+	}
+
+	rc = connect(ofd->fd, sa, sa_len);
+	return rc;
+}
+
+static void trx_udp_close(struct osmo_fd *ofd)
+{
+	if (ofd->fd > 0) {
+		osmo_fd_unregister(ofd);
+		close(ofd->fd);
+		ofd->fd = -1;
+	}
+}
+
+/* ------------------------------------------------------------------------ */
+/* Clock (CLCK) interface handlers                                          */
+/* ------------------------------------------------------------------------ */
+/* Indications on the Master Clock Interface                                */
+/*                                                                          */
+/* The master clock interface is output only (from the radio).              */
+/* Messages are "indications".                                              */
+/*                                                                          */
+/* CLOCK gives the current value of the transceiver clock to be used by the */
+/* core. This message is sent whenever a transmission packet arrives that   */
+/* is too late or too early. The clock value is NOT the current transceiver */
+/* time. It is a time setting the core should use to give better packet     */
+/* arrival times.                                                           */
+/*                                                                          */
+/* IND CLOCK <totalFrames>                                                  */
+/* ------------------------------------------------------------------------ */
+
+static int trx_clck_read_cb(struct osmo_fd *ofd, unsigned int what)
+{
+	char buf[1500];
+	uint32_t fn;
+	int len;
+
+	len = recv(ofd->fd, buf, sizeof(buf) - 1, 0);
+	if (len <= 0)
+		return len;
+
+	/* Terminate received string */
+	buf[len] = '\0';
+
+	if (!!strncmp(buf, "IND CLOCK ", 10)) {
+		LOGP(DTRX, LOGL_ERROR,
+			"Unknown message on CLCK socket: %s\n", buf);
+		return 0;
+	}
+
+	sscanf(buf, "IND CLOCK %u", &fn);
+
+	LOGP(DTRX, LOGL_DEBUG, "Clock indication: fn=%u\n", fn);
+
+	if (fn >= 2715648) {
+		fn %= 2715648;
+		LOGP(DTRX, LOGL_ERROR, "Indicated clock's FN is not wrapping "
+			"correctly, correcting to fn=%u\n", fn);
+	}
+
+	/* TODO: call the clck_ind callback */
+	return 0;
+}
+
+/* ------------------------------------------------------------------------ */
+/* Control (CTRL) interface handlers                                        */
+/* ------------------------------------------------------------------------ */
+/* Commands on the Per-ARFCN Control Interface                              */
+/*                                                                          */
+/* The per-ARFCN control interface uses a command-response protocol.        */
+/* Commands are NULL-terminated ASCII strings, one per UDP socket.          */
+/* Each command has a corresponding response.                               */
+/* Every command is of the form:                                            */
+/*                                                                          */
+/* CMD <cmdtype> [params]                                                   */
+/*                                                                          */
+/* The <cmdtype> is the actual command.                                     */
+/* Parameters are optional depending on the commands type.                  */
+/* Every response is of the form:                                           */
+/*                                                                          */
+/* RSP <cmdtype> <status> [result]                                          */
+/*                                                                          */
+/* The <status> is 0 for success and a non-zero error code for failure.     */
+/* Successful responses may include results, depending on the command type. */
+/* ------------------------------------------------------------------------ */
+
+static void trx_ctrl_timer_cb(void *data);
+
+/* Send first CTRL message and start timer */
+static void trx_ctrl_send(struct trx_instance *trx)
+{
+	struct trx_ctrl_msg *tcm;
+
+	if (llist_empty(&trx->trx_ctrl_list))
+		return;
+	tcm = llist_entry(trx->trx_ctrl_list.next, struct trx_ctrl_msg, list);
+
+	/* Send command */
+	LOGP(DTRX, LOGL_DEBUG, "Sending control '%s'\n", tcm->cmd);
+	send(trx->trx_ofd_ctrl.fd, tcm->cmd, strlen(tcm->cmd) + 1, 0);
+
+	/* Start expire timer */
+	trx->trx_ctrl_timer.data = trx;
+	trx->trx_ctrl_timer.cb = trx_ctrl_timer_cb;
+	osmo_timer_schedule(&trx->trx_ctrl_timer, 2, 0);
+}
+
+static void trx_ctrl_timer_cb(void *data)
+{
+	LOGP(DTRX, LOGL_NOTICE, "No response from transceiver...\n");
+
+	/* Attempt to send a command again */
+	trx_ctrl_send((struct trx_instance *) data);
+}
+
+/* Add a new CTRL command to the trx_ctrl_list */
+static int trx_ctrl_cmd(struct trx_instance *trx, int critical,
+	const char *cmd, const char *fmt, ...)
+{
+	struct trx_ctrl_msg *tcm;
+	int len, pending = 0;
+	va_list ap;
+
+	/*if (!transceiver_available && !!strcmp(cmd, "POWEROFF")) {
+		LOGP(DTRX, LOGL_ERROR, "CTRL ignored: No clock from "
+			"transceiver, please fix!\n");
+		return -EIO;
+	}*/
+
+	if (!llist_empty(&trx->trx_ctrl_list))
+		pending = 1;
+
+	/* Allocate a message */
+	tcm = talloc_zero(trx, struct trx_ctrl_msg);
+	if (!tcm)
+		return -ENOMEM;
+
+	/* Fill in command arguments */
+	if (fmt && fmt[0]) {
+		len = snprintf(tcm->cmd, sizeof(tcm->cmd) - 1, "CMD %s ", cmd);
+		va_start(ap, fmt);
+		vsnprintf(tcm->cmd + len, sizeof(tcm->cmd) - len - 1, fmt, ap);
+		va_end(ap);
+	} else {
+		snprintf(tcm->cmd, sizeof(tcm->cmd) - 1, "CMD %s", cmd);
+	}
+
+	tcm->cmd_len = strlen(cmd);
+	tcm->critical = critical;
+	llist_add_tail(&tcm->list, &trx->trx_ctrl_list);
+	LOGP(DTRX, LOGL_INFO, "Adding new control '%s'\n", tcm->cmd);
+
+	/* Send message, if no pending messages */
+	if (!pending)
+		trx_ctrl_send(trx);
+
+	return 0;
+}
+
+/*
+ * Power Control
+ *
+ * POWEROFF shuts off transmitter power and stops the demodulator.
+ * CMD POWEROFF
+ * RSP POWEROFF <status>
+ *
+ * POWERON starts the transmitter and starts the demodulator.
+ * Initial power level is very low.
+ * This command fails if the transmitter and receiver are not yet tuned.
+ * This command fails if the transmit or receive frequency creates a conflict
+ * with another ARFCN that is already running.
+ * If the transceiver is already on, it response with success to this command.
+ * CMD POWERON
+ * RSP POWERON <status>
+ */
+
+int trx_if_cmd_poweroff(struct trx_instance *trx)
+{
+	return trx_ctrl_cmd(trx, 1, "POWEROFF", "");
+}
+
+int trx_if_cmd_poweron(struct trx_instance *trx)
+{
+	return trx_ctrl_cmd(trx, 1, "POWERON", "");
+}
+
+/*
+ * SETPOWER sets output power in dB wrt full scale.
+ * This command fails if the transmitter and receiver are not running.
+ * CMD SETPOWER <dB>
+ * RSP SETPOWER <status> <dB>
+ */
+
+int trx_if_cmd_setpower(struct trx_instance *trx, int db)
+{
+	return trx_ctrl_cmd(trx, 0, "SETPOWER", "%d", db);
+}
+
+/*
+ * ADJPOWER adjusts power by the given dB step.
+ * Response returns resulting power level wrt full scale.
+ * This command fails if the transmitter and receiver are not running.
+ * CMD ADJPOWER <dBStep>
+ * RSP ADJPOWER <status> <dBLevel>
+*/
+
+int trx_if_cmd_adjpower(struct trx_instance *trx, int db)
+{
+	return trx_ctrl_cmd(trx, 0, "ADJPOWER", "%d", db);
+}
+
+int trx_if_cmd_setrxgain(struct trx_instance *trx, int db)
+{
+	return trx_ctrl_cmd(trx, 0, "SETRXGAIN", "%d", db);
+}
+
+int trx_if_cmd_setmaxdly(struct trx_instance *trx, int dly)
+{
+	return trx_ctrl_cmd(trx, 0, "SETMAXDLY", "%d", dly);
+}
+
+/*
+ * Timeslot Control
+ *
+ * SETSLOT sets the format of the uplink timeslots in the ARFCN.
+ * The <timeslot> indicates the timeslot of interest.
+ * The <chantype> indicates the type of channel that occupies the timeslot.
+ * A chantype of zero indicates the timeslot is off.
+ * CMD SETSLOT <timeslot> <chantype>
+ * RSP SETSLOT <status> <timeslot> <chantype>
+ */
+
+int trx_if_cmd_setslot(struct trx_instance *trx, uint8_t tn, uint8_t type)
+{
+	return trx_ctrl_cmd(trx, 1, "SETSLOT", "%d %d", tn, type);
+}
+
+/*
+ * Tuning Control
+ *
+ * (RX/TX)TUNE tunes the receiver to a given frequency in kHz.
+ * This command fails if the receiver is already running.
+ * (To re-tune you stop the radio, re-tune, and restart.)
+ * This command fails if the transmit or receive frequency
+ * creates a conflict with another ARFCN that is already running.
+ * CMD (RX/TX)TUNE <kHz>
+ * RSP (RX/TX)TUNE <status> <kHz>
+ */
+
+int trx_if_cmd_rxtune(struct trx_instance *trx, uint16_t arfcn)
+{
+	uint16_t freq10;
+
+	/* RX is downlink on MS side */
+	freq10 = gsm_arfcn2freq10(arfcn, 0);
+	if (freq10 == 0xffff) {
+		LOGP(DTRX, LOGL_ERROR, "ARFCN %d not defined\n", arfcn);
+		return -ENOTSUP;
+	}
+
+	return trx_ctrl_cmd(trx, 1, "RXTUNE", "%d", freq10 * 100);
+}
+
+int trx_if_cmd_txtune(struct trx_instance *trx, uint16_t arfcn)
+{
+	uint16_t freq10;
+
+	/* TX is uplink on MS side */
+	freq10 = gsm_arfcn2freq10(arfcn, 1);
+	if (freq10 == 0xffff) {
+		LOGP(DTRX, LOGL_ERROR, "ARFCN %d not defined\n", arfcn);
+		return -ENOTSUP;
+	}
+
+	return trx_ctrl_cmd(trx, 1, "TXTUNE", "%d", freq10 * 100);
+}
+
+/* Get response from CTRL socket */
+static int trx_ctrl_read_cb(struct osmo_fd *ofd, unsigned int what)
+{
+	struct trx_instance *trx = ofd->data;
+	struct trx_ctrl_msg *tcm;
+	int len, resp, rsp_len;
+	char buf[1500], *p;
+
+	len = recv(ofd->fd, buf, sizeof(buf) - 1, 0);
+	if (len <= 0)
+		return len;
+	buf[len] = '\0';
+
+	if (!!strncmp(buf, "RSP ", 4)) {
+		LOGP(DTRX, LOGL_NOTICE, "Unknown message on CTRL port: %s\n", buf);
+		return 0;
+	}
+
+	/* Calculate the length of response item */
+	p = strchr(buf + 4, ' ');
+	rsp_len = p ? p - buf - 4 : strlen(buf) - 4;
+
+	LOGP(DTRX, LOGL_INFO, "Response message: '%s'\n", buf);
+
+	/* Abort expire timer */
+	if (osmo_timer_pending(&trx->trx_ctrl_timer))
+		osmo_timer_del(&trx->trx_ctrl_timer);
+
+	/* Get command for response message */
+	if (llist_empty(&trx->trx_ctrl_list)) {
+		LOGP(DTRX, LOGL_NOTICE, "Response message without command\n");
+		return -EINVAL;
+	}
+
+	tcm = llist_entry(trx->trx_ctrl_list.next,
+		struct trx_ctrl_msg, list);
+
+	/* Check if response matches command */
+	if (rsp_len != tcm->cmd_len || !!strncmp(buf + 4, tcm->cmd + 4, rsp_len)) {
+		LOGP(DTRX, (tcm->critical) ? LOGL_FATAL : LOGL_ERROR,
+			"Response message '%s' does not match command "
+			"message '%s'\n", buf, tcm->cmd);
+		goto rsp_error;
+	}
+
+	/* Check for response code */
+	sscanf(p + 1, "%d", &resp);
+	if (resp) {
+		LOGP(DTRX, (tcm->critical) ? LOGL_FATAL : LOGL_ERROR,
+			"Transceiver rejected TRX command with "
+			"response: '%s'\n", buf);
+
+		if (tcm->critical)
+			goto rsp_error;
+	}
+
+	/* Remove command from list */
+	llist_del(&tcm->list);
+	talloc_free(tcm);
+
+	/* Send next message, if any */
+	trx_ctrl_send(trx);
+
+	return 0;
+
+rsp_error:
+	/**
+	 * TODO: stop/freeze trxcon process
+	 * or notify higher layers about the problem with L1
+	 */
+	return -EIO;
+}
+
+/* ------------------------------------------------------------------------ */
+/* Data interface handlers                                                  */
+/* ------------------------------------------------------------------------ */
+/* DATA interface                                                           */
+/*                                                                          */
+/* Messages on the data interface carry one radio burst per UDP message.    */
+/*                                                                          */
+/* Received Data Burst:                                                     */
+/* 1 byte timeslot index                                                    */
+/* 4 bytes GSM frame number, BE                                             */
+/* 1 byte RSSI in -dBm                                                      */
+/* 2 bytes correlator timing offset in 1/256 symbol steps, 2's-comp, BE     */
+/* 148 bytes soft symbol estimates, 0 -> definite "0", 255 -> definite "1"  */
+/*                                                                          */
+/* Transmit Data Burst:                                                     */
+/* 1 byte timeslot index                                                    */
+/* 4 bytes GSM frame number, BE                                             */
+/* 1 byte transmit level wrt ARFCN max, -dB (attenuation)                   */
+/* 148 bytes output symbol values, 0 & 1                                    */
+/* ------------------------------------------------------------------------ */
+
+static int trx_data_read_cb(struct osmo_fd *ofd, unsigned int what)
+{
+	struct trx_instance *trx = ofd->data;
+	uint8_t buf[256];
+	sbit_t bits[148];
+	int8_t rssi, tn;
+	uint32_t fn;
+	int len, i;
+	float toa;
+
+	len = recv(ofd->fd, buf, sizeof(buf), 0);
+	if (len <= 0)
+		return len;
+
+	if (len != 156) {
+		LOGP(DTRX, LOGL_ERROR, "Got data message with invalid length "
+			"'%d'\n", len);
+		return -EINVAL;
+	}
+
+	tn = buf[0];
+	fn = (buf[1] << 24) | (buf[2] << 16) | (buf[3] << 8) | buf[4];
+	rssi = -(int8_t) buf[5];
+	toa = ((int16_t) (buf[6] << 8) | buf[7]) / 256.0F;
+
+	/* Copy and convert bits {254..0} to sbits {-127..127} */
+	for (i = 0; i < 148; i++) {
+		if (buf[8 + i] == 255)
+			bits[i] = -127;
+		else
+			bits[i] = 127 - buf[8 + i];
+	}
+
+	if (tn >= 8) {
+		LOGP(DTRX, LOGL_ERROR, "Illegal TS %d\n", tn);
+		return -EINVAL;
+	}
+
+	if (fn >= 2715648) {
+		LOGP(DTRX, LOGL_ERROR, "Illegal FN %u\n", fn);
+		return -EINVAL;
+	}
+
+	LOGP(DTRX, LOGL_DEBUG, "RX burst tn=%u fn=%u rssi=%d toa=%.2f\n",
+		tn, fn, rssi, toa);
+
+	/* TODO: poke scheduler here! */
+	return 0;
+}
+
+int trx_if_data(struct trx_instance *trx, uint8_t tn, uint32_t fn,
+	uint8_t pwr, const ubit_t *bits)
+{
+	uint8_t buf[256];
+
+	LOGP(DTRX, LOGL_DEBUG, "TX burst tn=%u fn=%u pwr=%u\n", tn, fn, pwr);
+
+	buf[0] = tn;
+	buf[1] = (fn >> 24) & 0xff;
+	buf[2] = (fn >> 16) & 0xff;
+	buf[3] = (fn >>  8) & 0xff;
+	buf[4] = (fn >>  0) & 0xff;
+	buf[5] = pwr;
+
+	/* Copy ubits {0,1} */
+	memcpy(buf + 6, bits, 148);
+
+	/**
+	 * TODO: is transceiver available???
+	 *
+	 * We must be sure that we have clock,
+	 * and we have sent all control data
+	 *
+	 * if (transceiver_available && llist_empty(&l1h->trx_ctrl_list))
+	 *   send(l1h->trx_ofd_data.fd, buf, 154, 0);
+	 * else
+	 *   LOGP(DTRX, LOGL_DEBUG, "Ignoring TX data, transceiver offline.\n");
+	 */
+
+	return 0;
+}
+
+/*
+ * Open/close OsmoTRX connection
+ */
+
+int trx_if_open(struct trx_instance **trx, const char *host, uint16_t port)
+{
+	struct trx_instance *trx_new;
+	int rc;
+
+	LOGP(DTRX, LOGL_NOTICE, "Init transceiver interface\n");
+
+	/* Try to allocate memory */
+	trx_new = talloc_zero(tall_trx_ctx, struct trx_instance);
+	if (!trx_new) {
+		fprintf(stderr, "Failed to allocate memory\n");
+		return -ENOMEM;
+	}
+
+	/* Initialize CTRL queue */
+	INIT_LLIST_HEAD(&trx_new->trx_ctrl_list);
+
+	/* Open sockets */
+	rc = trx_udp_open(trx_new, &trx_new->trx_ofd_clck, host,
+		port + 100, port + 0, trx_clck_read_cb);
+	if (rc < 0)
+		goto error;
+
+	rc = trx_udp_open(trx_new, &trx_new->trx_ofd_ctrl, host,
+		port + 101, port + 1, trx_ctrl_read_cb);
+	if (rc < 0)
+		goto error;
+
+	rc = trx_udp_open(trx_new, &trx_new->trx_ofd_data, host,
+		port + 102, port + 2, trx_data_read_cb);
+	if (rc < 0)
+		goto error;
+
+	*trx = trx_new;
+
+	return 0;
+
+error:
+	LOGP(DTRX, LOGL_NOTICE, "Couldn't establish UDP connection\n");
+	talloc_free(trx_new);
+	return rc;
+}
+
+/* Flush pending control messages */
+static void trx_if_flush_ctrl(struct trx_instance *trx)
+{
+	struct trx_ctrl_msg *tcm;
+
+	while (!llist_empty(&trx->trx_ctrl_list)) {
+		tcm = llist_entry(trx->trx_ctrl_list.next,
+			struct trx_ctrl_msg, list);
+		llist_del(&tcm->list);
+		talloc_free(tcm);
+	}
+}
+
+void trx_if_close(struct trx_instance *trx)
+{
+	LOGP(DTRX, LOGL_NOTICE, "Shutdown transceiver interface\n");
+
+	/* Flush CTRL message list */
+	trx_if_flush_ctrl(trx);
+
+	/* Close sockets */
+	trx_udp_close(&trx->trx_ofd_clck);
+	trx_udp_close(&trx->trx_ofd_ctrl);
+	trx_udp_close(&trx->trx_ofd_data);
+
+	/* Free memory */
+	talloc_free(trx);
+}
diff --git a/src/host/trxcon/trx_if.h b/src/host/trxcon/trx_if.h
new file mode 100644
index 0000000..fadf604
--- /dev/null
+++ b/src/host/trxcon/trx_if.h
@@ -0,0 +1,38 @@
+#pragma once
+
+#include <osmocom/core/linuxlist.h>
+#include <osmocom/core/select.h>
+#include <osmocom/core/timer.h>
+
+struct trx_instance {
+	struct osmo_fd trx_ofd_clck;
+	struct osmo_fd trx_ofd_ctrl;
+	struct osmo_fd trx_ofd_data;
+
+	struct osmo_timer_list trx_ctrl_timer;
+	struct llist_head trx_ctrl_list;
+};
+
+struct trx_ctrl_msg {
+	struct llist_head list;
+	char cmd[128];
+	int critical;
+	int cmd_len;
+};
+
+int trx_if_open(struct trx_instance **trx, const char *host, uint16_t port);
+void trx_if_close(struct trx_instance *trx);
+
+int trx_if_cmd_poweron(struct trx_instance *trx);
+int trx_if_cmd_poweroff(struct trx_instance *trx);
+
+int trx_if_cmd_setpower(struct trx_instance *trx, int db);
+int trx_if_cmd_adjpower(struct trx_instance *trx, int db);
+
+int trx_if_cmd_setrxgain(struct trx_instance *trx, int db);
+int trx_if_cmd_setmaxdly(struct trx_instance *trx, int dly);
+
+int trx_if_cmd_rxtune(struct trx_instance *trx, uint16_t arfcn);
+int trx_if_cmd_txtune(struct trx_instance *trx, uint16_t arfcn);
+
+int trx_if_cmd_setslot(struct trx_instance *trx, uint8_t tn, uint8_t type);
diff --git a/src/host/trxcon/trxcon.c b/src/host/trxcon/trxcon.c
index 4ad8a0c..781942a 100644
--- a/src/host/trxcon/trxcon.c
+++ b/src/host/trxcon/trxcon.c
@@ -35,6 +35,7 @@
 #include <osmocom/core/select.h>
 #include <osmocom/core/application.h>
 
+#include "trx_if.h"
 #include "logging.h"
 #include "l1ctl_link.h"
 
@@ -54,6 +55,8 @@
 	struct l1ctl_link *l1l;
 	const char *bind_socket;
 
+	/* TRX specific */
+	struct trx_instance *trx;
 	const char *trx_ip;
 	uint16_t trx_base_port;
 } app_data;
@@ -177,6 +180,11 @@
 	if (rc)
 		goto exit;
 
+	/* Init transceiver interface */
+	rc = trx_if_open(&app_data.trx, app_data.trx_ip, app_data.trx_base_port);
+	if (rc)
+		goto exit;
+
 	LOGP(DAPP, LOGL_NOTICE, "Init complete\n");
 
 	if (app_data.daemonize) {
@@ -193,6 +201,7 @@
 exit:
 	/* Close active connections */
 	l1ctl_link_shutdown(app_data.l1l);
+	trx_if_close(app_data.trx);
 
 	/* Make Valgrind happy */
 	log_fini();

-- 
To view, visit https://gerrit.osmocom.org/6683
To unsubscribe, visit https://gerrit.osmocom.org/settings

Gerrit-MessageType: newchange
Gerrit-Change-Id: I96fa3ada05d010f31af419a4950fd8ae2b62ef34
Gerrit-PatchSet: 1
Gerrit-Project: osmocom-bb
Gerrit-Branch: master
Gerrit-Owner: Harald Welte <laforge at gnumonks.org>



More information about the gerrit-log mailing list