fixeria submitted this change.

View Change



3 is the latest approved patch-set.
No files were changed between the latest approved patch-set and the submitted one.

Approvals: laforge: Looks good to me, but someone else must approve pespin: Looks good to me, approved Jenkins Builder: Verified
proxy: implement freq. hopping

Handle TRXC SETFH ("<HSN> <MAIO> <RXF1> <TXF1> [... <RXFN> <TXFN>]"),
storing a per-channel struct proxy_trx_fh (HSN, MAIO, and the parsed
Mobile Allocation of Rx/Tx frequency pairs, struct proxy_trx_fh_freq).

burst_fwd.c resolves both the source channel's Tx frequency and each
candidate destination channel's Rx frequency per TDMA frame number via
proxy_trx_fh_resolve() whenever a channel has hopping configured,
falling back to the static RXTUNE/TXTUNE frequency otherwise.

Change-Id: I574b4d4dc337f771b044bd868088b29db9902de9
Related: OS#6672
---
M proxy/include/osmocom/proxy/trx.h
M proxy/src/burst_fwd.c
M proxy/src/ctrl_cmd.c
M proxy/src/trx.c
4 files changed, 163 insertions(+), 4 deletions(-)

diff --git a/proxy/include/osmocom/proxy/trx.h b/proxy/include/osmocom/proxy/trx.h
index 7301f62..633c9fa 100644
--- a/proxy/include/osmocom/proxy/trx.h
+++ b/proxy/include/osmocom/proxy/trx.h
@@ -25,6 +25,21 @@
bool valid; /*!< has SETSLOT been received for this TS? */
};

+/*! One Mobile Allocation entry: the Rx/Tx frequency pair for one ARFCN. */
+struct proxy_trx_fh_freq {
+ uint32_t rx_freq; /*!< Rx frequency in Hz */
+ uint32_t tx_freq; /*!< Tx frequency in Hz */
+};
+
+/*! Synthesizer frequency hopping parameters (SETFH), per 3GPP TS 45.002:
+ * HSN, MAIO and the Mobile Allocation (list of Rx/Tx frequency pairs). */
+struct proxy_trx_fh {
+ uint8_t hsn;
+ uint8_t maio;
+ unsigned int ma_len;
+ struct proxy_trx_fh_freq *ma; /*!< talloc array of ma_len entries */
+};
+
/*! Per-channel state: each channel is conceptually its own (child)
* transceiver with an independent Rx/Tx frequency, sharing the endpoint's
* power state and clock. */
@@ -34,6 +49,7 @@
bool rf_muted; /*!< RFMUTE: force NOPE.ind on bursts this channel transmits */
struct path_sim_state path_sim; /*!< RF path simulation state (path_sim.c) */
struct proxy_trx_ts ts[PROXY_TRX_NUM_TS]; /*!< per-timeslot config (SETSLOT) */
+ struct proxy_trx_fh *fh; /*!< frequency hopping config (SETFH), NULL if disabled */
};

/*! One virtual transceiver endpoint */
@@ -62,3 +78,8 @@

int proxy_trx_set_num_chans(struct proxy_trx *trx, unsigned int num_chans);
void proxy_trx_set_power(struct proxy_trx *trx, bool on);
+
+struct proxy_trx_fh *proxy_trx_fh_alloc(void *talloc_ctx, uint8_t hsn, uint8_t maio,
+ const struct proxy_trx_fh_freq *ma, unsigned int ma_len);
+void proxy_trx_fh_resolve(const struct proxy_trx_fh *fh, uint32_t fn,
+ uint32_t *rx_freq, uint32_t *tx_freq);
diff --git a/proxy/src/burst_fwd.c b/proxy/src/burst_fwd.c
index 2166714..de057b6 100644
--- a/proxy/src/burst_fwd.c
+++ b/proxy/src/burst_fwd.c
@@ -66,8 +66,8 @@
}

/*! Forward a Tx burst request to every powered-on endpoint/channel
- * whose Rx frequency matches the source channel's Tx frequency.
- * TODO: (no frequency hopping support yet, see SETFH in fake_trx.py). */
+ * whose Rx frequency matches the source channel's Tx frequency (resolved
+ * per TDMA frame number if frequency hopping (SETFH) is configured). */
void osmo_trx_ep_rx_burst_req(struct osmo_trx_ep *ep, unsigned int chan,
const struct osmo_trxd_burst_req *br)
{
@@ -81,7 +81,10 @@
return;
}

- tx_freq = src->chans[chan].tx_freq;
+ if (src->chans[chan].fh != NULL)
+ proxy_trx_fh_resolve(src->chans[chan].fh, br->fn, NULL, &tx_freq);
+ else
+ tx_freq = src->chans[chan].tx_freq;

