aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/osmo-bts/scheduler.h14
-rw-r--r--src/osmo-bts-trx/trx_if.c170
2 files changed, 183 insertions, 1 deletions
diff --git a/include/osmo-bts/scheduler.h b/include/osmo-bts/scheduler.h
index 9748d45c..4f406360 100644
--- a/include/osmo-bts/scheduler.h
+++ b/include/osmo-bts/scheduler.h
@@ -227,14 +227,28 @@ int find_sched_mframe_idx(enum gsm_phys_chan_config pchan, uint8_t tn);
bool trx_sched_is_sacch_fn(struct gsm_bts_trx_ts *ts, uint32_t fn, bool uplink);
extern const struct trx_sched_multiframe trx_sched_multiframes[];
+#define TRX_BI_F_NOPE_IND (1 << 0)
+#define TRX_BI_F_MOD_TYPE (1 << 1)
+#define TRX_BI_F_TS_INFO (1 << 2)
+#define TRX_BI_F_CI_CB (1 << 3)
+
/*! UL burst indication with the corresponding meta info */
struct trx_ul_burst_ind {
+ /* Field presence bitmask (see TRX_BI_F_*) */
+ uint8_t flags;
+
/* Mandatory fields */
uint32_t fn; /*!< TDMA frame number */
uint8_t tn; /*!< TDMA time-slot number */
int16_t toa256; /*!< Timing of Arrival in units of 1/256 of symbol */
int8_t rssi; /*!< Received Signal Strength Indication */
+ /* Optional fields (defined by flags) */
+ enum trx_burst_type bt; /*!< Modulation type */
+ uint8_t tsc_set; /*!< Training Sequence Set */
+ uint8_t tsc; /*!< Training Sequence Code */
+ int16_t ci_cb; /*!< Carrier-to-Interference ratio (in centiBels) */
+
/*! Burst soft-bits buffer */
sbit_t burst[EGPRS_BURST_LEN];
size_t burst_len;
diff --git a/src/osmo-bts-trx/trx_if.c b/src/osmo-bts-trx/trx_if.c
index a164f173..f2e8b906 100644
--- a/src/osmo-bts-trx/trx_if.c
+++ b/src/osmo-bts-trx/trx_if.c
@@ -593,6 +593,8 @@ rsp_error:
#define TRX_CHDR_LEN (1 + 4)
/* Uplink v0 header length: 1 RSSI + 2 ToA256 */
#define TRX_UL_V0HDR_LEN (TRX_CHDR_LEN + 1 + 2)
+/* Uplink v1 header length: + 1 MTS + 2 C/I */
+#define TRX_UL_V1HDR_LEN (TRX_UL_V0HDR_LEN + 1 + 2)
/* TRXD header dissector for version 0 */
static int trx_data_handle_hdr_v0(struct trx_l1h *l1h,
@@ -621,6 +623,64 @@ static int trx_data_handle_hdr_v0(struct trx_l1h *l1h,
return TRX_UL_V0HDR_LEN;
}
+/* TRXD header dissector for version 0x01 */
+static int trx_data_handle_hdr_v1(struct trx_l1h *l1h,
+ struct trx_ul_burst_ind *bi,
+ const uint8_t *buf, size_t buf_len)
+{
+ uint8_t mts;
+ int rc;
+
+ /* Make sure we have enough data */
+ if (buf_len < TRX_UL_V1HDR_LEN) {
+ LOGPPHI(l1h->phy_inst, DTRX, LOGL_ERROR,
+ "Short read on TRXD, missing version 1 header "
+ "(len=%zu vs expected %d)\n", buf_len, TRX_UL_V1HDR_LEN);
+ return -EIO;
+ }
+
+ /* Parse v0 specific part */
+ rc = trx_data_handle_hdr_v0(l1h, bi, buf, buf_len);
+ if (rc < 0)
+ return rc;
+
+ /* Move closer to the v1 specific part */
+ buf_len -= rc;
+ buf += rc;
+
+ /* IDLE / NOPE frame indication */
+ if (buf[0] & (1 << 7)) {
+ bi->flags |= TRX_BI_F_NOPE_IND;
+ return TRX_UL_V1HDR_LEN;
+ }
+
+ /* Modulation info and TSC set */
+ mts = (buf[0] >> 3) & 0b1111;
+ if ((mts & 0b1100) == 0x00) {
+ bi->bt = TRX_BURST_GMSK;
+ bi->tsc_set = mts & 0b11;
+ bi->flags |= TRX_BI_F_MOD_TYPE;
+ } else if ((mts & 0b0100) == 0b0100) {
+ bi->bt = TRX_BURST_8PSK;
+ bi->tsc_set = mts & 0b1;
+ bi->flags |= TRX_BI_F_MOD_TYPE;
+ } else {
+ LOGPPHI(l1h->phy_inst, DTRX, LOGL_ERROR,
+ "Indicated modulation 0x%02x is not supported\n", mts & 0b1110);
+ return -ENOTSUP;
+ }
+
+ /* Training Sequence Code */
+ bi->tsc = buf[0] & 0b111;
+ bi->flags |= TRX_BI_F_TS_INFO;
+
+ /* C/I: Carrier-to-Interference ratio (in centiBels) */
+ bi->ci_cb = (int16_t) osmo_load16be(buf + 1);
+ bi->flags |= TRX_BI_F_CI_CB;
+
+ return TRX_UL_V1HDR_LEN;
+}
+
/* TRXD burst handler for header version 0 */
static int trx_data_handle_burst_v0(struct trx_l1h *l1h,
struct trx_ul_burst_ind *bi,
@@ -657,6 +717,30 @@ static int trx_data_handle_burst_v0(struct trx_l1h *l1h,
return 0;
}
+/* TRXD burst handler for header version 1 */
+static int trx_data_handle_burst_v1(struct trx_l1h *l1h,
+ struct trx_ul_burst_ind *bi,
+ const uint8_t *buf, size_t buf_len)
+{
+ /* Modulation types defined in 3GPP TS 45.002 */
+ static const size_t bl[] = {
+ [TRX_BURST_GMSK] = 148, /* 1 bit per symbol */
+ [TRX_BURST_8PSK] = 444, /* 3 bits per symbol */
+ };
+
+ /* Verify burst length */
+ if (bl[bi->bt] != buf_len) {
+ LOGPPHI(l1h->phy_inst, DTRX, LOGL_NOTICE,
+ "Rx TRXD message with odd burst length %zu, "
+ "expected %zu\n", buf_len, bl[bi->bt]);
+ return -EINVAL;
+ }
+
+ /* The burst format is the same as for version 0.
+ * NOTE: other modulation types to be handled separately. */
+ return trx_data_handle_burst_v0(l1h, bi, buf, buf_len);
+}
+
/* Parse TRXD message from transceiver, compose an UL burst indication.
*
* This message contains a demodulated Uplink burst with fixed-size
@@ -697,12 +781,72 @@ static int trx_data_handle_burst_v0(struct trx_l1h *l1h,
* | RSSI | ToA | soft-bits (254..0) |
* +------+-----+--------------------+
*
+ * == Version 0x01
+ *
+ * +------+-----+-----+-----+--------------------+
+ * | RSSI | ToA | MTS | C/I | soft-bits (254..0) |
+ * +------+-----+-----+-----+--------------------+
+ *
* where:
*
* - RSSI (1 octet) - Received Signal Strength Indication
* encoded without the negative sign.
* - ToA (2 octets) - Timing of Arrival in units of 1/256
* of symbol (big endian).
+ * - MTS (1 octet) - Modulation and Training Sequence info.
+ * - C/I (2 octets) - Carrier-to-Interference ratio (big endian).
+ *
+ * == Coding of MTS: Modulation and Training Sequence info
+ *
+ * 3GPP TS 45.002 version 15.1.0 defines several modulation types,
+ * and a few sets of training sequences for each type. The most
+ * common are GMSK and 8-PSK (which is used in EDGE).
+ *
+ * +-----------------+---------------------------------------+
+ * | 7 6 5 4 3 2 1 0 | bit numbers (value range) |
+ * +-----------------+---------------------------------------+
+ * | . . . . . X X X | Training Sequence Code (0..7) |
+ * +-----------------+---------------------------------------+
+ * | . X X X X . . . | Modulation, TS set number (see below) |
+ * +-----------------+---------------------------------------+
+ * | X . . . . . . . | IDLE / nope frame indication (0 or 1) |
+ * +-----------------+---------------------------------------+
+ *
+ * The bit number 7 (MSB) is set to high when either nothing has been
+ * detected, or during IDLE frames, so we can deliver noise levels,
+ * and avoid clock gaps on the L1 side. Other bits are ignored,
+ * and should be set to low (0) in this case. L16 shall be set to 0x00.
+ *
+ * == Coding of modulation and TS set number
+ *
+ * GMSK has 4 sets of training sequences (see tables 5.2.3a-d),
+ * while 8-PSK (see tables 5.2.3f-g) and the others have 2 sets.
+ * Access and Synchronization bursts also have several synch.
+ * sequences.
+ *
+ * +-----------------+---------------------------------------+
+ * | 7 6 5 4 3 2 1 0 | bit numbers (value range) |
+ * +-----------------+---------------------------------------+
+ * | . 0 0 X X . . . | GMSK, 4 TS sets (0..3) |
+ * +-----------------+---------------------------------------+
+ * | . 0 1 0 X . . . | 8-PSK, 2 TS sets (0..1) |
+ * +-----------------+---------------------------------------+
+ * | . 0 1 1 X . . . | AQPSK, 2 TS sets (0..1) |
+ * +-----------------+---------------------------------------+
+ * | . 1 0 0 X . . . | 16QAM, 2 TS sets (0..1) |
+ * +-----------------+---------------------------------------+
+ * | . 1 0 1 X . . . | 32QAM, 2 TS sets (0..1) |
+ * +-----------------+---------------------------------------+
+ * | . 1 1 1 X . . . | RESERVED (0) |
+ * +-----------------+---------------------------------------+
+ *
+ * NOTE: we only support GMSK and 8-PSK.
+ *
+ * == C/I: Carrier-to-Interference ratio
+ *
+ * The C/I value can be computed from the training sequence of each
+ * burst, where we can compare the "ideal" training sequence with
+ * the actual training sequence and then express that in centiBels.
*
* == Coding of the burst bits
*
@@ -731,6 +875,9 @@ static int trx_data_read_cb(struct osmo_fd *ofd, unsigned int what)
return buf_len;
}
+ /* Pre-clean (initialize) the flags */
+ bi.flags = 0x00;
+
/* Parse the header depending on its version */
hdr_ver = buf[0] >> 4;
switch (hdr_ver) {
@@ -738,6 +885,9 @@ static int trx_data_read_cb(struct osmo_fd *ofd, unsigned int what)
/* Legacy protocol has no version indicator */
hdr_len = trx_data_handle_hdr_v0(l1h, &bi, buf, buf_len);
break;
+ case 1:
+ hdr_len = trx_data_handle_hdr_v1(l1h, &bi, buf, buf_len);
+ break;
default:
LOGPPHI(l1h->phy_inst, DTRX, LOGL_ERROR,
"TRXD header version %u is not supported\n", hdr_ver);
@@ -748,21 +898,39 @@ static int trx_data_read_cb(struct osmo_fd *ofd, unsigned int what)
if (hdr_len < 0)
return hdr_len;
+ /* TODO: we can use NOPE indications to get noise levels on IDLE
+ * TDMA frames, and properly drive scheduler if nothing has been
+ * detected on non-IDLE channels. */
+ if (bi.flags & TRX_BI_F_NOPE_IND) {
+ LOGPPHI(l1h->phy_inst, DTRX, LOGL_NOTICE,
+ "IDLE / NOPE indications are not (yet) supported\n");
+ return -ENOTSUP;
+ }
+
/* We're done with the header now */
buf_len -= hdr_len;
+ /* Handle burst bits */
switch (hdr_ver) {
case 0:
rc = trx_data_handle_burst_v0(l1h, &bi, buf + hdr_len, buf_len);
break;
+ case 1:
+ rc = trx_data_handle_burst_v1(l1h, &bi, buf + hdr_len, buf_len);
+ break;
+ default:
+ /* Shall not happen, just to make GCC happy */
+ OSMO_ASSERT(0);
}
/* Burst parsing error */
if (rc < 0)
return rc;
+ /* TODO: also print TSC and C/I */
LOGPPHI(l1h->phy_inst, DTRX, LOGL_DEBUG,
- "Rx UL burst (hdr_ver=%u) tn=%u fn=%u rssi=%d toa256=%d\n",
+ "Rx %s (hdr_ver=%u): tn=%u fn=%u rssi=%d toa256=%d\n",
+ (bi.flags & TRX_BI_F_NOPE_IND) ? "NOPE.ind" : "UL burst",
hdr_ver, bi.tn, bi.fn, bi.rssi, bi.toa256);
#ifdef TOA_RSSI_DEBUG