fixeria submitted this change.
trxcon/trx_if: migrate to libosmo-trx
libosmo-trx (part of osmo-trx.git) is a new library providing a more
advanced, shared implementation of the TRXC/TRXD protocol, factored out
of osmo-trx and osmo-bts-trx. Replace the existing TRXC/TRXD protocol
implementation in trx_if.c with it. This reduces code duplication and
gives us TRXDv1/v2 support for free.
Since this makes libosmo-trx a hard dependency of trx_if.c, gate the
trxcon binary itself behind a new --with-trxcon=yes|no (default yes),
so that building the rest of osmocom-bb doesn't force everyone to have
libosmo-trx installed; the scheduler/GPRS libraries are unaffected
and keep building unconditionally.
Change-Id: I4604f4b12ca903e936dedf167b478455bd28a2e8
Related: osmo-trx.git I817e394f74a10e3adae4a0b58342c82acdf0794e
Related: osmo-trx.git I767fa43a9ca88be40c385f6dcb9de22891a6afc3
Related: OS#6638
---
M contrib/jenkins.sh
M debian/control
M src/Makefile
M src/host/trxcon/configure.ac
M src/host/trxcon/src/Makefile.am
M src/host/trxcon/src/trx_if.c
6 files changed, 234 insertions(+), 452 deletions(-)
diff --git a/contrib/jenkins.sh b/contrib/jenkins.sh
index fce8744..2846a46 100755
--- a/contrib/jenkins.sh
+++ b/contrib/jenkins.sh
@@ -26,6 +26,7 @@
osmo-build-dep.sh libosmocore "" --disable-doxygen
osmo-build-dep.sh libosmo-gprs
+osmo-build-dep.sh osmo-trx "" --disable-doxygen --disable-multi-arfcn --without-proxy
osmo-build-dep.sh gapk
set +x
diff --git a/debian/control b/debian/control
index 0939ca4..aabe874 100644
--- a/debian/control
+++ b/debian/control
@@ -16,6 +16,7 @@
libosmo-gprs-rlcmac-dev,
libosmo-gprs-sm-dev,
libosmo-gprs-sndcp-dev,
+ libosmo-trx-dev (>= 1.8.0),
libosmogapk-dev,
osmo-gsm-manuals-dev (>= 1.6.0)
Standards-Version: 4.1.4
diff --git a/src/Makefile b/src/Makefile
index 0835a85..315e153 100644
--- a/src/Makefile
+++ b/src/Makefile
@@ -13,7 +13,9 @@
all: libosmocore-target nofirmware firmware mtk-firmware
-nofirmware: layer23 osmocon trxcon gprsdecode virtphy
+# trxcon is excluded on purpose because it requires libosmo-trx
+# and we don't want to make the rest of osmocom-bb depend on it.
+nofirmware: layer23 osmocon gprsdecode virtphy
libosmocore-target: shared/libosmocore/build-target/src/.libs/libosmocore.a
@@ -110,7 +112,6 @@
make -C host/osmocon $@
make -C host/gprsdecode $@
make -C host/virt_phy $@
- make -C host/trxcon $@
make -C target/firmware $@
make -C target/firmware -f Makefile.mtk $@
@@ -120,6 +121,5 @@
make -C host/osmocon $@
make -C host/gprsdecode $@
make -C host/virt_phy $@
- make -C host/trxcon $@
# 'firmware' also handles 'mtk-firmware'
make -C target/firmware $@
diff --git a/src/host/trxcon/configure.ac b/src/host/trxcon/configure.ac
index 6508689..df7b604 100644
--- a/src/host/trxcon/configure.ac
+++ b/src/host/trxcon/configure.ac
@@ -53,6 +53,23 @@
CPPFLAGS="$CPPFLAGS $WERROR_FLAGS"
fi
+dnl trxcon requires libosmo-trx (osmo-trx.git) for its TRXC/TRXD backend;
+dnl allow disabling the trxcon binary itself (--without-trxcon) so that
+dnl building libtrxcon, libl1sched, libl1gprs, and the rest of osmocom-bb
+dnl doesn't require libosmo-trx.
+AC_ARG_WITH([trxcon],
+ [AS_HELP_STRING([--with-trxcon],
+ [Build the trxcon binary @<:@default=yes@:>@])],
+ [], [with_trxcon=yes])
+AS_IF([test "x$with_trxcon" = "xyes"], [
+ PKG_CHECK_MODULES(LIBOSMOTRX, libosmo-trx)
+])
+
+AM_CONDITIONAL([BUILD_TRXCON], [test "x$with_trxcon" = "xyes"])
+
+AC_MSG_CHECKING([whether to build the trxcon binary])
+AC_MSG_RESULT([$with_trxcon])
+
AC_MSG_RESULT([CFLAGS="$CFLAGS"])
AC_MSG_RESULT([CPPFLAGS="$CPPFLAGS"])
diff --git a/src/host/trxcon/src/Makefile.am b/src/host/trxcon/src/Makefile.am
index 7be7de6..00505c1 100644
--- a/src/host/trxcon/src/Makefile.am
+++ b/src/host/trxcon/src/Makefile.am
@@ -8,6 +8,7 @@
$(LIBOSMOCORE_CFLAGS) \
$(LIBOSMOCODING_CFLAGS) \
$(LIBOSMOGSM_CFLAGS) \
+ $(LIBOSMOTRX_CFLAGS) \
$(NULL)
@@ -45,7 +46,10 @@
$(NULL)
-bin_PROGRAMS = trxcon
+bin_PROGRAMS =
+
+if BUILD_TRXCON
+bin_PROGRAMS += trxcon
trxcon_SOURCES = \
l1ctl_server.c \
@@ -61,4 +65,6 @@
$(LIBOSMOCORE_LIBS) \
$(LIBOSMOCODING_LIBS) \
$(LIBOSMOGSM_LIBS) \
+ $(LIBOSMOTRX_LIBS) \
$(NULL)
+endif
diff --git a/src/host/trxcon/src/trx_if.c b/src/host/trxcon/src/trx_if.c
index ec6f3ab..a974b46 100644
--- a/src/host/trxcon/src/trx_if.c
+++ b/src/host/trxcon/src/trx_if.c
@@ -4,7 +4,7 @@
*
* Copyright (C) 2013 by Andreas Eversberg <jolly@eversberg.eu>
* Copyright (C) 2016-2017 by Vadim Yanitskiy <axilirator@gmail.com>
- * Copyright (C) 2022 by sysmocom - s.f.m.c. GmbH <info@sysmocom.de>
+ * Copyright (C) 2022-2026 by sysmocom - s.f.m.c. GmbH <info@sysmocom.de>
*
* All Rights Reserved
*
@@ -26,16 +26,10 @@
#include <errno.h>
#include <stdint.h>
#include <stdbool.h>
-#include <unistd.h>
#include <stdlib.h>
#include <string.h>
-#include <netinet/in.h>
-
-#include <osmocom/core/linuxlist.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/core/fsm.h>
@@ -43,13 +37,16 @@
#include <osmocom/gsm/gsm_utils.h>
#include <osmocom/gsm/gsm0502.h>
+#include <osmocom/trx/trxc.h>
+#include <osmocom/trx/trxc_client.h>
+#include <osmocom/trx/trxd.h>
+#include <osmocom/trx/ep.h>
+
#include <osmocom/bb/trxcon/trx_if.h>
#include <osmocom/bb/trxcon/logging.h>
-#define TRXDv0_HDR_LEN 8
-
-#define TRXC_BUF_SIZE 1024
-#define TRXD_BUF_SIZE 512
+/* Give up after 3 retransmissions of a TRXC command */
+#define TRX_MAX_RETRANS 3
#define S(x) (1 << (x))
@@ -59,11 +56,9 @@
};
struct trx_instance {
- struct osmo_fd trx_ofd_ctrl;
- struct osmo_fd trx_ofd_data;
+ struct osmo_trx_ep *ep;
+ struct osmo_trxc_client *trxc_client;
- struct osmo_timer_list trx_ctrl_timer;
- struct llist_head trx_ctrl_list;
struct osmo_fsm_inst *fi;
uint32_t fn_advance;
@@ -76,162 +71,56 @@
void *priv;
};
-struct trx_ctrl_msg {
- struct llist_head list;
- char cmd[TRXC_BUF_SIZE];
- int retry_cnt;
- int critical;
- int cmd_len;
-};
-
static struct osmo_fsm trx_fsm;
-static int trx_udp_open(void *priv, struct osmo_fd *ofd, const char *host_local,
- uint16_t port_local, const char *host_remote, uint16_t port_remote,
- int (*cb)(struct osmo_fd *fd, unsigned int what))
-{
- int rc;
-
- ofd->data = priv;
- ofd->fd = -1;
- ofd->cb = cb;
-
- /* Init UDP Connection */
- rc = osmo_sock_init2_ofd(ofd, AF_UNSPEC, SOCK_DGRAM, 0, host_local, port_local,
- host_remote, port_remote,
- OSMO_SOCK_F_BIND | OSMO_SOCK_F_CONNECT);
- 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;
- }
-}
-
/* ------------------------------------------------------------------------ */
-/* 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. */
+/* Control (TRXC) interface handlers */
/* ------------------------------------------------------------------------ */
-static void trx_ctrl_timer_cb(void *data);
-
-/* Send first CTRL message and start timer */
-static void trx_ctrl_send(struct trx_instance *trx)
+/* Transmit a TRXC message enqueued by the command queue engine */
+static int trxc_client_tx_msg_cb(struct osmo_trxc_client *client,
+ const struct osmo_trxc_msg *msg)
{
- struct trx_ctrl_msg *tcm;
+ struct trx_instance *trx = osmo_trxc_client_get_priv(client);
- if (llist_empty(&trx->trx_ctrl_list))
- return;
- tcm = llist_entry(trx->trx_ctrl_list.next, struct trx_ctrl_msg, list);
-
- /* Send command */
- LOGPFSML(trx->fi, 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);
+ return osmo_trx_ep_send_ctrl_msg(trx->ep, 0, msg);
}
-static void trx_ctrl_timer_cb(void *data)
+/* A critical TRXC command failed (NACKed, mismatched, or timed out) */
+static void trxc_client_fatal_error_cb(struct osmo_trxc_client *client,
+ const struct osmo_trxc_msg *rsp)
{
- struct trx_instance *trx = (struct trx_instance *) data;
- struct trx_ctrl_msg *tcm;
+ struct trx_instance *trx = osmo_trxc_client_get_priv(client);
- /* Queue may be cleaned at this moment */
- if (llist_empty(&trx->trx_ctrl_list))
- return;
-
- LOGPFSML(trx->fi, LOGL_NOTICE, "No response from transceiver...\n");
-
- tcm = llist_entry(trx->trx_ctrl_list.next, struct trx_ctrl_msg, list);
- if (++tcm->retry_cnt > 3) {
+ if (rsp == NULL) { /* no response, retransmissions exhausted */
LOGPFSML(trx->fi, LOGL_NOTICE, "Transceiver offline\n");
osmo_fsm_inst_term(trx->fi, OSMO_FSM_TERM_TIMEOUT, NULL);
- return;
+ } else {
+ osmo_fsm_inst_term(trx->fi, OSMO_FSM_TERM_ERROR, NULL);
}
-
- /* Attempt to send a command again */
- trx_ctrl_send(trx);
}
-/* 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, ...)
+/* Feed responses received on the ctrl socket into the command queue engine */
+void osmo_trx_ep_rx_ctrl_msg(struct osmo_trx_ep *ep, unsigned int chan,
+ const struct osmo_trxc_msg *msg)
{
- struct trx_ctrl_msg *tcm;
- int len, pending = 0;
- va_list ap;
+ struct trx_instance *trx = osmo_trx_ep_get_priv(ep);
- /* TODO: make sure that transceiver online */
+ osmo_trxc_client_rx_msg(trx->trxc_client, msg);
+}
- if (!llist_empty(&trx->trx_ctrl_list))
- pending = 1;
+static int trx_poweroff_rsp_cb(struct osmo_trxc_client *client,
+ const struct osmo_trxc_msg *rsp, void *cb_data)
+{
+ struct trx_instance *trx = cb_data;
- /* Allocate a message */
- tcm = talloc_zero(trx, struct trx_ctrl_msg);
- if (!tcm)
- return -ENOMEM;
+ if (rsp->status != 0)
+ return -EINVAL; /* critical, escalate to fatal_error */
- /* 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);
- LOGPFSML(trx->fi, LOGL_INFO, "Adding new control '%s'\n", tcm->cmd);
-
- /* Send message, if no pending messages */
- if (!pending)
- trx_ctrl_send(trx);
-
+ osmo_fsm_inst_state_chg(trx->fi, TRX_ST_POWEROFF, 0, 0);
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 transceiver is already on.
- * CMD POWERON
- * RSP POWERON <status>
- */
-
static int trx_if_cmd_poweroff(struct trx_instance *trx)
{
/* The transceiver forgets the tuned Rx/Tx frequencies on POWEROFF */
@@ -239,44 +128,48 @@
trx->tx_freq_khz = 0;
trx->hopping = false;
- return trx_ctrl_cmd(trx, 1, "POWEROFF", "");
+ return osmo_trxc_client_poweroff(trx->trxc_client, &trx_poweroff_rsp_cb, trx);
+}
+
+static int trx_poweron_rsp_cb(struct osmo_trxc_client *client,
+ const struct osmo_trxc_msg *rsp, void *cb_data)
+{
+ struct trx_instance *trx = cb_data;
+
+ if (rsp->status != 0)
+ return -EINVAL; /* critical, escalate to fatal_error */
+
+ osmo_fsm_inst_state_chg(trx->fi, TRX_ST_POWERON, 0, 0);
+ return 0;
}
static int trx_if_cmd_poweron(struct trx_instance *trx)
{
- return trx_ctrl_cmd(trx, 1, "POWERON", "");
+ return osmo_trxc_client_poweron(trx->trxc_client, &trx_poweron_rsp_cb, trx);
}
-/*
- * 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>
- */
-
static int trx_if_cmd_setslot(struct trx_instance *trx,
const struct trxcon_phyif_cmdp_setslot *cmdp)
{
- /* Values correspond to 'enum ChannelCombination' in osmo-trx.git */
static const uint8_t chan_types[_GSM_PCHAN_MAX] = {
- [GSM_PCHAN_UNKNOWN] = 0,
- [GSM_PCHAN_NONE] = 0,
- [GSM_PCHAN_CCCH] = 4,
- [GSM_PCHAN_CCCH_SDCCH4] = 5,
- [GSM_PCHAN_CCCH_SDCCH4_CBCH] = 5,
- [GSM_PCHAN_TCH_F] = 1,
- [GSM_PCHAN_TCH_H] = 3,
- [GSM_PCHAN_SDCCH8_SACCH8C] = 7,
- [GSM_PCHAN_SDCCH8_SACCH8C_CBCH] = 7,
- [GSM_PCHAN_PDCH] = 13,
+ [GSM_PCHAN_UNKNOWN] = OSMO_TRXC_CHAN_COMB_UNUSED,
+ [GSM_PCHAN_NONE] = OSMO_TRXC_CHAN_COMB_UNUSED,
+ [GSM_PCHAN_CCCH] = OSMO_TRXC_CHAN_COMB_BCCH,
+ [GSM_PCHAN_CCCH_SDCCH4] = OSMO_TRXC_CHAN_COMB_BCCH_SDCCH4,
+ [GSM_PCHAN_CCCH_SDCCH4_CBCH] = OSMO_TRXC_CHAN_COMB_BCCH_SDCCH4,
+ [GSM_PCHAN_TCH_F] = OSMO_TRXC_CHAN_COMB_TCHF,
+ [GSM_PCHAN_TCH_H] = OSMO_TRXC_CHAN_COMB_TCHH,
+ [GSM_PCHAN_SDCCH8_SACCH8C] = OSMO_TRXC_CHAN_COMB_SDCCH8,
+ [GSM_PCHAN_SDCCH8_SACCH8C_CBCH] = OSMO_TRXC_CHAN_COMB_SDCCH8,
+ [GSM_PCHAN_PDCH] = OSMO_TRXC_CHAN_COMB_PDTCH,
};
- return trx_ctrl_cmd(trx, 1, "SETSLOT", "%u %u",
- cmdp->tn, chan_types[cmdp->pchan]);
+ /* SETSLOT may be pending for different timeslots at once, so the
+ * response needs to be matched against the params, too. */
+ return osmo_trxc_client_send_cmd(trx->trxc_client,
+ OSMO_TRXC_F_CRITICAL | OSMO_TRXC_F_MATCH_PARAMS,
+ NULL, NULL, OSMO_TRXC_CMD_SETSLOT,
+ "%u %u", cmdp->tn, chan_types[cmdp->pchan]);
}
/*
@@ -302,7 +195,7 @@
return -ENOTSUP;
}
- rc = trx_ctrl_cmd(trx, 1, "RXTUNE", "%u", freq10 * 100);
+ rc = osmo_trxc_client_rxtune(trx->trxc_client, freq10 * 100, NULL, NULL);
if (rc == 0) {
trx->rx_freq_khz = freq10 * 100;
trx->hopping = false;
@@ -323,7 +216,7 @@
return -ENOTSUP;
}
- rc = trx_ctrl_cmd(trx, 1, "TXTUNE", "%u", freq10 * 100);
+ rc = osmo_trxc_client_txtune(trx->trxc_client, freq10 * 100, NULL, NULL);
if (rc == 0) {
trx->tx_freq_khz = freq10 * 100;
trx->hopping = false;
@@ -343,6 +236,44 @@
* RSP MEASURE <status> <kHz> <dB>
*/
+static int trx_measure_rsp_cb(struct osmo_trxc_client *client,
+ const struct osmo_trxc_msg *rsp, void *cb_data)
+{
+ struct trx_instance *trx = cb_data;
+ unsigned int freq10;
+ uint16_t band_arfcn;
+ int dbm;
+
+ if (rsp->status != 0)
+ return 0; /* not critical */
+
+ /* Parse freq. and power level */
+ if (osmo_trxc_msg_params_scan(rsp, "%u %d", &freq10, &dbm) != 2) {
+ LOGPFSML(trx->fi, LOGL_ERROR,
+ "Failed to parse RSP MEASURE params: '%s'\n", rsp->params);
+ return 0;
+ }
+ freq10 /= 100;
+
+ band_arfcn = gsm_freq102arfcn((uint16_t)freq10, 0);
+ if (band_arfcn == 0xffff) {
+ LOGPFSML(trx->fi, LOGL_ERROR,
+ "Failed to parse ARFCN from RSP MEASURE: %s\n", rsp->params);
+ return 0;
+ }
+
+ const struct trxcon_phyif_rsp phyrsp = {
+ .type = TRXCON_PHYIF_CMDT_MEASURE,
+ .param.measure = {
+ .band_arfcn = band_arfcn,
+ .dbm = dbm,
+ },
+ };
+
+ trxcon_phyif_handle_rsp(trx->priv, &phyrsp);
+ return 0;
+}
+
static int trx_if_cmd_measure(struct trx_instance *trx,
const struct trxcon_phyif_cmdp_measure *cmdp)
{
@@ -356,35 +287,11 @@
return -ENOTSUP;
}
- return trx_ctrl_cmd(trx, 1, "MEASURE", "%u", freq10 * 100);
-}
-
-static void trx_if_measure_rsp_cb(struct trx_instance *trx, char *resp)
-{
- unsigned int freq10;
- uint16_t band_arfcn;
- int dbm;
-
- /* Parse freq. and power level */
- sscanf(resp, "%u %d", &freq10, &dbm);
- freq10 /= 100;
-
- band_arfcn = gsm_freq102arfcn((uint16_t) freq10, 0);
- if (band_arfcn == 0xffff) {
- LOGPFSML(trx->fi, LOGL_ERROR,
- "Failed to parse ARFCN from RSP MEASURE: %s\n", resp);
- return;
- }
-
- const struct trxcon_phyif_rsp rsp = {
- .type = TRXCON_PHYIF_CMDT_MEASURE,
- .param.measure = {
- .band_arfcn = band_arfcn,
- .dbm = dbm,
- },
- };
-
- trxcon_phyif_handle_rsp(trx->priv, &rsp);
+ /* MEASURE may be pending for different frequencies at once, so the
+ * response needs to be matched against the params, too. */
+ return osmo_trxc_client_send_cmd(trx->trxc_client, OSMO_TRXC_F_MATCH_PARAMS,
+ &trx_measure_rsp_cb, trx,
+ "MEASURE", "%u", freq10 * 100);
}
/*
@@ -403,7 +310,8 @@
static int trx_if_cmd_setta(struct trx_instance *trx,
const struct trxcon_phyif_cmdp_setta *cmdp)
{
- return trx_ctrl_cmd(trx, 0, "SETTA", "%d", cmdp->ta);
+ return osmo_trxc_client_send_cmd(trx->trxc_client, 0, NULL, NULL,
+ "SETTA", "%d", cmdp->ta);
}
/*
@@ -422,8 +330,8 @@
static int trx_if_cmd_setfh(struct trx_instance *trx,
const struct trxcon_phyif_cmdp_setfreq_h1 *cmdp)
{
- /* Reserve some room for CMD SETFH <HSN> <MAIO> */
- char ma_buf[TRXC_BUF_SIZE - 24];
+ /* Reserve some room for '<HSN> <MAIO> ' */
+ char ma_buf[OSMO_TRXC_PARAMS_LEN_MAX - 8];
size_t ma_buf_len = sizeof(ma_buf) - 1;
uint16_t rx_freq, tx_freq;
char *ptr;
@@ -463,7 +371,9 @@
/* Overwrite the last space */
*(ptr - 1) = '\0';
- rc = trx_ctrl_cmd(trx, 1, "SETFH", "%u %u %s", cmdp->hsn, cmdp->maio, ma_buf);
+ rc = osmo_trxc_client_send_cmd(trx->trxc_client, OSMO_TRXC_F_CRITICAL,
+ NULL, NULL, OSMO_TRXC_CMD_SETFH,
+ "%u %u %s", cmdp->hsn, cmdp->maio, ma_buf);
if (rc == 0) {
trx->rx_freq_khz = 0;
trx->tx_freq_khz = 0;
@@ -490,7 +400,7 @@
}
}
-/* No state change here: the POWERON response (see trx_ctrl_read_cb())
+/* No state change here: the POWERON response (see trx_poweron_rsp_cb())
* is what moves us to TRX_ST_POWERON. */
static void trx_fsm_handle_poweron_req(struct osmo_fsm_inst *fi)
{
@@ -555,87 +465,6 @@
}
}
-/* 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 resp, rsp_len;
- char buf[TRXC_BUF_SIZE], *p;
- ssize_t read_len;
-
- read_len = read(ofd->fd, buf, sizeof(buf) - 1);
- if (read_len <= 0) {
- LOGPFSML(trx->fi, LOGL_ERROR, "read() failed with rc=%zd\n", read_len);
- return read_len;
- }
- buf[read_len] = '\0';
-
- if (!!strncmp(buf, "RSP ", 4)) {
- LOGPFSML(trx->fi, 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;
-
- LOGPFSML(trx->fi, LOGL_INFO, "Response message: '%s'\n", buf);
-
- /* Abort expire timer */
- osmo_timer_del(&trx->trx_ctrl_timer);
-
- /* Get command for response message */
- if (llist_empty(&trx->trx_ctrl_list)) {
- LOGPFSML(trx->fi, 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 (!!strncmp(buf + 4, tcm->cmd + 4, rsp_len)) {
- LOGPFSML(trx->fi, (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) {
- LOGPFSML(trx->fi, (tcm->critical) ? LOGL_FATAL : LOGL_ERROR,
- "Transceiver rejected TRX command with "
- "response: '%s'\n", buf);
-
- if (tcm->critical)
- goto rsp_error;
- }
-
- /* Trigger state machine: only POWERON/POWEROFF responses drive a
- * state transition; everything else is state-transparent. */
- if (!strncmp(tcm->cmd + 4, "POWERON", 7))
- osmo_fsm_inst_state_chg(trx->fi, TRX_ST_POWERON, 0, 0);
- else if (!strncmp(tcm->cmd + 4, "POWEROFF", 8))
- osmo_fsm_inst_state_chg(trx->fi, TRX_ST_POWEROFF, 0, 0);
- else if (!strncmp(tcm->cmd + 4, "MEASURE", 7))
- trx_if_measure_rsp_cb(trx, buf + 14);
-
- /* Remove command from list */
- llist_del(&tcm->list);
- talloc_free(tcm);
-
- /* Send next message, if any */
- trx_ctrl_send(trx);
-
- return 0;
-
-rsp_error:
- osmo_fsm_inst_term(trx->fi, OSMO_FSM_TERM_ERROR, NULL);
- return -EIO;
-}
-
/* Dispatch a PHYIF command as an event of the trx_fsm */
int trx_if_handle_phyif_cmd(struct trx_instance *trx, const struct trxcon_phyif_cmd *cmd)
{
@@ -643,117 +472,46 @@
}
/* ------------------------------------------------------------------------ */
-/* 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" */
-/* 2 bytes are not used, but being sent by OsmoTRX */
-/* */
-/* 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 */
+/* Data (TRXD) interface handlers */
/* ------------------------------------------------------------------------ */
-static int trx_data_rx_cb(struct osmo_fd *ofd, unsigned int what)
+/* Handle a burst indication received on the data socket */
+void osmo_trx_ep_rx_burst_ind(struct osmo_trx_ep *ep, unsigned int chan,
+ const struct osmo_trxd_burst_ind *bi)
{
- struct trx_instance *trx = ofd->data;
- struct trxcon_phyif_burst_ind bi;
- uint8_t buf[TRXD_BUF_SIZE];
- ssize_t read_len;
- sbit_t *burst;
+ struct trx_instance *trx = osmo_trx_ep_get_priv(ep);
- read_len = read(ofd->fd, buf, sizeof(buf));
- if (read_len <= 0) {
- strerror_r(errno, (char *)buf, sizeof(buf));
- LOGPFSMSL(trx->fi, DTRXD, LOGL_ERROR,
- "read() failed on TRXD with rc=%zd (%s)\n",
- read_len, (const char *)buf);
- return read_len;
- }
+ LOGPFSMSL(trx->fi, DTRXD, LOGL_DEBUG, "Rx %s\n", osmo_trxd_burst_ind_name(bi));
- if (read_len < TRXDv0_HDR_LEN) {
- LOGPFSMSL(trx->fi, DTRXD, LOGL_ERROR,
- "Got malformed TRXD PDU (short length=%zd)\n", read_len);
- return -EINVAL;
- }
-
- if ((buf[0] >> 4) != 0) {
- LOGPFSMSL(trx->fi, DTRXD, LOGL_ERROR,
- "Got TRXD PDU with unexpected version\n");
- return -ENOTSUP;
- }
-
- read_len -= TRXDv0_HDR_LEN;
- switch (read_len) {
- /* TRXDv0 PDUs may have 2 dummy bytes at the end */
- case GSM_NBITS_NB_GMSK_BURST + 2:
- case GSM_NBITS_NB_8PSK_BURST + 2:
- read_len -= 2;
- break;
- case GSM_NBITS_NB_GMSK_BURST:
- case GSM_NBITS_NB_8PSK_BURST:
- break;
- default:
- LOGPFSMSL(trx->fi, DTRXD, LOGL_ERROR,
- "Got TRXD PDU unexpected burst length=%zd\n", read_len);
- return -EINVAL;
- }
-
- burst = (sbit_t *)&buf[8];
-
- bi = (struct trxcon_phyif_burst_ind) {
- .tn = buf[0] & 0x07,
- .fn = osmo_load32be(buf + 1),
- .rssi = -(int8_t) buf[5],
- .toa256 = (int16_t) (buf[6] << 8) | buf[7],
- .burst = burst, /* at least GSM_NBITS_NB_GMSK_BURST */
- .burst_len = read_len,
+ const struct trxcon_phyif_burst_ind phybi = {
+ .fn = bi->fn,
+ .tn = bi->tn,
+ .toa256 = bi->toa256,
+ .rssi = bi->rssi,
+ .burst = &bi->burst[0],
+ .burst_len = bi->burst_len,
};
- /* Convert ubits {254..0} to sbits {-127..127} in-place */
- for (unsigned int i = 0; i < bi.burst_len; i++) {
- if (buf[8 + i] == 255)
- burst[i] = -127;
- else
- burst[i] = 127 - buf[8 + i];
- }
+ trxcon_phyif_handle_burst_ind(trx->priv, &phybi);
- if (bi.fn >= GSM_TDMA_HYPERFRAME) {
- LOGPFSMSL(trx->fi, DTRXD, LOGL_ERROR, "Illegal FN %u\n", bi.fn);
- return -EINVAL;
- }
-
- LOGPFSMSL(trx->fi, DTRXD, LOGL_DEBUG,
- "RX burst tn=%u fn=%u rssi=%d toa=%d\n",
- bi.tn, bi.fn, bi.rssi, bi.toa256);
-
- trxcon_phyif_handle_burst_ind(trx->priv, &bi);
-
- struct trxcon_phyif_rts_ind rts = {
- .fn = GSM_TDMA_FN_SUM(bi.fn, trx->fn_advance),
- .tn = bi.tn,
+ const struct trxcon_phyif_rts_ind rts = {
+ .fn = GSM_TDMA_FN_SUM(bi->fn, trx->fn_advance),
+ .tn = bi->tn,
};
trxcon_phyif_handle_rts_ind(trx->priv, &rts);
-
- return 0;
}
int trx_if_handle_phyif_burst_req(struct trx_instance *trx,
const struct trxcon_phyif_burst_req *br)
{
- uint8_t buf[TRXD_BUF_SIZE];
- size_t length;
+ struct osmo_trxd_burst_req dbr = {
+ .fn = br->fn,
+ .tn = br->tn,
+ .att = br->pwr,
+ .burst_len = br->burst_len,
+ };
+ int rc;
/* We must be sure that POWERON has been acknowledged by the
* transceiver before attempting to transmit any bursts. */
@@ -763,31 +521,26 @@
return -EAGAIN;
}
- LOGPFSMSL(trx->fi, DTRXD, LOGL_DEBUG,
- "TX burst tn=%u fn=%u pwr=%u\n",
- br->tn, br->fn, br->pwr);
+ if (br->burst_len != 0)
+ memcpy(&dbr.burst[0], br->burst, br->burst_len);
+ else /* a burst request without a payload: NOPE.req */
+ dbr.flags |= OSMO_TRXD_F_NOPE_REQ;
- buf[0] = br->tn;
- osmo_store32be(br->fn, buf + 1);
- buf[5] = br->pwr;
- length = 6;
+ LOGPFSMSL(trx->fi, DTRXD, LOGL_DEBUG, "Tx %s\n", osmo_trxd_burst_req_name(&dbr));
- /* Copy ubits {0,1} */
- if (br->burst_len != 0) {
- memcpy(buf + 6, br->burst, br->burst_len);
- length += br->burst_len;
+ rc = osmo_trx_ep_send_burst_req(trx->ep, 0, &dbr);
+ if (rc < 0) {
+ LOGPFSMSL(trx->fi, DTRXD, LOGL_ERROR,
+ "osmo_trx_ep_send_burst_req(%s) failed: %d\n",
+ osmo_trxd_burst_req_name(&dbr), rc);
}
- /* Send data to transceiver */
- send(trx->trx_ofd_data.fd, buf, length, 0);
-
- return 0;
+ return rc;
}
/* Init TRX interface (TRXC, TRXD sockets and FSM) */
struct trx_instance *trx_if_open(const struct trx_if_params *params)
{
- const unsigned int offset = params->instance * 2;
struct trx_instance *trx;
struct osmo_fsm_inst *fi;
int rc;
@@ -814,51 +567,51 @@
return NULL;
}
- /* Initialize CTRL queue */
- INIT_LLIST_HEAD(&trx->trx_ctrl_list);
-
- /* Open sockets */
- rc = trx_udp_open(trx, &trx->trx_ofd_ctrl, /* TRXC */
- params->local_host, params->base_port + 101 + offset,
- params->remote_host, params->base_port + 1 + offset,
- trx_ctrl_read_cb);
- if (rc < 0)
- goto udp_error;
-
- rc = trx_udp_open(trx, &trx->trx_ofd_data, /* TRXD */
- params->local_host, params->base_port + 102 + offset,
- params->remote_host, params->base_port + 2 + offset,
- trx_data_rx_cb);
- if (rc < 0)
- goto udp_error;
-
trx->fn_advance = params->fn_advance;
trx->priv = params->priv;
fi->priv = trx;
trx->fi = fi;
+ /* The TRX protocol endpoint: per-channel ctrl/data UDP sockets.
+ * Shifting the base port by 2 * instance makes the single channel
+ * of this endpoint use the ports of the given TRX instance. */
+ trx->ep = osmo_trx_ep_alloc(trx, 1);
+ if (trx->ep == NULL)
+ goto error;
+ osmo_trx_ep_set_name(trx->ep, "trx_ep(%u)", params->instance);
+ osmo_trx_ep_set_log_cat(trx->ep, DTRXD);
+ osmo_trx_ep_set_priv(trx->ep, trx);
+ osmo_trx_ep_set_mode(trx->ep, OSMO_TRX_EP_MODE_L1);
+ osmo_trx_ep_set_laddr(trx->ep, params->local_host);
+ osmo_trx_ep_set_raddr(trx->ep, params->remote_host);
+ osmo_trx_ep_set_base_port(trx->ep, params->base_port + 2 * params->instance);
+ osmo_trx_ep_set_clock_socket(trx->ep, false);
+
+ /* The TRXC command queue engine */
+ trx->trxc_client = osmo_trxc_client_alloc(trx);
+ if (trx->trxc_client == NULL)
+ goto error;
+ osmo_trxc_client_set_name(trx->trxc_client, "trxc_client(%u)", params->instance);
+ osmo_trxc_client_set_log_cat(trx->trxc_client, DTRXC);
+ osmo_trxc_client_set_max_retrans(trx->trxc_client, TRX_MAX_RETRANS);
+ osmo_trxc_client_set_priv(trx->trxc_client, trx);
+ osmo_trxc_client_set_tx_msg_cb(trx->trxc_client, &trxc_client_tx_msg_cb);
+ osmo_trxc_client_set_fatal_error_cb(trx->trxc_client, &trxc_client_fatal_error_cb);
+
+ rc = osmo_trx_ep_open(trx->ep);
+ if (rc != 0) {
+ LOGPFSML(params->parent_fi, LOGL_ERROR,
+ "osmo_trx_ep_open() failed: %d\n", rc);
+ goto error;
+ }
+
return trx;
-udp_error:
- LOGPFSML(params->parent_fi, LOGL_ERROR, "Couldn't establish UDP connection\n");
- osmo_fsm_inst_free(trx->fi);
+error:
+ osmo_fsm_inst_free(fi);
return NULL;
}
-/* Flush pending control messages */
-static void trx_if_flush_ctrl(struct trx_instance *trx)
-{
- struct trx_ctrl_msg *tcm;
-
- /* Clear command queue */
- 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)
{
if (trx == NULL || trx->fi == NULL)
@@ -869,7 +622,6 @@
static void trx_fsm_cleanup_cb(struct osmo_fsm_inst *fi,
enum osmo_fsm_term_cause cause)
{
- static const char cmd_poweroff[] = "CMD POWEROFF";
struct trx_instance *trx = fi->priv;
/* May be unallocated due to init error */
@@ -878,19 +630,24 @@
LOGPFSML(fi, LOGL_NOTICE, "Shutdown transceiver interface\n");
- /* Abort TRXC response timer (if pending) */
- osmo_timer_del(&trx->trx_ctrl_timer);
+ /* Flush the TRXC command queue */
+ osmo_trxc_client_free(trx->trxc_client);
+ trx->trxc_client = NULL;
- /* Flush CTRL message list */
- trx_if_flush_ctrl(trx);
+ /* Power off if the transceiver is up (osmo_trx_ep API takes care of
+ * sending pending TRXC data, even after osmo_trx_ep_{close,free}()). */
+ if (fi->state == TRX_ST_POWERON && trx->ep != NULL) {
+ const struct osmo_trxc_msg cmd_poweroff = {
+ .type = OSMO_TRXC_MT_CMD,
+ .cmd = OSMO_TRXC_CMD_POWEROFF,
+ };
+ osmo_trx_ep_send_ctrl_msg(trx->ep, 0, &cmd_poweroff);
+ }
- /* Power off if the transceiver is up */
- if (fi->state == TRX_ST_POWERON && trx->trx_ofd_ctrl.fd >= 0)
- send(trx->trx_ofd_ctrl.fd, &cmd_poweroff[0], sizeof(cmd_poweroff), 0);
-
- /* Close sockets */
- trx_udp_close(&trx->trx_ofd_ctrl);
- trx_udp_close(&trx->trx_ofd_data);
+ /* Shutdown the TRX endpoint */
+ osmo_trx_ep_close(trx->ep);
+ osmo_trx_ep_free(trx->ep);
+ trx->ep = NULL;
/* Free memory */
trx->fi->priv = NULL;
To view, visit change 43828. To unsubscribe, or for help writing mail filters, visit settings.