llist_for_each_entry(dst, &g_proxy_ctx->trx_list, list) {
unsigned int dst_chan;
@@ -90,7 +93,15 @@
continue;

for (dst_chan = 0; dst_chan < dst->num_chans; dst_chan++) {
- if (dst->chans[dst_chan].rx_freq != tx_freq)
+ struct proxy_trx_chan *dc = &dst->chans[dst_chan];
+ uint32_t rx_freq;
+
+ if (dc->fh != NULL)
+ proxy_trx_fh_resolve(dc->fh, br->fn, &rx_freq, NULL);
+ else
+ rx_freq = dc->rx_freq;
+
+ if (rx_freq != tx_freq)
continue;
burst_fwd_to_chan(src, chan, dst, dst_chan, br);
}
diff --git a/proxy/src/ctrl_cmd.c b/proxy/src/ctrl_cmd.c
index 1f8c543..c6b238a 100644
--- a/proxy/src/ctrl_cmd.c
+++ b/proxy/src/ctrl_cmd.c
@@ -26,6 +26,9 @@
#include <stdio.h>
#include <string.h>

+#include <osmocom/core/utils.h>
+#include <osmocom/core/talloc.h>
+
#include <osmocom/trx/ep.h>
#include <osmocom/trx/trxc.h>
#include <osmocom/trx/trxd.h>
@@ -38,6 +41,7 @@
/* Not part of the well-known OSMO_TRXC_CMD_* verbs (libosmo-trx/trxc.h) since
* they are specific to this transceiver's RF path simulation. */
#define CTRL_CMD_SETTA "SETTA"
+#define CTRL_CMD_SETFH "SETFH"
#define CTRL_CMD_MEASURE "MEASURE"
#define CTRL_CMD_FAKE_TOA "FAKE_TOA"
#define CTRL_CMD_FAKE_RSSI "FAKE_RSSI"
@@ -185,6 +189,82 @@
trx->chans[chan].ts[ss.tn].valid = true;
}

