fixeria has submitted this change. ( https://gerrit.osmocom.org/c/osmo-trx/+/43611?usp=email )
(
3 is the latest approved patch-set. No files were changed between the latest approved patch-set and the submitted one. )Change subject: proxy: implement freq. hopping ......................................................................
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(-)
Approvals: laforge: Looks good to me, but someone else must approve pespin: Looks good to me, approved Jenkins Builder: Verified
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(>, fn); + mai = gsm0502_hop_seq_gen(>, 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; +}