+/* Max Mobile Allocation length accepted by SETFH (GSM ARFCN range) */
+#define CTRL_CMD_SETFH_MA_MAX 64
+
+/* Syntax: "CMD SETFH <HSN> <MAIO> <RXF1> <TXF1> [... <RXFN> <TXFN>]",
+ * frequencies in kHz. Configures synthesizer frequency hopping (3GPP TS
+ * 45.002); the per-burst Rx/Tx frequencies are then resolved by TDMA frame
+ * number (see proxy_trx_fh_resolve(), used from burst_fwd.c). */
+static void ctrl_cmd_setfh(struct proxy_trx *trx, unsigned int chan,
+ const struct osmo_trxc_msg *cmd, struct osmo_trxc_msg *rsp)
+{
+ struct proxy_trx_fh_freq ma[CTRL_CMD_SETFH_MA_MAX];
+ char params[OSMO_TRXC_PARAMS_LEN_MAX];
+ char *saveptr, *tok;
+ unsigned int hsn, maio, ma_len = 0;
+
+ OSMO_STRLCPY_ARRAY(params, cmd->params);
+
+ tok = strtok_r(params, " ", &saveptr);
+ if (tok == NULL || sscanf(tok, "%u", &hsn) != 1 || hsn > 63) {
+ LOGP_TRXCH(trx, chan, DTRXC, LOGL_ERROR, "Rx SETFH with invalid HSN\n");
+ rsp->status = 1;
+ return;
+ }
+
+ tok = strtok_r(NULL, " ", &saveptr);
+ if (tok == NULL || sscanf(tok, "%u", &maio) != 1 || maio > 63) {
+ LOGP_TRXCH(trx, chan, DTRXC, LOGL_ERROR, "Rx SETFH with invalid MAIO\n");
+ rsp->status = 1;
+ return;
+ }
+
+ while ((tok = strtok_r(NULL, " ", &saveptr)) != NULL) {
+ unsigned int rx_khz, tx_khz;
+ char *tok2;
+
+ if (ma_len >= ARRAY_SIZE(ma) || sscanf(tok, "%u", &rx_khz) != 1) {
+ LOGP_TRXCH(trx, chan, DTRXC, LOGL_ERROR,
+ "Rx SETFH with an invalid/too long Mobile Allocation\n");
+ rsp->status = 1;
+ return;
+ }
+
+ tok2 = strtok_r(NULL, " ", &saveptr);
+ if (tok2 == NULL || sscanf(tok2, "%u", &tx_khz) != 1) {
+ LOGP_TRXCH(trx, chan, DTRXC, LOGL_ERROR,
+ "Rx SETFH with an odd/malformed Mobile Allocation\n");
+ rsp->status = 1;
+ return;
+ }
+
+ ma[ma_len].rx_freq = rx_khz * 1000;
+ ma[ma_len].tx_freq = tx_khz * 1000;
+ ma_len++;
+ }
+
+ if (ma_len == 0) {
+ LOGP_TRXCH(trx, chan, DTRXC, LOGL_ERROR,
+ "Rx SETFH with an empty Mobile Allocation\n");
+ rsp->status = 1;
+ return;
+ }
+
+ talloc_free(trx->chans[chan].fh);
+ trx->chans[chan].fh = proxy_trx_fh_alloc(trx, hsn, maio, ma, ma_len);
+ if (trx->chans[chan].fh == NULL) {
+ LOGP_TRXCH(trx, chan, DTRXC, LOGL_ERROR,
+ "%s(): Failed to allocate frequency hopping state\n", __func__);
+ rsp->status = 1;
+ return;
+ }
+
+ LOGP_TRXCH(trx, chan, DTRXC, LOGL_INFO,
+ "Frequency hopping configured: hsn=%u, maio=%u, ma_len=%u\n",
+ hsn, maio, ma_len);
+}
+
/* SETFORMAT negotiates the TRXD PDU version used on the data socket: the
* response status carries the version to use (the requested one, or our
* preferred version if out of range), not a plain ACK/NACK. */
@@ -375,6 +455,8 @@
ctrl_cmd_setformat(trx, chan, cmd, &rsp);
} else if (!strcmp(cmd->cmd, CTRL_CMD_SETTA)) {
ctrl_cmd_setta(trx, chan, cmd, &rsp);
+ } else if (!strcmp(cmd->cmd, CTRL_CMD_SETFH)) {
+ ctrl_cmd_setfh(trx, chan, cmd, &rsp);
} else if (!strcmp(cmd->cmd, CTRL_CMD_MEASURE)) {
ctrl_cmd_measure(trx, chan, cmd, &rsp);
} else if (!strcmp(cmd->cmd, CTRL_CMD_FAKE_TOA)) {
diff --git a/proxy/src/trx.c b/proxy/src/trx.c
index eb42ebe..da315d1 100644
--- a/proxy/src/trx.c
+++ b/proxy/src/trx.c
@@ -30,6 +30,9 @@
#include <osmocom/core/talloc.h>
#include <osmocom/core/linuxlist.h>

+#include <osmocom/gsm/gsm_utils.h>
+#include <osmocom/gsm/gsm0502.h>
+
#include <osmocom/trx/ep.h>

#include <osmocom/proxy/proxy.h>
@@ -150,3 +153,45 @@
trx->num_chans = num_chans;
return 0;
}
+
+/*! Allocate a frequency hopping configuration; ma is copied. */
+struct proxy_trx_fh *proxy_trx_fh_alloc(void *talloc_ctx, uint8_t hsn, uint8_t maio,
+ const struct proxy_trx_fh_freq *ma, unsigned int ma_len)
+{
+ struct proxy_trx_fh *fh;
+
+ if (ma_len == 0)
+ return NULL;
+
+ fh = talloc_zero(talloc_ctx, struct proxy_trx_fh);
+ if (fh == NULL)
+ return NULL;
+
+ fh->ma = talloc_memdup(fh, ma, ma_len * sizeof(*ma));
+ if (fh->ma == NULL) {
+ talloc_free(fh);
+ return NULL;
+ }
+
+ fh->hsn = hsn;
+ fh->maio = maio;
+ fh->ma_len = ma_len;
+
+ return fh;
+}
+
+/*! Resolve the Rx/Tx frequencies to use for the given TDMA frame number. */
+void proxy_trx_fh_resolve(const struct proxy_trx_fh *fh, uint32_t fn,
+ uint32_t *rx_freq, uint32_t *tx_freq)
+{
+ struct gsm_time gt;
+ uint16_t mai;
+
+ gsm_fn2gsmtime(&gt, fn);
+ mai = gsm0502_hop_seq_gen(&gt, fh->hsn, fh->maio, fh->ma_len, NULL);
+
+ if (rx_freq)
+ *rx_freq = fh->ma[mai].rx_freq;
+ if (tx_freq)
+ *tx_freq = fh->ma[mai].tx_freq;
+}

To view, visit change 43611. To unsubscribe, or for help writing mail filters, visit settings.

Gerrit-MessageType: merged
Gerrit-Project: osmo-trx
Gerrit-Branch: master
Gerrit-Change-Id: I574b4d4dc337f771b044bd868088b29db9902de9
Gerrit-Change-Number: 43611
Gerrit-PatchSet: 6
Gerrit-Owner: fixeria <vyanitskiy@sysmocom.de>
Gerrit-Reviewer: Jenkins Builder
Gerrit-Reviewer: fixeria <vyanitskiy@sysmocom.de>
Gerrit-Reviewer: laforge <laforge@osmocom.org>
Gerrit-Reviewer: pespin <pespin@sysmocom.de>