<p>fixeria has uploaded this change for <strong>review</strong>.</p><p><a href="https://gerrit.osmocom.org/c/osmo-bts/+/18820">View Change</a></p><pre style="font-family: monospace,monospace; white-space: pre-wrap;">osmo-bts-trx: move logical channel handlers to separate files<br><br>It's easier to maintain the logical channel handlers in separate<br>files, rather than in a huge one (scheduler_trx.c, ~2k lines).<br><br>Change-Id: Ie5663fd90596b4800a4546675a323250bbb24c80<br>---<br>M src/osmo-bts-trx/Makefile.am<br>A src/osmo-bts-trx/sched_lchan_fcch_sch.c<br>A src/osmo-bts-trx/sched_lchan_pdtch.c<br>A src/osmo-bts-trx/sched_lchan_rach.c<br>A src/osmo-bts-trx/sched_lchan_tchf.c<br>A src/osmo-bts-trx/sched_lchan_tchh.c<br>A src/osmo-bts-trx/sched_lchan_xcch.c<br>A src/osmo-bts-trx/sched_utils.h<br>M src/osmo-bts-trx/scheduler_trx.c<br>9 files changed, 1,816 insertions(+), 1,562 deletions(-)<br><br></pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;">git pull ssh://gerrit.osmocom.org:29418/osmo-bts refs/changes/20/18820/1</pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;"><span>diff --git a/src/osmo-bts-trx/Makefile.am b/src/osmo-bts-trx/Makefile.am</span><br><span>index b2d9b19..ae69000 100644</span><br><span>--- a/src/osmo-bts-trx/Makefile.am</span><br><span>+++ b/src/osmo-bts-trx/Makefile.am</span><br><span>@@ -28,6 +28,7 @@</span><br><span> $(NULL)</span><br><span> </span><br><span> noinst_HEADERS = \</span><br><span style="color: hsl(120, 100%, 40%);">+ sched_utils.h \</span><br><span> trx_if.h \</span><br><span> l1_if.h \</span><br><span> loops.h \</span><br><span>@@ -40,6 +41,12 @@</span><br><span> trx_if.c \</span><br><span> l1_if.c \</span><br><span> scheduler_trx.c \</span><br><span style="color: hsl(120, 100%, 40%);">+ sched_lchan_fcch_sch.c \</span><br><span style="color: hsl(120, 100%, 40%);">+ sched_lchan_rach.c \</span><br><span style="color: hsl(120, 100%, 40%);">+ sched_lchan_xcch.c \</span><br><span style="color: hsl(120, 100%, 40%);">+ sched_lchan_pdtch.c \</span><br><span style="color: hsl(120, 100%, 40%);">+ sched_lchan_tchf.c \</span><br><span style="color: hsl(120, 100%, 40%);">+ sched_lchan_tchh.c \</span><br><span> trx_vty.c \</span><br><span> loops.c \</span><br><span> $(NULL)</span><br><span>diff --git a/src/osmo-bts-trx/sched_lchan_fcch_sch.c b/src/osmo-bts-trx/sched_lchan_fcch_sch.c</span><br><span>new file mode 100644</span><br><span>index 0000000..63dd468</span><br><span>--- /dev/null</span><br><span>+++ b/src/osmo-bts-trx/sched_lchan_fcch_sch.c</span><br><span>@@ -0,0 +1,94 @@</span><br><span style="color: hsl(120, 100%, 40%);">+/*</span><br><span style="color: hsl(120, 100%, 40%);">+ * (C) 2013 by Andreas Eversberg <jolly@eversberg.eu></span><br><span style="color: hsl(120, 100%, 40%);">+ * (C) 2015-2017 by Harald Welte <laforge@gnumonks.org></span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * All Rights Reserved</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * This program is free software; you can redistribute it and/or modify</span><br><span style="color: hsl(120, 100%, 40%);">+ * it under the terms of the GNU Affero General Public License as published by</span><br><span style="color: hsl(120, 100%, 40%);">+ * the Free Software Foundation; either version 3 of the License, or</span><br><span style="color: hsl(120, 100%, 40%);">+ * (at your option) any later version.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * This program is distributed in the hope that it will be useful,</span><br><span style="color: hsl(120, 100%, 40%);">+ * but WITHOUT ANY WARRANTY; without even the implied warranty of</span><br><span style="color: hsl(120, 100%, 40%);">+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the</span><br><span style="color: hsl(120, 100%, 40%);">+ * GNU General Public License for more details.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * You should have received a copy of the GNU Affero General Public License</span><br><span style="color: hsl(120, 100%, 40%);">+ * along with this program. If not, see <http://www.gnu.org/licenses/>.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#include <stdint.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <errno.h></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/core/bits.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/core/utils.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/coding/gsm0503_coding.h></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmo-bts/bts.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmo-bts/l1sap.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmo-bts/logging.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmo-bts/scheduler.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmo-bts/scheduler_backend.h></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#include <sched_utils.h></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/* obtain a to-be-transmitted FCCH (frequency correction channel) burst */</span><br><span style="color: hsl(120, 100%, 40%);">+ubit_t *tx_fcch_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn,</span><br><span style="color: hsl(120, 100%, 40%);">+ enum trx_chan_type chan, uint8_t bid, uint16_t *nbits)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ LOGL1S(DL1P, LOGL_DEBUG, l1t, tn, chan, fn, "Transmitting FCCH\n");</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ if (nbits)</span><br><span style="color: hsl(120, 100%, 40%);">+ *nbits = GSM_BURST_LEN;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* BURST BYPASS */</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ return (ubit_t *) _sched_fcch_burst;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/* obtain a to-be-transmitted SCH (synchronization channel) burst */</span><br><span style="color: hsl(120, 100%, 40%);">+ubit_t *tx_sch_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn,</span><br><span style="color: hsl(120, 100%, 40%);">+ enum trx_chan_type chan, uint8_t bid, uint16_t *nbits)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ static ubit_t bits[GSM_BURST_LEN], burst[78];</span><br><span style="color: hsl(120, 100%, 40%);">+ uint8_t sb_info[4];</span><br><span style="color: hsl(120, 100%, 40%);">+ struct gsm_time t;</span><br><span style="color: hsl(120, 100%, 40%);">+ uint8_t t3p, bsic;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ LOGL1S(DL1P, LOGL_DEBUG, l1t, tn, chan, fn, "Transmitting SCH\n");</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* BURST BYPASS */</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* create SB info from GSM time and BSIC */</span><br><span style="color: hsl(120, 100%, 40%);">+ gsm_fn2gsmtime(&t, fn);</span><br><span style="color: hsl(120, 100%, 40%);">+ t3p = t.t3 / 10;</span><br><span style="color: hsl(120, 100%, 40%);">+ bsic = l1t->trx->bts->bsic;</span><br><span style="color: hsl(120, 100%, 40%);">+ sb_info[0] =</span><br><span style="color: hsl(120, 100%, 40%);">+ ((bsic & 0x3f) << 2) |</span><br><span style="color: hsl(120, 100%, 40%);">+ ((t.t1 & 0x600) >> 9);</span><br><span style="color: hsl(120, 100%, 40%);">+ sb_info[1] =</span><br><span style="color: hsl(120, 100%, 40%);">+ ((t.t1 & 0x1fe) >> 1);</span><br><span style="color: hsl(120, 100%, 40%);">+ sb_info[2] =</span><br><span style="color: hsl(120, 100%, 40%);">+ ((t.t1 & 0x001) << 7) |</span><br><span style="color: hsl(120, 100%, 40%);">+ ((t.t2 & 0x1f) << 2) |</span><br><span style="color: hsl(120, 100%, 40%);">+ ((t3p & 0x6) >> 1);</span><br><span style="color: hsl(120, 100%, 40%);">+ sb_info[3] =</span><br><span style="color: hsl(120, 100%, 40%);">+ (t3p & 0x1);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* encode bursts */</span><br><span style="color: hsl(120, 100%, 40%);">+ gsm0503_sch_encode(burst, sb_info);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* compose burst */</span><br><span style="color: hsl(120, 100%, 40%);">+ memset(bits, 0, 3);</span><br><span style="color: hsl(120, 100%, 40%);">+ memcpy(bits + 3, burst, 39);</span><br><span style="color: hsl(120, 100%, 40%);">+ memcpy(bits + 42, _sched_sch_train, 64);</span><br><span style="color: hsl(120, 100%, 40%);">+ memcpy(bits + 106, burst + 39, 39);</span><br><span style="color: hsl(120, 100%, 40%);">+ memset(bits + 145, 0, 3);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ if (nbits)</span><br><span style="color: hsl(120, 100%, 40%);">+ *nbits = GSM_BURST_LEN;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ return bits;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span>diff --git a/src/osmo-bts-trx/sched_lchan_pdtch.c b/src/osmo-bts-trx/sched_lchan_pdtch.c</span><br><span>new file mode 100644</span><br><span>index 0000000..8b39797</span><br><span>--- /dev/null</span><br><span>+++ b/src/osmo-bts-trx/sched_lchan_pdtch.c</span><br><span>@@ -0,0 +1,249 @@</span><br><span style="color: hsl(120, 100%, 40%);">+/*</span><br><span style="color: hsl(120, 100%, 40%);">+ * (C) 2013 by Andreas Eversberg <jolly@eversberg.eu></span><br><span style="color: hsl(120, 100%, 40%);">+ * (C) 2015-2017 by Harald Welte <laforge@gnumonks.org></span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * All Rights Reserved</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * This program is free software; you can redistribute it and/or modify</span><br><span style="color: hsl(120, 100%, 40%);">+ * it under the terms of the GNU Affero General Public License as published by</span><br><span style="color: hsl(120, 100%, 40%);">+ * the Free Software Foundation; either version 3 of the License, or</span><br><span style="color: hsl(120, 100%, 40%);">+ * (at your option) any later version.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * This program is distributed in the hope that it will be useful,</span><br><span style="color: hsl(120, 100%, 40%);">+ * but WITHOUT ANY WARRANTY; without even the implied warranty of</span><br><span style="color: hsl(120, 100%, 40%);">+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the</span><br><span style="color: hsl(120, 100%, 40%);">+ * GNU General Public License for more details.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * You should have received a copy of the GNU Affero General Public License</span><br><span style="color: hsl(120, 100%, 40%);">+ * along with this program. If not, see <http://www.gnu.org/licenses/>.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#include <stdint.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <errno.h></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/core/bits.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/core/utils.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/coding/gsm0503_coding.h></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmo-bts/bts.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmo-bts/l1sap.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmo-bts/logging.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmo-bts/scheduler.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmo-bts/scheduler_backend.h></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#include <sched_utils.h></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/* Maximum size of a EGPRS message in bytes */</span><br><span style="color: hsl(120, 100%, 40%);">+#define EGPRS_0503_MAX_BYTES 155</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/*! \brief a single PDTCH burst was received by the PHY, process it */</span><br><span style="color: hsl(120, 100%, 40%);">+int rx_pdtch_fn(struct l1sched_trx *l1t, enum trx_chan_type chan,</span><br><span style="color: hsl(120, 100%, 40%);">+ uint8_t bid, const struct trx_ul_burst_ind *bi)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ struct l1sched_ts *l1ts = l1sched_trx_get_ts(l1t, bi->tn);</span><br><span style="color: hsl(120, 100%, 40%);">+ struct l1sched_chan_state *chan_state = &l1ts->chan_state[chan];</span><br><span style="color: hsl(120, 100%, 40%);">+ sbit_t *burst, **bursts_p = &chan_state->ul_bursts;</span><br><span style="color: hsl(120, 100%, 40%);">+ uint32_t *first_fn = &chan_state->ul_first_fn;</span><br><span style="color: hsl(120, 100%, 40%);">+ uint8_t *mask = &chan_state->ul_mask;</span><br><span style="color: hsl(120, 100%, 40%);">+ float *rssi_sum = &chan_state->rssi_sum;</span><br><span style="color: hsl(120, 100%, 40%);">+ uint8_t *rssi_num = &chan_state->rssi_num;</span><br><span style="color: hsl(120, 100%, 40%);">+ int32_t *toa256_sum = &chan_state->toa256_sum;</span><br><span style="color: hsl(120, 100%, 40%);">+ uint8_t *toa_num = &chan_state->toa_num;</span><br><span style="color: hsl(120, 100%, 40%);">+ int32_t *ci_cb_sum = &chan_state->ci_cb_sum;</span><br><span style="color: hsl(120, 100%, 40%);">+ uint8_t *ci_cb_num = &chan_state->ci_cb_num;</span><br><span style="color: hsl(120, 100%, 40%);">+ uint8_t l2[EGPRS_0503_MAX_BYTES];</span><br><span style="color: hsl(120, 100%, 40%);">+ int n_errors = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+ int n_bursts_bits = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+ int n_bits_total = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+ int16_t lqual_cb;</span><br><span style="color: hsl(120, 100%, 40%);">+ uint16_t ber10k;</span><br><span style="color: hsl(120, 100%, 40%);">+ int rc;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ LOGL1S(DL1P, LOGL_DEBUG, l1t, bi->tn, chan, bi->fn,</span><br><span style="color: hsl(120, 100%, 40%);">+ "Received PDTCH bid=%u\n", bid);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* allocate burst memory, if not already */</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!*bursts_p) {</span><br><span style="color: hsl(120, 100%, 40%);">+ *bursts_p = talloc_zero_size(tall_bts_ctx,</span><br><span style="color: hsl(120, 100%, 40%);">+ GSM0503_EGPRS_BURSTS_NBITS);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!*bursts_p)</span><br><span style="color: hsl(120, 100%, 40%);">+ return -ENOMEM;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* clear burst */</span><br><span style="color: hsl(120, 100%, 40%);">+ if (bid == 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+ memset(*bursts_p, 0, GSM0503_EGPRS_BURSTS_NBITS);</span><br><span style="color: hsl(120, 100%, 40%);">+ *mask = 0x0;</span><br><span style="color: hsl(120, 100%, 40%);">+ *first_fn = bi->fn;</span><br><span style="color: hsl(120, 100%, 40%);">+ *rssi_sum = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+ *rssi_num = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+ *toa256_sum = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+ *toa_num = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+ *ci_cb_sum = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+ *ci_cb_num = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* update mask + rssi */</span><br><span style="color: hsl(120, 100%, 40%);">+ *mask |= (1 << bid);</span><br><span style="color: hsl(120, 100%, 40%);">+ *rssi_sum += bi->rssi;</span><br><span style="color: hsl(120, 100%, 40%);">+ (*rssi_num)++;</span><br><span style="color: hsl(120, 100%, 40%);">+ *toa256_sum += bi->toa256;</span><br><span style="color: hsl(120, 100%, 40%);">+ (*toa_num)++;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* C/I: Carrier-to-Interference ratio (in centiBels) */</span><br><span style="color: hsl(120, 100%, 40%);">+ if (bi->flags & TRX_BI_F_CI_CB) {</span><br><span style="color: hsl(120, 100%, 40%);">+ *ci_cb_sum += bi->ci_cb;</span><br><span style="color: hsl(120, 100%, 40%);">+ (*ci_cb_num)++;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* copy burst to buffer of 4 bursts */</span><br><span style="color: hsl(120, 100%, 40%);">+ if (bi->burst_len == EGPRS_BURST_LEN) {</span><br><span style="color: hsl(120, 100%, 40%);">+ burst = *bursts_p + bid * 348;</span><br><span style="color: hsl(120, 100%, 40%);">+ memcpy(burst, bi->burst + 9, 174);</span><br><span style="color: hsl(120, 100%, 40%);">+ memcpy(burst + 174, bi->burst + 261, 174);</span><br><span style="color: hsl(120, 100%, 40%);">+ n_bursts_bits = GSM0503_EGPRS_BURSTS_NBITS;</span><br><span style="color: hsl(120, 100%, 40%);">+ } else {</span><br><span style="color: hsl(120, 100%, 40%);">+ burst = *bursts_p + bid * 116;</span><br><span style="color: hsl(120, 100%, 40%);">+ memcpy(burst, bi->burst + 3, 58);</span><br><span style="color: hsl(120, 100%, 40%);">+ memcpy(burst + 58, bi->burst + 87, 58);</span><br><span style="color: hsl(120, 100%, 40%);">+ n_bursts_bits = GSM0503_GPRS_BURSTS_NBITS;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* wait until complete set of bursts */</span><br><span style="color: hsl(120, 100%, 40%);">+ if (bid != 3)</span><br><span style="color: hsl(120, 100%, 40%);">+ return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* check for complete set of bursts */</span><br><span style="color: hsl(120, 100%, 40%);">+ if ((*mask & 0xf) != 0xf) {</span><br><span style="color: hsl(120, 100%, 40%);">+ LOGL1S(DL1P, LOGL_DEBUG, l1t, bi->tn, chan, bi->fn,</span><br><span style="color: hsl(120, 100%, 40%);">+ "Received incomplete frame (%u/%u)\n",</span><br><span style="color: hsl(120, 100%, 40%);">+ bi->fn % l1ts->mf_period, l1ts->mf_period);</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+ *mask = 0x0;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /*</span><br><span style="color: hsl(120, 100%, 40%);">+ * Attempt to decode EGPRS bursts first. For 8-PSK EGPRS this is all we</span><br><span style="color: hsl(120, 100%, 40%);">+ * do. Attempt GPRS decoding on EGPRS failure. If the burst is GPRS,</span><br><span style="color: hsl(120, 100%, 40%);">+ * then we incur decoding overhead of 31 bits on the Type 3 EGPRS</span><br><span style="color: hsl(120, 100%, 40%);">+ * header, which is tolerable.</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+ rc = gsm0503_pdtch_egprs_decode(l2, *bursts_p, n_bursts_bits,</span><br><span style="color: hsl(120, 100%, 40%);">+ NULL, &n_errors, &n_bits_total);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ if ((bi->burst_len == GSM_BURST_LEN) && (rc < 0)) {</span><br><span style="color: hsl(120, 100%, 40%);">+ rc = gsm0503_pdtch_decode(l2, *bursts_p, NULL,</span><br><span style="color: hsl(120, 100%, 40%);">+ &n_errors, &n_bits_total);</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ if (rc <= 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+ LOGL1S(DL1P, LOGL_DEBUG, l1t, bi->tn, chan, bi->fn,</span><br><span style="color: hsl(120, 100%, 40%);">+ "Received bad PDTCH (%u/%u)\n",</span><br><span style="color: hsl(120, 100%, 40%);">+ bi->fn % l1ts->mf_period, l1ts->mf_period);</span><br><span style="color: hsl(120, 100%, 40%);">+ return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ lqual_cb = *ci_cb_num ? (*ci_cb_sum / *ci_cb_num) : 0;</span><br><span style="color: hsl(120, 100%, 40%);">+ ber10k = compute_ber10k(n_bits_total, n_errors);</span><br><span style="color: hsl(120, 100%, 40%);">+ return _sched_compose_ph_data_ind(l1t, bi->tn,</span><br><span style="color: hsl(120, 100%, 40%);">+ *first_fn, chan, l2, rc,</span><br><span style="color: hsl(120, 100%, 40%);">+ *rssi_sum / *rssi_num,</span><br><span style="color: hsl(120, 100%, 40%);">+ *toa256_sum / *toa_num,</span><br><span style="color: hsl(120, 100%, 40%);">+ lqual_cb, ber10k,</span><br><span style="color: hsl(120, 100%, 40%);">+ PRES_INFO_BOTH);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/* obtain a to-be-transmitted PDTCH (packet data) burst */</span><br><span style="color: hsl(120, 100%, 40%);">+ubit_t *tx_pdtch_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn,</span><br><span style="color: hsl(120, 100%, 40%);">+ enum trx_chan_type chan, uint8_t bid, uint16_t *nbits)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ struct l1sched_ts *l1ts = l1sched_trx_get_ts(l1t, tn);</span><br><span style="color: hsl(120, 100%, 40%);">+ struct gsm_bts_trx_ts *ts = &l1t->trx->ts[tn];</span><br><span style="color: hsl(120, 100%, 40%);">+ struct msgb *msg = NULL; /* make GCC happy */</span><br><span style="color: hsl(120, 100%, 40%);">+ ubit_t *burst, **bursts_p = &l1ts->chan_state[chan].dl_bursts;</span><br><span style="color: hsl(120, 100%, 40%);">+ enum trx_burst_type *burst_type = &l1ts->chan_state[chan].dl_burst_type;</span><br><span style="color: hsl(120, 100%, 40%);">+ static ubit_t bits[EGPRS_BURST_LEN];</span><br><span style="color: hsl(120, 100%, 40%);">+ int rc = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* send burst, if we already got a frame */</span><br><span style="color: hsl(120, 100%, 40%);">+ if (bid > 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!*bursts_p)</span><br><span style="color: hsl(120, 100%, 40%);">+ return NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+ goto send_burst;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* get mac block from queue */</span><br><span style="color: hsl(120, 100%, 40%);">+ msg = _sched_dequeue_prim(l1t, tn, fn, chan);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (msg)</span><br><span style="color: hsl(120, 100%, 40%);">+ goto got_msg;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ LOGL1S(DL1P, LOGL_INFO, l1t, tn, chan, fn, "No prim for transmit.\n");</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+no_msg:</span><br><span style="color: hsl(120, 100%, 40%);">+ /* free burst memory */</span><br><span style="color: hsl(120, 100%, 40%);">+ if (*bursts_p) {</span><br><span style="color: hsl(120, 100%, 40%);">+ talloc_free(*bursts_p);</span><br><span style="color: hsl(120, 100%, 40%);">+ *bursts_p = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+ return NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+got_msg:</span><br><span style="color: hsl(120, 100%, 40%);">+ /* BURST BYPASS */</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* allocate burst memory, if not already */</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!*bursts_p) {</span><br><span style="color: hsl(120, 100%, 40%);">+ *bursts_p = talloc_zero_size(tall_bts_ctx,</span><br><span style="color: hsl(120, 100%, 40%);">+ GSM0503_EGPRS_BURSTS_NBITS);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!*bursts_p)</span><br><span style="color: hsl(120, 100%, 40%);">+ return NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* encode bursts */</span><br><span style="color: hsl(120, 100%, 40%);">+ rc = gsm0503_pdtch_egprs_encode(*bursts_p, msg->l2h, msg->tail - msg->l2h);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (rc < 0)</span><br><span style="color: hsl(120, 100%, 40%);">+ rc = gsm0503_pdtch_encode(*bursts_p, msg->l2h, msg->tail - msg->l2h);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* check validity of message */</span><br><span style="color: hsl(120, 100%, 40%);">+ if (rc < 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+ LOGL1S(DL1P, LOGL_FATAL, l1t, tn, chan, fn, "Prim invalid length, please FIX! "</span><br><span style="color: hsl(120, 100%, 40%);">+ "(len=%ld)\n", (long)(msg->tail - msg->l2h));</span><br><span style="color: hsl(120, 100%, 40%);">+ /* free message */</span><br><span style="color: hsl(120, 100%, 40%);">+ msgb_free(msg);</span><br><span style="color: hsl(120, 100%, 40%);">+ goto no_msg;</span><br><span style="color: hsl(120, 100%, 40%);">+ } else if (rc == GSM0503_EGPRS_BURSTS_NBITS) {</span><br><span style="color: hsl(120, 100%, 40%);">+ *burst_type = TRX_BURST_8PSK;</span><br><span style="color: hsl(120, 100%, 40%);">+ } else {</span><br><span style="color: hsl(120, 100%, 40%);">+ *burst_type = TRX_BURST_GMSK;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* free message */</span><br><span style="color: hsl(120, 100%, 40%);">+ msgb_free(msg);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+send_burst:</span><br><span style="color: hsl(120, 100%, 40%);">+ /* compose burst */</span><br><span style="color: hsl(120, 100%, 40%);">+ if (*burst_type == TRX_BURST_8PSK) {</span><br><span style="color: hsl(120, 100%, 40%);">+ burst = *bursts_p + bid * 348;</span><br><span style="color: hsl(120, 100%, 40%);">+ memset(bits, 1, 9);</span><br><span style="color: hsl(120, 100%, 40%);">+ memcpy(bits + 9, burst, 174);</span><br><span style="color: hsl(120, 100%, 40%);">+ memcpy(bits + 183, _sched_egprs_tsc[gsm_ts_tsc(ts)], 78);</span><br><span style="color: hsl(120, 100%, 40%);">+ memcpy(bits + 261, burst + 174, 174);</span><br><span style="color: hsl(120, 100%, 40%);">+ memset(bits + 435, 1, 9);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ if (nbits)</span><br><span style="color: hsl(120, 100%, 40%);">+ *nbits = EGPRS_BURST_LEN;</span><br><span style="color: hsl(120, 100%, 40%);">+ } else {</span><br><span style="color: hsl(120, 100%, 40%);">+ burst = *bursts_p + bid * 116;</span><br><span style="color: hsl(120, 100%, 40%);">+ memset(bits, 0, 3);</span><br><span style="color: hsl(120, 100%, 40%);">+ memcpy(bits + 3, burst, 58);</span><br><span style="color: hsl(120, 100%, 40%);">+ memcpy(bits + 61, _sched_tsc[gsm_ts_tsc(ts)], 26);</span><br><span style="color: hsl(120, 100%, 40%);">+ memcpy(bits + 87, burst + 58, 58);</span><br><span style="color: hsl(120, 100%, 40%);">+ memset(bits + 145, 0, 3);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ if (nbits)</span><br><span style="color: hsl(120, 100%, 40%);">+ *nbits = GSM_BURST_LEN;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ LOGL1S(DL1P, LOGL_DEBUG, l1t, tn, chan, fn, "Transmitting burst=%u.\n", bid);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ return bits;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span>diff --git a/src/osmo-bts-trx/sched_lchan_rach.c b/src/osmo-bts-trx/sched_lchan_rach.c</span><br><span>new file mode 100644</span><br><span>index 0000000..fa50f14</span><br><span>--- /dev/null</span><br><span>+++ b/src/osmo-bts-trx/sched_lchan_rach.c</span><br><span>@@ -0,0 +1,212 @@</span><br><span style="color: hsl(120, 100%, 40%);">+/*</span><br><span style="color: hsl(120, 100%, 40%);">+ * (C) 2013 by Andreas Eversberg <jolly@eversberg.eu></span><br><span style="color: hsl(120, 100%, 40%);">+ * (C) 2015-2017 by Harald Welte <laforge@gnumonks.org></span><br><span style="color: hsl(120, 100%, 40%);">+ * (C) 2019 by Vadim Yanitskiy <axilirator@gmail.com></span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * All Rights Reserved</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * This program is free software; you can redistribute it and/or modify</span><br><span style="color: hsl(120, 100%, 40%);">+ * it under the terms of the GNU Affero General Public License as published by</span><br><span style="color: hsl(120, 100%, 40%);">+ * the Free Software Foundation; either version 3 of the License, or</span><br><span style="color: hsl(120, 100%, 40%);">+ * (at your option) any later version.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * This program is distributed in the hope that it will be useful,</span><br><span style="color: hsl(120, 100%, 40%);">+ * but WITHOUT ANY WARRANTY; without even the implied warranty of</span><br><span style="color: hsl(120, 100%, 40%);">+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the</span><br><span style="color: hsl(120, 100%, 40%);">+ * GNU General Public License for more details.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * You should have received a copy of the GNU Affero General Public License</span><br><span style="color: hsl(120, 100%, 40%);">+ * along with this program. If not, see <http://www.gnu.org/licenses/>.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#include <stdint.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <limits.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <errno.h></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/core/bits.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/core/utils.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/coding/gsm0503_coding.h></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmo-bts/bts.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmo-bts/l1sap.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmo-bts/logging.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmo-bts/scheduler.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmo-bts/scheduler_backend.h></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#include <sched_utils.h></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/* 3GPP TS 05.02, section 5.2.7 */</span><br><span style="color: hsl(120, 100%, 40%);">+#define RACH_EXT_TAIL_LEN 8</span><br><span style="color: hsl(120, 100%, 40%);">+#define RACH_SYNCH_SEQ_LEN 41</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+enum rach_synch_seq_t {</span><br><span style="color: hsl(120, 100%, 40%);">+ RACH_SYNCH_SEQ_UNKNOWN = -1,</span><br><span style="color: hsl(120, 100%, 40%);">+ RACH_SYNCH_SEQ_TS0, /* GSM, GMSK (default) */</span><br><span style="color: hsl(120, 100%, 40%);">+ RACH_SYNCH_SEQ_TS1, /* EGPRS, 8-PSK */</span><br><span style="color: hsl(120, 100%, 40%);">+ RACH_SYNCH_SEQ_TS2, /* EGPRS, GMSK */</span><br><span style="color: hsl(120, 100%, 40%);">+ RACH_SYNCH_SEQ_NUM</span><br><span style="color: hsl(120, 100%, 40%);">+};</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static struct value_string rach_synch_seq_names[] = {</span><br><span style="color: hsl(120, 100%, 40%);">+ { RACH_SYNCH_SEQ_UNKNOWN, "UNKNOWN" },</span><br><span style="color: hsl(120, 100%, 40%);">+ { RACH_SYNCH_SEQ_TS0, "TS0: GSM, GMSK" },</span><br><span style="color: hsl(120, 100%, 40%);">+ { RACH_SYNCH_SEQ_TS1, "TS1: EGPRS, 8-PSK" },</span><br><span style="color: hsl(120, 100%, 40%);">+ { RACH_SYNCH_SEQ_TS2, "TS2: EGPRS, GMSK" },</span><br><span style="color: hsl(120, 100%, 40%);">+ { 0, NULL },</span><br><span style="color: hsl(120, 100%, 40%);">+};</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static enum rach_synch_seq_t rach_get_synch_seq(sbit_t *bits, int *best_score)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ sbit_t *synch_seq_burst = bits + RACH_EXT_TAIL_LEN;</span><br><span style="color: hsl(120, 100%, 40%);">+ enum rach_synch_seq_t seq = RACH_SYNCH_SEQ_TS0;</span><br><span style="color: hsl(120, 100%, 40%);">+ int score[RACH_SYNCH_SEQ_NUM] = { 0 };</span><br><span style="color: hsl(120, 100%, 40%);">+ int max_score = INT_MIN;</span><br><span style="color: hsl(120, 100%, 40%);">+ int i, j;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* 3GPP TS 05.02, section 5.2.7 "Access burst (AB)", synch. sequence bits */</span><br><span style="color: hsl(120, 100%, 40%);">+ static const char synch_seq_ref[RACH_SYNCH_SEQ_NUM][RACH_SYNCH_SEQ_LEN] = {</span><br><span style="color: hsl(120, 100%, 40%);">+ [RACH_SYNCH_SEQ_TS0] = "01001011011111111001100110101010001111000",</span><br><span style="color: hsl(120, 100%, 40%);">+ [RACH_SYNCH_SEQ_TS1] = "01010100111110001000011000101111001001101",</span><br><span style="color: hsl(120, 100%, 40%);">+ [RACH_SYNCH_SEQ_TS2] = "11101111001001110101011000001101101110111",</span><br><span style="color: hsl(120, 100%, 40%);">+ };</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* Get a multiplier for j-th bit of i-th synch. sequence */</span><br><span style="color: hsl(120, 100%, 40%);">+#define RACH_SYNCH_SEQ_MULT \</span><br><span style="color: hsl(120, 100%, 40%);">+ (synch_seq_ref[i][j] == '1' ? -1 : 1)</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* For each synch. sequence, count the bit match score. Since we deal with</span><br><span style="color: hsl(120, 100%, 40%);">+ * soft-bits (-127...127), we sum the absolute values of matching ones,</span><br><span style="color: hsl(120, 100%, 40%);">+ * and subtract the absolute values of different ones, so the resulting</span><br><span style="color: hsl(120, 100%, 40%);">+ * score is more accurate than it could be with hard-bits. */</span><br><span style="color: hsl(120, 100%, 40%);">+ for (i = 0; i < RACH_SYNCH_SEQ_NUM; i++) {</span><br><span style="color: hsl(120, 100%, 40%);">+ for (j = 0; j < RACH_SYNCH_SEQ_LEN; j++)</span><br><span style="color: hsl(120, 100%, 40%);">+ score[i] += RACH_SYNCH_SEQ_MULT * synch_seq_burst[j];</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* Keep the maximum value updated */</span><br><span style="color: hsl(120, 100%, 40%);">+ if (score[i] > max_score) {</span><br><span style="color: hsl(120, 100%, 40%);">+ max_score = score[i];</span><br><span style="color: hsl(120, 100%, 40%);">+ seq = i;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* Calculate an approximate level of our confidence */</span><br><span style="color: hsl(120, 100%, 40%);">+ if (best_score != NULL)</span><br><span style="color: hsl(120, 100%, 40%);">+ *best_score = max_score;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* At least 1/3 of a synch. sequence shall match */</span><br><span style="color: hsl(120, 100%, 40%);">+ if (max_score < (127 * RACH_SYNCH_SEQ_LEN / 3))</span><br><span style="color: hsl(120, 100%, 40%);">+ return RACH_SYNCH_SEQ_UNKNOWN;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ return seq;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+int rx_rach_fn(struct l1sched_trx *l1t, enum trx_chan_type chan,</span><br><span style="color: hsl(120, 100%, 40%);">+ uint8_t bid, const struct trx_ul_burst_ind *bi)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ struct osmo_phsap_prim l1sap;</span><br><span style="color: hsl(120, 100%, 40%);">+ int n_errors = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+ int n_bits_total = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+ uint16_t ra11;</span><br><span style="color: hsl(120, 100%, 40%);">+ uint8_t ra;</span><br><span style="color: hsl(120, 100%, 40%);">+ int rc;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* TSC (Training Sequence Code) is an optional parameter of the UL burst</span><br><span style="color: hsl(120, 100%, 40%);">+ * indication. We need this information in order to decide whether an</span><br><span style="color: hsl(120, 100%, 40%);">+ * Access Burst is 11-bit encoded or not (see OS#1854). If this information</span><br><span style="color: hsl(120, 100%, 40%);">+ * is absent, we try to correlate the received synch. sequence with the</span><br><span style="color: hsl(120, 100%, 40%);">+ * known ones (3GPP TS 05.02, section 5.2.7), and fall-back to the default</span><br><span style="color: hsl(120, 100%, 40%);">+ * TS0 if it fails. */</span><br><span style="color: hsl(120, 100%, 40%);">+ enum rach_synch_seq_t synch_seq = RACH_SYNCH_SEQ_TS0;</span><br><span style="color: hsl(120, 100%, 40%);">+ int best_score = 127 * RACH_SYNCH_SEQ_LEN;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* If logical channel is not either of RACH, PDTCH or PTCCH, this is a</span><br><span style="color: hsl(120, 100%, 40%);">+ * handover Access Burst, which is always encoded as 8-bit and shall</span><br><span style="color: hsl(120, 100%, 40%);">+ * contain the generic training sequence (TS0). */</span><br><span style="color: hsl(120, 100%, 40%);">+ if (chan == TRXC_RACH || chan == TRXC_PDTCH || chan == TRXC_PTCCH) {</span><br><span style="color: hsl(120, 100%, 40%);">+ if (bi->flags & TRX_BI_F_TS_INFO)</span><br><span style="color: hsl(120, 100%, 40%);">+ synch_seq = (enum rach_synch_seq_t) bi->tsc;</span><br><span style="color: hsl(120, 100%, 40%);">+ else</span><br><span style="color: hsl(120, 100%, 40%);">+ synch_seq = rach_get_synch_seq((sbit_t *) bi->burst, &best_score);</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ LOGL1S(DL1P, LOGL_DEBUG, l1t, bi->tn, chan, bi->fn,</span><br><span style="color: hsl(120, 100%, 40%);">+ "Received%s RACH (%s): rssi=%d toa256=%d",</span><br><span style="color: hsl(120, 100%, 40%);">+ (chan != TRXC_RACH) ? " handover" : "",</span><br><span style="color: hsl(120, 100%, 40%);">+ get_value_string(rach_synch_seq_names, synch_seq),</span><br><span style="color: hsl(120, 100%, 40%);">+ bi->rssi, bi->toa256);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (bi->flags & TRX_BI_F_CI_CB)</span><br><span style="color: hsl(120, 100%, 40%);">+ LOGPC(DL1P, LOGL_DEBUG, " C/I=%d cB", bi->ci_cb);</span><br><span style="color: hsl(120, 100%, 40%);">+ else</span><br><span style="color: hsl(120, 100%, 40%);">+ LOGPC(DL1P, LOGL_DEBUG, " match=%.1f%%",</span><br><span style="color: hsl(120, 100%, 40%);">+ best_score * 100.0 / (127 * RACH_SYNCH_SEQ_LEN));</span><br><span style="color: hsl(120, 100%, 40%);">+ LOGPC(DL1P, LOGL_DEBUG, "\n");</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* Compose a new L1SAP primitive */</span><br><span style="color: hsl(120, 100%, 40%);">+ memset(&l1sap, 0x00, sizeof(l1sap));</span><br><span style="color: hsl(120, 100%, 40%);">+ osmo_prim_init(&l1sap.oph, SAP_GSM_PH, PRIM_PH_RACH, PRIM_OP_INDICATION, NULL);</span><br><span style="color: hsl(120, 100%, 40%);">+ l1sap.u.rach_ind.chan_nr = trx_chan_desc[chan].chan_nr | bi->tn;</span><br><span style="color: hsl(120, 100%, 40%);">+ l1sap.u.rach_ind.acc_delay = (bi->toa256 >= 0) ? bi->toa256 / 256 : 0;</span><br><span style="color: hsl(120, 100%, 40%);">+ l1sap.u.rach_ind.acc_delay_256bits = bi->toa256;</span><br><span style="color: hsl(120, 100%, 40%);">+ l1sap.u.rach_ind.rssi = bi->rssi;</span><br><span style="color: hsl(120, 100%, 40%);">+ l1sap.u.rach_ind.fn = bi->fn;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* Link quality is defined by C/I (Carrier-to-Interference ratio),</span><br><span style="color: hsl(120, 100%, 40%);">+ * which has optional presence. If it's absent, report the</span><br><span style="color: hsl(120, 100%, 40%);">+ * minimum acceptable value to pass L1SAP checks. */</span><br><span style="color: hsl(120, 100%, 40%);">+ if (bi->flags & TRX_BI_F_CI_CB)</span><br><span style="color: hsl(120, 100%, 40%);">+ l1sap.u.rach_ind.lqual_cb = bi->ci_cb;</span><br><span style="color: hsl(120, 100%, 40%);">+ else</span><br><span style="color: hsl(120, 100%, 40%);">+ l1sap.u.rach_ind.lqual_cb = l1t->trx->bts->min_qual_rach;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* Decode RACH depending on its synch. sequence */</span><br><span style="color: hsl(120, 100%, 40%);">+ switch (synch_seq) {</span><br><span style="color: hsl(120, 100%, 40%);">+ case RACH_SYNCH_SEQ_TS1:</span><br><span style="color: hsl(120, 100%, 40%);">+ case RACH_SYNCH_SEQ_TS2:</span><br><span style="color: hsl(120, 100%, 40%);">+ rc = gsm0503_rach_ext_decode_ber(&ra11, bi->burst + RACH_EXT_TAIL_LEN + RACH_SYNCH_SEQ_LEN,</span><br><span style="color: hsl(120, 100%, 40%);">+ l1t->trx->bts->bsic, &n_errors, &n_bits_total);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (rc) {</span><br><span style="color: hsl(120, 100%, 40%);">+ LOGL1S(DL1P, LOGL_DEBUG, l1t, bi->tn, chan, bi->fn,</span><br><span style="color: hsl(120, 100%, 40%);">+ "Received bad Access Burst\n");</span><br><span style="color: hsl(120, 100%, 40%);">+ return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ if (synch_seq == RACH_SYNCH_SEQ_TS1)</span><br><span style="color: hsl(120, 100%, 40%);">+ l1sap.u.rach_ind.burst_type = GSM_L1_BURST_TYPE_ACCESS_1;</span><br><span style="color: hsl(120, 100%, 40%);">+ else</span><br><span style="color: hsl(120, 100%, 40%);">+ l1sap.u.rach_ind.burst_type = GSM_L1_BURST_TYPE_ACCESS_2;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ l1sap.u.rach_ind.is_11bit = 1;</span><br><span style="color: hsl(120, 100%, 40%);">+ l1sap.u.rach_ind.ra = ra11;</span><br><span style="color: hsl(120, 100%, 40%);">+ break;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ case RACH_SYNCH_SEQ_TS0:</span><br><span style="color: hsl(120, 100%, 40%);">+ default:</span><br><span style="color: hsl(120, 100%, 40%);">+ /* Fall-back to the default TS0 if needed */</span><br><span style="color: hsl(120, 100%, 40%);">+ if (synch_seq != RACH_SYNCH_SEQ_TS0) {</span><br><span style="color: hsl(120, 100%, 40%);">+ LOGL1S(DL1P, LOGL_DEBUG, l1t, bi->tn, chan, bi->fn,</span><br><span style="color: hsl(120, 100%, 40%);">+ "Falling-back to the default TS0\n");</span><br><span style="color: hsl(120, 100%, 40%);">+ synch_seq = RACH_SYNCH_SEQ_TS0;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ rc = gsm0503_rach_decode_ber(&ra, bi->burst + RACH_EXT_TAIL_LEN + RACH_SYNCH_SEQ_LEN,</span><br><span style="color: hsl(120, 100%, 40%);">+ l1t->trx->bts->bsic, &n_errors, &n_bits_total);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (rc) {</span><br><span style="color: hsl(120, 100%, 40%);">+ LOGL1S(DL1P, LOGL_DEBUG, l1t, bi->tn, chan, bi->fn,</span><br><span style="color: hsl(120, 100%, 40%);">+ "Received bad Access Burst\n");</span><br><span style="color: hsl(120, 100%, 40%);">+ return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ l1sap.u.rach_ind.burst_type = GSM_L1_BURST_TYPE_ACCESS_0;</span><br><span style="color: hsl(120, 100%, 40%);">+ l1sap.u.rach_ind.is_11bit = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+ l1sap.u.rach_ind.ra = ra;</span><br><span style="color: hsl(120, 100%, 40%);">+ break;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ l1sap.u.rach_ind.ber10k = compute_ber10k(n_bits_total, n_errors);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* forward primitive */</span><br><span style="color: hsl(120, 100%, 40%);">+ l1sap_up(l1t->trx, &l1sap);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span>diff --git a/src/osmo-bts-trx/sched_lchan_tchf.c b/src/osmo-bts-trx/sched_lchan_tchf.c</span><br><span>new file mode 100644</span><br><span>index 0000000..fb11f45</span><br><span>--- /dev/null</span><br><span>+++ b/src/osmo-bts-trx/sched_lchan_tchf.c</span><br><span>@@ -0,0 +1,570 @@</span><br><span style="color: hsl(120, 100%, 40%);">+/*</span><br><span style="color: hsl(120, 100%, 40%);">+ * (C) 2013 by Andreas Eversberg <jolly@eversberg.eu></span><br><span style="color: hsl(120, 100%, 40%);">+ * (C) 2015-2017 by Harald Welte <laforge@gnumonks.org></span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * All Rights Reserved</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * This program is free software; you can redistribute it and/or modify</span><br><span style="color: hsl(120, 100%, 40%);">+ * it under the terms of the GNU Affero General Public License as published by</span><br><span style="color: hsl(120, 100%, 40%);">+ * the Free Software Foundation; either version 3 of the License, or</span><br><span style="color: hsl(120, 100%, 40%);">+ * (at your option) any later version.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * This program is distributed in the hope that it will be useful,</span><br><span style="color: hsl(120, 100%, 40%);">+ * but WITHOUT ANY WARRANTY; without even the implied warranty of</span><br><span style="color: hsl(120, 100%, 40%);">+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the</span><br><span style="color: hsl(120, 100%, 40%);">+ * GNU General Public License for more details.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * You should have received a copy of the GNU Affero General Public License</span><br><span style="color: hsl(120, 100%, 40%);">+ * along with this program. If not, see <http://www.gnu.org/licenses/>.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#include <stdint.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <errno.h></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/core/bits.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/core/msgb.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/core/utils.h></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/gsm/gsm0502.h></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/codec/codec.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/codec/ecu.h></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/coding/gsm0503_coding.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/coding/gsm0503_amr_dtx.h></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmo-bts/bts.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmo-bts/l1sap.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmo-bts/logging.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmo-bts/scheduler.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmo-bts/scheduler_backend.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmo-bts/msg_utils.h></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#include <sched_utils.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <loops.h></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/*! \brief a single TCH/F burst was received by the PHY, process it */</span><br><span style="color: hsl(120, 100%, 40%);">+int rx_tchf_fn(struct l1sched_trx *l1t, enum trx_chan_type chan,</span><br><span style="color: hsl(120, 100%, 40%);">+ uint8_t bid, const struct trx_ul_burst_ind *bi)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ struct l1sched_ts *l1ts = l1sched_trx_get_ts(l1t, bi->tn);</span><br><span style="color: hsl(120, 100%, 40%);">+ struct l1sched_chan_state *chan_state = &l1ts->chan_state[chan];</span><br><span style="color: hsl(120, 100%, 40%);">+ sbit_t *burst, **bursts_p = &chan_state->ul_bursts;</span><br><span style="color: hsl(120, 100%, 40%);">+ uint8_t *mask = &chan_state->ul_mask;</span><br><span style="color: hsl(120, 100%, 40%);">+ uint8_t rsl_cmode = chan_state->rsl_cmode;</span><br><span style="color: hsl(120, 100%, 40%);">+ uint8_t tch_mode = chan_state->tch_mode;</span><br><span style="color: hsl(120, 100%, 40%);">+ uint8_t tch_data[128]; /* just to be safe */</span><br><span style="color: hsl(120, 100%, 40%);">+ int rc, amr = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+ int n_errors = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+ int n_bits_total = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+ bool bfi_flag = false;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct gsm_lchan *lchan =</span><br><span style="color: hsl(120, 100%, 40%);">+ get_lchan_by_chan_nr(l1t->trx, trx_chan_desc[chan].chan_nr | bi->tn);</span><br><span style="color: hsl(120, 100%, 40%);">+ unsigned int fn_begin;</span><br><span style="color: hsl(120, 100%, 40%);">+ uint16_t ber10k;</span><br><span style="color: hsl(120, 100%, 40%);">+ uint8_t is_sub = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+ uint8_t ft;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* If handover RACH detection is turned on, treat this burst as an Access Burst.</span><br><span style="color: hsl(120, 100%, 40%);">+ * Handle NOPE.ind as usually to ensure proper Uplink measurement reporting. */</span><br><span style="color: hsl(120, 100%, 40%);">+ if (chan_state->ho_rach_detect == 1 && ~bi->flags & TRX_BI_F_NOPE_IND)</span><br><span style="color: hsl(120, 100%, 40%);">+ return rx_rach_fn(l1t, chan, bid, bi);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ LOGL1S(DL1P, LOGL_DEBUG, l1t, bi->tn, chan, bi->fn,</span><br><span style="color: hsl(120, 100%, 40%);">+ "Received TCH/F, bid=%u\n", bid);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* allocate burst memory, if not already */</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!*bursts_p) {</span><br><span style="color: hsl(120, 100%, 40%);">+ *bursts_p = talloc_zero_size(tall_bts_ctx, 928);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!*bursts_p)</span><br><span style="color: hsl(120, 100%, 40%);">+ return -ENOMEM;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* clear burst */</span><br><span style="color: hsl(120, 100%, 40%);">+ if (bid == 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+ memset(*bursts_p + 464, 0, 464);</span><br><span style="color: hsl(120, 100%, 40%);">+ *mask = 0x0;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* update mask */</span><br><span style="color: hsl(120, 100%, 40%);">+ *mask |= (1 << bid);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* copy burst to end of buffer of 8 bursts */</span><br><span style="color: hsl(120, 100%, 40%);">+ burst = *bursts_p + bid * 116 + 464;</span><br><span style="color: hsl(120, 100%, 40%);">+ if (bi->burst_len > 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+ memcpy(burst, bi->burst + 3, 58);</span><br><span style="color: hsl(120, 100%, 40%);">+ memcpy(burst + 58, bi->burst + 87, 58);</span><br><span style="color: hsl(120, 100%, 40%);">+ } else</span><br><span style="color: hsl(120, 100%, 40%);">+ memset(burst, 0, 116);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* wait until complete set of bursts */</span><br><span style="color: hsl(120, 100%, 40%);">+ if (bid != 3)</span><br><span style="color: hsl(120, 100%, 40%);">+ return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* check for complete set of bursts */</span><br><span style="color: hsl(120, 100%, 40%);">+ if ((*mask & 0xf) != 0xf) {</span><br><span style="color: hsl(120, 100%, 40%);">+ LOGL1S(DL1P, LOGL_NOTICE, l1t, bi->tn, chan, bi->fn,</span><br><span style="color: hsl(120, 100%, 40%);">+ "Received incomplete frame (%u/%u)\n",</span><br><span style="color: hsl(120, 100%, 40%);">+ bi->fn % l1ts->mf_period, l1ts->mf_period);</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+ *mask = 0x0;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* decode</span><br><span style="color: hsl(120, 100%, 40%);">+ * also shift buffer by 4 bursts for interleaving */</span><br><span style="color: hsl(120, 100%, 40%);">+ switch ((rsl_cmode != RSL_CMOD_SPD_SPEECH) ? GSM48_CMODE_SPEECH_V1</span><br><span style="color: hsl(120, 100%, 40%);">+ : tch_mode) {</span><br><span style="color: hsl(120, 100%, 40%);">+ case GSM48_CMODE_SPEECH_V1: /* FR */</span><br><span style="color: hsl(120, 100%, 40%);">+ rc = gsm0503_tch_fr_decode(tch_data, *bursts_p, 1, 0, &n_errors, &n_bits_total);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (rc >= 0)</span><br><span style="color: hsl(120, 100%, 40%);">+ lchan_set_marker(osmo_fr_check_sid(tch_data, rc), lchan); /* DTXu */</span><br><span style="color: hsl(120, 100%, 40%);">+ break;</span><br><span style="color: hsl(120, 100%, 40%);">+ case GSM48_CMODE_SPEECH_EFR: /* EFR */</span><br><span style="color: hsl(120, 100%, 40%);">+ rc = gsm0503_tch_fr_decode(tch_data, *bursts_p, 1, 1, &n_errors, &n_bits_total);</span><br><span style="color: hsl(120, 100%, 40%);">+ break;</span><br><span style="color: hsl(120, 100%, 40%);">+ case GSM48_CMODE_SPEECH_AMR: /* AMR */</span><br><span style="color: hsl(120, 100%, 40%);">+ /* the first FN 0,8,17 defines that CMI is included in frame,</span><br><span style="color: hsl(120, 100%, 40%);">+ * the first FN 4,13,21 defines that CMR is included in frame.</span><br><span style="color: hsl(120, 100%, 40%);">+ * NOTE: A frame ends 7 FN after start.</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* The AFS_ONSET frame itself does not result into an RTP frame</span><br><span style="color: hsl(120, 100%, 40%);">+ * since it only contains a recognition pattern that marks the</span><br><span style="color: hsl(120, 100%, 40%);">+ * end of the DTX interval. To mark the end of the DTX interval</span><br><span style="color: hsl(120, 100%, 40%);">+ * in the RTP stream as well, the voice frame after the</span><br><span style="color: hsl(120, 100%, 40%);">+ * AFS_ONSET frame is used. */</span><br><span style="color: hsl(120, 100%, 40%);">+ if (chan_state->amr_last_dtx == AFS_ONSET)</span><br><span style="color: hsl(120, 100%, 40%);">+ lchan_set_marker(false, lchan);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* we store tch_data + 2 header bytes, the amr variable set to</span><br><span style="color: hsl(120, 100%, 40%);">+ * 2 will allow us to skip the first 2 bytes in case we did</span><br><span style="color: hsl(120, 100%, 40%);">+ * receive an FACCH frame instead of a voice frame (we do not</span><br><span style="color: hsl(120, 100%, 40%);">+ * know this before we actually decode the frame) */</span><br><span style="color: hsl(120, 100%, 40%);">+ amr = 2;</span><br><span style="color: hsl(120, 100%, 40%);">+ rc = gsm0503_tch_afs_decode_dtx(tch_data + amr, *bursts_p,</span><br><span style="color: hsl(120, 100%, 40%);">+ (((bi->fn + 26 - 7) % 26) >> 2) & 1, chan_state->codec,</span><br><span style="color: hsl(120, 100%, 40%);">+ chan_state->codecs, &chan_state->ul_ft,</span><br><span style="color: hsl(120, 100%, 40%);">+ &chan_state->ul_cmr, &n_errors, &n_bits_total, &chan_state->amr_last_dtx);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* Tag all frames that are not regular AMR voice frames as</span><br><span style="color: hsl(120, 100%, 40%);">+ * SUB-Frames */</span><br><span style="color: hsl(120, 100%, 40%);">+ if (chan_state->amr_last_dtx != AMR_OTHER) {</span><br><span style="color: hsl(120, 100%, 40%);">+ LOGL1S(DL1P, LOGL_DEBUG, l1t, bi->tn, chan, bi->fn,</span><br><span style="color: hsl(120, 100%, 40%);">+ "Received AMR SID frame: %s\n",</span><br><span style="color: hsl(120, 100%, 40%);">+ gsm0503_amr_dtx_frame_name(chan_state->amr_last_dtx));</span><br><span style="color: hsl(120, 100%, 40%);">+ is_sub = 1;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* The occurrence of the following frames indicates that we</span><br><span style="color: hsl(120, 100%, 40%);">+ * are either at the beginning or in the middle of a talk</span><br><span style="color: hsl(120, 100%, 40%);">+ * spurt. We update the SID status accordingly, but we do</span><br><span style="color: hsl(120, 100%, 40%);">+ * not want the marker to be set, since this must only</span><br><span style="color: hsl(120, 100%, 40%);">+ * happen when the talk spurt is over (see above) */</span><br><span style="color: hsl(120, 100%, 40%);">+ switch (chan_state->amr_last_dtx) {</span><br><span style="color: hsl(120, 100%, 40%);">+ case AFS_SID_FIRST:</span><br><span style="color: hsl(120, 100%, 40%);">+ case AFS_SID_UPDATE:</span><br><span style="color: hsl(120, 100%, 40%);">+ case AFS_SID_UPDATE_CN:</span><br><span style="color: hsl(120, 100%, 40%);">+ lchan_set_marker(true, lchan);</span><br><span style="color: hsl(120, 100%, 40%);">+ lchan->rtp_tx_marker = false;</span><br><span style="color: hsl(120, 100%, 40%);">+ break;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ if (rc)</span><br><span style="color: hsl(120, 100%, 40%);">+ trx_loop_amr_input(l1t,</span><br><span style="color: hsl(120, 100%, 40%);">+ trx_chan_desc[chan].chan_nr | bi->tn, chan_state,</span><br><span style="color: hsl(120, 100%, 40%);">+ n_errors, n_bits_total);</span><br><span style="color: hsl(120, 100%, 40%);">+ /* only good speech frames get rtp header */</span><br><span style="color: hsl(120, 100%, 40%);">+ if (rc != GSM_MACBLOCK_LEN && rc >= 4) {</span><br><span style="color: hsl(120, 100%, 40%);">+ if (chan_state->amr_last_dtx == AMR_OTHER) {</span><br><span style="color: hsl(120, 100%, 40%);">+ ft = chan_state->codec[chan_state->ul_cmr];</span><br><span style="color: hsl(120, 100%, 40%);">+ } else {</span><br><span style="color: hsl(120, 100%, 40%);">+ /* SID frames will always get Frame Type Index 8 (AMR_SID) */</span><br><span style="color: hsl(120, 100%, 40%);">+ ft = AMR_SID;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+ rc = osmo_amr_rtp_enc(tch_data,</span><br><span style="color: hsl(120, 100%, 40%);">+ chan_state->codec[chan_state->ul_cmr],</span><br><span style="color: hsl(120, 100%, 40%);">+ ft, AMR_GOOD);</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ break;</span><br><span style="color: hsl(120, 100%, 40%);">+ default:</span><br><span style="color: hsl(120, 100%, 40%);">+ LOGL1S(DL1P, LOGL_ERROR, l1t, bi->tn, chan, bi->fn,</span><br><span style="color: hsl(120, 100%, 40%);">+ "TCH mode %u invalid, please fix!\n",</span><br><span style="color: hsl(120, 100%, 40%);">+ tch_mode);</span><br><span style="color: hsl(120, 100%, 40%);">+ return -EINVAL;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+ memcpy(*bursts_p, *bursts_p + 464, 464);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* Check if the frame is bad */</span><br><span style="color: hsl(120, 100%, 40%);">+ if (rc < 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+ LOGL1S(DL1P, LOGL_NOTICE, l1t, bi->tn, chan, bi->fn,</span><br><span style="color: hsl(120, 100%, 40%);">+ "Received bad data (%u/%u)\n",</span><br><span style="color: hsl(120, 100%, 40%);">+ bi->fn % l1ts->mf_period, l1ts->mf_period);</span><br><span style="color: hsl(120, 100%, 40%);">+ bfi_flag = true;</span><br><span style="color: hsl(120, 100%, 40%);">+ } else if (rc < 4) {</span><br><span style="color: hsl(120, 100%, 40%);">+ LOGL1S(DL1P, LOGL_NOTICE, l1t, bi->tn, chan, bi->fn,</span><br><span style="color: hsl(120, 100%, 40%);">+ "Received bad data (%u/%u) with invalid codec mode %d\n",</span><br><span style="color: hsl(120, 100%, 40%);">+ bi->fn % l1ts->mf_period, l1ts->mf_period, rc);</span><br><span style="color: hsl(120, 100%, 40%);">+ bfi_flag = true;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ if (rc != GSM_MACBLOCK_LEN && lchan->ecu_state)</span><br><span style="color: hsl(120, 100%, 40%);">+ osmo_ecu_frame_in(lchan->ecu_state, bfi_flag, tch_data, rc);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ ber10k = compute_ber10k(n_bits_total, n_errors);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (bfi_flag)</span><br><span style="color: hsl(120, 100%, 40%);">+ goto bfi;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* FACCH */</span><br><span style="color: hsl(120, 100%, 40%);">+ if (rc == GSM_MACBLOCK_LEN) {</span><br><span style="color: hsl(120, 100%, 40%);">+ fn_begin = gsm0502_fn_remap(bi->fn, FN_REMAP_FACCH_F);</span><br><span style="color: hsl(120, 100%, 40%);">+ _sched_compose_ph_data_ind(l1t, bi->tn, fn_begin, chan,</span><br><span style="color: hsl(120, 100%, 40%);">+ tch_data + amr, GSM_MACBLOCK_LEN,</span><br><span style="color: hsl(120, 100%, 40%);">+ /* FIXME: AVG RSSI and ToA256 */</span><br><span style="color: hsl(120, 100%, 40%);">+ bi->rssi, bi->toa256,</span><br><span style="color: hsl(120, 100%, 40%);">+ 0 /* FIXME: AVG C/I */,</span><br><span style="color: hsl(120, 100%, 40%);">+ ber10k, PRES_INFO_UNKNOWN);</span><br><span style="color: hsl(120, 100%, 40%);">+bfi:</span><br><span style="color: hsl(120, 100%, 40%);">+ if (rsl_cmode == RSL_CMOD_SPD_SPEECH) {</span><br><span style="color: hsl(120, 100%, 40%);">+ /* indicate bad frame */</span><br><span style="color: hsl(120, 100%, 40%);">+ if (lchan->tch.dtx.ul_sid) {</span><br><span style="color: hsl(120, 100%, 40%);">+ /* DTXu: pause in progress. Push empty payload to upper layers */</span><br><span style="color: hsl(120, 100%, 40%);">+ rc = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+ goto compose_l1sap;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* If there is an ECU active on this channel, use its output */</span><br><span style="color: hsl(120, 100%, 40%);">+ if (lchan->ecu_state) {</span><br><span style="color: hsl(120, 100%, 40%);">+ rc = osmo_ecu_frame_out(lchan->ecu_state, tch_data);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (rc >= 0) /* Otherwise we send a BFI */</span><br><span style="color: hsl(120, 100%, 40%);">+ goto compose_l1sap;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ switch (tch_mode) {</span><br><span style="color: hsl(120, 100%, 40%);">+ case GSM48_CMODE_SPEECH_V1: /* FR */</span><br><span style="color: hsl(120, 100%, 40%);">+ memset(tch_data, 0, GSM_FR_BYTES);</span><br><span style="color: hsl(120, 100%, 40%);">+ tch_data[0] = 0xd0;</span><br><span style="color: hsl(120, 100%, 40%);">+ rc = GSM_FR_BYTES;</span><br><span style="color: hsl(120, 100%, 40%);">+ break;</span><br><span style="color: hsl(120, 100%, 40%);">+ case GSM48_CMODE_SPEECH_EFR: /* EFR */</span><br><span style="color: hsl(120, 100%, 40%);">+ memset(tch_data, 0, GSM_EFR_BYTES);</span><br><span style="color: hsl(120, 100%, 40%);">+ tch_data[0] = 0xc0;</span><br><span style="color: hsl(120, 100%, 40%);">+ rc = GSM_EFR_BYTES;</span><br><span style="color: hsl(120, 100%, 40%);">+ break;</span><br><span style="color: hsl(120, 100%, 40%);">+ case GSM48_CMODE_SPEECH_AMR: /* AMR */</span><br><span style="color: hsl(120, 100%, 40%);">+ rc = osmo_amr_rtp_enc(tch_data,</span><br><span style="color: hsl(120, 100%, 40%);">+ chan_state->codec[chan_state->dl_cmr],</span><br><span style="color: hsl(120, 100%, 40%);">+ chan_state->codec[chan_state->dl_ft],</span><br><span style="color: hsl(120, 100%, 40%);">+ AMR_BAD);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (rc < 2) {</span><br><span style="color: hsl(120, 100%, 40%);">+ LOGL1S(DL1P, LOGL_ERROR, l1t, bi->tn, chan, bi->fn,</span><br><span style="color: hsl(120, 100%, 40%);">+ "Failed to encode AMR_BAD frame (rc=%d), "</span><br><span style="color: hsl(120, 100%, 40%);">+ "not sending BFI\n", rc);</span><br><span style="color: hsl(120, 100%, 40%);">+ return -EINVAL;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+ memset(tch_data + 2, 0, rc - 2);</span><br><span style="color: hsl(120, 100%, 40%);">+ break;</span><br><span style="color: hsl(120, 100%, 40%);">+ default:</span><br><span style="color: hsl(120, 100%, 40%);">+ LOGL1S(DL1P, LOGL_ERROR, l1t, bi->tn, chan, bi->fn,</span><br><span style="color: hsl(120, 100%, 40%);">+ "TCH mode %u invalid, please fix!\n", tch_mode);</span><br><span style="color: hsl(120, 100%, 40%);">+ return -EINVAL;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ if (rsl_cmode != RSL_CMOD_SPD_SPEECH)</span><br><span style="color: hsl(120, 100%, 40%);">+ return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* TCH or BFI */</span><br><span style="color: hsl(120, 100%, 40%);">+compose_l1sap:</span><br><span style="color: hsl(120, 100%, 40%);">+ fn_begin = gsm0502_fn_remap(bi->fn, FN_REMAP_TCH_F);</span><br><span style="color: hsl(120, 100%, 40%);">+ return _sched_compose_tch_ind(l1t, bi->tn, fn_begin, chan,</span><br><span style="color: hsl(120, 100%, 40%);">+ tch_data, rc, bi->toa256, ber10k, bi->rssi, is_sub);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/* common section for generation of TCH bursts (TCH/H and TCH/F).</span><br><span style="color: hsl(120, 100%, 40%);">+ * FIXME: this function is over-complicated, refactor / get rid of it. */</span><br><span style="color: hsl(120, 100%, 40%);">+void tx_tch_common(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn,</span><br><span style="color: hsl(120, 100%, 40%);">+ enum trx_chan_type chan, uint8_t bid,</span><br><span style="color: hsl(120, 100%, 40%);">+ struct msgb **_msg_tch, struct msgb **_msg_facch)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ struct l1sched_ts *l1ts = l1sched_trx_get_ts(l1t, tn);</span><br><span style="color: hsl(120, 100%, 40%);">+ struct msgb *msg1, *msg2, *msg_tch = NULL, *msg_facch = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct l1sched_chan_state *chan_state = &l1ts->chan_state[chan];</span><br><span style="color: hsl(120, 100%, 40%);">+ uint8_t rsl_cmode = chan_state->rsl_cmode;</span><br><span style="color: hsl(120, 100%, 40%);">+ uint8_t tch_mode = chan_state->tch_mode;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct osmo_phsap_prim *l1sap;</span><br><span style="color: hsl(120, 100%, 40%);">+ int32_t *toa256_sum = &chan_state->toa256_sum;</span><br><span style="color: hsl(120, 100%, 40%);">+ uint8_t *toa_num = &chan_state->toa_num;</span><br><span style="color: hsl(120, 100%, 40%);">+ int16_t toa256;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* handle loss detection of received TCH frames */</span><br><span style="color: hsl(120, 100%, 40%);">+ if (rsl_cmode == RSL_CMOD_SPD_SPEECH</span><br><span style="color: hsl(120, 100%, 40%);">+ && ++(chan_state->lost_frames) > 5) {</span><br><span style="color: hsl(120, 100%, 40%);">+ uint8_t tch_data[GSM_FR_BYTES];</span><br><span style="color: hsl(120, 100%, 40%);">+ int len;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ LOGL1S(DL1P, LOGL_NOTICE, l1t, tn, chan, fn,</span><br><span style="color: hsl(120, 100%, 40%);">+ "Missing TCH bursts detected, sending BFI\n");</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* indicate bad frame */</span><br><span style="color: hsl(120, 100%, 40%);">+ switch (tch_mode) {</span><br><span style="color: hsl(120, 100%, 40%);">+ case GSM48_CMODE_SPEECH_V1: /* FR / HR */</span><br><span style="color: hsl(120, 100%, 40%);">+ if (chan != TRXC_TCHF) { /* HR */</span><br><span style="color: hsl(120, 100%, 40%);">+ tch_data[0] = 0x70; /* F = 0, FT = 111 */</span><br><span style="color: hsl(120, 100%, 40%);">+ memset(tch_data + 1, 0, 14);</span><br><span style="color: hsl(120, 100%, 40%);">+ len = 15;</span><br><span style="color: hsl(120, 100%, 40%);">+ break;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+ memset(tch_data, 0, GSM_FR_BYTES);</span><br><span style="color: hsl(120, 100%, 40%);">+ len = GSM_FR_BYTES;</span><br><span style="color: hsl(120, 100%, 40%);">+ break;</span><br><span style="color: hsl(120, 100%, 40%);">+ case GSM48_CMODE_SPEECH_EFR: /* EFR */</span><br><span style="color: hsl(120, 100%, 40%);">+ if (chan != TRXC_TCHF)</span><br><span style="color: hsl(120, 100%, 40%);">+ goto inval_mode1;</span><br><span style="color: hsl(120, 100%, 40%);">+ memset(tch_data, 0, GSM_EFR_BYTES);</span><br><span style="color: hsl(120, 100%, 40%);">+ len = GSM_EFR_BYTES;</span><br><span style="color: hsl(120, 100%, 40%);">+ break;</span><br><span style="color: hsl(120, 100%, 40%);">+ case GSM48_CMODE_SPEECH_AMR: /* AMR */</span><br><span style="color: hsl(120, 100%, 40%);">+ len = osmo_amr_rtp_enc(tch_data,</span><br><span style="color: hsl(120, 100%, 40%);">+ chan_state->codec[chan_state->dl_cmr],</span><br><span style="color: hsl(120, 100%, 40%);">+ chan_state->codec[chan_state->dl_ft], AMR_BAD);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (len < 2) {</span><br><span style="color: hsl(120, 100%, 40%);">+ LOGL1S(DL1P, LOGL_ERROR, l1t, tn, chan, fn,</span><br><span style="color: hsl(120, 100%, 40%);">+ "Failed to encode AMR_BAD frame (rc=%d), "</span><br><span style="color: hsl(120, 100%, 40%);">+ "not sending BFI\n", len);</span><br><span style="color: hsl(120, 100%, 40%);">+ return;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+ memset(tch_data + 2, 0, len - 2);</span><br><span style="color: hsl(120, 100%, 40%);">+ break;</span><br><span style="color: hsl(120, 100%, 40%);">+ default:</span><br><span style="color: hsl(120, 100%, 40%);">+inval_mode1:</span><br><span style="color: hsl(120, 100%, 40%);">+ LOGL1S(DL1P, LOGL_ERROR, l1t, tn, chan, fn, "TCH mode invalid, please fix!\n");</span><br><span style="color: hsl(120, 100%, 40%);">+ len = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ if (len) {</span><br><span style="color: hsl(120, 100%, 40%);">+ if (*toa_num == 0)</span><br><span style="color: hsl(120, 100%, 40%);">+ toa256 = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+ else</span><br><span style="color: hsl(120, 100%, 40%);">+ toa256 = *toa256_sum / *toa_num;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* Note: RSSI is set to 0 to indicate to the higher</span><br><span style="color: hsl(120, 100%, 40%);">+ * layers that this is a faked tch_ind */</span><br><span style="color: hsl(120, 100%, 40%);">+ _sched_compose_tch_ind(l1t, tn, fn, chan, tch_data, len, toa256, 10000, 0, 0);</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* get frame and unlink from queue */</span><br><span style="color: hsl(120, 100%, 40%);">+ msg1 = _sched_dequeue_prim(l1t, tn, fn, chan);</span><br><span style="color: hsl(120, 100%, 40%);">+ msg2 = _sched_dequeue_prim(l1t, tn, fn, chan);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (msg1) {</span><br><span style="color: hsl(120, 100%, 40%);">+ l1sap = msgb_l1sap_prim(msg1);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (l1sap->oph.primitive == PRIM_TCH) {</span><br><span style="color: hsl(120, 100%, 40%);">+ msg_tch = msg1;</span><br><span style="color: hsl(120, 100%, 40%);">+ if (msg2) {</span><br><span style="color: hsl(120, 100%, 40%);">+ l1sap = msgb_l1sap_prim(msg2);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (l1sap->oph.primitive == PRIM_TCH) {</span><br><span style="color: hsl(120, 100%, 40%);">+ LOGL1S(DL1P, LOGL_FATAL, l1t, tn, chan, fn,</span><br><span style="color: hsl(120, 100%, 40%);">+ "TCH twice, please FIX!\n");</span><br><span style="color: hsl(120, 100%, 40%);">+ msgb_free(msg2);</span><br><span style="color: hsl(120, 100%, 40%);">+ } else</span><br><span style="color: hsl(120, 100%, 40%);">+ msg_facch = msg2;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+ } else {</span><br><span style="color: hsl(120, 100%, 40%);">+ msg_facch = msg1;</span><br><span style="color: hsl(120, 100%, 40%);">+ if (msg2) {</span><br><span style="color: hsl(120, 100%, 40%);">+ l1sap = msgb_l1sap_prim(msg2);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (l1sap->oph.primitive != PRIM_TCH) {</span><br><span style="color: hsl(120, 100%, 40%);">+ LOGL1S(DL1P, LOGL_FATAL, l1t, tn, chan, fn,</span><br><span style="color: hsl(120, 100%, 40%);">+ "FACCH twice, please FIX!\n");</span><br><span style="color: hsl(120, 100%, 40%);">+ msgb_free(msg2);</span><br><span style="color: hsl(120, 100%, 40%);">+ } else</span><br><span style="color: hsl(120, 100%, 40%);">+ msg_tch = msg2;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+ } else if (msg2) {</span><br><span style="color: hsl(120, 100%, 40%);">+ l1sap = msgb_l1sap_prim(msg2);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (l1sap->oph.primitive == PRIM_TCH)</span><br><span style="color: hsl(120, 100%, 40%);">+ msg_tch = msg2;</span><br><span style="color: hsl(120, 100%, 40%);">+ else</span><br><span style="color: hsl(120, 100%, 40%);">+ msg_facch = msg2;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* check validity of message */</span><br><span style="color: hsl(120, 100%, 40%);">+ if (msg_facch && msgb_l2len(msg_facch) != GSM_MACBLOCK_LEN) {</span><br><span style="color: hsl(120, 100%, 40%);">+ LOGL1S(DL1P, LOGL_FATAL, l1t, tn, chan, fn, "Prim not 23 bytes, please FIX! "</span><br><span style="color: hsl(120, 100%, 40%);">+ "(len=%d)\n", msgb_l2len(msg_facch));</span><br><span style="color: hsl(120, 100%, 40%);">+ /* free message */</span><br><span style="color: hsl(120, 100%, 40%);">+ msgb_free(msg_facch);</span><br><span style="color: hsl(120, 100%, 40%);">+ msg_facch = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* check validity of message, get AMR ft and cmr */</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!msg_facch && msg_tch) {</span><br><span style="color: hsl(120, 100%, 40%);">+ int len;</span><br><span style="color: hsl(120, 100%, 40%);">+ uint8_t cmr_codec;</span><br><span style="color: hsl(120, 100%, 40%);">+ int cmr, ft, i;</span><br><span style="color: hsl(120, 100%, 40%);">+ enum osmo_amr_type ft_codec;</span><br><span style="color: hsl(120, 100%, 40%);">+ enum osmo_amr_quality bfi;</span><br><span style="color: hsl(120, 100%, 40%);">+ int8_t sti, cmi;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ if (rsl_cmode != RSL_CMOD_SPD_SPEECH) {</span><br><span style="color: hsl(120, 100%, 40%);">+ LOGL1S(DL1P, LOGL_NOTICE, l1t, tn, chan, fn, "Dropping speech frame, "</span><br><span style="color: hsl(120, 100%, 40%);">+ "because we are not in speech mode\n");</span><br><span style="color: hsl(120, 100%, 40%);">+ goto free_bad_msg;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ switch (tch_mode) {</span><br><span style="color: hsl(120, 100%, 40%);">+ case GSM48_CMODE_SPEECH_V1: /* FR / HR */</span><br><span style="color: hsl(120, 100%, 40%);">+ if (chan != TRXC_TCHF) /* HR */</span><br><span style="color: hsl(120, 100%, 40%);">+ len = 15;</span><br><span style="color: hsl(120, 100%, 40%);">+ else</span><br><span style="color: hsl(120, 100%, 40%);">+ len = GSM_FR_BYTES;</span><br><span style="color: hsl(120, 100%, 40%);">+ break;</span><br><span style="color: hsl(120, 100%, 40%);">+ case GSM48_CMODE_SPEECH_EFR: /* EFR */</span><br><span style="color: hsl(120, 100%, 40%);">+ if (chan != TRXC_TCHF)</span><br><span style="color: hsl(120, 100%, 40%);">+ goto inval_mode2;</span><br><span style="color: hsl(120, 100%, 40%);">+ len = GSM_EFR_BYTES;</span><br><span style="color: hsl(120, 100%, 40%);">+ break;</span><br><span style="color: hsl(120, 100%, 40%);">+ case GSM48_CMODE_SPEECH_AMR: /* AMR */</span><br><span style="color: hsl(120, 100%, 40%);">+ len = osmo_amr_rtp_dec(msg_tch->l2h, msgb_l2len(msg_tch),</span><br><span style="color: hsl(120, 100%, 40%);">+ &cmr_codec, &cmi, &ft_codec,</span><br><span style="color: hsl(120, 100%, 40%);">+ &bfi, &sti);</span><br><span style="color: hsl(120, 100%, 40%);">+ cmr = -1;</span><br><span style="color: hsl(120, 100%, 40%);">+ ft = -1;</span><br><span style="color: hsl(120, 100%, 40%);">+ for (i = 0; i < chan_state->codecs; i++) {</span><br><span style="color: hsl(120, 100%, 40%);">+ if (chan_state->codec[i] == cmr_codec)</span><br><span style="color: hsl(120, 100%, 40%);">+ cmr = i;</span><br><span style="color: hsl(120, 100%, 40%);">+ if (chan_state->codec[i] == ft_codec)</span><br><span style="color: hsl(120, 100%, 40%);">+ ft = i;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+ if (cmr >= 0) { /* new request */</span><br><span style="color: hsl(120, 100%, 40%);">+ chan_state->dl_cmr = cmr;</span><br><span style="color: hsl(120, 100%, 40%);">+ /* disable AMR loop */</span><br><span style="color: hsl(120, 100%, 40%);">+ trx_loop_amr_set(chan_state, 0);</span><br><span style="color: hsl(120, 100%, 40%);">+ } else {</span><br><span style="color: hsl(120, 100%, 40%);">+ /* enable AMR loop */</span><br><span style="color: hsl(120, 100%, 40%);">+ trx_loop_amr_set(chan_state, 1);</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+ if (ft < 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+ LOGL1S(DL1P, LOGL_ERROR, l1t, tn, chan, fn,</span><br><span style="color: hsl(120, 100%, 40%);">+ "Codec (FT = %d) of RTP frame not in list\n", ft_codec);</span><br><span style="color: hsl(120, 100%, 40%);">+ goto free_bad_msg;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+ if (fn_is_codec_mode_request(fn) && chan_state->dl_ft != ft) {</span><br><span style="color: hsl(120, 100%, 40%);">+ LOGL1S(DL1P, LOGL_NOTICE, l1t, tn, chan, fn, "Codec (FT = %d) "</span><br><span style="color: hsl(120, 100%, 40%);">+ " of RTP cannot be changed now, but in next frame\n", ft_codec);</span><br><span style="color: hsl(120, 100%, 40%);">+ goto free_bad_msg;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+ chan_state->dl_ft = ft;</span><br><span style="color: hsl(120, 100%, 40%);">+ if (bfi == AMR_BAD) {</span><br><span style="color: hsl(120, 100%, 40%);">+ LOGL1S(DL1P, LOGL_NOTICE, l1t, tn, chan, fn,</span><br><span style="color: hsl(120, 100%, 40%);">+ "Transmitting 'bad AMR frame'\n");</span><br><span style="color: hsl(120, 100%, 40%);">+ goto free_bad_msg;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+ break;</span><br><span style="color: hsl(120, 100%, 40%);">+ default:</span><br><span style="color: hsl(120, 100%, 40%);">+inval_mode2:</span><br><span style="color: hsl(120, 100%, 40%);">+ LOGL1S(DL1P, LOGL_ERROR, l1t, tn, chan, fn, "TCH mode invalid, please fix!\n");</span><br><span style="color: hsl(120, 100%, 40%);">+ goto free_bad_msg;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+ if (len < 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+ LOGL1S(DL1P, LOGL_ERROR, l1t, tn, chan, fn, "Cannot send invalid AMR payload\n");</span><br><span style="color: hsl(120, 100%, 40%);">+ goto free_bad_msg;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+ if (msgb_l2len(msg_tch) != len) {</span><br><span style="color: hsl(120, 100%, 40%);">+ LOGL1S(DL1P, LOGL_ERROR, l1t, tn, chan, fn, "Cannot send payload with "</span><br><span style="color: hsl(120, 100%, 40%);">+ "invalid length! (expecting %d, received %d)\n",</span><br><span style="color: hsl(120, 100%, 40%);">+ len, msgb_l2len(msg_tch));</span><br><span style="color: hsl(120, 100%, 40%);">+free_bad_msg:</span><br><span style="color: hsl(120, 100%, 40%);">+ /* free message */</span><br><span style="color: hsl(120, 100%, 40%);">+ msgb_free(msg_tch);</span><br><span style="color: hsl(120, 100%, 40%);">+ msg_tch = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+ goto send_frame;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+send_frame:</span><br><span style="color: hsl(120, 100%, 40%);">+ *_msg_tch = msg_tch;</span><br><span style="color: hsl(120, 100%, 40%);">+ *_msg_facch = msg_facch;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/* obtain a to-be-transmitted TCH/F (Full Traffic Channel) burst */</span><br><span style="color: hsl(120, 100%, 40%);">+ubit_t *tx_tchf_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn,</span><br><span style="color: hsl(120, 100%, 40%);">+ enum trx_chan_type chan, uint8_t bid, uint16_t *nbits)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ struct msgb *msg_tch = NULL, *msg_facch = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct l1sched_ts *l1ts = l1sched_trx_get_ts(l1t, tn);</span><br><span style="color: hsl(120, 100%, 40%);">+ struct gsm_bts_trx_ts *ts = &l1t->trx->ts[tn];</span><br><span style="color: hsl(120, 100%, 40%);">+ struct l1sched_chan_state *chan_state = &l1ts->chan_state[chan];</span><br><span style="color: hsl(120, 100%, 40%);">+ uint8_t tch_mode = chan_state->tch_mode;</span><br><span style="color: hsl(120, 100%, 40%);">+ ubit_t *burst, **bursts_p = &chan_state->dl_bursts;</span><br><span style="color: hsl(120, 100%, 40%);">+ static ubit_t bits[GSM_BURST_LEN];</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* send burst, if we already got a frame */</span><br><span style="color: hsl(120, 100%, 40%);">+ if (bid > 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!*bursts_p)</span><br><span style="color: hsl(120, 100%, 40%);">+ return NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+ goto send_burst;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ tx_tch_common(l1t, tn, fn, chan, bid, &msg_tch, &msg_facch);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* BURST BYPASS */</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* allocate burst memory, if not already,</span><br><span style="color: hsl(120, 100%, 40%);">+ * otherwise shift buffer by 4 bursts for interleaving */</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!*bursts_p) {</span><br><span style="color: hsl(120, 100%, 40%);">+ *bursts_p = talloc_zero_size(tall_bts_ctx, 928);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!*bursts_p)</span><br><span style="color: hsl(120, 100%, 40%);">+ return NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+ } else {</span><br><span style="color: hsl(120, 100%, 40%);">+ memcpy(*bursts_p, *bursts_p + 464, 464);</span><br><span style="color: hsl(120, 100%, 40%);">+ memset(*bursts_p + 464, 0, 464);</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* no message at all */</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!msg_tch && !msg_facch) {</span><br><span style="color: hsl(120, 100%, 40%);">+ LOGL1S(DL1P, LOGL_INFO, l1t, tn, chan, fn, "No TCH or FACCH prim for transmit.\n");</span><br><span style="color: hsl(120, 100%, 40%);">+ goto send_burst;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* encode bursts (prioritize FACCH) */</span><br><span style="color: hsl(120, 100%, 40%);">+ if (msg_facch)</span><br><span style="color: hsl(120, 100%, 40%);">+ gsm0503_tch_fr_encode(*bursts_p, msg_facch->l2h, msgb_l2len(msg_facch),</span><br><span style="color: hsl(120, 100%, 40%);">+ 1);</span><br><span style="color: hsl(120, 100%, 40%);">+ else if (tch_mode == GSM48_CMODE_SPEECH_AMR)</span><br><span style="color: hsl(120, 100%, 40%);">+ /* the first FN 4,13,21 defines that CMI is included in frame,</span><br><span style="color: hsl(120, 100%, 40%);">+ * the first FN 0,8,17 defines that CMR is included in frame.</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+ gsm0503_tch_afs_encode(*bursts_p, msg_tch->l2h + 2,</span><br><span style="color: hsl(120, 100%, 40%);">+ msgb_l2len(msg_tch) - 2, fn_is_codec_mode_request(fn),</span><br><span style="color: hsl(120, 100%, 40%);">+ chan_state->codec, chan_state->codecs,</span><br><span style="color: hsl(120, 100%, 40%);">+ chan_state->dl_ft,</span><br><span style="color: hsl(120, 100%, 40%);">+ chan_state->dl_cmr);</span><br><span style="color: hsl(120, 100%, 40%);">+ else</span><br><span style="color: hsl(120, 100%, 40%);">+ gsm0503_tch_fr_encode(*bursts_p, msg_tch->l2h, msgb_l2len(msg_tch), 1);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* free message */</span><br><span style="color: hsl(120, 100%, 40%);">+ if (msg_tch)</span><br><span style="color: hsl(120, 100%, 40%);">+ msgb_free(msg_tch);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (msg_facch)</span><br><span style="color: hsl(120, 100%, 40%);">+ msgb_free(msg_facch);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+send_burst:</span><br><span style="color: hsl(120, 100%, 40%);">+ /* compose burst */</span><br><span style="color: hsl(120, 100%, 40%);">+ burst = *bursts_p + bid * 116;</span><br><span style="color: hsl(120, 100%, 40%);">+ memset(bits, 0, 3);</span><br><span style="color: hsl(120, 100%, 40%);">+ memcpy(bits + 3, burst, 58);</span><br><span style="color: hsl(120, 100%, 40%);">+ memcpy(bits + 61, _sched_tsc[gsm_ts_tsc(ts)], 26);</span><br><span style="color: hsl(120, 100%, 40%);">+ memcpy(bits + 87, burst + 58, 58);</span><br><span style="color: hsl(120, 100%, 40%);">+ memset(bits + 145, 0, 3);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ if (nbits)</span><br><span style="color: hsl(120, 100%, 40%);">+ *nbits = GSM_BURST_LEN;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ LOGL1S(DL1P, LOGL_DEBUG, l1t, tn, chan, fn, "Transmitting burst=%u.\n", bid);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ return bits;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span>diff --git a/src/osmo-bts-trx/sched_lchan_tchh.c b/src/osmo-bts-trx/sched_lchan_tchh.c</span><br><span>new file mode 100644</span><br><span>index 0000000..1895038</span><br><span>--- /dev/null</span><br><span>+++ b/src/osmo-bts-trx/sched_lchan_tchh.c</span><br><span>@@ -0,0 +1,408 @@</span><br><span style="color: hsl(120, 100%, 40%);">+/*</span><br><span style="color: hsl(120, 100%, 40%);">+ * (C) 2013 by Andreas Eversberg <jolly@eversberg.eu></span><br><span style="color: hsl(120, 100%, 40%);">+ * (C) 2015-2017 by Harald Welte <laforge@gnumonks.org></span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * All Rights Reserved</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * This program is free software; you can redistribute it and/or modify</span><br><span style="color: hsl(120, 100%, 40%);">+ * it under the terms of the GNU Affero General Public License as published by</span><br><span style="color: hsl(120, 100%, 40%);">+ * the Free Software Foundation; either version 3 of the License, or</span><br><span style="color: hsl(120, 100%, 40%);">+ * (at your option) any later version.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * This program is distributed in the hope that it will be useful,</span><br><span style="color: hsl(120, 100%, 40%);">+ * but WITHOUT ANY WARRANTY; without even the implied warranty of</span><br><span style="color: hsl(120, 100%, 40%);">+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the</span><br><span style="color: hsl(120, 100%, 40%);">+ * GNU General Public License for more details.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * You should have received a copy of the GNU Affero General Public License</span><br><span style="color: hsl(120, 100%, 40%);">+ * along with this program. If not, see <http://www.gnu.org/licenses/>.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#include <stdint.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <errno.h></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/core/bits.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/core/msgb.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/core/utils.h></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/gsm/gsm0502.h></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/codec/codec.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/codec/ecu.h></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/coding/gsm0503_coding.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/coding/gsm0503_amr_dtx.h></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmo-bts/bts.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmo-bts/l1sap.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmo-bts/logging.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmo-bts/scheduler.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmo-bts/scheduler_backend.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmo-bts/msg_utils.h></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#include <sched_utils.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <loops.h></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/*! \brief a single TCH/H burst was received by the PHY, process it */</span><br><span style="color: hsl(120, 100%, 40%);">+int rx_tchh_fn(struct l1sched_trx *l1t, enum trx_chan_type chan,</span><br><span style="color: hsl(120, 100%, 40%);">+ uint8_t bid, const struct trx_ul_burst_ind *bi)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ struct l1sched_ts *l1ts = l1sched_trx_get_ts(l1t, bi->tn);</span><br><span style="color: hsl(120, 100%, 40%);">+ struct l1sched_chan_state *chan_state = &l1ts->chan_state[chan];</span><br><span style="color: hsl(120, 100%, 40%);">+ sbit_t *burst, **bursts_p = &chan_state->ul_bursts;</span><br><span style="color: hsl(120, 100%, 40%);">+ uint8_t *mask = &chan_state->ul_mask;</span><br><span style="color: hsl(120, 100%, 40%);">+ uint8_t rsl_cmode = chan_state->rsl_cmode;</span><br><span style="color: hsl(120, 100%, 40%);">+ uint8_t tch_mode = chan_state->tch_mode;</span><br><span style="color: hsl(120, 100%, 40%);">+ uint8_t tch_data[128]; /* just to be safe */</span><br><span style="color: hsl(120, 100%, 40%);">+ int rc, amr = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+ int n_errors = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+ int n_bits_total = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+ bool bfi_flag = false;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct gsm_lchan *lchan =</span><br><span style="color: hsl(120, 100%, 40%);">+ get_lchan_by_chan_nr(l1t->trx, trx_chan_desc[chan].chan_nr | bi->tn);</span><br><span style="color: hsl(120, 100%, 40%);">+ /* Note on FN-10: If we are at FN 10, we decoded an even aligned</span><br><span style="color: hsl(120, 100%, 40%);">+ * TCH/FACCH frame, because our burst buffer carries 6 bursts.</span><br><span style="color: hsl(120, 100%, 40%);">+ * Even FN ending at: 10,11,19,20,2,3</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+ int fn_is_odd = (((bi->fn + 26 - 10) % 26) >> 2) & 1;</span><br><span style="color: hsl(120, 100%, 40%);">+ unsigned int fn_begin;</span><br><span style="color: hsl(120, 100%, 40%);">+ uint16_t ber10k;</span><br><span style="color: hsl(120, 100%, 40%);">+ uint8_t is_sub = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+ uint8_t ft;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* If handover RACH detection is turned on, treat this burst as an Access Burst.</span><br><span style="color: hsl(120, 100%, 40%);">+ * Handle NOPE.ind as usually to ensure proper Uplink measurement reporting. */</span><br><span style="color: hsl(120, 100%, 40%);">+ if (chan_state->ho_rach_detect == 1 && ~bi->flags & TRX_BI_F_NOPE_IND)</span><br><span style="color: hsl(120, 100%, 40%);">+ return rx_rach_fn(l1t, chan, bid, bi);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ LOGL1S(DL1P, LOGL_DEBUG, l1t, bi->tn, chan, bi->fn,</span><br><span style="color: hsl(120, 100%, 40%);">+ "Received TCH/H, bid=%u\n", bid);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* allocate burst memory, if not already */</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!*bursts_p) {</span><br><span style="color: hsl(120, 100%, 40%);">+ *bursts_p = talloc_zero_size(tall_bts_ctx, 696);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!*bursts_p)</span><br><span style="color: hsl(120, 100%, 40%);">+ return -ENOMEM;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* clear burst */</span><br><span style="color: hsl(120, 100%, 40%);">+ if (bid == 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+ memset(*bursts_p + 464, 0, 232);</span><br><span style="color: hsl(120, 100%, 40%);">+ *mask = 0x0;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* update mask */</span><br><span style="color: hsl(120, 100%, 40%);">+ *mask |= (1 << bid);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* copy burst to end of buffer of 6 bursts */</span><br><span style="color: hsl(120, 100%, 40%);">+ burst = *bursts_p + bid * 116 + 464;</span><br><span style="color: hsl(120, 100%, 40%);">+ if (bi->burst_len > 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+ memcpy(burst, bi->burst + 3, 58);</span><br><span style="color: hsl(120, 100%, 40%);">+ memcpy(burst + 58, bi->burst + 87, 58);</span><br><span style="color: hsl(120, 100%, 40%);">+ } else</span><br><span style="color: hsl(120, 100%, 40%);">+ memset(burst, 0, 116);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* wait until complete set of bursts */</span><br><span style="color: hsl(120, 100%, 40%);">+ if (bid != 1)</span><br><span style="color: hsl(120, 100%, 40%);">+ return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* check for complete set of bursts */</span><br><span style="color: hsl(120, 100%, 40%);">+ if ((*mask & 0x3) != 0x3) {</span><br><span style="color: hsl(120, 100%, 40%);">+ LOGL1S(DL1P, LOGL_NOTICE, l1t, bi->tn, chan, bi->fn,</span><br><span style="color: hsl(120, 100%, 40%);">+ "Received incomplete frame (%u/%u)\n",</span><br><span style="color: hsl(120, 100%, 40%);">+ bi->fn % l1ts->mf_period, l1ts->mf_period);</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+ *mask = 0x0;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* skip second of two TCH frames of FACCH was received */</span><br><span style="color: hsl(120, 100%, 40%);">+ if (chan_state->ul_ongoing_facch) {</span><br><span style="color: hsl(120, 100%, 40%);">+ chan_state->ul_ongoing_facch = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+ memcpy(*bursts_p, *bursts_p + 232, 232);</span><br><span style="color: hsl(120, 100%, 40%);">+ memcpy(*bursts_p + 232, *bursts_p + 464, 232);</span><br><span style="color: hsl(120, 100%, 40%);">+ ber10k = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+ goto bfi;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* decode</span><br><span style="color: hsl(120, 100%, 40%);">+ * also shift buffer by 4 bursts for interleaving */</span><br><span style="color: hsl(120, 100%, 40%);">+ switch ((rsl_cmode != RSL_CMOD_SPD_SPEECH) ? GSM48_CMODE_SPEECH_V1</span><br><span style="color: hsl(120, 100%, 40%);">+ : tch_mode) {</span><br><span style="color: hsl(120, 100%, 40%);">+ case GSM48_CMODE_SPEECH_V1: /* HR or signalling */</span><br><span style="color: hsl(120, 100%, 40%);">+ /* Note on FN-10: If we are at FN 10, we decoded an even aligned</span><br><span style="color: hsl(120, 100%, 40%);">+ * TCH/FACCH frame, because our burst buffer carries 6 bursts.</span><br><span style="color: hsl(120, 100%, 40%);">+ * Even FN ending at: 10,11,19,20,2,3</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+ rc = gsm0503_tch_hr_decode(tch_data, *bursts_p,</span><br><span style="color: hsl(120, 100%, 40%);">+ fn_is_odd, &n_errors, &n_bits_total);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (rc >= 0) /* DTXu */</span><br><span style="color: hsl(120, 100%, 40%);">+ lchan_set_marker(osmo_hr_check_sid(tch_data, rc), lchan);</span><br><span style="color: hsl(120, 100%, 40%);">+ break;</span><br><span style="color: hsl(120, 100%, 40%);">+ case GSM48_CMODE_SPEECH_AMR: /* AMR */</span><br><span style="color: hsl(120, 100%, 40%);">+ /* the first FN 0,8,17 or 1,9,18 defines that CMI is included</span><br><span style="color: hsl(120, 100%, 40%);">+ * in frame, the first FN 4,13,21 or 5,14,22 defines that CMR</span><br><span style="color: hsl(120, 100%, 40%);">+ * is included in frame.</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* See comment in function rx_tchf_fn() */</span><br><span style="color: hsl(120, 100%, 40%);">+ switch (chan_state->amr_last_dtx) {</span><br><span style="color: hsl(120, 100%, 40%);">+ case AHS_ONSET:</span><br><span style="color: hsl(120, 100%, 40%);">+ case AHS_SID_FIRST_INH:</span><br><span style="color: hsl(120, 100%, 40%);">+ case AHS_SID_UPDATE_INH:</span><br><span style="color: hsl(120, 100%, 40%);">+ lchan_set_marker(false, lchan);</span><br><span style="color: hsl(120, 100%, 40%);">+ break;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* See comment in function rx_tchf_fn() */</span><br><span style="color: hsl(120, 100%, 40%);">+ amr = 2;</span><br><span style="color: hsl(120, 100%, 40%);">+ rc = gsm0503_tch_ahs_decode_dtx(tch_data + amr, *bursts_p,</span><br><span style="color: hsl(120, 100%, 40%);">+ fn_is_odd, fn_is_odd, chan_state->codec,</span><br><span style="color: hsl(120, 100%, 40%);">+ chan_state->codecs, &chan_state->ul_ft,</span><br><span style="color: hsl(120, 100%, 40%);">+ &chan_state->ul_cmr, &n_errors, &n_bits_total, &chan_state->amr_last_dtx);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* Tag all frames that are not regular AMR voice frames</span><br><span style="color: hsl(120, 100%, 40%);">+ as SUB-Frames */</span><br><span style="color: hsl(120, 100%, 40%);">+ if (chan_state->amr_last_dtx != AMR_OTHER) {</span><br><span style="color: hsl(120, 100%, 40%);">+ LOGL1S(DL1P, LOGL_DEBUG, l1t, bi->tn, chan, bi->fn,</span><br><span style="color: hsl(120, 100%, 40%);">+ "Received AMR SID frame: %s\n",</span><br><span style="color: hsl(120, 100%, 40%);">+ gsm0503_amr_dtx_frame_name(chan_state->amr_last_dtx));</span><br><span style="color: hsl(120, 100%, 40%);">+ is_sub = 1;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* See comment in function rx_tchf_fn() */</span><br><span style="color: hsl(120, 100%, 40%);">+ switch (chan_state->amr_last_dtx) {</span><br><span style="color: hsl(120, 100%, 40%);">+ case AHS_SID_FIRST_P1:</span><br><span style="color: hsl(120, 100%, 40%);">+ case AHS_SID_FIRST_P2:</span><br><span style="color: hsl(120, 100%, 40%);">+ case AHS_SID_UPDATE:</span><br><span style="color: hsl(120, 100%, 40%);">+ case AHS_SID_UPDATE_CN:</span><br><span style="color: hsl(120, 100%, 40%);">+ lchan_set_marker(true, lchan);</span><br><span style="color: hsl(120, 100%, 40%);">+ lchan->rtp_tx_marker = false;</span><br><span style="color: hsl(120, 100%, 40%);">+ break;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ if (rc)</span><br><span style="color: hsl(120, 100%, 40%);">+ trx_loop_amr_input(l1t,</span><br><span style="color: hsl(120, 100%, 40%);">+ trx_chan_desc[chan].chan_nr | bi->tn, chan_state,</span><br><span style="color: hsl(120, 100%, 40%);">+ n_errors, n_bits_total);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* only good speech frames get rtp header */</span><br><span style="color: hsl(120, 100%, 40%);">+ if (rc != GSM_MACBLOCK_LEN && rc >= 4) {</span><br><span style="color: hsl(120, 100%, 40%);">+ if (chan_state->amr_last_dtx == AMR_OTHER) {</span><br><span style="color: hsl(120, 100%, 40%);">+ ft = chan_state->codec[chan_state->ul_cmr];</span><br><span style="color: hsl(120, 100%, 40%);">+ } else {</span><br><span style="color: hsl(120, 100%, 40%);">+ /* SID frames will always get Frame Type Index 8 (AMR_SID) */</span><br><span style="color: hsl(120, 100%, 40%);">+ ft = AMR_SID;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+ rc = osmo_amr_rtp_enc(tch_data,</span><br><span style="color: hsl(120, 100%, 40%);">+ chan_state->codec[chan_state->ul_cmr],</span><br><span style="color: hsl(120, 100%, 40%);">+ ft, AMR_GOOD);</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ break;</span><br><span style="color: hsl(120, 100%, 40%);">+ default:</span><br><span style="color: hsl(120, 100%, 40%);">+ LOGL1S(DL1P, LOGL_ERROR, l1t, bi->tn, chan, bi->fn,</span><br><span style="color: hsl(120, 100%, 40%);">+ "TCH mode %u invalid, please fix!\n",</span><br><span style="color: hsl(120, 100%, 40%);">+ tch_mode);</span><br><span style="color: hsl(120, 100%, 40%);">+ return -EINVAL;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+ memcpy(*bursts_p, *bursts_p + 232, 232);</span><br><span style="color: hsl(120, 100%, 40%);">+ memcpy(*bursts_p + 232, *bursts_p + 464, 232);</span><br><span style="color: hsl(120, 100%, 40%);">+ ber10k = compute_ber10k(n_bits_total, n_errors);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* Check if the frame is bad */</span><br><span style="color: hsl(120, 100%, 40%);">+ if (rc < 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+ LOGL1S(DL1P, LOGL_NOTICE, l1t, bi->tn, chan, bi->fn,</span><br><span style="color: hsl(120, 100%, 40%);">+ "Received bad data (%u/%u)\n",</span><br><span style="color: hsl(120, 100%, 40%);">+ bi->fn % l1ts->mf_period, l1ts->mf_period);</span><br><span style="color: hsl(120, 100%, 40%);">+ bfi_flag = true;</span><br><span style="color: hsl(120, 100%, 40%);">+ } else if (rc < 4) {</span><br><span style="color: hsl(120, 100%, 40%);">+ LOGL1S(DL1P, LOGL_NOTICE, l1t, bi->tn, chan, bi->fn,</span><br><span style="color: hsl(120, 100%, 40%);">+ "Received bad data (%u/%u) with invalid codec mode %d\n",</span><br><span style="color: hsl(120, 100%, 40%);">+ bi->fn % l1ts->mf_period, l1ts->mf_period, rc);</span><br><span style="color: hsl(120, 100%, 40%);">+ bfi_flag = true;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ if (rc != GSM_MACBLOCK_LEN && lchan->ecu_state)</span><br><span style="color: hsl(120, 100%, 40%);">+ osmo_ecu_frame_in(lchan->ecu_state, bfi_flag, tch_data, rc);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ if (bfi_flag)</span><br><span style="color: hsl(120, 100%, 40%);">+ goto bfi;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* FACCH */</span><br><span style="color: hsl(120, 100%, 40%);">+ if (rc == GSM_MACBLOCK_LEN) {</span><br><span style="color: hsl(120, 100%, 40%);">+ chan_state->ul_ongoing_facch = 1;</span><br><span style="color: hsl(120, 100%, 40%);">+ uint16_t ber10k = compute_ber10k(n_bits_total, n_errors);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (lchan->nr == 0)</span><br><span style="color: hsl(120, 100%, 40%);">+ fn_begin = gsm0502_fn_remap(bi->fn, FN_REMAP_FACCH_H0);</span><br><span style="color: hsl(120, 100%, 40%);">+ else</span><br><span style="color: hsl(120, 100%, 40%);">+ fn_begin = gsm0502_fn_remap(bi->fn, FN_REMAP_FACCH_H1);</span><br><span style="color: hsl(120, 100%, 40%);">+ _sched_compose_ph_data_ind(l1t, bi->tn, fn_begin, chan,</span><br><span style="color: hsl(120, 100%, 40%);">+ tch_data + amr, GSM_MACBLOCK_LEN,</span><br><span style="color: hsl(120, 100%, 40%);">+ /* FIXME: AVG both RSSI and ToA */</span><br><span style="color: hsl(120, 100%, 40%);">+ bi->rssi, bi->toa256,</span><br><span style="color: hsl(120, 100%, 40%);">+ 0 /* FIXME: AVG C/I */,</span><br><span style="color: hsl(120, 100%, 40%);">+ ber10k, PRES_INFO_UNKNOWN);</span><br><span style="color: hsl(120, 100%, 40%);">+bfi:</span><br><span style="color: hsl(120, 100%, 40%);">+ /* FIXME: a FACCH/H frame replaces two speech frames,</span><br><span style="color: hsl(120, 100%, 40%);">+ * so we actually need to send two bad frame indications! */</span><br><span style="color: hsl(120, 100%, 40%);">+ if (rsl_cmode == RSL_CMOD_SPD_SPEECH) {</span><br><span style="color: hsl(120, 100%, 40%);">+ /* indicate bad frame */</span><br><span style="color: hsl(120, 100%, 40%);">+ if (lchan->tch.dtx.ul_sid) {</span><br><span style="color: hsl(120, 100%, 40%);">+ /* DTXu: pause in progress. Push empty payload to upper layers */</span><br><span style="color: hsl(120, 100%, 40%);">+ rc = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+ goto compose_l1sap;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* If there is an ECU active on this channel, use its output */</span><br><span style="color: hsl(120, 100%, 40%);">+ if (lchan->ecu_state) {</span><br><span style="color: hsl(120, 100%, 40%);">+ rc = osmo_ecu_frame_out(lchan->ecu_state, tch_data);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (rc >= 0) /* Otherwise we send a BFI */</span><br><span style="color: hsl(120, 100%, 40%);">+ goto compose_l1sap;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ switch (tch_mode) {</span><br><span style="color: hsl(120, 100%, 40%);">+ case GSM48_CMODE_SPEECH_V1: /* HR */</span><br><span style="color: hsl(120, 100%, 40%);">+ tch_data[0] = 0x70; /* F = 0, FT = 111 */</span><br><span style="color: hsl(120, 100%, 40%);">+ memset(tch_data + 1, 0, 14);</span><br><span style="color: hsl(120, 100%, 40%);">+ rc = 15;</span><br><span style="color: hsl(120, 100%, 40%);">+ break;</span><br><span style="color: hsl(120, 100%, 40%);">+ case GSM48_CMODE_SPEECH_AMR: /* AMR */</span><br><span style="color: hsl(120, 100%, 40%);">+ rc = osmo_amr_rtp_enc(tch_data,</span><br><span style="color: hsl(120, 100%, 40%);">+ chan_state->codec[chan_state->dl_cmr],</span><br><span style="color: hsl(120, 100%, 40%);">+ chan_state->codec[chan_state->dl_ft],</span><br><span style="color: hsl(120, 100%, 40%);">+ AMR_BAD);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (rc < 2) {</span><br><span style="color: hsl(120, 100%, 40%);">+ LOGL1S(DL1P, LOGL_ERROR, l1t, bi->tn, chan, bi->fn,</span><br><span style="color: hsl(120, 100%, 40%);">+ "Failed to encode AMR_BAD frame (rc=%d), "</span><br><span style="color: hsl(120, 100%, 40%);">+ "not sending BFI\n", rc);</span><br><span style="color: hsl(120, 100%, 40%);">+ return -EINVAL;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+ memset(tch_data + 2, 0, rc - 2);</span><br><span style="color: hsl(120, 100%, 40%);">+ break;</span><br><span style="color: hsl(120, 100%, 40%);">+ default:</span><br><span style="color: hsl(120, 100%, 40%);">+ LOGL1S(DL1P, LOGL_ERROR, l1t, bi->tn, chan, bi->fn,</span><br><span style="color: hsl(120, 100%, 40%);">+ "TCH mode %u invalid, please fix!\n", tch_mode);</span><br><span style="color: hsl(120, 100%, 40%);">+ return -EINVAL;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ if (rsl_cmode != RSL_CMOD_SPD_SPEECH)</span><br><span style="color: hsl(120, 100%, 40%);">+ return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+compose_l1sap:</span><br><span style="color: hsl(120, 100%, 40%);">+ /* TCH or BFI */</span><br><span style="color: hsl(120, 100%, 40%);">+ /* Note on FN 19 or 20: If we received the last burst of a frame,</span><br><span style="color: hsl(120, 100%, 40%);">+ * it actually starts at FN 8 or 9. A burst starting there, overlaps</span><br><span style="color: hsl(120, 100%, 40%);">+ * with the slot 12, so an extra FN must be subtracted to get correct</span><br><span style="color: hsl(120, 100%, 40%);">+ * start of frame.</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+ if (lchan->nr == 0)</span><br><span style="color: hsl(120, 100%, 40%);">+ fn_begin = gsm0502_fn_remap(bi->fn, FN_REMAP_TCH_H0);</span><br><span style="color: hsl(120, 100%, 40%);">+ else</span><br><span style="color: hsl(120, 100%, 40%);">+ fn_begin = gsm0502_fn_remap(bi->fn, FN_REMAP_TCH_H1);</span><br><span style="color: hsl(120, 100%, 40%);">+ return _sched_compose_tch_ind(l1t, bi->tn, fn_begin, chan,</span><br><span style="color: hsl(120, 100%, 40%);">+ tch_data, rc, bi->toa256, ber10k, bi->rssi, is_sub);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/* common section for generation of TCH bursts (TCH/H and TCH/F).</span><br><span style="color: hsl(120, 100%, 40%);">+ * FIXME: this function is over-complicated, refactor / get rid of it. */</span><br><span style="color: hsl(120, 100%, 40%);">+extern void tx_tch_common(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn,</span><br><span style="color: hsl(120, 100%, 40%);">+ enum trx_chan_type chan, uint8_t bid,</span><br><span style="color: hsl(120, 100%, 40%);">+ struct msgb **_msg_tch, struct msgb **_msg_facch);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/* obtain a to-be-transmitted TCH/H (Half Traffic Channel) burst */</span><br><span style="color: hsl(120, 100%, 40%);">+ubit_t *tx_tchh_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn,</span><br><span style="color: hsl(120, 100%, 40%);">+ enum trx_chan_type chan, uint8_t bid, uint16_t *nbits)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ struct msgb *msg_tch = NULL, *msg_facch = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct l1sched_ts *l1ts = l1sched_trx_get_ts(l1t, tn);</span><br><span style="color: hsl(120, 100%, 40%);">+ struct gsm_bts_trx_ts *ts = &l1t->trx->ts[tn];</span><br><span style="color: hsl(120, 100%, 40%);">+ struct l1sched_chan_state *chan_state = &l1ts->chan_state[chan];</span><br><span style="color: hsl(120, 100%, 40%);">+ uint8_t tch_mode = chan_state->tch_mode;</span><br><span style="color: hsl(120, 100%, 40%);">+ ubit_t *burst, **bursts_p = &chan_state->dl_bursts;</span><br><span style="color: hsl(120, 100%, 40%);">+ static ubit_t bits[GSM_BURST_LEN];</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* send burst, if we already got a frame */</span><br><span style="color: hsl(120, 100%, 40%);">+ if (bid > 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!*bursts_p)</span><br><span style="color: hsl(120, 100%, 40%);">+ return NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+ goto send_burst;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* get TCH and/or FACCH */</span><br><span style="color: hsl(120, 100%, 40%);">+ tx_tch_common(l1t, tn, fn, chan, bid, &msg_tch, &msg_facch);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* check for FACCH alignment */</span><br><span style="color: hsl(120, 100%, 40%);">+ if (msg_facch && ((((fn + 4) % 26) >> 2) & 1)) {</span><br><span style="color: hsl(120, 100%, 40%);">+ LOGL1S(DL1P, LOGL_ERROR, l1t, tn, chan, fn, "Cannot transmit FACCH starting on "</span><br><span style="color: hsl(120, 100%, 40%);">+ "even frames, please fix RTS!\n");</span><br><span style="color: hsl(120, 100%, 40%);">+ msgb_free(msg_facch);</span><br><span style="color: hsl(120, 100%, 40%);">+ msg_facch = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* BURST BYPASS */</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* allocate burst memory, if not already,</span><br><span style="color: hsl(120, 100%, 40%);">+ * otherwise shift buffer by 2 bursts for interleaving */</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!*bursts_p) {</span><br><span style="color: hsl(120, 100%, 40%);">+ *bursts_p = talloc_zero_size(tall_bts_ctx, 696);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!*bursts_p)</span><br><span style="color: hsl(120, 100%, 40%);">+ return NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+ } else {</span><br><span style="color: hsl(120, 100%, 40%);">+ memcpy(*bursts_p, *bursts_p + 232, 232);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (chan_state->dl_ongoing_facch) {</span><br><span style="color: hsl(120, 100%, 40%);">+ memcpy(*bursts_p + 232, *bursts_p + 464, 232);</span><br><span style="color: hsl(120, 100%, 40%);">+ memset(*bursts_p + 464, 0, 232);</span><br><span style="color: hsl(120, 100%, 40%);">+ } else {</span><br><span style="color: hsl(120, 100%, 40%);">+ memset(*bursts_p + 232, 0, 232);</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* no message at all */</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!msg_tch && !msg_facch && !chan_state->dl_ongoing_facch) {</span><br><span style="color: hsl(120, 100%, 40%);">+ LOGL1S(DL1P, LOGL_INFO, l1t, tn, chan, fn, "No TCH or FACCH prim for transmit.\n");</span><br><span style="color: hsl(120, 100%, 40%);">+ goto send_burst;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* encode bursts (prioritize FACCH) */</span><br><span style="color: hsl(120, 100%, 40%);">+ if (msg_facch) {</span><br><span style="color: hsl(120, 100%, 40%);">+ gsm0503_tch_hr_encode(*bursts_p, msg_facch->l2h, msgb_l2len(msg_facch));</span><br><span style="color: hsl(120, 100%, 40%);">+ chan_state->dl_ongoing_facch = 1; /* first of two TCH frames */</span><br><span style="color: hsl(120, 100%, 40%);">+ } else if (chan_state->dl_ongoing_facch) /* second of two TCH frames */</span><br><span style="color: hsl(120, 100%, 40%);">+ chan_state->dl_ongoing_facch = 0; /* we are done with FACCH */</span><br><span style="color: hsl(120, 100%, 40%);">+ else if (tch_mode == GSM48_CMODE_SPEECH_AMR)</span><br><span style="color: hsl(120, 100%, 40%);">+ /* the first FN 4,13,21 or 5,14,22 defines that CMI is included</span><br><span style="color: hsl(120, 100%, 40%);">+ * in frame, the first FN 0,8,17 or 1,9,18 defines that CMR is</span><br><span style="color: hsl(120, 100%, 40%);">+ * included in frame. */</span><br><span style="color: hsl(120, 100%, 40%);">+ gsm0503_tch_ahs_encode(*bursts_p, msg_tch->l2h + 2,</span><br><span style="color: hsl(120, 100%, 40%);">+ msgb_l2len(msg_tch) - 2, fn_is_codec_mode_request(fn),</span><br><span style="color: hsl(120, 100%, 40%);">+ chan_state->codec, chan_state->codecs,</span><br><span style="color: hsl(120, 100%, 40%);">+ chan_state->dl_ft,</span><br><span style="color: hsl(120, 100%, 40%);">+ chan_state->dl_cmr);</span><br><span style="color: hsl(120, 100%, 40%);">+ else</span><br><span style="color: hsl(120, 100%, 40%);">+ gsm0503_tch_hr_encode(*bursts_p, msg_tch->l2h, msgb_l2len(msg_tch));</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* free message */</span><br><span style="color: hsl(120, 100%, 40%);">+ if (msg_tch)</span><br><span style="color: hsl(120, 100%, 40%);">+ msgb_free(msg_tch);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (msg_facch)</span><br><span style="color: hsl(120, 100%, 40%);">+ msgb_free(msg_facch);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+send_burst:</span><br><span style="color: hsl(120, 100%, 40%);">+ /* compose burst */</span><br><span style="color: hsl(120, 100%, 40%);">+ burst = *bursts_p + bid * 116;</span><br><span style="color: hsl(120, 100%, 40%);">+ memset(bits, 0, 3);</span><br><span style="color: hsl(120, 100%, 40%);">+ memcpy(bits + 3, burst, 58);</span><br><span style="color: hsl(120, 100%, 40%);">+ memcpy(bits + 61, _sched_tsc[gsm_ts_tsc(ts)], 26);</span><br><span style="color: hsl(120, 100%, 40%);">+ memcpy(bits + 87, burst + 58, 58);</span><br><span style="color: hsl(120, 100%, 40%);">+ memset(bits + 145, 0, 3);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ if (nbits)</span><br><span style="color: hsl(120, 100%, 40%);">+ *nbits = GSM_BURST_LEN;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ LOGL1S(DL1P, LOGL_DEBUG, l1t, tn, chan, fn, "Transmitting burst=%u.\n", bid);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ return bits;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span>diff --git a/src/osmo-bts-trx/sched_lchan_xcch.c b/src/osmo-bts-trx/sched_lchan_xcch.c</span><br><span>new file mode 100644</span><br><span>index 0000000..a16553f</span><br><span>--- /dev/null</span><br><span>+++ b/src/osmo-bts-trx/sched_lchan_xcch.c</span><br><span>@@ -0,0 +1,234 @@</span><br><span style="color: hsl(120, 100%, 40%);">+/*</span><br><span style="color: hsl(120, 100%, 40%);">+ * (C) 2013 by Andreas Eversberg <jolly@eversberg.eu></span><br><span style="color: hsl(120, 100%, 40%);">+ * (C) 2015-2017 by Harald Welte <laforge@gnumonks.org></span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * All Rights Reserved</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * This program is free software; you can redistribute it and/or modify</span><br><span style="color: hsl(120, 100%, 40%);">+ * it under the terms of the GNU Affero General Public License as published by</span><br><span style="color: hsl(120, 100%, 40%);">+ * the Free Software Foundation; either version 3 of the License, or</span><br><span style="color: hsl(120, 100%, 40%);">+ * (at your option) any later version.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * This program is distributed in the hope that it will be useful,</span><br><span style="color: hsl(120, 100%, 40%);">+ * but WITHOUT ANY WARRANTY; without even the implied warranty of</span><br><span style="color: hsl(120, 100%, 40%);">+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the</span><br><span style="color: hsl(120, 100%, 40%);">+ * GNU General Public License for more details.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * You should have received a copy of the GNU Affero General Public License</span><br><span style="color: hsl(120, 100%, 40%);">+ * along with this program. If not, see <http://www.gnu.org/licenses/>.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#include <stdint.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <errno.h></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/core/bits.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/core/utils.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/coding/gsm0503_coding.h></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmo-bts/bts.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmo-bts/l1sap.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmo-bts/logging.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmo-bts/scheduler.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmo-bts/scheduler_backend.h></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#include <sched_utils.h></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/*! \brief a single (SDCCH/SACCH) burst was received by the PHY, process it */</span><br><span style="color: hsl(120, 100%, 40%);">+int rx_data_fn(struct l1sched_trx *l1t, enum trx_chan_type chan,</span><br><span style="color: hsl(120, 100%, 40%);">+ uint8_t bid, const struct trx_ul_burst_ind *bi)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ struct l1sched_ts *l1ts = l1sched_trx_get_ts(l1t, bi->tn);</span><br><span style="color: hsl(120, 100%, 40%);">+ struct l1sched_chan_state *chan_state = &l1ts->chan_state[chan];</span><br><span style="color: hsl(120, 100%, 40%);">+ sbit_t *burst, **bursts_p = &chan_state->ul_bursts;</span><br><span style="color: hsl(120, 100%, 40%);">+ uint32_t *first_fn = &chan_state->ul_first_fn;</span><br><span style="color: hsl(120, 100%, 40%);">+ uint8_t *mask = &chan_state->ul_mask;</span><br><span style="color: hsl(120, 100%, 40%);">+ float *rssi_sum = &chan_state->rssi_sum;</span><br><span style="color: hsl(120, 100%, 40%);">+ uint8_t *rssi_num = &chan_state->rssi_num;</span><br><span style="color: hsl(120, 100%, 40%);">+ int32_t *toa256_sum = &chan_state->toa256_sum;</span><br><span style="color: hsl(120, 100%, 40%);">+ uint8_t *toa_num = &chan_state->toa_num;</span><br><span style="color: hsl(120, 100%, 40%);">+ int32_t *ci_cb_sum = &chan_state->ci_cb_sum;</span><br><span style="color: hsl(120, 100%, 40%);">+ uint8_t *ci_cb_num = &chan_state->ci_cb_num;</span><br><span style="color: hsl(120, 100%, 40%);">+ uint8_t l2[GSM_MACBLOCK_LEN], l2_len;</span><br><span style="color: hsl(120, 100%, 40%);">+ int n_errors = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+ int n_bits_total = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+ int16_t lqual_cb;</span><br><span style="color: hsl(120, 100%, 40%);">+ uint16_t ber10k;</span><br><span style="color: hsl(120, 100%, 40%);">+ int rc;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* If handover RACH detection is turned on, treat this burst as an Access Burst.</span><br><span style="color: hsl(120, 100%, 40%);">+ * Handle NOPE.ind as usually to ensure proper Uplink measurement reporting. */</span><br><span style="color: hsl(120, 100%, 40%);">+ if (chan_state->ho_rach_detect == 1 && ~bi->flags & TRX_BI_F_NOPE_IND)</span><br><span style="color: hsl(120, 100%, 40%);">+ return rx_rach_fn(l1t, chan, bid, bi);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ LOGL1S(DL1P, LOGL_DEBUG, l1t, bi->tn, chan, bi->fn,</span><br><span style="color: hsl(120, 100%, 40%);">+ "Received Data, bid=%u\n", bid);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* allocate burst memory, if not already */</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!*bursts_p) {</span><br><span style="color: hsl(120, 100%, 40%);">+ *bursts_p = talloc_zero_size(tall_bts_ctx, 464);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!*bursts_p)</span><br><span style="color: hsl(120, 100%, 40%);">+ return -ENOMEM;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* clear burst & store frame number of first burst */</span><br><span style="color: hsl(120, 100%, 40%);">+ if (bid == 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+ memset(*bursts_p, 0, 464);</span><br><span style="color: hsl(120, 100%, 40%);">+ *mask = 0x0;</span><br><span style="color: hsl(120, 100%, 40%);">+ *first_fn = bi->fn;</span><br><span style="color: hsl(120, 100%, 40%);">+ *rssi_sum = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+ *rssi_num = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+ *toa256_sum = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+ *toa_num = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+ *ci_cb_sum = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+ *ci_cb_num = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* update mask + RSSI */</span><br><span style="color: hsl(120, 100%, 40%);">+ *mask |= (1 << bid);</span><br><span style="color: hsl(120, 100%, 40%);">+ *rssi_sum += bi->rssi;</span><br><span style="color: hsl(120, 100%, 40%);">+ (*rssi_num)++;</span><br><span style="color: hsl(120, 100%, 40%);">+ *toa256_sum += bi->toa256;</span><br><span style="color: hsl(120, 100%, 40%);">+ (*toa_num)++;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* C/I: Carrier-to-Interference ratio (in centiBels) */</span><br><span style="color: hsl(120, 100%, 40%);">+ if (bi->flags & TRX_BI_F_CI_CB) {</span><br><span style="color: hsl(120, 100%, 40%);">+ *ci_cb_sum += bi->ci_cb;</span><br><span style="color: hsl(120, 100%, 40%);">+ (*ci_cb_num)++;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* Copy burst to buffer of 4 bursts. If the burst indication contains</span><br><span style="color: hsl(120, 100%, 40%);">+ * no data, ensure that the buffer does not stay uninitialized */</span><br><span style="color: hsl(120, 100%, 40%);">+ burst = *bursts_p + bid * 116;</span><br><span style="color: hsl(120, 100%, 40%);">+ if (bi->burst_len > 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+ memcpy(burst, bi->burst + 3, 58);</span><br><span style="color: hsl(120, 100%, 40%);">+ memcpy(burst + 58, bi->burst + 87, 58);</span><br><span style="color: hsl(120, 100%, 40%);">+ } else</span><br><span style="color: hsl(120, 100%, 40%);">+ memset(burst, 0, 58 * 2);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* wait until complete set of bursts */</span><br><span style="color: hsl(120, 100%, 40%);">+ if (bid != 3)</span><br><span style="color: hsl(120, 100%, 40%);">+ return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* check for complete set of bursts */</span><br><span style="color: hsl(120, 100%, 40%);">+ if ((*mask & 0xf) != 0xf) {</span><br><span style="color: hsl(120, 100%, 40%);">+ LOGL1S(DL1P, LOGL_NOTICE, l1t, bi->tn, chan, bi->fn,</span><br><span style="color: hsl(120, 100%, 40%);">+ "Received incomplete data (%u/%u)\n",</span><br><span style="color: hsl(120, 100%, 40%);">+ bi->fn % l1ts->mf_period, l1ts->mf_period);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* we require first burst to have correct FN */</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!(*mask & 0x1)) {</span><br><span style="color: hsl(120, 100%, 40%);">+ *mask = 0x0;</span><br><span style="color: hsl(120, 100%, 40%);">+ return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+ *mask = 0x0;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* decode */</span><br><span style="color: hsl(120, 100%, 40%);">+ rc = gsm0503_xcch_decode(l2, *bursts_p, &n_errors, &n_bits_total);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (rc) {</span><br><span style="color: hsl(120, 100%, 40%);">+ LOGL1S(DL1P, LOGL_NOTICE, l1t, bi->tn, chan, bi->fn,</span><br><span style="color: hsl(120, 100%, 40%);">+ "Received bad data (%u/%u)\n",</span><br><span style="color: hsl(120, 100%, 40%);">+ bi->fn % l1ts->mf_period, l1ts->mf_period);</span><br><span style="color: hsl(120, 100%, 40%);">+ l2_len = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+ } else</span><br><span style="color: hsl(120, 100%, 40%);">+ l2_len = GSM_MACBLOCK_LEN;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ lqual_cb = *ci_cb_num ? (*ci_cb_sum / *ci_cb_num) : 0;</span><br><span style="color: hsl(120, 100%, 40%);">+ ber10k = compute_ber10k(n_bits_total, n_errors);</span><br><span style="color: hsl(120, 100%, 40%);">+ return _sched_compose_ph_data_ind(l1t, bi->tn, *first_fn,</span><br><span style="color: hsl(120, 100%, 40%);">+ chan, l2, l2_len,</span><br><span style="color: hsl(120, 100%, 40%);">+ *rssi_sum / *rssi_num,</span><br><span style="color: hsl(120, 100%, 40%);">+ *toa256_sum / *toa_num,</span><br><span style="color: hsl(120, 100%, 40%);">+ lqual_cb, ber10k,</span><br><span style="color: hsl(120, 100%, 40%);">+ PRES_INFO_UNKNOWN);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/* obtain a to-be-transmitted xCCH (e.g SACCH or SDCCH) burst */</span><br><span style="color: hsl(120, 100%, 40%);">+ubit_t *tx_data_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn,</span><br><span style="color: hsl(120, 100%, 40%);">+ enum trx_chan_type chan, uint8_t bid, uint16_t *nbits)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ struct l1sched_ts *l1ts = l1sched_trx_get_ts(l1t, tn);</span><br><span style="color: hsl(120, 100%, 40%);">+ struct gsm_bts_trx_ts *ts = &l1t->trx->ts[tn];</span><br><span style="color: hsl(120, 100%, 40%);">+ struct msgb *msg = NULL; /* make GCC happy */</span><br><span style="color: hsl(120, 100%, 40%);">+ ubit_t *burst, **bursts_p = &l1ts->chan_state[chan].dl_bursts;</span><br><span style="color: hsl(120, 100%, 40%);">+ static ubit_t bits[GSM_BURST_LEN];</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* send burst, if we already got a frame */</span><br><span style="color: hsl(120, 100%, 40%);">+ if (bid > 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!*bursts_p)</span><br><span style="color: hsl(120, 100%, 40%);">+ return NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+ goto send_burst;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* get mac block from queue */</span><br><span style="color: hsl(120, 100%, 40%);">+ msg = _sched_dequeue_prim(l1t, tn, fn, chan);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (msg)</span><br><span style="color: hsl(120, 100%, 40%);">+ goto got_msg;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ LOGL1S(DL1P, LOGL_INFO, l1t, tn, chan, fn, "No prim for transmit.\n");</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+no_msg:</span><br><span style="color: hsl(120, 100%, 40%);">+ /* free burst memory */</span><br><span style="color: hsl(120, 100%, 40%);">+ if (*bursts_p) {</span><br><span style="color: hsl(120, 100%, 40%);">+ talloc_free(*bursts_p);</span><br><span style="color: hsl(120, 100%, 40%);">+ *bursts_p = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+ return NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+got_msg:</span><br><span style="color: hsl(120, 100%, 40%);">+ /* check validity of message */</span><br><span style="color: hsl(120, 100%, 40%);">+ if (msgb_l2len(msg) != GSM_MACBLOCK_LEN) {</span><br><span style="color: hsl(120, 100%, 40%);">+ LOGL1S(DL1P, LOGL_FATAL, l1t, tn, chan, fn, "Prim not 23 bytes, please FIX! "</span><br><span style="color: hsl(120, 100%, 40%);">+ "(len=%d)\n", msgb_l2len(msg));</span><br><span style="color: hsl(120, 100%, 40%);">+ /* free message */</span><br><span style="color: hsl(120, 100%, 40%);">+ msgb_free(msg);</span><br><span style="color: hsl(120, 100%, 40%);">+ goto no_msg;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* BURST BYPASS */</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* handle loss detection of SACCH */</span><br><span style="color: hsl(120, 100%, 40%);">+ if (L1SAP_IS_LINK_SACCH(trx_chan_desc[chan].link_id)) {</span><br><span style="color: hsl(120, 100%, 40%);">+ /* count and send BFI */</span><br><span style="color: hsl(120, 100%, 40%);">+ if (++(l1ts->chan_state[chan].lost_frames) > 1) {</span><br><span style="color: hsl(120, 100%, 40%);">+ /* TODO: Should we pass old TOA here? Otherwise we risk</span><br><span style="color: hsl(120, 100%, 40%);">+ * unnecessary decreasing TA */</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* Note: RSSI is set to 0 to indicate to the higher</span><br><span style="color: hsl(120, 100%, 40%);">+ * layers that this is a faked ph_data_ind */</span><br><span style="color: hsl(120, 100%, 40%);">+ _sched_compose_ph_data_ind(l1t, tn, 0, chan, NULL, 0,</span><br><span style="color: hsl(120, 100%, 40%);">+ 0, 0, 0, 10000,</span><br><span style="color: hsl(120, 100%, 40%);">+ PRES_INFO_INVALID);</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* allocate burst memory, if not already */</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!*bursts_p) {</span><br><span style="color: hsl(120, 100%, 40%);">+ *bursts_p = talloc_zero_size(tall_bts_ctx, 464);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!*bursts_p)</span><br><span style="color: hsl(120, 100%, 40%);">+ return NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* encode bursts */</span><br><span style="color: hsl(120, 100%, 40%);">+ gsm0503_xcch_encode(*bursts_p, msg->l2h);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* free message */</span><br><span style="color: hsl(120, 100%, 40%);">+ msgb_free(msg);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+send_burst:</span><br><span style="color: hsl(120, 100%, 40%);">+ /* compose burst */</span><br><span style="color: hsl(120, 100%, 40%);">+ burst = *bursts_p + bid * 116;</span><br><span style="color: hsl(120, 100%, 40%);">+ memset(bits, 0, 3);</span><br><span style="color: hsl(120, 100%, 40%);">+ memcpy(bits + 3, burst, 58);</span><br><span style="color: hsl(120, 100%, 40%);">+ memcpy(bits + 61, _sched_tsc[gsm_ts_tsc(ts)], 26);</span><br><span style="color: hsl(120, 100%, 40%);">+ memcpy(bits + 87, burst + 58, 58);</span><br><span style="color: hsl(120, 100%, 40%);">+ memset(bits + 145, 0, 3);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ if (nbits)</span><br><span style="color: hsl(120, 100%, 40%);">+ *nbits = GSM_BURST_LEN;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ LOGL1S(DL1P, LOGL_DEBUG, l1t, tn, chan, fn, "Transmitting burst=%u.\n", bid);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ return bits;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span>diff --git a/src/osmo-bts-trx/sched_utils.h b/src/osmo-bts-trx/sched_utils.h</span><br><span>new file mode 100644</span><br><span>index 0000000..4a1aaf5</span><br><span>--- /dev/null</span><br><span>+++ b/src/osmo-bts-trx/sched_utils.h</span><br><span>@@ -0,0 +1,42 @@</span><br><span style="color: hsl(120, 100%, 40%);">+/* Auxiliary scheduler utilities.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * (C) 2017 by Harald Welte <laforge@gnumonks.org></span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * All Rights Reserved</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * This program is free software; you can redistribute it and/or modify</span><br><span style="color: hsl(120, 100%, 40%);">+ * it under the terms of the GNU Affero General Public License as published by</span><br><span style="color: hsl(120, 100%, 40%);">+ * the Free Software Foundation; either version 3 of the License, or</span><br><span style="color: hsl(120, 100%, 40%);">+ * (at your option) any later version.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * This program is distributed in the hope that it will be useful,</span><br><span style="color: hsl(120, 100%, 40%);">+ * but WITHOUT ANY WARRANTY; without even the implied warranty of</span><br><span style="color: hsl(120, 100%, 40%);">+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the</span><br><span style="color: hsl(120, 100%, 40%);">+ * GNU General Public License for more details.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * You should have received a copy of the GNU Affero General Public License</span><br><span style="color: hsl(120, 100%, 40%);">+ * along with this program. If not, see <http://www.gnu.org/licenses/>.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#pragma once</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#include <stdint.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <errno.h></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+extern void *tall_bts_ctx;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/* Compute the bit error rate in 1/10000 units */</span><br><span style="color: hsl(120, 100%, 40%);">+static inline uint16_t compute_ber10k(int n_bits_total, int n_errors)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ if (n_bits_total == 0)</span><br><span style="color: hsl(120, 100%, 40%);">+ return 10000;</span><br><span style="color: hsl(120, 100%, 40%);">+ else</span><br><span style="color: hsl(120, 100%, 40%);">+ return 10000 * n_errors / n_bits_total;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/* determine if the FN is transmitting a CMR (1) or not (0) */</span><br><span style="color: hsl(120, 100%, 40%);">+static inline int fn_is_codec_mode_request(uint32_t fn)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ return (((fn + 4) % 26) >> 2) & 1;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span>diff --git a/src/osmo-bts-trx/scheduler_trx.c b/src/osmo-bts-trx/scheduler_trx.c</span><br><span>index 97b590d..4fb0e23 100644</span><br><span>--- a/src/osmo-bts-trx/scheduler_trx.c</span><br><span>+++ b/src/osmo-bts-trx/scheduler_trx.c</span><br><span>@@ -32,12 +32,8 @@</span><br><span> #include <osmocom/core/msgb.h></span><br><span> #include <osmocom/core/talloc.h></span><br><span> #include <osmocom/core/timer_compat.h></span><br><span style="color: hsl(0, 100%, 40%);">-#include <osmocom/codec/codec.h></span><br><span style="color: hsl(0, 100%, 40%);">-#include <osmocom/codec/ecu.h></span><br><span> #include <osmocom/core/bits.h></span><br><span> #include <osmocom/gsm/a5.h></span><br><span style="color: hsl(0, 100%, 40%);">-#include <osmocom/coding/gsm0503_coding.h></span><br><span style="color: hsl(0, 100%, 40%);">-#include <osmocom/coding/gsm0503_amr_dtx.h></span><br><span> </span><br><span> </span><br><span> #include <osmo-bts/gsm_data.h></span><br><span>@@ -45,33 +41,11 @@</span><br><span> #include <osmo-bts/rsl.h></span><br><span> #include <osmo-bts/bts.h></span><br><span> #include <osmo-bts/l1sap.h></span><br><span style="color: hsl(0, 100%, 40%);">-#include <osmo-bts/msg_utils.h></span><br><span> #include <osmo-bts/scheduler.h></span><br><span> #include <osmo-bts/scheduler_backend.h></span><br><span style="color: hsl(0, 100%, 40%);">-#include <osmocom/gsm/gsm0502.h></span><br><span> </span><br><span> #include "l1_if.h"</span><br><span> #include "trx_if.h"</span><br><span style="color: hsl(0, 100%, 40%);">-#include "loops.h"</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-extern void *tall_bts_ctx;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-/* Maximum size of a EGPRS message in bytes */</span><br><span style="color: hsl(0, 100%, 40%);">-#define EGPRS_0503_MAX_BYTES 155</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-/* Compute the bit error rate in 1/10000 units */</span><br><span style="color: hsl(0, 100%, 40%);">-static inline uint16_t compute_ber10k(int n_bits_total, int n_errors)</span><br><span style="color: hsl(0, 100%, 40%);">-{</span><br><span style="color: hsl(0, 100%, 40%);">- if (n_bits_total == 0)</span><br><span style="color: hsl(0, 100%, 40%);">- return 10000;</span><br><span style="color: hsl(0, 100%, 40%);">- else</span><br><span style="color: hsl(0, 100%, 40%);">- return 10000 * n_errors / n_bits_total;</span><br><span style="color: hsl(0, 100%, 40%);">-}</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-/*</span><br><span style="color: hsl(0, 100%, 40%);">- * TX on downlink</span><br><span style="color: hsl(0, 100%, 40%);">- */</span><br><span> </span><br><span> /* an IDLE burst returns nothing. on C0 it is replaced by dummy burst */</span><br><span> ubit_t *tx_idle_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn,</span><br><span>@@ -85,1542 +59,6 @@</span><br><span> return NULL;</span><br><span> }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-/* obtain a to-be-transmitted FCCH (frequency correction channel) burst */</span><br><span style="color: hsl(0, 100%, 40%);">-ubit_t *tx_fcch_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn,</span><br><span style="color: hsl(0, 100%, 40%);">- enum trx_chan_type chan, uint8_t bid, uint16_t *nbits)</span><br><span style="color: hsl(0, 100%, 40%);">-{</span><br><span style="color: hsl(0, 100%, 40%);">- LOGL1S(DL1P, LOGL_DEBUG, l1t, tn, chan, fn, "Transmitting FCCH\n");</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- if (nbits)</span><br><span style="color: hsl(0, 100%, 40%);">- *nbits = GSM_BURST_LEN;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- /* BURST BYPASS */</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- return (ubit_t *) _sched_fcch_burst;</span><br><span style="color: hsl(0, 100%, 40%);">-}</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-/* obtain a to-be-transmitted SCH (synchronization channel) burst */</span><br><span style="color: hsl(0, 100%, 40%);">-ubit_t *tx_sch_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn,</span><br><span style="color: hsl(0, 100%, 40%);">- enum trx_chan_type chan, uint8_t bid, uint16_t *nbits)</span><br><span style="color: hsl(0, 100%, 40%);">-{</span><br><span style="color: hsl(0, 100%, 40%);">- static ubit_t bits[GSM_BURST_LEN], burst[78];</span><br><span style="color: hsl(0, 100%, 40%);">- uint8_t sb_info[4];</span><br><span style="color: hsl(0, 100%, 40%);">- struct gsm_time t;</span><br><span style="color: hsl(0, 100%, 40%);">- uint8_t t3p, bsic;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- LOGL1S(DL1P, LOGL_DEBUG, l1t, tn, chan, fn, "Transmitting SCH\n");</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- /* BURST BYPASS */</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- /* create SB info from GSM time and BSIC */</span><br><span style="color: hsl(0, 100%, 40%);">- gsm_fn2gsmtime(&t, fn);</span><br><span style="color: hsl(0, 100%, 40%);">- t3p = t.t3 / 10;</span><br><span style="color: hsl(0, 100%, 40%);">- bsic = l1t->trx->bts->bsic;</span><br><span style="color: hsl(0, 100%, 40%);">- sb_info[0] =</span><br><span style="color: hsl(0, 100%, 40%);">- ((bsic & 0x3f) << 2) |</span><br><span style="color: hsl(0, 100%, 40%);">- ((t.t1 & 0x600) >> 9);</span><br><span style="color: hsl(0, 100%, 40%);">- sb_info[1] =</span><br><span style="color: hsl(0, 100%, 40%);">- ((t.t1 & 0x1fe) >> 1);</span><br><span style="color: hsl(0, 100%, 40%);">- sb_info[2] =</span><br><span style="color: hsl(0, 100%, 40%);">- ((t.t1 & 0x001) << 7) |</span><br><span style="color: hsl(0, 100%, 40%);">- ((t.t2 & 0x1f) << 2) |</span><br><span style="color: hsl(0, 100%, 40%);">- ((t3p & 0x6) >> 1);</span><br><span style="color: hsl(0, 100%, 40%);">- sb_info[3] =</span><br><span style="color: hsl(0, 100%, 40%);">- (t3p & 0x1);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- /* encode bursts */</span><br><span style="color: hsl(0, 100%, 40%);">- gsm0503_sch_encode(burst, sb_info);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- /* compose burst */</span><br><span style="color: hsl(0, 100%, 40%);">- memset(bits, 0, 3);</span><br><span style="color: hsl(0, 100%, 40%);">- memcpy(bits + 3, burst, 39);</span><br><span style="color: hsl(0, 100%, 40%);">- memcpy(bits + 42, _sched_sch_train, 64);</span><br><span style="color: hsl(0, 100%, 40%);">- memcpy(bits + 106, burst + 39, 39);</span><br><span style="color: hsl(0, 100%, 40%);">- memset(bits + 145, 0, 3);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- if (nbits)</span><br><span style="color: hsl(0, 100%, 40%);">- *nbits = GSM_BURST_LEN;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- return bits;</span><br><span style="color: hsl(0, 100%, 40%);">-}</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-/* obtain a to-be-transmitted data (SACCH/SDCCH) burst */</span><br><span style="color: hsl(0, 100%, 40%);">-ubit_t *tx_data_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn,</span><br><span style="color: hsl(0, 100%, 40%);">- enum trx_chan_type chan, uint8_t bid, uint16_t *nbits)</span><br><span style="color: hsl(0, 100%, 40%);">-{</span><br><span style="color: hsl(0, 100%, 40%);">- struct l1sched_ts *l1ts = l1sched_trx_get_ts(l1t, tn);</span><br><span style="color: hsl(0, 100%, 40%);">- struct gsm_bts_trx_ts *ts = &l1t->trx->ts[tn];</span><br><span style="color: hsl(0, 100%, 40%);">- struct msgb *msg = NULL; /* make GCC happy */</span><br><span style="color: hsl(0, 100%, 40%);">- ubit_t *burst, **bursts_p = &l1ts->chan_state[chan].dl_bursts;</span><br><span style="color: hsl(0, 100%, 40%);">- static ubit_t bits[GSM_BURST_LEN];</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- /* send burst, if we already got a frame */</span><br><span style="color: hsl(0, 100%, 40%);">- if (bid > 0) {</span><br><span style="color: hsl(0, 100%, 40%);">- if (!*bursts_p)</span><br><span style="color: hsl(0, 100%, 40%);">- return NULL;</span><br><span style="color: hsl(0, 100%, 40%);">- goto send_burst;</span><br><span style="color: hsl(0, 100%, 40%);">- }</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- /* get mac block from queue */</span><br><span style="color: hsl(0, 100%, 40%);">- msg = _sched_dequeue_prim(l1t, tn, fn, chan);</span><br><span style="color: hsl(0, 100%, 40%);">- if (msg)</span><br><span style="color: hsl(0, 100%, 40%);">- goto got_msg;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- LOGL1S(DL1P, LOGL_INFO, l1t, tn, chan, fn, "No prim for transmit.\n");</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-no_msg:</span><br><span style="color: hsl(0, 100%, 40%);">- /* free burst memory */</span><br><span style="color: hsl(0, 100%, 40%);">- if (*bursts_p) {</span><br><span style="color: hsl(0, 100%, 40%);">- talloc_free(*bursts_p);</span><br><span style="color: hsl(0, 100%, 40%);">- *bursts_p = NULL;</span><br><span style="color: hsl(0, 100%, 40%);">- }</span><br><span style="color: hsl(0, 100%, 40%);">- return NULL;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-got_msg:</span><br><span style="color: hsl(0, 100%, 40%);">- /* check validity of message */</span><br><span style="color: hsl(0, 100%, 40%);">- if (msgb_l2len(msg) != GSM_MACBLOCK_LEN) {</span><br><span style="color: hsl(0, 100%, 40%);">- LOGL1S(DL1P, LOGL_FATAL, l1t, tn, chan, fn, "Prim not 23 bytes, please FIX! "</span><br><span style="color: hsl(0, 100%, 40%);">- "(len=%d)\n", msgb_l2len(msg));</span><br><span style="color: hsl(0, 100%, 40%);">- /* free message */</span><br><span style="color: hsl(0, 100%, 40%);">- msgb_free(msg);</span><br><span style="color: hsl(0, 100%, 40%);">- goto no_msg;</span><br><span style="color: hsl(0, 100%, 40%);">- }</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- /* BURST BYPASS */</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- /* handle loss detection of SACCH */</span><br><span style="color: hsl(0, 100%, 40%);">- if (L1SAP_IS_LINK_SACCH(trx_chan_desc[chan].link_id)) {</span><br><span style="color: hsl(0, 100%, 40%);">- /* count and send BFI */</span><br><span style="color: hsl(0, 100%, 40%);">- if (++(l1ts->chan_state[chan].lost_frames) > 1) {</span><br><span style="color: hsl(0, 100%, 40%);">- /* TODO: Should we pass old TOA here? Otherwise we risk</span><br><span style="color: hsl(0, 100%, 40%);">- * unnecessary decreasing TA */</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- /* Note: RSSI is set to 0 to indicate to the higher</span><br><span style="color: hsl(0, 100%, 40%);">- * layers that this is a faked ph_data_ind */</span><br><span style="color: hsl(0, 100%, 40%);">- _sched_compose_ph_data_ind(l1t, tn, 0, chan, NULL, 0,</span><br><span style="color: hsl(0, 100%, 40%);">- 0, 0, 0, 10000,</span><br><span style="color: hsl(0, 100%, 40%);">- PRES_INFO_INVALID);</span><br><span style="color: hsl(0, 100%, 40%);">- }</span><br><span style="color: hsl(0, 100%, 40%);">- }</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- /* allocate burst memory, if not already */</span><br><span style="color: hsl(0, 100%, 40%);">- if (!*bursts_p) {</span><br><span style="color: hsl(0, 100%, 40%);">- *bursts_p = talloc_zero_size(tall_bts_ctx, 464);</span><br><span style="color: hsl(0, 100%, 40%);">- if (!*bursts_p)</span><br><span style="color: hsl(0, 100%, 40%);">- return NULL;</span><br><span style="color: hsl(0, 100%, 40%);">- }</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- /* encode bursts */</span><br><span style="color: hsl(0, 100%, 40%);">- gsm0503_xcch_encode(*bursts_p, msg->l2h);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- /* free message */</span><br><span style="color: hsl(0, 100%, 40%);">- msgb_free(msg);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-send_burst:</span><br><span style="color: hsl(0, 100%, 40%);">- /* compose burst */</span><br><span style="color: hsl(0, 100%, 40%);">- burst = *bursts_p + bid * 116;</span><br><span style="color: hsl(0, 100%, 40%);">- memset(bits, 0, 3);</span><br><span style="color: hsl(0, 100%, 40%);">- memcpy(bits + 3, burst, 58);</span><br><span style="color: hsl(0, 100%, 40%);">- memcpy(bits + 61, _sched_tsc[gsm_ts_tsc(ts)], 26);</span><br><span style="color: hsl(0, 100%, 40%);">- memcpy(bits + 87, burst + 58, 58);</span><br><span style="color: hsl(0, 100%, 40%);">- memset(bits + 145, 0, 3);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- if (nbits)</span><br><span style="color: hsl(0, 100%, 40%);">- *nbits = GSM_BURST_LEN;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- LOGL1S(DL1P, LOGL_DEBUG, l1t, tn, chan, fn, "Transmitting burst=%u.\n", bid);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- return bits;</span><br><span style="color: hsl(0, 100%, 40%);">-}</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-/* obtain a to-be-transmitted PDTCH (packet data) burst */</span><br><span style="color: hsl(0, 100%, 40%);">-ubit_t *tx_pdtch_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn,</span><br><span style="color: hsl(0, 100%, 40%);">- enum trx_chan_type chan, uint8_t bid, uint16_t *nbits)</span><br><span style="color: hsl(0, 100%, 40%);">-{</span><br><span style="color: hsl(0, 100%, 40%);">- struct l1sched_ts *l1ts = l1sched_trx_get_ts(l1t, tn);</span><br><span style="color: hsl(0, 100%, 40%);">- struct gsm_bts_trx_ts *ts = &l1t->trx->ts[tn];</span><br><span style="color: hsl(0, 100%, 40%);">- struct msgb *msg = NULL; /* make GCC happy */</span><br><span style="color: hsl(0, 100%, 40%);">- ubit_t *burst, **bursts_p = &l1ts->chan_state[chan].dl_bursts;</span><br><span style="color: hsl(0, 100%, 40%);">- enum trx_burst_type *burst_type = &l1ts->chan_state[chan].dl_burst_type;</span><br><span style="color: hsl(0, 100%, 40%);">- static ubit_t bits[EGPRS_BURST_LEN];</span><br><span style="color: hsl(0, 100%, 40%);">- int rc = 0;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- /* send burst, if we already got a frame */</span><br><span style="color: hsl(0, 100%, 40%);">- if (bid > 0) {</span><br><span style="color: hsl(0, 100%, 40%);">- if (!*bursts_p)</span><br><span style="color: hsl(0, 100%, 40%);">- return NULL;</span><br><span style="color: hsl(0, 100%, 40%);">- goto send_burst;</span><br><span style="color: hsl(0, 100%, 40%);">- }</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- /* get mac block from queue */</span><br><span style="color: hsl(0, 100%, 40%);">- msg = _sched_dequeue_prim(l1t, tn, fn, chan);</span><br><span style="color: hsl(0, 100%, 40%);">- if (msg)</span><br><span style="color: hsl(0, 100%, 40%);">- goto got_msg;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- LOGL1S(DL1P, LOGL_INFO, l1t, tn, chan, fn, "No prim for transmit.\n");</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-no_msg:</span><br><span style="color: hsl(0, 100%, 40%);">- /* free burst memory */</span><br><span style="color: hsl(0, 100%, 40%);">- if (*bursts_p) {</span><br><span style="color: hsl(0, 100%, 40%);">- talloc_free(*bursts_p);</span><br><span style="color: hsl(0, 100%, 40%);">- *bursts_p = NULL;</span><br><span style="color: hsl(0, 100%, 40%);">- }</span><br><span style="color: hsl(0, 100%, 40%);">- return NULL;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-got_msg:</span><br><span style="color: hsl(0, 100%, 40%);">- /* BURST BYPASS */</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- /* allocate burst memory, if not already */</span><br><span style="color: hsl(0, 100%, 40%);">- if (!*bursts_p) {</span><br><span style="color: hsl(0, 100%, 40%);">- *bursts_p = talloc_zero_size(tall_bts_ctx,</span><br><span style="color: hsl(0, 100%, 40%);">- GSM0503_EGPRS_BURSTS_NBITS);</span><br><span style="color: hsl(0, 100%, 40%);">- if (!*bursts_p)</span><br><span style="color: hsl(0, 100%, 40%);">- return NULL;</span><br><span style="color: hsl(0, 100%, 40%);">- }</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- /* encode bursts */</span><br><span style="color: hsl(0, 100%, 40%);">- rc = gsm0503_pdtch_egprs_encode(*bursts_p, msg->l2h, msg->tail - msg->l2h);</span><br><span style="color: hsl(0, 100%, 40%);">- if (rc < 0)</span><br><span style="color: hsl(0, 100%, 40%);">- rc = gsm0503_pdtch_encode(*bursts_p, msg->l2h, msg->tail - msg->l2h);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- /* check validity of message */</span><br><span style="color: hsl(0, 100%, 40%);">- if (rc < 0) {</span><br><span style="color: hsl(0, 100%, 40%);">- LOGL1S(DL1P, LOGL_FATAL, l1t, tn, chan, fn, "Prim invalid length, please FIX! "</span><br><span style="color: hsl(0, 100%, 40%);">- "(len=%ld)\n", (long)(msg->tail - msg->l2h));</span><br><span style="color: hsl(0, 100%, 40%);">- /* free message */</span><br><span style="color: hsl(0, 100%, 40%);">- msgb_free(msg);</span><br><span style="color: hsl(0, 100%, 40%);">- goto no_msg;</span><br><span style="color: hsl(0, 100%, 40%);">- } else if (rc == GSM0503_EGPRS_BURSTS_NBITS) {</span><br><span style="color: hsl(0, 100%, 40%);">- *burst_type = TRX_BURST_8PSK;</span><br><span style="color: hsl(0, 100%, 40%);">- } else {</span><br><span style="color: hsl(0, 100%, 40%);">- *burst_type = TRX_BURST_GMSK;</span><br><span style="color: hsl(0, 100%, 40%);">- }</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- /* free message */</span><br><span style="color: hsl(0, 100%, 40%);">- msgb_free(msg);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-send_burst:</span><br><span style="color: hsl(0, 100%, 40%);">- /* compose burst */</span><br><span style="color: hsl(0, 100%, 40%);">- if (*burst_type == TRX_BURST_8PSK) {</span><br><span style="color: hsl(0, 100%, 40%);">- burst = *bursts_p + bid * 348;</span><br><span style="color: hsl(0, 100%, 40%);">- memset(bits, 1, 9);</span><br><span style="color: hsl(0, 100%, 40%);">- memcpy(bits + 9, burst, 174);</span><br><span style="color: hsl(0, 100%, 40%);">- memcpy(bits + 183, _sched_egprs_tsc[gsm_ts_tsc(ts)], 78);</span><br><span style="color: hsl(0, 100%, 40%);">- memcpy(bits + 261, burst + 174, 174);</span><br><span style="color: hsl(0, 100%, 40%);">- memset(bits + 435, 1, 9);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- if (nbits)</span><br><span style="color: hsl(0, 100%, 40%);">- *nbits = EGPRS_BURST_LEN;</span><br><span style="color: hsl(0, 100%, 40%);">- } else {</span><br><span style="color: hsl(0, 100%, 40%);">- burst = *bursts_p + bid * 116;</span><br><span style="color: hsl(0, 100%, 40%);">- memset(bits, 0, 3);</span><br><span style="color: hsl(0, 100%, 40%);">- memcpy(bits + 3, burst, 58);</span><br><span style="color: hsl(0, 100%, 40%);">- memcpy(bits + 61, _sched_tsc[gsm_ts_tsc(ts)], 26);</span><br><span style="color: hsl(0, 100%, 40%);">- memcpy(bits + 87, burst + 58, 58);</span><br><span style="color: hsl(0, 100%, 40%);">- memset(bits + 145, 0, 3);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- if (nbits)</span><br><span style="color: hsl(0, 100%, 40%);">- *nbits = GSM_BURST_LEN;</span><br><span style="color: hsl(0, 100%, 40%);">- }</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- LOGL1S(DL1P, LOGL_DEBUG, l1t, tn, chan, fn, "Transmitting burst=%u.\n", bid);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- return bits;</span><br><span style="color: hsl(0, 100%, 40%);">-}</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-/* determine if the FN is transmitting a CMR (1) or not (0) */</span><br><span style="color: hsl(0, 100%, 40%);">-static inline int fn_is_codec_mode_request(uint32_t fn)</span><br><span style="color: hsl(0, 100%, 40%);">-{</span><br><span style="color: hsl(0, 100%, 40%);">- return (((fn + 4) % 26) >> 2) & 1;</span><br><span style="color: hsl(0, 100%, 40%);">-}</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-/* common section for generation of TCH bursts (TCH/H and TCH/F) */</span><br><span style="color: hsl(0, 100%, 40%);">-static void tx_tch_common(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn,</span><br><span style="color: hsl(0, 100%, 40%);">- enum trx_chan_type chan, uint8_t bid, struct msgb **_msg_tch,</span><br><span style="color: hsl(0, 100%, 40%);">- struct msgb **_msg_facch)</span><br><span style="color: hsl(0, 100%, 40%);">-{</span><br><span style="color: hsl(0, 100%, 40%);">- struct l1sched_ts *l1ts = l1sched_trx_get_ts(l1t, tn);</span><br><span style="color: hsl(0, 100%, 40%);">- struct msgb *msg1, *msg2, *msg_tch = NULL, *msg_facch = NULL;</span><br><span style="color: hsl(0, 100%, 40%);">- struct l1sched_chan_state *chan_state = &l1ts->chan_state[chan];</span><br><span style="color: hsl(0, 100%, 40%);">- uint8_t rsl_cmode = chan_state->rsl_cmode;</span><br><span style="color: hsl(0, 100%, 40%);">- uint8_t tch_mode = chan_state->tch_mode;</span><br><span style="color: hsl(0, 100%, 40%);">- struct osmo_phsap_prim *l1sap;</span><br><span style="color: hsl(0, 100%, 40%);">- int32_t *toa256_sum = &chan_state->toa256_sum;</span><br><span style="color: hsl(0, 100%, 40%);">- uint8_t *toa_num = &chan_state->toa_num;</span><br><span style="color: hsl(0, 100%, 40%);">- int16_t toa256;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- /* handle loss detection of received TCH frames */</span><br><span style="color: hsl(0, 100%, 40%);">- if (rsl_cmode == RSL_CMOD_SPD_SPEECH</span><br><span style="color: hsl(0, 100%, 40%);">- && ++(chan_state->lost_frames) > 5) {</span><br><span style="color: hsl(0, 100%, 40%);">- uint8_t tch_data[GSM_FR_BYTES];</span><br><span style="color: hsl(0, 100%, 40%);">- int len;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- LOGL1S(DL1P, LOGL_NOTICE, l1t, tn, chan, fn,</span><br><span style="color: hsl(0, 100%, 40%);">- "Missing TCH bursts detected, sending BFI\n");</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- /* indicate bad frame */</span><br><span style="color: hsl(0, 100%, 40%);">- switch (tch_mode) {</span><br><span style="color: hsl(0, 100%, 40%);">- case GSM48_CMODE_SPEECH_V1: /* FR / HR */</span><br><span style="color: hsl(0, 100%, 40%);">- if (chan != TRXC_TCHF) { /* HR */</span><br><span style="color: hsl(0, 100%, 40%);">- tch_data[0] = 0x70; /* F = 0, FT = 111 */</span><br><span style="color: hsl(0, 100%, 40%);">- memset(tch_data + 1, 0, 14);</span><br><span style="color: hsl(0, 100%, 40%);">- len = 15;</span><br><span style="color: hsl(0, 100%, 40%);">- break;</span><br><span style="color: hsl(0, 100%, 40%);">- }</span><br><span style="color: hsl(0, 100%, 40%);">- memset(tch_data, 0, GSM_FR_BYTES);</span><br><span style="color: hsl(0, 100%, 40%);">- len = GSM_FR_BYTES;</span><br><span style="color: hsl(0, 100%, 40%);">- break;</span><br><span style="color: hsl(0, 100%, 40%);">- case GSM48_CMODE_SPEECH_EFR: /* EFR */</span><br><span style="color: hsl(0, 100%, 40%);">- if (chan != TRXC_TCHF)</span><br><span style="color: hsl(0, 100%, 40%);">- goto inval_mode1;</span><br><span style="color: hsl(0, 100%, 40%);">- memset(tch_data, 0, GSM_EFR_BYTES);</span><br><span style="color: hsl(0, 100%, 40%);">- len = GSM_EFR_BYTES;</span><br><span style="color: hsl(0, 100%, 40%);">- break;</span><br><span style="color: hsl(0, 100%, 40%);">- case GSM48_CMODE_SPEECH_AMR: /* AMR */</span><br><span style="color: hsl(0, 100%, 40%);">- len = osmo_amr_rtp_enc(tch_data,</span><br><span style="color: hsl(0, 100%, 40%);">- chan_state->codec[chan_state->dl_cmr],</span><br><span style="color: hsl(0, 100%, 40%);">- chan_state->codec[chan_state->dl_ft], AMR_BAD);</span><br><span style="color: hsl(0, 100%, 40%);">- if (len < 2) {</span><br><span style="color: hsl(0, 100%, 40%);">- LOGL1S(DL1P, LOGL_ERROR, l1t, tn, chan, fn,</span><br><span style="color: hsl(0, 100%, 40%);">- "Failed to encode AMR_BAD frame (rc=%d), "</span><br><span style="color: hsl(0, 100%, 40%);">- "not sending BFI\n", len);</span><br><span style="color: hsl(0, 100%, 40%);">- return;</span><br><span style="color: hsl(0, 100%, 40%);">- }</span><br><span style="color: hsl(0, 100%, 40%);">- memset(tch_data + 2, 0, len - 2);</span><br><span style="color: hsl(0, 100%, 40%);">- break;</span><br><span style="color: hsl(0, 100%, 40%);">- default:</span><br><span style="color: hsl(0, 100%, 40%);">-inval_mode1:</span><br><span style="color: hsl(0, 100%, 40%);">- LOGL1S(DL1P, LOGL_ERROR, l1t, tn, chan, fn, "TCH mode invalid, please fix!\n");</span><br><span style="color: hsl(0, 100%, 40%);">- len = 0;</span><br><span style="color: hsl(0, 100%, 40%);">- }</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- if (len) {</span><br><span style="color: hsl(0, 100%, 40%);">- if (*toa_num == 0)</span><br><span style="color: hsl(0, 100%, 40%);">- toa256 = 0;</span><br><span style="color: hsl(0, 100%, 40%);">- else</span><br><span style="color: hsl(0, 100%, 40%);">- toa256 = *toa256_sum / *toa_num;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- /* Note: RSSI is set to 0 to indicate to the higher</span><br><span style="color: hsl(0, 100%, 40%);">- * layers that this is a faked tch_ind */</span><br><span style="color: hsl(0, 100%, 40%);">- _sched_compose_tch_ind(l1t, tn, fn, chan, tch_data, len, toa256, 10000, 0, 0);</span><br><span style="color: hsl(0, 100%, 40%);">- }</span><br><span style="color: hsl(0, 100%, 40%);">- }</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- /* get frame and unlink from queue */</span><br><span style="color: hsl(0, 100%, 40%);">- msg1 = _sched_dequeue_prim(l1t, tn, fn, chan);</span><br><span style="color: hsl(0, 100%, 40%);">- msg2 = _sched_dequeue_prim(l1t, tn, fn, chan);</span><br><span style="color: hsl(0, 100%, 40%);">- if (msg1) {</span><br><span style="color: hsl(0, 100%, 40%);">- l1sap = msgb_l1sap_prim(msg1);</span><br><span style="color: hsl(0, 100%, 40%);">- if (l1sap->oph.primitive == PRIM_TCH) {</span><br><span style="color: hsl(0, 100%, 40%);">- msg_tch = msg1;</span><br><span style="color: hsl(0, 100%, 40%);">- if (msg2) {</span><br><span style="color: hsl(0, 100%, 40%);">- l1sap = msgb_l1sap_prim(msg2);</span><br><span style="color: hsl(0, 100%, 40%);">- if (l1sap->oph.primitive == PRIM_TCH) {</span><br><span style="color: hsl(0, 100%, 40%);">- LOGL1S(DL1P, LOGL_FATAL, l1t, tn, chan, fn,</span><br><span style="color: hsl(0, 100%, 40%);">- "TCH twice, please FIX!\n");</span><br><span style="color: hsl(0, 100%, 40%);">- msgb_free(msg2);</span><br><span style="color: hsl(0, 100%, 40%);">- } else</span><br><span style="color: hsl(0, 100%, 40%);">- msg_facch = msg2;</span><br><span style="color: hsl(0, 100%, 40%);">- }</span><br><span style="color: hsl(0, 100%, 40%);">- } else {</span><br><span style="color: hsl(0, 100%, 40%);">- msg_facch = msg1;</span><br><span style="color: hsl(0, 100%, 40%);">- if (msg2) {</span><br><span style="color: hsl(0, 100%, 40%);">- l1sap = msgb_l1sap_prim(msg2);</span><br><span style="color: hsl(0, 100%, 40%);">- if (l1sap->oph.primitive != PRIM_TCH) {</span><br><span style="color: hsl(0, 100%, 40%);">- LOGL1S(DL1P, LOGL_FATAL, l1t, tn, chan, fn,</span><br><span style="color: hsl(0, 100%, 40%);">- "FACCH twice, please FIX!\n");</span><br><span style="color: hsl(0, 100%, 40%);">- msgb_free(msg2);</span><br><span style="color: hsl(0, 100%, 40%);">- } else</span><br><span style="color: hsl(0, 100%, 40%);">- msg_tch = msg2;</span><br><span style="color: hsl(0, 100%, 40%);">- }</span><br><span style="color: hsl(0, 100%, 40%);">- }</span><br><span style="color: hsl(0, 100%, 40%);">- } else if (msg2) {</span><br><span style="color: hsl(0, 100%, 40%);">- l1sap = msgb_l1sap_prim(msg2);</span><br><span style="color: hsl(0, 100%, 40%);">- if (l1sap->oph.primitive == PRIM_TCH)</span><br><span style="color: hsl(0, 100%, 40%);">- msg_tch = msg2;</span><br><span style="color: hsl(0, 100%, 40%);">- else</span><br><span style="color: hsl(0, 100%, 40%);">- msg_facch = msg2;</span><br><span style="color: hsl(0, 100%, 40%);">- }</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- /* check validity of message */</span><br><span style="color: hsl(0, 100%, 40%);">- if (msg_facch && msgb_l2len(msg_facch) != GSM_MACBLOCK_LEN) {</span><br><span style="color: hsl(0, 100%, 40%);">- LOGL1S(DL1P, LOGL_FATAL, l1t, tn, chan, fn, "Prim not 23 bytes, please FIX! "</span><br><span style="color: hsl(0, 100%, 40%);">- "(len=%d)\n", msgb_l2len(msg_facch));</span><br><span style="color: hsl(0, 100%, 40%);">- /* free message */</span><br><span style="color: hsl(0, 100%, 40%);">- msgb_free(msg_facch);</span><br><span style="color: hsl(0, 100%, 40%);">- msg_facch = NULL;</span><br><span style="color: hsl(0, 100%, 40%);">- }</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- /* check validity of message, get AMR ft and cmr */</span><br><span style="color: hsl(0, 100%, 40%);">- if (!msg_facch && msg_tch) {</span><br><span style="color: hsl(0, 100%, 40%);">- int len;</span><br><span style="color: hsl(0, 100%, 40%);">- uint8_t cmr_codec;</span><br><span style="color: hsl(0, 100%, 40%);">- int cmr, ft, i;</span><br><span style="color: hsl(0, 100%, 40%);">- enum osmo_amr_type ft_codec;</span><br><span style="color: hsl(0, 100%, 40%);">- enum osmo_amr_quality bfi;</span><br><span style="color: hsl(0, 100%, 40%);">- int8_t sti, cmi;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- if (rsl_cmode != RSL_CMOD_SPD_SPEECH) {</span><br><span style="color: hsl(0, 100%, 40%);">- LOGL1S(DL1P, LOGL_NOTICE, l1t, tn, chan, fn, "Dropping speech frame, "</span><br><span style="color: hsl(0, 100%, 40%);">- "because we are not in speech mode\n");</span><br><span style="color: hsl(0, 100%, 40%);">- goto free_bad_msg;</span><br><span style="color: hsl(0, 100%, 40%);">- }</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- switch (tch_mode) {</span><br><span style="color: hsl(0, 100%, 40%);">- case GSM48_CMODE_SPEECH_V1: /* FR / HR */</span><br><span style="color: hsl(0, 100%, 40%);">- if (chan != TRXC_TCHF) /* HR */</span><br><span style="color: hsl(0, 100%, 40%);">- len = 15;</span><br><span style="color: hsl(0, 100%, 40%);">- else</span><br><span style="color: hsl(0, 100%, 40%);">- len = GSM_FR_BYTES;</span><br><span style="color: hsl(0, 100%, 40%);">- break;</span><br><span style="color: hsl(0, 100%, 40%);">- case GSM48_CMODE_SPEECH_EFR: /* EFR */</span><br><span style="color: hsl(0, 100%, 40%);">- if (chan != TRXC_TCHF)</span><br><span style="color: hsl(0, 100%, 40%);">- goto inval_mode2;</span><br><span style="color: hsl(0, 100%, 40%);">- len = GSM_EFR_BYTES;</span><br><span style="color: hsl(0, 100%, 40%);">- break;</span><br><span style="color: hsl(0, 100%, 40%);">- case GSM48_CMODE_SPEECH_AMR: /* AMR */</span><br><span style="color: hsl(0, 100%, 40%);">- len = osmo_amr_rtp_dec(msg_tch->l2h, msgb_l2len(msg_tch),</span><br><span style="color: hsl(0, 100%, 40%);">- &cmr_codec, &cmi, &ft_codec,</span><br><span style="color: hsl(0, 100%, 40%);">- &bfi, &sti);</span><br><span style="color: hsl(0, 100%, 40%);">- cmr = -1;</span><br><span style="color: hsl(0, 100%, 40%);">- ft = -1;</span><br><span style="color: hsl(0, 100%, 40%);">- for (i = 0; i < chan_state->codecs; i++) {</span><br><span style="color: hsl(0, 100%, 40%);">- if (chan_state->codec[i] == cmr_codec)</span><br><span style="color: hsl(0, 100%, 40%);">- cmr = i;</span><br><span style="color: hsl(0, 100%, 40%);">- if (chan_state->codec[i] == ft_codec)</span><br><span style="color: hsl(0, 100%, 40%);">- ft = i;</span><br><span style="color: hsl(0, 100%, 40%);">- }</span><br><span style="color: hsl(0, 100%, 40%);">- if (cmr >= 0) { /* new request */</span><br><span style="color: hsl(0, 100%, 40%);">- chan_state->dl_cmr = cmr;</span><br><span style="color: hsl(0, 100%, 40%);">- /* disable AMR loop */</span><br><span style="color: hsl(0, 100%, 40%);">- trx_loop_amr_set(chan_state, 0);</span><br><span style="color: hsl(0, 100%, 40%);">- } else {</span><br><span style="color: hsl(0, 100%, 40%);">- /* enable AMR loop */</span><br><span style="color: hsl(0, 100%, 40%);">- trx_loop_amr_set(chan_state, 1);</span><br><span style="color: hsl(0, 100%, 40%);">- }</span><br><span style="color: hsl(0, 100%, 40%);">- if (ft < 0) {</span><br><span style="color: hsl(0, 100%, 40%);">- LOGL1S(DL1P, LOGL_ERROR, l1t, tn, chan, fn,</span><br><span style="color: hsl(0, 100%, 40%);">- "Codec (FT = %d) of RTP frame not in list\n", ft_codec);</span><br><span style="color: hsl(0, 100%, 40%);">- goto free_bad_msg;</span><br><span style="color: hsl(0, 100%, 40%);">- }</span><br><span style="color: hsl(0, 100%, 40%);">- if (fn_is_codec_mode_request(fn) && chan_state->dl_ft != ft) {</span><br><span style="color: hsl(0, 100%, 40%);">- LOGL1S(DL1P, LOGL_NOTICE, l1t, tn, chan, fn, "Codec (FT = %d) "</span><br><span style="color: hsl(0, 100%, 40%);">- " of RTP cannot be changed now, but in next frame\n", ft_codec);</span><br><span style="color: hsl(0, 100%, 40%);">- goto free_bad_msg;</span><br><span style="color: hsl(0, 100%, 40%);">- }</span><br><span style="color: hsl(0, 100%, 40%);">- chan_state->dl_ft = ft;</span><br><span style="color: hsl(0, 100%, 40%);">- if (bfi == AMR_BAD) {</span><br><span style="color: hsl(0, 100%, 40%);">- LOGL1S(DL1P, LOGL_NOTICE, l1t, tn, chan, fn,</span><br><span style="color: hsl(0, 100%, 40%);">- "Transmitting 'bad AMR frame'\n");</span><br><span style="color: hsl(0, 100%, 40%);">- goto free_bad_msg;</span><br><span style="color: hsl(0, 100%, 40%);">- }</span><br><span style="color: hsl(0, 100%, 40%);">- break;</span><br><span style="color: hsl(0, 100%, 40%);">- default:</span><br><span style="color: hsl(0, 100%, 40%);">-inval_mode2:</span><br><span style="color: hsl(0, 100%, 40%);">- LOGL1S(DL1P, LOGL_ERROR, l1t, tn, chan, fn, "TCH mode invalid, please fix!\n");</span><br><span style="color: hsl(0, 100%, 40%);">- goto free_bad_msg;</span><br><span style="color: hsl(0, 100%, 40%);">- }</span><br><span style="color: hsl(0, 100%, 40%);">- if (len < 0) {</span><br><span style="color: hsl(0, 100%, 40%);">- LOGL1S(DL1P, LOGL_ERROR, l1t, tn, chan, fn, "Cannot send invalid AMR payload\n");</span><br><span style="color: hsl(0, 100%, 40%);">- goto free_bad_msg;</span><br><span style="color: hsl(0, 100%, 40%);">- }</span><br><span style="color: hsl(0, 100%, 40%);">- if (msgb_l2len(msg_tch) != len) {</span><br><span style="color: hsl(0, 100%, 40%);">- LOGL1S(DL1P, LOGL_ERROR, l1t, tn, chan, fn, "Cannot send payload with "</span><br><span style="color: hsl(0, 100%, 40%);">- "invalid length! (expecting %d, received %d)\n",</span><br><span style="color: hsl(0, 100%, 40%);">- len, msgb_l2len(msg_tch));</span><br><span style="color: hsl(0, 100%, 40%);">-free_bad_msg:</span><br><span style="color: hsl(0, 100%, 40%);">- /* free message */</span><br><span style="color: hsl(0, 100%, 40%);">- msgb_free(msg_tch);</span><br><span style="color: hsl(0, 100%, 40%);">- msg_tch = NULL;</span><br><span style="color: hsl(0, 100%, 40%);">- goto send_frame;</span><br><span style="color: hsl(0, 100%, 40%);">- }</span><br><span style="color: hsl(0, 100%, 40%);">- }</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-send_frame:</span><br><span style="color: hsl(0, 100%, 40%);">- *_msg_tch = msg_tch;</span><br><span style="color: hsl(0, 100%, 40%);">- *_msg_facch = msg_facch;</span><br><span style="color: hsl(0, 100%, 40%);">-}</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-/* obtain a to-be-transmitted TCH/F (Full Traffic Channel) burst */</span><br><span style="color: hsl(0, 100%, 40%);">-ubit_t *tx_tchf_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn,</span><br><span style="color: hsl(0, 100%, 40%);">- enum trx_chan_type chan, uint8_t bid, uint16_t *nbits)</span><br><span style="color: hsl(0, 100%, 40%);">-{</span><br><span style="color: hsl(0, 100%, 40%);">- struct msgb *msg_tch = NULL, *msg_facch = NULL;</span><br><span style="color: hsl(0, 100%, 40%);">- struct l1sched_ts *l1ts = l1sched_trx_get_ts(l1t, tn);</span><br><span style="color: hsl(0, 100%, 40%);">- struct gsm_bts_trx_ts *ts = &l1t->trx->ts[tn];</span><br><span style="color: hsl(0, 100%, 40%);">- struct l1sched_chan_state *chan_state = &l1ts->chan_state[chan];</span><br><span style="color: hsl(0, 100%, 40%);">- uint8_t tch_mode = chan_state->tch_mode;</span><br><span style="color: hsl(0, 100%, 40%);">- ubit_t *burst, **bursts_p = &chan_state->dl_bursts;</span><br><span style="color: hsl(0, 100%, 40%);">- static ubit_t bits[GSM_BURST_LEN];</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- /* send burst, if we already got a frame */</span><br><span style="color: hsl(0, 100%, 40%);">- if (bid > 0) {</span><br><span style="color: hsl(0, 100%, 40%);">- if (!*bursts_p)</span><br><span style="color: hsl(0, 100%, 40%);">- return NULL;</span><br><span style="color: hsl(0, 100%, 40%);">- goto send_burst;</span><br><span style="color: hsl(0, 100%, 40%);">- }</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- tx_tch_common(l1t, tn, fn, chan, bid, &msg_tch, &msg_facch);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- /* BURST BYPASS */</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- /* allocate burst memory, if not already,</span><br><span style="color: hsl(0, 100%, 40%);">- * otherwise shift buffer by 4 bursts for interleaving */</span><br><span style="color: hsl(0, 100%, 40%);">- if (!*bursts_p) {</span><br><span style="color: hsl(0, 100%, 40%);">- *bursts_p = talloc_zero_size(tall_bts_ctx, 928);</span><br><span style="color: hsl(0, 100%, 40%);">- if (!*bursts_p)</span><br><span style="color: hsl(0, 100%, 40%);">- return NULL;</span><br><span style="color: hsl(0, 100%, 40%);">- } else {</span><br><span style="color: hsl(0, 100%, 40%);">- memcpy(*bursts_p, *bursts_p + 464, 464);</span><br><span style="color: hsl(0, 100%, 40%);">- memset(*bursts_p + 464, 0, 464);</span><br><span style="color: hsl(0, 100%, 40%);">- }</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- /* no message at all */</span><br><span style="color: hsl(0, 100%, 40%);">- if (!msg_tch && !msg_facch) {</span><br><span style="color: hsl(0, 100%, 40%);">- LOGL1S(DL1P, LOGL_INFO, l1t, tn, chan, fn, "No TCH or FACCH prim for transmit.\n");</span><br><span style="color: hsl(0, 100%, 40%);">- goto send_burst;</span><br><span style="color: hsl(0, 100%, 40%);">- }</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- /* encode bursts (prioritize FACCH) */</span><br><span style="color: hsl(0, 100%, 40%);">- if (msg_facch)</span><br><span style="color: hsl(0, 100%, 40%);">- gsm0503_tch_fr_encode(*bursts_p, msg_facch->l2h, msgb_l2len(msg_facch),</span><br><span style="color: hsl(0, 100%, 40%);">- 1);</span><br><span style="color: hsl(0, 100%, 40%);">- else if (tch_mode == GSM48_CMODE_SPEECH_AMR)</span><br><span style="color: hsl(0, 100%, 40%);">- /* the first FN 4,13,21 defines that CMI is included in frame,</span><br><span style="color: hsl(0, 100%, 40%);">- * the first FN 0,8,17 defines that CMR is included in frame.</span><br><span style="color: hsl(0, 100%, 40%);">- */</span><br><span style="color: hsl(0, 100%, 40%);">- gsm0503_tch_afs_encode(*bursts_p, msg_tch->l2h + 2,</span><br><span style="color: hsl(0, 100%, 40%);">- msgb_l2len(msg_tch) - 2, fn_is_codec_mode_request(fn),</span><br><span style="color: hsl(0, 100%, 40%);">- chan_state->codec, chan_state->codecs,</span><br><span style="color: hsl(0, 100%, 40%);">- chan_state->dl_ft,</span><br><span style="color: hsl(0, 100%, 40%);">- chan_state->dl_cmr);</span><br><span style="color: hsl(0, 100%, 40%);">- else</span><br><span style="color: hsl(0, 100%, 40%);">- gsm0503_tch_fr_encode(*bursts_p, msg_tch->l2h, msgb_l2len(msg_tch), 1);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- /* free message */</span><br><span style="color: hsl(0, 100%, 40%);">- if (msg_tch)</span><br><span style="color: hsl(0, 100%, 40%);">- msgb_free(msg_tch);</span><br><span style="color: hsl(0, 100%, 40%);">- if (msg_facch)</span><br><span style="color: hsl(0, 100%, 40%);">- msgb_free(msg_facch);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-send_burst:</span><br><span style="color: hsl(0, 100%, 40%);">- /* compose burst */</span><br><span style="color: hsl(0, 100%, 40%);">- burst = *bursts_p + bid * 116;</span><br><span style="color: hsl(0, 100%, 40%);">- memset(bits, 0, 3);</span><br><span style="color: hsl(0, 100%, 40%);">- memcpy(bits + 3, burst, 58);</span><br><span style="color: hsl(0, 100%, 40%);">- memcpy(bits + 61, _sched_tsc[gsm_ts_tsc(ts)], 26);</span><br><span style="color: hsl(0, 100%, 40%);">- memcpy(bits + 87, burst + 58, 58);</span><br><span style="color: hsl(0, 100%, 40%);">- memset(bits + 145, 0, 3);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- if (nbits)</span><br><span style="color: hsl(0, 100%, 40%);">- *nbits = GSM_BURST_LEN;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- LOGL1S(DL1P, LOGL_DEBUG, l1t, tn, chan, fn, "Transmitting burst=%u.\n", bid);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- return bits;</span><br><span style="color: hsl(0, 100%, 40%);">-}</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-/* obtain a to-be-transmitted TCH/H (Half Traffic Channel) burst */</span><br><span style="color: hsl(0, 100%, 40%);">-ubit_t *tx_tchh_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn,</span><br><span style="color: hsl(0, 100%, 40%);">- enum trx_chan_type chan, uint8_t bid, uint16_t *nbits)</span><br><span style="color: hsl(0, 100%, 40%);">-{</span><br><span style="color: hsl(0, 100%, 40%);">- struct msgb *msg_tch = NULL, *msg_facch = NULL;</span><br><span style="color: hsl(0, 100%, 40%);">- struct l1sched_ts *l1ts = l1sched_trx_get_ts(l1t, tn);</span><br><span style="color: hsl(0, 100%, 40%);">- struct gsm_bts_trx_ts *ts = &l1t->trx->ts[tn];</span><br><span style="color: hsl(0, 100%, 40%);">- struct l1sched_chan_state *chan_state = &l1ts->chan_state[chan];</span><br><span style="color: hsl(0, 100%, 40%);">- uint8_t tch_mode = chan_state->tch_mode;</span><br><span style="color: hsl(0, 100%, 40%);">- ubit_t *burst, **bursts_p = &chan_state->dl_bursts;</span><br><span style="color: hsl(0, 100%, 40%);">- static ubit_t bits[GSM_BURST_LEN];</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- /* send burst, if we already got a frame */</span><br><span style="color: hsl(0, 100%, 40%);">- if (bid > 0) {</span><br><span style="color: hsl(0, 100%, 40%);">- if (!*bursts_p)</span><br><span style="color: hsl(0, 100%, 40%);">- return NULL;</span><br><span style="color: hsl(0, 100%, 40%);">- goto send_burst;</span><br><span style="color: hsl(0, 100%, 40%);">- }</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- /* get TCH and/or FACCH */</span><br><span style="color: hsl(0, 100%, 40%);">- tx_tch_common(l1t, tn, fn, chan, bid, &msg_tch, &msg_facch);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- /* check for FACCH alignment */</span><br><span style="color: hsl(0, 100%, 40%);">- if (msg_facch && ((((fn + 4) % 26) >> 2) & 1)) {</span><br><span style="color: hsl(0, 100%, 40%);">- LOGL1S(DL1P, LOGL_ERROR, l1t, tn, chan, fn, "Cannot transmit FACCH starting on "</span><br><span style="color: hsl(0, 100%, 40%);">- "even frames, please fix RTS!\n");</span><br><span style="color: hsl(0, 100%, 40%);">- msgb_free(msg_facch);</span><br><span style="color: hsl(0, 100%, 40%);">- msg_facch = NULL;</span><br><span style="color: hsl(0, 100%, 40%);">- }</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- /* BURST BYPASS */</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- /* allocate burst memory, if not already,</span><br><span style="color: hsl(0, 100%, 40%);">- * otherwise shift buffer by 2 bursts for interleaving */</span><br><span style="color: hsl(0, 100%, 40%);">- if (!*bursts_p) {</span><br><span style="color: hsl(0, 100%, 40%);">- *bursts_p = talloc_zero_size(tall_bts_ctx, 696);</span><br><span style="color: hsl(0, 100%, 40%);">- if (!*bursts_p)</span><br><span style="color: hsl(0, 100%, 40%);">- return NULL;</span><br><span style="color: hsl(0, 100%, 40%);">- } else {</span><br><span style="color: hsl(0, 100%, 40%);">- memcpy(*bursts_p, *bursts_p + 232, 232);</span><br><span style="color: hsl(0, 100%, 40%);">- if (chan_state->dl_ongoing_facch) {</span><br><span style="color: hsl(0, 100%, 40%);">- memcpy(*bursts_p + 232, *bursts_p + 464, 232);</span><br><span style="color: hsl(0, 100%, 40%);">- memset(*bursts_p + 464, 0, 232);</span><br><span style="color: hsl(0, 100%, 40%);">- } else {</span><br><span style="color: hsl(0, 100%, 40%);">- memset(*bursts_p + 232, 0, 232);</span><br><span style="color: hsl(0, 100%, 40%);">- }</span><br><span style="color: hsl(0, 100%, 40%);">- }</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- /* no message at all */</span><br><span style="color: hsl(0, 100%, 40%);">- if (!msg_tch && !msg_facch && !chan_state->dl_ongoing_facch) {</span><br><span style="color: hsl(0, 100%, 40%);">- LOGL1S(DL1P, LOGL_INFO, l1t, tn, chan, fn, "No TCH or FACCH prim for transmit.\n");</span><br><span style="color: hsl(0, 100%, 40%);">- goto send_burst;</span><br><span style="color: hsl(0, 100%, 40%);">- }</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- /* encode bursts (prioritize FACCH) */</span><br><span style="color: hsl(0, 100%, 40%);">- if (msg_facch) {</span><br><span style="color: hsl(0, 100%, 40%);">- gsm0503_tch_hr_encode(*bursts_p, msg_facch->l2h, msgb_l2len(msg_facch));</span><br><span style="color: hsl(0, 100%, 40%);">- chan_state->dl_ongoing_facch = 1; /* first of two TCH frames */</span><br><span style="color: hsl(0, 100%, 40%);">- } else if (chan_state->dl_ongoing_facch) /* second of two TCH frames */</span><br><span style="color: hsl(0, 100%, 40%);">- chan_state->dl_ongoing_facch = 0; /* we are done with FACCH */</span><br><span style="color: hsl(0, 100%, 40%);">- else if (tch_mode == GSM48_CMODE_SPEECH_AMR)</span><br><span style="color: hsl(0, 100%, 40%);">- /* the first FN 4,13,21 or 5,14,22 defines that CMI is included</span><br><span style="color: hsl(0, 100%, 40%);">- * in frame, the first FN 0,8,17 or 1,9,18 defines that CMR is</span><br><span style="color: hsl(0, 100%, 40%);">- * included in frame. */</span><br><span style="color: hsl(0, 100%, 40%);">- gsm0503_tch_ahs_encode(*bursts_p, msg_tch->l2h + 2,</span><br><span style="color: hsl(0, 100%, 40%);">- msgb_l2len(msg_tch) - 2, fn_is_codec_mode_request(fn),</span><br><span style="color: hsl(0, 100%, 40%);">- chan_state->codec, chan_state->codecs,</span><br><span style="color: hsl(0, 100%, 40%);">- chan_state->dl_ft,</span><br><span style="color: hsl(0, 100%, 40%);">- chan_state->dl_cmr);</span><br><span style="color: hsl(0, 100%, 40%);">- else</span><br><span style="color: hsl(0, 100%, 40%);">- gsm0503_tch_hr_encode(*bursts_p, msg_tch->l2h, msgb_l2len(msg_tch));</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- /* free message */</span><br><span style="color: hsl(0, 100%, 40%);">- if (msg_tch)</span><br><span style="color: hsl(0, 100%, 40%);">- msgb_free(msg_tch);</span><br><span style="color: hsl(0, 100%, 40%);">- if (msg_facch)</span><br><span style="color: hsl(0, 100%, 40%);">- msgb_free(msg_facch);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-send_burst:</span><br><span style="color: hsl(0, 100%, 40%);">- /* compose burst */</span><br><span style="color: hsl(0, 100%, 40%);">- burst = *bursts_p + bid * 116;</span><br><span style="color: hsl(0, 100%, 40%);">- memset(bits, 0, 3);</span><br><span style="color: hsl(0, 100%, 40%);">- memcpy(bits + 3, burst, 58);</span><br><span style="color: hsl(0, 100%, 40%);">- memcpy(bits + 61, _sched_tsc[gsm_ts_tsc(ts)], 26);</span><br><span style="color: hsl(0, 100%, 40%);">- memcpy(bits + 87, burst + 58, 58);</span><br><span style="color: hsl(0, 100%, 40%);">- memset(bits + 145, 0, 3);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- if (nbits)</span><br><span style="color: hsl(0, 100%, 40%);">- *nbits = GSM_BURST_LEN;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- LOGL1S(DL1P, LOGL_DEBUG, l1t, tn, chan, fn, "Transmitting burst=%u.\n", bid);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- return bits;</span><br><span style="color: hsl(0, 100%, 40%);">-}</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-/*</span><br><span style="color: hsl(0, 100%, 40%);">- * RX on uplink (indication to upper layer)</span><br><span style="color: hsl(0, 100%, 40%);">- */</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-/* 3GPP TS 05.02, section 5.2.7 */</span><br><span style="color: hsl(0, 100%, 40%);">-#define RACH_EXT_TAIL_LEN 8</span><br><span style="color: hsl(0, 100%, 40%);">-#define RACH_SYNCH_SEQ_LEN 41</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-enum rach_synch_seq_t {</span><br><span style="color: hsl(0, 100%, 40%);">- RACH_SYNCH_SEQ_UNKNOWN = -1,</span><br><span style="color: hsl(0, 100%, 40%);">- RACH_SYNCH_SEQ_TS0, /* GSM, GMSK (default) */</span><br><span style="color: hsl(0, 100%, 40%);">- RACH_SYNCH_SEQ_TS1, /* EGPRS, 8-PSK */</span><br><span style="color: hsl(0, 100%, 40%);">- RACH_SYNCH_SEQ_TS2, /* EGPRS, GMSK */</span><br><span style="color: hsl(0, 100%, 40%);">- RACH_SYNCH_SEQ_NUM</span><br><span style="color: hsl(0, 100%, 40%);">-};</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-static struct value_string rach_synch_seq_names[] = {</span><br><span style="color: hsl(0, 100%, 40%);">- { RACH_SYNCH_SEQ_UNKNOWN, "UNKNOWN" },</span><br><span style="color: hsl(0, 100%, 40%);">- { RACH_SYNCH_SEQ_TS0, "TS0: GSM, GMSK" },</span><br><span style="color: hsl(0, 100%, 40%);">- { RACH_SYNCH_SEQ_TS1, "TS1: EGPRS, 8-PSK" },</span><br><span style="color: hsl(0, 100%, 40%);">- { RACH_SYNCH_SEQ_TS2, "TS2: EGPRS, GMSK" },</span><br><span style="color: hsl(0, 100%, 40%);">- { 0, NULL },</span><br><span style="color: hsl(0, 100%, 40%);">-};</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-static enum rach_synch_seq_t rach_get_synch_seq(sbit_t *bits, int *best_score)</span><br><span style="color: hsl(0, 100%, 40%);">-{</span><br><span style="color: hsl(0, 100%, 40%);">- sbit_t *synch_seq_burst = bits + RACH_EXT_TAIL_LEN;</span><br><span style="color: hsl(0, 100%, 40%);">- enum rach_synch_seq_t seq = RACH_SYNCH_SEQ_TS0;</span><br><span style="color: hsl(0, 100%, 40%);">- int score[RACH_SYNCH_SEQ_NUM] = { 0 };</span><br><span style="color: hsl(0, 100%, 40%);">- int max_score = INT_MIN;</span><br><span style="color: hsl(0, 100%, 40%);">- int i, j;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- /* 3GPP TS 05.02, section 5.2.7 "Access burst (AB)", synch. sequence bits */</span><br><span style="color: hsl(0, 100%, 40%);">- static const char synch_seq_ref[RACH_SYNCH_SEQ_NUM][RACH_SYNCH_SEQ_LEN] = {</span><br><span style="color: hsl(0, 100%, 40%);">- [RACH_SYNCH_SEQ_TS0] = "01001011011111111001100110101010001111000",</span><br><span style="color: hsl(0, 100%, 40%);">- [RACH_SYNCH_SEQ_TS1] = "01010100111110001000011000101111001001101",</span><br><span style="color: hsl(0, 100%, 40%);">- [RACH_SYNCH_SEQ_TS2] = "11101111001001110101011000001101101110111",</span><br><span style="color: hsl(0, 100%, 40%);">- };</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- /* Get a multiplier for j-th bit of i-th synch. sequence */</span><br><span style="color: hsl(0, 100%, 40%);">-#define RACH_SYNCH_SEQ_MULT \</span><br><span style="color: hsl(0, 100%, 40%);">- (synch_seq_ref[i][j] == '1' ? -1 : 1)</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- /* For each synch. sequence, count the bit match score. Since we deal with</span><br><span style="color: hsl(0, 100%, 40%);">- * soft-bits (-127...127), we sum the absolute values of matching ones,</span><br><span style="color: hsl(0, 100%, 40%);">- * and subtract the absolute values of different ones, so the resulting</span><br><span style="color: hsl(0, 100%, 40%);">- * score is more accurate than it could be with hard-bits. */</span><br><span style="color: hsl(0, 100%, 40%);">- for (i = 0; i < RACH_SYNCH_SEQ_NUM; i++) {</span><br><span style="color: hsl(0, 100%, 40%);">- for (j = 0; j < RACH_SYNCH_SEQ_LEN; j++)</span><br><span style="color: hsl(0, 100%, 40%);">- score[i] += RACH_SYNCH_SEQ_MULT * synch_seq_burst[j];</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- /* Keep the maximum value updated */</span><br><span style="color: hsl(0, 100%, 40%);">- if (score[i] > max_score) {</span><br><span style="color: hsl(0, 100%, 40%);">- max_score = score[i];</span><br><span style="color: hsl(0, 100%, 40%);">- seq = i;</span><br><span style="color: hsl(0, 100%, 40%);">- }</span><br><span style="color: hsl(0, 100%, 40%);">- }</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- /* Calculate an approximate level of our confidence */</span><br><span style="color: hsl(0, 100%, 40%);">- if (best_score != NULL)</span><br><span style="color: hsl(0, 100%, 40%);">- *best_score = max_score;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- /* At least 1/3 of a synch. sequence shall match */</span><br><span style="color: hsl(0, 100%, 40%);">- if (max_score < (127 * RACH_SYNCH_SEQ_LEN / 3))</span><br><span style="color: hsl(0, 100%, 40%);">- return RACH_SYNCH_SEQ_UNKNOWN;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- return seq;</span><br><span style="color: hsl(0, 100%, 40%);">-}</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-int rx_rach_fn(struct l1sched_trx *l1t, enum trx_chan_type chan,</span><br><span style="color: hsl(0, 100%, 40%);">- uint8_t bid, const struct trx_ul_burst_ind *bi)</span><br><span style="color: hsl(0, 100%, 40%);">-{</span><br><span style="color: hsl(0, 100%, 40%);">- struct osmo_phsap_prim l1sap;</span><br><span style="color: hsl(0, 100%, 40%);">- int n_errors = 0;</span><br><span style="color: hsl(0, 100%, 40%);">- int n_bits_total = 0;</span><br><span style="color: hsl(0, 100%, 40%);">- uint16_t ra11;</span><br><span style="color: hsl(0, 100%, 40%);">- uint8_t ra;</span><br><span style="color: hsl(0, 100%, 40%);">- int rc;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- /* TSC (Training Sequence Code) is an optional parameter of the UL burst</span><br><span style="color: hsl(0, 100%, 40%);">- * indication. We need this information in order to decide whether an</span><br><span style="color: hsl(0, 100%, 40%);">- * Access Burst is 11-bit encoded or not (see OS#1854). If this information</span><br><span style="color: hsl(0, 100%, 40%);">- * is absent, we try to correlate the received synch. sequence with the</span><br><span style="color: hsl(0, 100%, 40%);">- * known ones (3GPP TS 05.02, section 5.2.7), and fall-back to the default</span><br><span style="color: hsl(0, 100%, 40%);">- * TS0 if it fails. */</span><br><span style="color: hsl(0, 100%, 40%);">- enum rach_synch_seq_t synch_seq = RACH_SYNCH_SEQ_TS0;</span><br><span style="color: hsl(0, 100%, 40%);">- int best_score = 127 * RACH_SYNCH_SEQ_LEN;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- /* If logical channel is not either of RACH, PDTCH or PTCCH, this is a</span><br><span style="color: hsl(0, 100%, 40%);">- * handover Access Burst, which is always encoded as 8-bit and shall</span><br><span style="color: hsl(0, 100%, 40%);">- * contain the generic training sequence (TS0). */</span><br><span style="color: hsl(0, 100%, 40%);">- if (chan == TRXC_RACH || chan == TRXC_PDTCH || chan == TRXC_PTCCH) {</span><br><span style="color: hsl(0, 100%, 40%);">- if (bi->flags & TRX_BI_F_TS_INFO)</span><br><span style="color: hsl(0, 100%, 40%);">- synch_seq = (enum rach_synch_seq_t) bi->tsc;</span><br><span style="color: hsl(0, 100%, 40%);">- else</span><br><span style="color: hsl(0, 100%, 40%);">- synch_seq = rach_get_synch_seq((sbit_t *) bi->burst, &best_score);</span><br><span style="color: hsl(0, 100%, 40%);">- }</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- LOGL1S(DL1P, LOGL_DEBUG, l1t, bi->tn, chan, bi->fn,</span><br><span style="color: hsl(0, 100%, 40%);">- "Received%s RACH (%s): rssi=%d toa256=%d",</span><br><span style="color: hsl(0, 100%, 40%);">- (chan != TRXC_RACH) ? " handover" : "",</span><br><span style="color: hsl(0, 100%, 40%);">- get_value_string(rach_synch_seq_names, synch_seq),</span><br><span style="color: hsl(0, 100%, 40%);">- bi->rssi, bi->toa256);</span><br><span style="color: hsl(0, 100%, 40%);">- if (bi->flags & TRX_BI_F_CI_CB)</span><br><span style="color: hsl(0, 100%, 40%);">- LOGPC(DL1P, LOGL_DEBUG, " C/I=%d cB", bi->ci_cb);</span><br><span style="color: hsl(0, 100%, 40%);">- else</span><br><span style="color: hsl(0, 100%, 40%);">- LOGPC(DL1P, LOGL_DEBUG, " match=%.1f%%",</span><br><span style="color: hsl(0, 100%, 40%);">- best_score * 100.0 / (127 * RACH_SYNCH_SEQ_LEN));</span><br><span style="color: hsl(0, 100%, 40%);">- LOGPC(DL1P, LOGL_DEBUG, "\n");</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- /* Compose a new L1SAP primitive */</span><br><span style="color: hsl(0, 100%, 40%);">- memset(&l1sap, 0x00, sizeof(l1sap));</span><br><span style="color: hsl(0, 100%, 40%);">- osmo_prim_init(&l1sap.oph, SAP_GSM_PH, PRIM_PH_RACH, PRIM_OP_INDICATION, NULL);</span><br><span style="color: hsl(0, 100%, 40%);">- l1sap.u.rach_ind.chan_nr = trx_chan_desc[chan].chan_nr | bi->tn;</span><br><span style="color: hsl(0, 100%, 40%);">- l1sap.u.rach_ind.acc_delay = (bi->toa256 >= 0) ? bi->toa256 / 256 : 0;</span><br><span style="color: hsl(0, 100%, 40%);">- l1sap.u.rach_ind.acc_delay_256bits = bi->toa256;</span><br><span style="color: hsl(0, 100%, 40%);">- l1sap.u.rach_ind.rssi = bi->rssi;</span><br><span style="color: hsl(0, 100%, 40%);">- l1sap.u.rach_ind.fn = bi->fn;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- /* Link quality is defined by C/I (Carrier-to-Interference ratio),</span><br><span style="color: hsl(0, 100%, 40%);">- * which has optional presence. If it's absent, report the</span><br><span style="color: hsl(0, 100%, 40%);">- * minimum acceptable value to pass L1SAP checks. */</span><br><span style="color: hsl(0, 100%, 40%);">- if (bi->flags & TRX_BI_F_CI_CB)</span><br><span style="color: hsl(0, 100%, 40%);">- l1sap.u.rach_ind.lqual_cb = bi->ci_cb;</span><br><span style="color: hsl(0, 100%, 40%);">- else</span><br><span style="color: hsl(0, 100%, 40%);">- l1sap.u.rach_ind.lqual_cb = l1t->trx->bts->min_qual_rach;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- /* Decode RACH depending on its synch. sequence */</span><br><span style="color: hsl(0, 100%, 40%);">- switch (synch_seq) {</span><br><span style="color: hsl(0, 100%, 40%);">- case RACH_SYNCH_SEQ_TS1:</span><br><span style="color: hsl(0, 100%, 40%);">- case RACH_SYNCH_SEQ_TS2:</span><br><span style="color: hsl(0, 100%, 40%);">- rc = gsm0503_rach_ext_decode_ber(&ra11, bi->burst + RACH_EXT_TAIL_LEN + RACH_SYNCH_SEQ_LEN,</span><br><span style="color: hsl(0, 100%, 40%);">- l1t->trx->bts->bsic, &n_errors, &n_bits_total);</span><br><span style="color: hsl(0, 100%, 40%);">- if (rc) {</span><br><span style="color: hsl(0, 100%, 40%);">- LOGL1S(DL1P, LOGL_DEBUG, l1t, bi->tn, chan, bi->fn,</span><br><span style="color: hsl(0, 100%, 40%);">- "Received bad Access Burst\n");</span><br><span style="color: hsl(0, 100%, 40%);">- return 0;</span><br><span style="color: hsl(0, 100%, 40%);">- }</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- if (synch_seq == RACH_SYNCH_SEQ_TS1)</span><br><span style="color: hsl(0, 100%, 40%);">- l1sap.u.rach_ind.burst_type = GSM_L1_BURST_TYPE_ACCESS_1;</span><br><span style="color: hsl(0, 100%, 40%);">- else</span><br><span style="color: hsl(0, 100%, 40%);">- l1sap.u.rach_ind.burst_type = GSM_L1_BURST_TYPE_ACCESS_2;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- l1sap.u.rach_ind.is_11bit = 1;</span><br><span style="color: hsl(0, 100%, 40%);">- l1sap.u.rach_ind.ra = ra11;</span><br><span style="color: hsl(0, 100%, 40%);">- break;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- case RACH_SYNCH_SEQ_TS0:</span><br><span style="color: hsl(0, 100%, 40%);">- default:</span><br><span style="color: hsl(0, 100%, 40%);">- /* Fall-back to the default TS0 if needed */</span><br><span style="color: hsl(0, 100%, 40%);">- if (synch_seq != RACH_SYNCH_SEQ_TS0) {</span><br><span style="color: hsl(0, 100%, 40%);">- LOGL1S(DL1P, LOGL_DEBUG, l1t, bi->tn, chan, bi->fn,</span><br><span style="color: hsl(0, 100%, 40%);">- "Falling-back to the default TS0\n");</span><br><span style="color: hsl(0, 100%, 40%);">- synch_seq = RACH_SYNCH_SEQ_TS0;</span><br><span style="color: hsl(0, 100%, 40%);">- }</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- rc = gsm0503_rach_decode_ber(&ra, bi->burst + RACH_EXT_TAIL_LEN + RACH_SYNCH_SEQ_LEN,</span><br><span style="color: hsl(0, 100%, 40%);">- l1t->trx->bts->bsic, &n_errors, &n_bits_total);</span><br><span style="color: hsl(0, 100%, 40%);">- if (rc) {</span><br><span style="color: hsl(0, 100%, 40%);">- LOGL1S(DL1P, LOGL_DEBUG, l1t, bi->tn, chan, bi->fn,</span><br><span style="color: hsl(0, 100%, 40%);">- "Received bad Access Burst\n");</span><br><span style="color: hsl(0, 100%, 40%);">- return 0;</span><br><span style="color: hsl(0, 100%, 40%);">- }</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- l1sap.u.rach_ind.burst_type = GSM_L1_BURST_TYPE_ACCESS_0;</span><br><span style="color: hsl(0, 100%, 40%);">- l1sap.u.rach_ind.is_11bit = 0;</span><br><span style="color: hsl(0, 100%, 40%);">- l1sap.u.rach_ind.ra = ra;</span><br><span style="color: hsl(0, 100%, 40%);">- break;</span><br><span style="color: hsl(0, 100%, 40%);">- }</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- l1sap.u.rach_ind.ber10k = compute_ber10k(n_bits_total, n_errors);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- /* forward primitive */</span><br><span style="color: hsl(0, 100%, 40%);">- l1sap_up(l1t->trx, &l1sap);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- return 0;</span><br><span style="color: hsl(0, 100%, 40%);">-}</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-/*! \brief a single (SDCCH/SACCH) burst was received by the PHY, process it */</span><br><span style="color: hsl(0, 100%, 40%);">-int rx_data_fn(struct l1sched_trx *l1t, enum trx_chan_type chan,</span><br><span style="color: hsl(0, 100%, 40%);">- uint8_t bid, const struct trx_ul_burst_ind *bi)</span><br><span style="color: hsl(0, 100%, 40%);">-{</span><br><span style="color: hsl(0, 100%, 40%);">- struct l1sched_ts *l1ts = l1sched_trx_get_ts(l1t, bi->tn);</span><br><span style="color: hsl(0, 100%, 40%);">- struct l1sched_chan_state *chan_state = &l1ts->chan_state[chan];</span><br><span style="color: hsl(0, 100%, 40%);">- sbit_t *burst, **bursts_p = &chan_state->ul_bursts;</span><br><span style="color: hsl(0, 100%, 40%);">- uint32_t *first_fn = &chan_state->ul_first_fn;</span><br><span style="color: hsl(0, 100%, 40%);">- uint8_t *mask = &chan_state->ul_mask;</span><br><span style="color: hsl(0, 100%, 40%);">- float *rssi_sum = &chan_state->rssi_sum;</span><br><span style="color: hsl(0, 100%, 40%);">- uint8_t *rssi_num = &chan_state->rssi_num;</span><br><span style="color: hsl(0, 100%, 40%);">- int32_t *toa256_sum = &chan_state->toa256_sum;</span><br><span style="color: hsl(0, 100%, 40%);">- uint8_t *toa_num = &chan_state->toa_num;</span><br><span style="color: hsl(0, 100%, 40%);">- int32_t *ci_cb_sum = &chan_state->ci_cb_sum;</span><br><span style="color: hsl(0, 100%, 40%);">- uint8_t *ci_cb_num = &chan_state->ci_cb_num;</span><br><span style="color: hsl(0, 100%, 40%);">- uint8_t l2[GSM_MACBLOCK_LEN], l2_len;</span><br><span style="color: hsl(0, 100%, 40%);">- int n_errors = 0;</span><br><span style="color: hsl(0, 100%, 40%);">- int n_bits_total = 0;</span><br><span style="color: hsl(0, 100%, 40%);">- int16_t lqual_cb;</span><br><span style="color: hsl(0, 100%, 40%);">- uint16_t ber10k;</span><br><span style="color: hsl(0, 100%, 40%);">- int rc;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- /* If handover RACH detection is turned on, treat this burst as an Access Burst.</span><br><span style="color: hsl(0, 100%, 40%);">- * Handle NOPE.ind as usually to ensure proper Uplink measurement reporting. */</span><br><span style="color: hsl(0, 100%, 40%);">- if (chan_state->ho_rach_detect == 1 && ~bi->flags & TRX_BI_F_NOPE_IND)</span><br><span style="color: hsl(0, 100%, 40%);">- return rx_rach_fn(l1t, chan, bid, bi);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- LOGL1S(DL1P, LOGL_DEBUG, l1t, bi->tn, chan, bi->fn,</span><br><span style="color: hsl(0, 100%, 40%);">- "Received Data, bid=%u\n", bid);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- /* allocate burst memory, if not already */</span><br><span style="color: hsl(0, 100%, 40%);">- if (!*bursts_p) {</span><br><span style="color: hsl(0, 100%, 40%);">- *bursts_p = talloc_zero_size(tall_bts_ctx, 464);</span><br><span style="color: hsl(0, 100%, 40%);">- if (!*bursts_p)</span><br><span style="color: hsl(0, 100%, 40%);">- return -ENOMEM;</span><br><span style="color: hsl(0, 100%, 40%);">- }</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- /* clear burst & store frame number of first burst */</span><br><span style="color: hsl(0, 100%, 40%);">- if (bid == 0) {</span><br><span style="color: hsl(0, 100%, 40%);">- memset(*bursts_p, 0, 464);</span><br><span style="color: hsl(0, 100%, 40%);">- *mask = 0x0;</span><br><span style="color: hsl(0, 100%, 40%);">- *first_fn = bi->fn;</span><br><span style="color: hsl(0, 100%, 40%);">- *rssi_sum = 0;</span><br><span style="color: hsl(0, 100%, 40%);">- *rssi_num = 0;</span><br><span style="color: hsl(0, 100%, 40%);">- *toa256_sum = 0;</span><br><span style="color: hsl(0, 100%, 40%);">- *toa_num = 0;</span><br><span style="color: hsl(0, 100%, 40%);">- *ci_cb_sum = 0;</span><br><span style="color: hsl(0, 100%, 40%);">- *ci_cb_num = 0;</span><br><span style="color: hsl(0, 100%, 40%);">- }</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- /* update mask + RSSI */</span><br><span style="color: hsl(0, 100%, 40%);">- *mask |= (1 << bid);</span><br><span style="color: hsl(0, 100%, 40%);">- *rssi_sum += bi->rssi;</span><br><span style="color: hsl(0, 100%, 40%);">- (*rssi_num)++;</span><br><span style="color: hsl(0, 100%, 40%);">- *toa256_sum += bi->toa256;</span><br><span style="color: hsl(0, 100%, 40%);">- (*toa_num)++;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- /* C/I: Carrier-to-Interference ratio (in centiBels) */</span><br><span style="color: hsl(0, 100%, 40%);">- if (bi->flags & TRX_BI_F_CI_CB) {</span><br><span style="color: hsl(0, 100%, 40%);">- *ci_cb_sum += bi->ci_cb;</span><br><span style="color: hsl(0, 100%, 40%);">- (*ci_cb_num)++;</span><br><span style="color: hsl(0, 100%, 40%);">- }</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- /* Copy burst to buffer of 4 bursts. If the burst indication contains</span><br><span style="color: hsl(0, 100%, 40%);">- * no data, ensure that the buffer does not stay uninitialized */</span><br><span style="color: hsl(0, 100%, 40%);">- burst = *bursts_p + bid * 116;</span><br><span style="color: hsl(0, 100%, 40%);">- if (bi->burst_len > 0) {</span><br><span style="color: hsl(0, 100%, 40%);">- memcpy(burst, bi->burst + 3, 58);</span><br><span style="color: hsl(0, 100%, 40%);">- memcpy(burst + 58, bi->burst + 87, 58);</span><br><span style="color: hsl(0, 100%, 40%);">- } else</span><br><span style="color: hsl(0, 100%, 40%);">- memset(burst, 0, 58 * 2);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- /* wait until complete set of bursts */</span><br><span style="color: hsl(0, 100%, 40%);">- if (bid != 3)</span><br><span style="color: hsl(0, 100%, 40%);">- return 0;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- /* check for complete set of bursts */</span><br><span style="color: hsl(0, 100%, 40%);">- if ((*mask & 0xf) != 0xf) {</span><br><span style="color: hsl(0, 100%, 40%);">- LOGL1S(DL1P, LOGL_NOTICE, l1t, bi->tn, chan, bi->fn,</span><br><span style="color: hsl(0, 100%, 40%);">- "Received incomplete data (%u/%u)\n",</span><br><span style="color: hsl(0, 100%, 40%);">- bi->fn % l1ts->mf_period, l1ts->mf_period);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- /* we require first burst to have correct FN */</span><br><span style="color: hsl(0, 100%, 40%);">- if (!(*mask & 0x1)) {</span><br><span style="color: hsl(0, 100%, 40%);">- *mask = 0x0;</span><br><span style="color: hsl(0, 100%, 40%);">- return 0;</span><br><span style="color: hsl(0, 100%, 40%);">- }</span><br><span style="color: hsl(0, 100%, 40%);">- }</span><br><span style="color: hsl(0, 100%, 40%);">- *mask = 0x0;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- /* decode */</span><br><span style="color: hsl(0, 100%, 40%);">- rc = gsm0503_xcch_decode(l2, *bursts_p, &n_errors, &n_bits_total);</span><br><span style="color: hsl(0, 100%, 40%);">- if (rc) {</span><br><span style="color: hsl(0, 100%, 40%);">- LOGL1S(DL1P, LOGL_NOTICE, l1t, bi->tn, chan, bi->fn,</span><br><span style="color: hsl(0, 100%, 40%);">- "Received bad data (%u/%u)\n",</span><br><span style="color: hsl(0, 100%, 40%);">- bi->fn % l1ts->mf_period, l1ts->mf_period);</span><br><span style="color: hsl(0, 100%, 40%);">- l2_len = 0;</span><br><span style="color: hsl(0, 100%, 40%);">- } else</span><br><span style="color: hsl(0, 100%, 40%);">- l2_len = GSM_MACBLOCK_LEN;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- lqual_cb = *ci_cb_num ? (*ci_cb_sum / *ci_cb_num) : 0;</span><br><span style="color: hsl(0, 100%, 40%);">- ber10k = compute_ber10k(n_bits_total, n_errors);</span><br><span style="color: hsl(0, 100%, 40%);">- return _sched_compose_ph_data_ind(l1t, bi->tn, *first_fn,</span><br><span style="color: hsl(0, 100%, 40%);">- chan, l2, l2_len,</span><br><span style="color: hsl(0, 100%, 40%);">- *rssi_sum / *rssi_num,</span><br><span style="color: hsl(0, 100%, 40%);">- *toa256_sum / *toa_num,</span><br><span style="color: hsl(0, 100%, 40%);">- lqual_cb, ber10k,</span><br><span style="color: hsl(0, 100%, 40%);">- PRES_INFO_UNKNOWN);</span><br><span style="color: hsl(0, 100%, 40%);">-}</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-/*! \brief a single PDTCH burst was received by the PHY, process it */</span><br><span style="color: hsl(0, 100%, 40%);">-int rx_pdtch_fn(struct l1sched_trx *l1t, enum trx_chan_type chan,</span><br><span style="color: hsl(0, 100%, 40%);">- uint8_t bid, const struct trx_ul_burst_ind *bi)</span><br><span style="color: hsl(0, 100%, 40%);">-{</span><br><span style="color: hsl(0, 100%, 40%);">- struct l1sched_ts *l1ts = l1sched_trx_get_ts(l1t, bi->tn);</span><br><span style="color: hsl(0, 100%, 40%);">- struct l1sched_chan_state *chan_state = &l1ts->chan_state[chan];</span><br><span style="color: hsl(0, 100%, 40%);">- sbit_t *burst, **bursts_p = &chan_state->ul_bursts;</span><br><span style="color: hsl(0, 100%, 40%);">- uint32_t *first_fn = &chan_state->ul_first_fn;</span><br><span style="color: hsl(0, 100%, 40%);">- uint8_t *mask = &chan_state->ul_mask;</span><br><span style="color: hsl(0, 100%, 40%);">- float *rssi_sum = &chan_state->rssi_sum;</span><br><span style="color: hsl(0, 100%, 40%);">- uint8_t *rssi_num = &chan_state->rssi_num;</span><br><span style="color: hsl(0, 100%, 40%);">- int32_t *toa256_sum = &chan_state->toa256_sum;</span><br><span style="color: hsl(0, 100%, 40%);">- uint8_t *toa_num = &chan_state->toa_num;</span><br><span style="color: hsl(0, 100%, 40%);">- int32_t *ci_cb_sum = &chan_state->ci_cb_sum;</span><br><span style="color: hsl(0, 100%, 40%);">- uint8_t *ci_cb_num = &chan_state->ci_cb_num;</span><br><span style="color: hsl(0, 100%, 40%);">- uint8_t l2[EGPRS_0503_MAX_BYTES];</span><br><span style="color: hsl(0, 100%, 40%);">- int n_errors = 0;</span><br><span style="color: hsl(0, 100%, 40%);">- int n_bursts_bits = 0;</span><br><span style="color: hsl(0, 100%, 40%);">- int n_bits_total = 0;</span><br><span style="color: hsl(0, 100%, 40%);">- int16_t lqual_cb;</span><br><span style="color: hsl(0, 100%, 40%);">- uint16_t ber10k;</span><br><span style="color: hsl(0, 100%, 40%);">- int rc;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- LOGL1S(DL1P, LOGL_DEBUG, l1t, bi->tn, chan, bi->fn,</span><br><span style="color: hsl(0, 100%, 40%);">- "Received PDTCH bid=%u\n", bid);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- /* allocate burst memory, if not already */</span><br><span style="color: hsl(0, 100%, 40%);">- if (!*bursts_p) {</span><br><span style="color: hsl(0, 100%, 40%);">- *bursts_p = talloc_zero_size(tall_bts_ctx,</span><br><span style="color: hsl(0, 100%, 40%);">- GSM0503_EGPRS_BURSTS_NBITS);</span><br><span style="color: hsl(0, 100%, 40%);">- if (!*bursts_p)</span><br><span style="color: hsl(0, 100%, 40%);">- return -ENOMEM;</span><br><span style="color: hsl(0, 100%, 40%);">- }</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- /* clear burst */</span><br><span style="color: hsl(0, 100%, 40%);">- if (bid == 0) {</span><br><span style="color: hsl(0, 100%, 40%);">- memset(*bursts_p, 0, GSM0503_EGPRS_BURSTS_NBITS);</span><br><span style="color: hsl(0, 100%, 40%);">- *mask = 0x0;</span><br><span style="color: hsl(0, 100%, 40%);">- *first_fn = bi->fn;</span><br><span style="color: hsl(0, 100%, 40%);">- *rssi_sum = 0;</span><br><span style="color: hsl(0, 100%, 40%);">- *rssi_num = 0;</span><br><span style="color: hsl(0, 100%, 40%);">- *toa256_sum = 0;</span><br><span style="color: hsl(0, 100%, 40%);">- *toa_num = 0;</span><br><span style="color: hsl(0, 100%, 40%);">- *ci_cb_sum = 0;</span><br><span style="color: hsl(0, 100%, 40%);">- *ci_cb_num = 0;</span><br><span style="color: hsl(0, 100%, 40%);">- }</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- /* update mask + rssi */</span><br><span style="color: hsl(0, 100%, 40%);">- *mask |= (1 << bid);</span><br><span style="color: hsl(0, 100%, 40%);">- *rssi_sum += bi->rssi;</span><br><span style="color: hsl(0, 100%, 40%);">- (*rssi_num)++;</span><br><span style="color: hsl(0, 100%, 40%);">- *toa256_sum += bi->toa256;</span><br><span style="color: hsl(0, 100%, 40%);">- (*toa_num)++;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- /* C/I: Carrier-to-Interference ratio (in centiBels) */</span><br><span style="color: hsl(0, 100%, 40%);">- if (bi->flags & TRX_BI_F_CI_CB) {</span><br><span style="color: hsl(0, 100%, 40%);">- *ci_cb_sum += bi->ci_cb;</span><br><span style="color: hsl(0, 100%, 40%);">- (*ci_cb_num)++;</span><br><span style="color: hsl(0, 100%, 40%);">- }</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- /* copy burst to buffer of 4 bursts */</span><br><span style="color: hsl(0, 100%, 40%);">- if (bi->burst_len == EGPRS_BURST_LEN) {</span><br><span style="color: hsl(0, 100%, 40%);">- burst = *bursts_p + bid * 348;</span><br><span style="color: hsl(0, 100%, 40%);">- memcpy(burst, bi->burst + 9, 174);</span><br><span style="color: hsl(0, 100%, 40%);">- memcpy(burst + 174, bi->burst + 261, 174);</span><br><span style="color: hsl(0, 100%, 40%);">- n_bursts_bits = GSM0503_EGPRS_BURSTS_NBITS;</span><br><span style="color: hsl(0, 100%, 40%);">- } else {</span><br><span style="color: hsl(0, 100%, 40%);">- burst = *bursts_p + bid * 116;</span><br><span style="color: hsl(0, 100%, 40%);">- memcpy(burst, bi->burst + 3, 58);</span><br><span style="color: hsl(0, 100%, 40%);">- memcpy(burst + 58, bi->burst + 87, 58);</span><br><span style="color: hsl(0, 100%, 40%);">- n_bursts_bits = GSM0503_GPRS_BURSTS_NBITS;</span><br><span style="color: hsl(0, 100%, 40%);">- }</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- /* wait until complete set of bursts */</span><br><span style="color: hsl(0, 100%, 40%);">- if (bid != 3)</span><br><span style="color: hsl(0, 100%, 40%);">- return 0;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- /* check for complete set of bursts */</span><br><span style="color: hsl(0, 100%, 40%);">- if ((*mask & 0xf) != 0xf) {</span><br><span style="color: hsl(0, 100%, 40%);">- LOGL1S(DL1P, LOGL_DEBUG, l1t, bi->tn, chan, bi->fn,</span><br><span style="color: hsl(0, 100%, 40%);">- "Received incomplete frame (%u/%u)\n",</span><br><span style="color: hsl(0, 100%, 40%);">- bi->fn % l1ts->mf_period, l1ts->mf_period);</span><br><span style="color: hsl(0, 100%, 40%);">- }</span><br><span style="color: hsl(0, 100%, 40%);">- *mask = 0x0;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- /*</span><br><span style="color: hsl(0, 100%, 40%);">- * Attempt to decode EGPRS bursts first. For 8-PSK EGPRS this is all we</span><br><span style="color: hsl(0, 100%, 40%);">- * do. Attempt GPRS decoding on EGPRS failure. If the burst is GPRS,</span><br><span style="color: hsl(0, 100%, 40%);">- * then we incur decoding overhead of 31 bits on the Type 3 EGPRS</span><br><span style="color: hsl(0, 100%, 40%);">- * header, which is tolerable.</span><br><span style="color: hsl(0, 100%, 40%);">- */</span><br><span style="color: hsl(0, 100%, 40%);">- rc = gsm0503_pdtch_egprs_decode(l2, *bursts_p, n_bursts_bits,</span><br><span style="color: hsl(0, 100%, 40%);">- NULL, &n_errors, &n_bits_total);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- if ((bi->burst_len == GSM_BURST_LEN) && (rc < 0)) {</span><br><span style="color: hsl(0, 100%, 40%);">- rc = gsm0503_pdtch_decode(l2, *bursts_p, NULL,</span><br><span style="color: hsl(0, 100%, 40%);">- &n_errors, &n_bits_total);</span><br><span style="color: hsl(0, 100%, 40%);">- }</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- if (rc <= 0) {</span><br><span style="color: hsl(0, 100%, 40%);">- LOGL1S(DL1P, LOGL_DEBUG, l1t, bi->tn, chan, bi->fn,</span><br><span style="color: hsl(0, 100%, 40%);">- "Received bad PDTCH (%u/%u)\n",</span><br><span style="color: hsl(0, 100%, 40%);">- bi->fn % l1ts->mf_period, l1ts->mf_period);</span><br><span style="color: hsl(0, 100%, 40%);">- return 0;</span><br><span style="color: hsl(0, 100%, 40%);">- }</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- lqual_cb = *ci_cb_num ? (*ci_cb_sum / *ci_cb_num) : 0;</span><br><span style="color: hsl(0, 100%, 40%);">- ber10k = compute_ber10k(n_bits_total, n_errors);</span><br><span style="color: hsl(0, 100%, 40%);">- return _sched_compose_ph_data_ind(l1t, bi->tn,</span><br><span style="color: hsl(0, 100%, 40%);">- *first_fn, chan, l2, rc,</span><br><span style="color: hsl(0, 100%, 40%);">- *rssi_sum / *rssi_num,</span><br><span style="color: hsl(0, 100%, 40%);">- *toa256_sum / *toa_num,</span><br><span style="color: hsl(0, 100%, 40%);">- lqual_cb, ber10k,</span><br><span style="color: hsl(0, 100%, 40%);">- PRES_INFO_BOTH);</span><br><span style="color: hsl(0, 100%, 40%);">-}</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-/*! \brief a single TCH/F burst was received by the PHY, process it */</span><br><span style="color: hsl(0, 100%, 40%);">-int rx_tchf_fn(struct l1sched_trx *l1t, enum trx_chan_type chan,</span><br><span style="color: hsl(0, 100%, 40%);">- uint8_t bid, const struct trx_ul_burst_ind *bi)</span><br><span style="color: hsl(0, 100%, 40%);">-{</span><br><span style="color: hsl(0, 100%, 40%);">- struct l1sched_ts *l1ts = l1sched_trx_get_ts(l1t, bi->tn);</span><br><span style="color: hsl(0, 100%, 40%);">- struct l1sched_chan_state *chan_state = &l1ts->chan_state[chan];</span><br><span style="color: hsl(0, 100%, 40%);">- sbit_t *burst, **bursts_p = &chan_state->ul_bursts;</span><br><span style="color: hsl(0, 100%, 40%);">- uint8_t *mask = &chan_state->ul_mask;</span><br><span style="color: hsl(0, 100%, 40%);">- uint8_t rsl_cmode = chan_state->rsl_cmode;</span><br><span style="color: hsl(0, 100%, 40%);">- uint8_t tch_mode = chan_state->tch_mode;</span><br><span style="color: hsl(0, 100%, 40%);">- uint8_t tch_data[128]; /* just to be safe */</span><br><span style="color: hsl(0, 100%, 40%);">- int rc, amr = 0;</span><br><span style="color: hsl(0, 100%, 40%);">- int n_errors = 0;</span><br><span style="color: hsl(0, 100%, 40%);">- int n_bits_total = 0;</span><br><span style="color: hsl(0, 100%, 40%);">- bool bfi_flag = false;</span><br><span style="color: hsl(0, 100%, 40%);">- struct gsm_lchan *lchan =</span><br><span style="color: hsl(0, 100%, 40%);">- get_lchan_by_chan_nr(l1t->trx, trx_chan_desc[chan].chan_nr | bi->tn);</span><br><span style="color: hsl(0, 100%, 40%);">- unsigned int fn_begin;</span><br><span style="color: hsl(0, 100%, 40%);">- uint16_t ber10k;</span><br><span style="color: hsl(0, 100%, 40%);">- uint8_t is_sub = 0;</span><br><span style="color: hsl(0, 100%, 40%);">- uint8_t ft;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- /* If handover RACH detection is turned on, treat this burst as an Access Burst.</span><br><span style="color: hsl(0, 100%, 40%);">- * Handle NOPE.ind as usually to ensure proper Uplink measurement reporting. */</span><br><span style="color: hsl(0, 100%, 40%);">- if (chan_state->ho_rach_detect == 1 && ~bi->flags & TRX_BI_F_NOPE_IND)</span><br><span style="color: hsl(0, 100%, 40%);">- return rx_rach_fn(l1t, chan, bid, bi);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- LOGL1S(DL1P, LOGL_DEBUG, l1t, bi->tn, chan, bi->fn,</span><br><span style="color: hsl(0, 100%, 40%);">- "Received TCH/F, bid=%u\n", bid);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- /* allocate burst memory, if not already */</span><br><span style="color: hsl(0, 100%, 40%);">- if (!*bursts_p) {</span><br><span style="color: hsl(0, 100%, 40%);">- *bursts_p = talloc_zero_size(tall_bts_ctx, 928);</span><br><span style="color: hsl(0, 100%, 40%);">- if (!*bursts_p)</span><br><span style="color: hsl(0, 100%, 40%);">- return -ENOMEM;</span><br><span style="color: hsl(0, 100%, 40%);">- }</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- /* clear burst */</span><br><span style="color: hsl(0, 100%, 40%);">- if (bid == 0) {</span><br><span style="color: hsl(0, 100%, 40%);">- memset(*bursts_p + 464, 0, 464);</span><br><span style="color: hsl(0, 100%, 40%);">- *mask = 0x0;</span><br><span style="color: hsl(0, 100%, 40%);">- }</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- /* update mask */</span><br><span style="color: hsl(0, 100%, 40%);">- *mask |= (1 << bid);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- /* copy burst to end of buffer of 8 bursts */</span><br><span style="color: hsl(0, 100%, 40%);">- burst = *bursts_p + bid * 116 + 464;</span><br><span style="color: hsl(0, 100%, 40%);">- if (bi->burst_len > 0) {</span><br><span style="color: hsl(0, 100%, 40%);">- memcpy(burst, bi->burst + 3, 58);</span><br><span style="color: hsl(0, 100%, 40%);">- memcpy(burst + 58, bi->burst + 87, 58);</span><br><span style="color: hsl(0, 100%, 40%);">- } else</span><br><span style="color: hsl(0, 100%, 40%);">- memset(burst, 0, 116);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- /* wait until complete set of bursts */</span><br><span style="color: hsl(0, 100%, 40%);">- if (bid != 3)</span><br><span style="color: hsl(0, 100%, 40%);">- return 0;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- /* check for complete set of bursts */</span><br><span style="color: hsl(0, 100%, 40%);">- if ((*mask & 0xf) != 0xf) {</span><br><span style="color: hsl(0, 100%, 40%);">- LOGL1S(DL1P, LOGL_NOTICE, l1t, bi->tn, chan, bi->fn,</span><br><span style="color: hsl(0, 100%, 40%);">- "Received incomplete frame (%u/%u)\n",</span><br><span style="color: hsl(0, 100%, 40%);">- bi->fn % l1ts->mf_period, l1ts->mf_period);</span><br><span style="color: hsl(0, 100%, 40%);">- }</span><br><span style="color: hsl(0, 100%, 40%);">- *mask = 0x0;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- /* decode</span><br><span style="color: hsl(0, 100%, 40%);">- * also shift buffer by 4 bursts for interleaving */</span><br><span style="color: hsl(0, 100%, 40%);">- switch ((rsl_cmode != RSL_CMOD_SPD_SPEECH) ? GSM48_CMODE_SPEECH_V1</span><br><span style="color: hsl(0, 100%, 40%);">- : tch_mode) {</span><br><span style="color: hsl(0, 100%, 40%);">- case GSM48_CMODE_SPEECH_V1: /* FR */</span><br><span style="color: hsl(0, 100%, 40%);">- rc = gsm0503_tch_fr_decode(tch_data, *bursts_p, 1, 0, &n_errors, &n_bits_total);</span><br><span style="color: hsl(0, 100%, 40%);">- if (rc >= 0)</span><br><span style="color: hsl(0, 100%, 40%);">- lchan_set_marker(osmo_fr_check_sid(tch_data, rc), lchan); /* DTXu */</span><br><span style="color: hsl(0, 100%, 40%);">- break;</span><br><span style="color: hsl(0, 100%, 40%);">- case GSM48_CMODE_SPEECH_EFR: /* EFR */</span><br><span style="color: hsl(0, 100%, 40%);">- rc = gsm0503_tch_fr_decode(tch_data, *bursts_p, 1, 1, &n_errors, &n_bits_total);</span><br><span style="color: hsl(0, 100%, 40%);">- break;</span><br><span style="color: hsl(0, 100%, 40%);">- case GSM48_CMODE_SPEECH_AMR: /* AMR */</span><br><span style="color: hsl(0, 100%, 40%);">- /* the first FN 0,8,17 defines that CMI is included in frame,</span><br><span style="color: hsl(0, 100%, 40%);">- * the first FN 4,13,21 defines that CMR is included in frame.</span><br><span style="color: hsl(0, 100%, 40%);">- * NOTE: A frame ends 7 FN after start.</span><br><span style="color: hsl(0, 100%, 40%);">- */</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- /* The AFS_ONSET frame itself does not result into an RTP frame</span><br><span style="color: hsl(0, 100%, 40%);">- * since it only contains a recognition pattern that marks the</span><br><span style="color: hsl(0, 100%, 40%);">- * end of the DTX interval. To mark the end of the DTX interval</span><br><span style="color: hsl(0, 100%, 40%);">- * in the RTP stream as well, the voice frame after the</span><br><span style="color: hsl(0, 100%, 40%);">- * AFS_ONSET frame is used. */</span><br><span style="color: hsl(0, 100%, 40%);">- if (chan_state->amr_last_dtx == AFS_ONSET)</span><br><span style="color: hsl(0, 100%, 40%);">- lchan_set_marker(false, lchan);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- /* we store tch_data + 2 header bytes, the amr variable set to</span><br><span style="color: hsl(0, 100%, 40%);">- * 2 will allow us to skip the first 2 bytes in case we did</span><br><span style="color: hsl(0, 100%, 40%);">- * receive an FACCH frame instead of a voice frame (we do not</span><br><span style="color: hsl(0, 100%, 40%);">- * know this before we actually decode the frame) */</span><br><span style="color: hsl(0, 100%, 40%);">- amr = 2;</span><br><span style="color: hsl(0, 100%, 40%);">- rc = gsm0503_tch_afs_decode_dtx(tch_data + amr, *bursts_p,</span><br><span style="color: hsl(0, 100%, 40%);">- (((bi->fn + 26 - 7) % 26) >> 2) & 1, chan_state->codec,</span><br><span style="color: hsl(0, 100%, 40%);">- chan_state->codecs, &chan_state->ul_ft,</span><br><span style="color: hsl(0, 100%, 40%);">- &chan_state->ul_cmr, &n_errors, &n_bits_total, &chan_state->amr_last_dtx);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- /* Tag all frames that are not regular AMR voice frames as</span><br><span style="color: hsl(0, 100%, 40%);">- * SUB-Frames */</span><br><span style="color: hsl(0, 100%, 40%);">- if (chan_state->amr_last_dtx != AMR_OTHER) {</span><br><span style="color: hsl(0, 100%, 40%);">- LOGL1S(DL1P, LOGL_DEBUG, l1t, bi->tn, chan, bi->fn,</span><br><span style="color: hsl(0, 100%, 40%);">- "Received AMR SID frame: %s\n",</span><br><span style="color: hsl(0, 100%, 40%);">- gsm0503_amr_dtx_frame_name(chan_state->amr_last_dtx));</span><br><span style="color: hsl(0, 100%, 40%);">- is_sub = 1;</span><br><span style="color: hsl(0, 100%, 40%);">- }</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- /* The occurrence of the following frames indicates that we</span><br><span style="color: hsl(0, 100%, 40%);">- * are either at the beginning or in the middle of a talk</span><br><span style="color: hsl(0, 100%, 40%);">- * spurt. We update the SID status accordingly, but we do</span><br><span style="color: hsl(0, 100%, 40%);">- * not want the marker to be set, since this must only</span><br><span style="color: hsl(0, 100%, 40%);">- * happen when the talk spurt is over (see above) */</span><br><span style="color: hsl(0, 100%, 40%);">- switch (chan_state->amr_last_dtx) {</span><br><span style="color: hsl(0, 100%, 40%);">- case AFS_SID_FIRST:</span><br><span style="color: hsl(0, 100%, 40%);">- case AFS_SID_UPDATE:</span><br><span style="color: hsl(0, 100%, 40%);">- case AFS_SID_UPDATE_CN:</span><br><span style="color: hsl(0, 100%, 40%);">- lchan_set_marker(true, lchan);</span><br><span style="color: hsl(0, 100%, 40%);">- lchan->rtp_tx_marker = false;</span><br><span style="color: hsl(0, 100%, 40%);">- break;</span><br><span style="color: hsl(0, 100%, 40%);">- }</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- if (rc)</span><br><span style="color: hsl(0, 100%, 40%);">- trx_loop_amr_input(l1t,</span><br><span style="color: hsl(0, 100%, 40%);">- trx_chan_desc[chan].chan_nr | bi->tn, chan_state,</span><br><span style="color: hsl(0, 100%, 40%);">- n_errors, n_bits_total);</span><br><span style="color: hsl(0, 100%, 40%);">- /* only good speech frames get rtp header */</span><br><span style="color: hsl(0, 100%, 40%);">- if (rc != GSM_MACBLOCK_LEN && rc >= 4) {</span><br><span style="color: hsl(0, 100%, 40%);">- if (chan_state->amr_last_dtx == AMR_OTHER) {</span><br><span style="color: hsl(0, 100%, 40%);">- ft = chan_state->codec[chan_state->ul_cmr];</span><br><span style="color: hsl(0, 100%, 40%);">- } else {</span><br><span style="color: hsl(0, 100%, 40%);">- /* SID frames will always get Frame Type Index 8 (AMR_SID) */</span><br><span style="color: hsl(0, 100%, 40%);">- ft = AMR_SID;</span><br><span style="color: hsl(0, 100%, 40%);">- }</span><br><span style="color: hsl(0, 100%, 40%);">- rc = osmo_amr_rtp_enc(tch_data,</span><br><span style="color: hsl(0, 100%, 40%);">- chan_state->codec[chan_state->ul_cmr],</span><br><span style="color: hsl(0, 100%, 40%);">- ft, AMR_GOOD);</span><br><span style="color: hsl(0, 100%, 40%);">- }</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- break;</span><br><span style="color: hsl(0, 100%, 40%);">- default:</span><br><span style="color: hsl(0, 100%, 40%);">- LOGL1S(DL1P, LOGL_ERROR, l1t, bi->tn, chan, bi->fn,</span><br><span style="color: hsl(0, 100%, 40%);">- "TCH mode %u invalid, please fix!\n",</span><br><span style="color: hsl(0, 100%, 40%);">- tch_mode);</span><br><span style="color: hsl(0, 100%, 40%);">- return -EINVAL;</span><br><span style="color: hsl(0, 100%, 40%);">- }</span><br><span style="color: hsl(0, 100%, 40%);">- memcpy(*bursts_p, *bursts_p + 464, 464);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- /* Check if the frame is bad */</span><br><span style="color: hsl(0, 100%, 40%);">- if (rc < 0) {</span><br><span style="color: hsl(0, 100%, 40%);">- LOGL1S(DL1P, LOGL_NOTICE, l1t, bi->tn, chan, bi->fn,</span><br><span style="color: hsl(0, 100%, 40%);">- "Received bad data (%u/%u)\n",</span><br><span style="color: hsl(0, 100%, 40%);">- bi->fn % l1ts->mf_period, l1ts->mf_period);</span><br><span style="color: hsl(0, 100%, 40%);">- bfi_flag = true;</span><br><span style="color: hsl(0, 100%, 40%);">- } else if (rc < 4) {</span><br><span style="color: hsl(0, 100%, 40%);">- LOGL1S(DL1P, LOGL_NOTICE, l1t, bi->tn, chan, bi->fn,</span><br><span style="color: hsl(0, 100%, 40%);">- "Received bad data (%u/%u) with invalid codec mode %d\n",</span><br><span style="color: hsl(0, 100%, 40%);">- bi->fn % l1ts->mf_period, l1ts->mf_period, rc);</span><br><span style="color: hsl(0, 100%, 40%);">- bfi_flag = true;</span><br><span style="color: hsl(0, 100%, 40%);">- }</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- if (rc != GSM_MACBLOCK_LEN && lchan->ecu_state)</span><br><span style="color: hsl(0, 100%, 40%);">- osmo_ecu_frame_in(lchan->ecu_state, bfi_flag, tch_data, rc);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- ber10k = compute_ber10k(n_bits_total, n_errors);</span><br><span style="color: hsl(0, 100%, 40%);">- if (bfi_flag)</span><br><span style="color: hsl(0, 100%, 40%);">- goto bfi;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- /* FACCH */</span><br><span style="color: hsl(0, 100%, 40%);">- if (rc == GSM_MACBLOCK_LEN) {</span><br><span style="color: hsl(0, 100%, 40%);">- fn_begin = gsm0502_fn_remap(bi->fn, FN_REMAP_FACCH_F);</span><br><span style="color: hsl(0, 100%, 40%);">- _sched_compose_ph_data_ind(l1t, bi->tn, fn_begin, chan,</span><br><span style="color: hsl(0, 100%, 40%);">- tch_data + amr, GSM_MACBLOCK_LEN,</span><br><span style="color: hsl(0, 100%, 40%);">- /* FIXME: AVG RSSI and ToA256 */</span><br><span style="color: hsl(0, 100%, 40%);">- bi->rssi, bi->toa256,</span><br><span style="color: hsl(0, 100%, 40%);">- 0 /* FIXME: AVG C/I */,</span><br><span style="color: hsl(0, 100%, 40%);">- ber10k, PRES_INFO_UNKNOWN);</span><br><span style="color: hsl(0, 100%, 40%);">-bfi:</span><br><span style="color: hsl(0, 100%, 40%);">- if (rsl_cmode == RSL_CMOD_SPD_SPEECH) {</span><br><span style="color: hsl(0, 100%, 40%);">- /* indicate bad frame */</span><br><span style="color: hsl(0, 100%, 40%);">- if (lchan->tch.dtx.ul_sid) {</span><br><span style="color: hsl(0, 100%, 40%);">- /* DTXu: pause in progress. Push empty payload to upper layers */</span><br><span style="color: hsl(0, 100%, 40%);">- rc = 0;</span><br><span style="color: hsl(0, 100%, 40%);">- goto compose_l1sap;</span><br><span style="color: hsl(0, 100%, 40%);">- }</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- /* If there is an ECU active on this channel, use its output */</span><br><span style="color: hsl(0, 100%, 40%);">- if (lchan->ecu_state) {</span><br><span style="color: hsl(0, 100%, 40%);">- rc = osmo_ecu_frame_out(lchan->ecu_state, tch_data);</span><br><span style="color: hsl(0, 100%, 40%);">- if (rc >= 0) /* Otherwise we send a BFI */</span><br><span style="color: hsl(0, 100%, 40%);">- goto compose_l1sap;</span><br><span style="color: hsl(0, 100%, 40%);">- }</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- switch (tch_mode) {</span><br><span style="color: hsl(0, 100%, 40%);">- case GSM48_CMODE_SPEECH_V1: /* FR */</span><br><span style="color: hsl(0, 100%, 40%);">- memset(tch_data, 0, GSM_FR_BYTES);</span><br><span style="color: hsl(0, 100%, 40%);">- tch_data[0] = 0xd0;</span><br><span style="color: hsl(0, 100%, 40%);">- rc = GSM_FR_BYTES;</span><br><span style="color: hsl(0, 100%, 40%);">- break;</span><br><span style="color: hsl(0, 100%, 40%);">- case GSM48_CMODE_SPEECH_EFR: /* EFR */</span><br><span style="color: hsl(0, 100%, 40%);">- memset(tch_data, 0, GSM_EFR_BYTES);</span><br><span style="color: hsl(0, 100%, 40%);">- tch_data[0] = 0xc0;</span><br><span style="color: hsl(0, 100%, 40%);">- rc = GSM_EFR_BYTES;</span><br><span style="color: hsl(0, 100%, 40%);">- break;</span><br><span style="color: hsl(0, 100%, 40%);">- case GSM48_CMODE_SPEECH_AMR: /* AMR */</span><br><span style="color: hsl(0, 100%, 40%);">- rc = osmo_amr_rtp_enc(tch_data,</span><br><span style="color: hsl(0, 100%, 40%);">- chan_state->codec[chan_state->dl_cmr],</span><br><span style="color: hsl(0, 100%, 40%);">- chan_state->codec[chan_state->dl_ft],</span><br><span style="color: hsl(0, 100%, 40%);">- AMR_BAD);</span><br><span style="color: hsl(0, 100%, 40%);">- if (rc < 2) {</span><br><span style="color: hsl(0, 100%, 40%);">- LOGL1S(DL1P, LOGL_ERROR, l1t, bi->tn, chan, bi->fn,</span><br><span style="color: hsl(0, 100%, 40%);">- "Failed to encode AMR_BAD frame (rc=%d), "</span><br><span style="color: hsl(0, 100%, 40%);">- "not sending BFI\n", rc);</span><br><span style="color: hsl(0, 100%, 40%);">- return -EINVAL;</span><br><span style="color: hsl(0, 100%, 40%);">- }</span><br><span style="color: hsl(0, 100%, 40%);">- memset(tch_data + 2, 0, rc - 2);</span><br><span style="color: hsl(0, 100%, 40%);">- break;</span><br><span style="color: hsl(0, 100%, 40%);">- default:</span><br><span style="color: hsl(0, 100%, 40%);">- LOGL1S(DL1P, LOGL_ERROR, l1t, bi->tn, chan, bi->fn,</span><br><span style="color: hsl(0, 100%, 40%);">- "TCH mode %u invalid, please fix!\n", tch_mode);</span><br><span style="color: hsl(0, 100%, 40%);">- return -EINVAL;</span><br><span style="color: hsl(0, 100%, 40%);">- }</span><br><span style="color: hsl(0, 100%, 40%);">- }</span><br><span style="color: hsl(0, 100%, 40%);">- }</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- if (rsl_cmode != RSL_CMOD_SPD_SPEECH)</span><br><span style="color: hsl(0, 100%, 40%);">- return 0;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- /* TCH or BFI */</span><br><span style="color: hsl(0, 100%, 40%);">-compose_l1sap:</span><br><span style="color: hsl(0, 100%, 40%);">- fn_begin = gsm0502_fn_remap(bi->fn, FN_REMAP_TCH_F);</span><br><span style="color: hsl(0, 100%, 40%);">- return _sched_compose_tch_ind(l1t, bi->tn, fn_begin, chan,</span><br><span style="color: hsl(0, 100%, 40%);">- tch_data, rc, bi->toa256, ber10k, bi->rssi, is_sub);</span><br><span style="color: hsl(0, 100%, 40%);">-}</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-/*! \brief a single TCH/H burst was received by the PHY, process it */</span><br><span style="color: hsl(0, 100%, 40%);">-int rx_tchh_fn(struct l1sched_trx *l1t, enum trx_chan_type chan,</span><br><span style="color: hsl(0, 100%, 40%);">- uint8_t bid, const struct trx_ul_burst_ind *bi)</span><br><span style="color: hsl(0, 100%, 40%);">-{</span><br><span style="color: hsl(0, 100%, 40%);">- struct l1sched_ts *l1ts = l1sched_trx_get_ts(l1t, bi->tn);</span><br><span style="color: hsl(0, 100%, 40%);">- struct l1sched_chan_state *chan_state = &l1ts->chan_state[chan];</span><br><span style="color: hsl(0, 100%, 40%);">- sbit_t *burst, **bursts_p = &chan_state->ul_bursts;</span><br><span style="color: hsl(0, 100%, 40%);">- uint8_t *mask = &chan_state->ul_mask;</span><br><span style="color: hsl(0, 100%, 40%);">- uint8_t rsl_cmode = chan_state->rsl_cmode;</span><br><span style="color: hsl(0, 100%, 40%);">- uint8_t tch_mode = chan_state->tch_mode;</span><br><span style="color: hsl(0, 100%, 40%);">- uint8_t tch_data[128]; /* just to be safe */</span><br><span style="color: hsl(0, 100%, 40%);">- int rc, amr = 0;</span><br><span style="color: hsl(0, 100%, 40%);">- int n_errors = 0;</span><br><span style="color: hsl(0, 100%, 40%);">- int n_bits_total = 0;</span><br><span style="color: hsl(0, 100%, 40%);">- bool bfi_flag = false;</span><br><span style="color: hsl(0, 100%, 40%);">- struct gsm_lchan *lchan =</span><br><span style="color: hsl(0, 100%, 40%);">- get_lchan_by_chan_nr(l1t->trx, trx_chan_desc[chan].chan_nr | bi->tn);</span><br><span style="color: hsl(0, 100%, 40%);">- /* Note on FN-10: If we are at FN 10, we decoded an even aligned</span><br><span style="color: hsl(0, 100%, 40%);">- * TCH/FACCH frame, because our burst buffer carries 6 bursts.</span><br><span style="color: hsl(0, 100%, 40%);">- * Even FN ending at: 10,11,19,20,2,3</span><br><span style="color: hsl(0, 100%, 40%);">- */</span><br><span style="color: hsl(0, 100%, 40%);">- int fn_is_odd = (((bi->fn + 26 - 10) % 26) >> 2) & 1;</span><br><span style="color: hsl(0, 100%, 40%);">- unsigned int fn_begin;</span><br><span style="color: hsl(0, 100%, 40%);">- uint16_t ber10k;</span><br><span style="color: hsl(0, 100%, 40%);">- uint8_t is_sub = 0;</span><br><span style="color: hsl(0, 100%, 40%);">- uint8_t ft;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- /* If handover RACH detection is turned on, treat this burst as an Access Burst.</span><br><span style="color: hsl(0, 100%, 40%);">- * Handle NOPE.ind as usually to ensure proper Uplink measurement reporting. */</span><br><span style="color: hsl(0, 100%, 40%);">- if (chan_state->ho_rach_detect == 1 && ~bi->flags & TRX_BI_F_NOPE_IND)</span><br><span style="color: hsl(0, 100%, 40%);">- return rx_rach_fn(l1t, chan, bid, bi);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- LOGL1S(DL1P, LOGL_DEBUG, l1t, bi->tn, chan, bi->fn,</span><br><span style="color: hsl(0, 100%, 40%);">- "Received TCH/H, bid=%u\n", bid);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- /* allocate burst memory, if not already */</span><br><span style="color: hsl(0, 100%, 40%);">- if (!*bursts_p) {</span><br><span style="color: hsl(0, 100%, 40%);">- *bursts_p = talloc_zero_size(tall_bts_ctx, 696);</span><br><span style="color: hsl(0, 100%, 40%);">- if (!*bursts_p)</span><br><span style="color: hsl(0, 100%, 40%);">- return -ENOMEM;</span><br><span style="color: hsl(0, 100%, 40%);">- }</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- /* clear burst */</span><br><span style="color: hsl(0, 100%, 40%);">- if (bid == 0) {</span><br><span style="color: hsl(0, 100%, 40%);">- memset(*bursts_p + 464, 0, 232);</span><br><span style="color: hsl(0, 100%, 40%);">- *mask = 0x0;</span><br><span style="color: hsl(0, 100%, 40%);">- }</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- /* update mask */</span><br><span style="color: hsl(0, 100%, 40%);">- *mask |= (1 << bid);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- /* copy burst to end of buffer of 6 bursts */</span><br><span style="color: hsl(0, 100%, 40%);">- burst = *bursts_p + bid * 116 + 464;</span><br><span style="color: hsl(0, 100%, 40%);">- if (bi->burst_len > 0) {</span><br><span style="color: hsl(0, 100%, 40%);">- memcpy(burst, bi->burst + 3, 58);</span><br><span style="color: hsl(0, 100%, 40%);">- memcpy(burst + 58, bi->burst + 87, 58);</span><br><span style="color: hsl(0, 100%, 40%);">- } else</span><br><span style="color: hsl(0, 100%, 40%);">- memset(burst, 0, 116);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- /* wait until complete set of bursts */</span><br><span style="color: hsl(0, 100%, 40%);">- if (bid != 1)</span><br><span style="color: hsl(0, 100%, 40%);">- return 0;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- /* check for complete set of bursts */</span><br><span style="color: hsl(0, 100%, 40%);">- if ((*mask & 0x3) != 0x3) {</span><br><span style="color: hsl(0, 100%, 40%);">- LOGL1S(DL1P, LOGL_NOTICE, l1t, bi->tn, chan, bi->fn,</span><br><span style="color: hsl(0, 100%, 40%);">- "Received incomplete frame (%u/%u)\n",</span><br><span style="color: hsl(0, 100%, 40%);">- bi->fn % l1ts->mf_period, l1ts->mf_period);</span><br><span style="color: hsl(0, 100%, 40%);">- }</span><br><span style="color: hsl(0, 100%, 40%);">- *mask = 0x0;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- /* skip second of two TCH frames of FACCH was received */</span><br><span style="color: hsl(0, 100%, 40%);">- if (chan_state->ul_ongoing_facch) {</span><br><span style="color: hsl(0, 100%, 40%);">- chan_state->ul_ongoing_facch = 0;</span><br><span style="color: hsl(0, 100%, 40%);">- memcpy(*bursts_p, *bursts_p + 232, 232);</span><br><span style="color: hsl(0, 100%, 40%);">- memcpy(*bursts_p + 232, *bursts_p + 464, 232);</span><br><span style="color: hsl(0, 100%, 40%);">- ber10k = 0;</span><br><span style="color: hsl(0, 100%, 40%);">- goto bfi;</span><br><span style="color: hsl(0, 100%, 40%);">- }</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- /* decode</span><br><span style="color: hsl(0, 100%, 40%);">- * also shift buffer by 4 bursts for interleaving */</span><br><span style="color: hsl(0, 100%, 40%);">- switch ((rsl_cmode != RSL_CMOD_SPD_SPEECH) ? GSM48_CMODE_SPEECH_V1</span><br><span style="color: hsl(0, 100%, 40%);">- : tch_mode) {</span><br><span style="color: hsl(0, 100%, 40%);">- case GSM48_CMODE_SPEECH_V1: /* HR or signalling */</span><br><span style="color: hsl(0, 100%, 40%);">- /* Note on FN-10: If we are at FN 10, we decoded an even aligned</span><br><span style="color: hsl(0, 100%, 40%);">- * TCH/FACCH frame, because our burst buffer carries 6 bursts.</span><br><span style="color: hsl(0, 100%, 40%);">- * Even FN ending at: 10,11,19,20,2,3</span><br><span style="color: hsl(0, 100%, 40%);">- */</span><br><span style="color: hsl(0, 100%, 40%);">- rc = gsm0503_tch_hr_decode(tch_data, *bursts_p,</span><br><span style="color: hsl(0, 100%, 40%);">- fn_is_odd, &n_errors, &n_bits_total);</span><br><span style="color: hsl(0, 100%, 40%);">- if (rc >= 0) /* DTXu */</span><br><span style="color: hsl(0, 100%, 40%);">- lchan_set_marker(osmo_hr_check_sid(tch_data, rc), lchan);</span><br><span style="color: hsl(0, 100%, 40%);">- break;</span><br><span style="color: hsl(0, 100%, 40%);">- case GSM48_CMODE_SPEECH_AMR: /* AMR */</span><br><span style="color: hsl(0, 100%, 40%);">- /* the first FN 0,8,17 or 1,9,18 defines that CMI is included</span><br><span style="color: hsl(0, 100%, 40%);">- * in frame, the first FN 4,13,21 or 5,14,22 defines that CMR</span><br><span style="color: hsl(0, 100%, 40%);">- * is included in frame.</span><br><span style="color: hsl(0, 100%, 40%);">- */</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- /* See comment in function rx_tchf_fn() */</span><br><span style="color: hsl(0, 100%, 40%);">- switch (chan_state->amr_last_dtx) {</span><br><span style="color: hsl(0, 100%, 40%);">- case AHS_ONSET:</span><br><span style="color: hsl(0, 100%, 40%);">- case AHS_SID_FIRST_INH:</span><br><span style="color: hsl(0, 100%, 40%);">- case AHS_SID_UPDATE_INH:</span><br><span style="color: hsl(0, 100%, 40%);">- lchan_set_marker(false, lchan);</span><br><span style="color: hsl(0, 100%, 40%);">- break;</span><br><span style="color: hsl(0, 100%, 40%);">- }</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- /* See comment in function rx_tchf_fn() */</span><br><span style="color: hsl(0, 100%, 40%);">- amr = 2;</span><br><span style="color: hsl(0, 100%, 40%);">- rc = gsm0503_tch_ahs_decode_dtx(tch_data + amr, *bursts_p,</span><br><span style="color: hsl(0, 100%, 40%);">- fn_is_odd, fn_is_odd, chan_state->codec,</span><br><span style="color: hsl(0, 100%, 40%);">- chan_state->codecs, &chan_state->ul_ft,</span><br><span style="color: hsl(0, 100%, 40%);">- &chan_state->ul_cmr, &n_errors, &n_bits_total, &chan_state->amr_last_dtx);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- /* Tag all frames that are not regular AMR voice frames</span><br><span style="color: hsl(0, 100%, 40%);">- as SUB-Frames */</span><br><span style="color: hsl(0, 100%, 40%);">- if (chan_state->amr_last_dtx != AMR_OTHER) {</span><br><span style="color: hsl(0, 100%, 40%);">- LOGL1S(DL1P, LOGL_DEBUG, l1t, bi->tn, chan, bi->fn,</span><br><span style="color: hsl(0, 100%, 40%);">- "Received AMR SID frame: %s\n",</span><br><span style="color: hsl(0, 100%, 40%);">- gsm0503_amr_dtx_frame_name(chan_state->amr_last_dtx));</span><br><span style="color: hsl(0, 100%, 40%);">- is_sub = 1;</span><br><span style="color: hsl(0, 100%, 40%);">- }</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- /* See comment in function rx_tchf_fn() */</span><br><span style="color: hsl(0, 100%, 40%);">- switch (chan_state->amr_last_dtx) {</span><br><span style="color: hsl(0, 100%, 40%);">- case AHS_SID_FIRST_P1:</span><br><span style="color: hsl(0, 100%, 40%);">- case AHS_SID_FIRST_P2:</span><br><span style="color: hsl(0, 100%, 40%);">- case AHS_SID_UPDATE:</span><br><span style="color: hsl(0, 100%, 40%);">- case AHS_SID_UPDATE_CN:</span><br><span style="color: hsl(0, 100%, 40%);">- lchan_set_marker(true, lchan);</span><br><span style="color: hsl(0, 100%, 40%);">- lchan->rtp_tx_marker = false;</span><br><span style="color: hsl(0, 100%, 40%);">- break;</span><br><span style="color: hsl(0, 100%, 40%);">- }</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- if (rc)</span><br><span style="color: hsl(0, 100%, 40%);">- trx_loop_amr_input(l1t,</span><br><span style="color: hsl(0, 100%, 40%);">- trx_chan_desc[chan].chan_nr | bi->tn, chan_state,</span><br><span style="color: hsl(0, 100%, 40%);">- n_errors, n_bits_total);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- /* only good speech frames get rtp header */</span><br><span style="color: hsl(0, 100%, 40%);">- if (rc != GSM_MACBLOCK_LEN && rc >= 4) {</span><br><span style="color: hsl(0, 100%, 40%);">- if (chan_state->amr_last_dtx == AMR_OTHER) {</span><br><span style="color: hsl(0, 100%, 40%);">- ft = chan_state->codec[chan_state->ul_cmr];</span><br><span style="color: hsl(0, 100%, 40%);">- } else {</span><br><span style="color: hsl(0, 100%, 40%);">- /* SID frames will always get Frame Type Index 8 (AMR_SID) */</span><br><span style="color: hsl(0, 100%, 40%);">- ft = AMR_SID;</span><br><span style="color: hsl(0, 100%, 40%);">- }</span><br><span style="color: hsl(0, 100%, 40%);">- rc = osmo_amr_rtp_enc(tch_data,</span><br><span style="color: hsl(0, 100%, 40%);">- chan_state->codec[chan_state->ul_cmr],</span><br><span style="color: hsl(0, 100%, 40%);">- ft, AMR_GOOD);</span><br><span style="color: hsl(0, 100%, 40%);">- }</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- break;</span><br><span style="color: hsl(0, 100%, 40%);">- default:</span><br><span style="color: hsl(0, 100%, 40%);">- LOGL1S(DL1P, LOGL_ERROR, l1t, bi->tn, chan, bi->fn,</span><br><span style="color: hsl(0, 100%, 40%);">- "TCH mode %u invalid, please fix!\n",</span><br><span style="color: hsl(0, 100%, 40%);">- tch_mode);</span><br><span style="color: hsl(0, 100%, 40%);">- return -EINVAL;</span><br><span style="color: hsl(0, 100%, 40%);">- }</span><br><span style="color: hsl(0, 100%, 40%);">- memcpy(*bursts_p, *bursts_p + 232, 232);</span><br><span style="color: hsl(0, 100%, 40%);">- memcpy(*bursts_p + 232, *bursts_p + 464, 232);</span><br><span style="color: hsl(0, 100%, 40%);">- ber10k = compute_ber10k(n_bits_total, n_errors);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- /* Check if the frame is bad */</span><br><span style="color: hsl(0, 100%, 40%);">- if (rc < 0) {</span><br><span style="color: hsl(0, 100%, 40%);">- LOGL1S(DL1P, LOGL_NOTICE, l1t, bi->tn, chan, bi->fn,</span><br><span style="color: hsl(0, 100%, 40%);">- "Received bad data (%u/%u)\n",</span><br><span style="color: hsl(0, 100%, 40%);">- bi->fn % l1ts->mf_period, l1ts->mf_period);</span><br><span style="color: hsl(0, 100%, 40%);">- bfi_flag = true;</span><br><span style="color: hsl(0, 100%, 40%);">- } else if (rc < 4) {</span><br><span style="color: hsl(0, 100%, 40%);">- LOGL1S(DL1P, LOGL_NOTICE, l1t, bi->tn, chan, bi->fn,</span><br><span style="color: hsl(0, 100%, 40%);">- "Received bad data (%u/%u) with invalid codec mode %d\n",</span><br><span style="color: hsl(0, 100%, 40%);">- bi->fn % l1ts->mf_period, l1ts->mf_period, rc);</span><br><span style="color: hsl(0, 100%, 40%);">- bfi_flag = true;</span><br><span style="color: hsl(0, 100%, 40%);">- }</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- if (rc != GSM_MACBLOCK_LEN && lchan->ecu_state)</span><br><span style="color: hsl(0, 100%, 40%);">- osmo_ecu_frame_in(lchan->ecu_state, bfi_flag, tch_data, rc);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- if (bfi_flag)</span><br><span style="color: hsl(0, 100%, 40%);">- goto bfi;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- /* FACCH */</span><br><span style="color: hsl(0, 100%, 40%);">- if (rc == GSM_MACBLOCK_LEN) {</span><br><span style="color: hsl(0, 100%, 40%);">- chan_state->ul_ongoing_facch = 1;</span><br><span style="color: hsl(0, 100%, 40%);">- uint16_t ber10k = compute_ber10k(n_bits_total, n_errors);</span><br><span style="color: hsl(0, 100%, 40%);">- if (lchan->nr == 0)</span><br><span style="color: hsl(0, 100%, 40%);">- fn_begin = gsm0502_fn_remap(bi->fn, FN_REMAP_FACCH_H0);</span><br><span style="color: hsl(0, 100%, 40%);">- else</span><br><span style="color: hsl(0, 100%, 40%);">- fn_begin = gsm0502_fn_remap(bi->fn, FN_REMAP_FACCH_H1);</span><br><span style="color: hsl(0, 100%, 40%);">- _sched_compose_ph_data_ind(l1t, bi->tn, fn_begin, chan,</span><br><span style="color: hsl(0, 100%, 40%);">- tch_data + amr, GSM_MACBLOCK_LEN,</span><br><span style="color: hsl(0, 100%, 40%);">- /* FIXME: AVG both RSSI and ToA */</span><br><span style="color: hsl(0, 100%, 40%);">- bi->rssi, bi->toa256,</span><br><span style="color: hsl(0, 100%, 40%);">- 0 /* FIXME: AVG C/I */,</span><br><span style="color: hsl(0, 100%, 40%);">- ber10k, PRES_INFO_UNKNOWN);</span><br><span style="color: hsl(0, 100%, 40%);">-bfi:</span><br><span style="color: hsl(0, 100%, 40%);">- /* FIXME: a FACCH/H frame replaces two speech frames,</span><br><span style="color: hsl(0, 100%, 40%);">- * so we actually need to send two bad frame indications! */</span><br><span style="color: hsl(0, 100%, 40%);">- if (rsl_cmode == RSL_CMOD_SPD_SPEECH) {</span><br><span style="color: hsl(0, 100%, 40%);">- /* indicate bad frame */</span><br><span style="color: hsl(0, 100%, 40%);">- if (lchan->tch.dtx.ul_sid) {</span><br><span style="color: hsl(0, 100%, 40%);">- /* DTXu: pause in progress. Push empty payload to upper layers */</span><br><span style="color: hsl(0, 100%, 40%);">- rc = 0;</span><br><span style="color: hsl(0, 100%, 40%);">- goto compose_l1sap;</span><br><span style="color: hsl(0, 100%, 40%);">- }</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- /* If there is an ECU active on this channel, use its output */</span><br><span style="color: hsl(0, 100%, 40%);">- if (lchan->ecu_state) {</span><br><span style="color: hsl(0, 100%, 40%);">- rc = osmo_ecu_frame_out(lchan->ecu_state, tch_data);</span><br><span style="color: hsl(0, 100%, 40%);">- if (rc >= 0) /* Otherwise we send a BFI */</span><br><span style="color: hsl(0, 100%, 40%);">- goto compose_l1sap;</span><br><span style="color: hsl(0, 100%, 40%);">- }</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- switch (tch_mode) {</span><br><span style="color: hsl(0, 100%, 40%);">- case GSM48_CMODE_SPEECH_V1: /* HR */</span><br><span style="color: hsl(0, 100%, 40%);">- tch_data[0] = 0x70; /* F = 0, FT = 111 */</span><br><span style="color: hsl(0, 100%, 40%);">- memset(tch_data + 1, 0, 14);</span><br><span style="color: hsl(0, 100%, 40%);">- rc = 15;</span><br><span style="color: hsl(0, 100%, 40%);">- break;</span><br><span style="color: hsl(0, 100%, 40%);">- case GSM48_CMODE_SPEECH_AMR: /* AMR */</span><br><span style="color: hsl(0, 100%, 40%);">- rc = osmo_amr_rtp_enc(tch_data,</span><br><span style="color: hsl(0, 100%, 40%);">- chan_state->codec[chan_state->dl_cmr],</span><br><span style="color: hsl(0, 100%, 40%);">- chan_state->codec[chan_state->dl_ft],</span><br><span style="color: hsl(0, 100%, 40%);">- AMR_BAD);</span><br><span style="color: hsl(0, 100%, 40%);">- if (rc < 2) {</span><br><span style="color: hsl(0, 100%, 40%);">- LOGL1S(DL1P, LOGL_ERROR, l1t, bi->tn, chan, bi->fn,</span><br><span style="color: hsl(0, 100%, 40%);">- "Failed to encode AMR_BAD frame (rc=%d), "</span><br><span style="color: hsl(0, 100%, 40%);">- "not sending BFI\n", rc);</span><br><span style="color: hsl(0, 100%, 40%);">- return -EINVAL;</span><br><span style="color: hsl(0, 100%, 40%);">- }</span><br><span style="color: hsl(0, 100%, 40%);">- memset(tch_data + 2, 0, rc - 2);</span><br><span style="color: hsl(0, 100%, 40%);">- break;</span><br><span style="color: hsl(0, 100%, 40%);">- default:</span><br><span style="color: hsl(0, 100%, 40%);">- LOGL1S(DL1P, LOGL_ERROR, l1t, bi->tn, chan, bi->fn,</span><br><span style="color: hsl(0, 100%, 40%);">- "TCH mode %u invalid, please fix!\n", tch_mode);</span><br><span style="color: hsl(0, 100%, 40%);">- return -EINVAL;</span><br><span style="color: hsl(0, 100%, 40%);">- }</span><br><span style="color: hsl(0, 100%, 40%);">- }</span><br><span style="color: hsl(0, 100%, 40%);">- }</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- if (rsl_cmode != RSL_CMOD_SPD_SPEECH)</span><br><span style="color: hsl(0, 100%, 40%);">- return 0;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-compose_l1sap:</span><br><span style="color: hsl(0, 100%, 40%);">- /* TCH or BFI */</span><br><span style="color: hsl(0, 100%, 40%);">- /* Note on FN 19 or 20: If we received the last burst of a frame,</span><br><span style="color: hsl(0, 100%, 40%);">- * it actually starts at FN 8 or 9. A burst starting there, overlaps</span><br><span style="color: hsl(0, 100%, 40%);">- * with the slot 12, so an extra FN must be subtracted to get correct</span><br><span style="color: hsl(0, 100%, 40%);">- * start of frame.</span><br><span style="color: hsl(0, 100%, 40%);">- */</span><br><span style="color: hsl(0, 100%, 40%);">- if (lchan->nr == 0)</span><br><span style="color: hsl(0, 100%, 40%);">- fn_begin = gsm0502_fn_remap(bi->fn, FN_REMAP_TCH_H0);</span><br><span style="color: hsl(0, 100%, 40%);">- else</span><br><span style="color: hsl(0, 100%, 40%);">- fn_begin = gsm0502_fn_remap(bi->fn, FN_REMAP_TCH_H1);</span><br><span style="color: hsl(0, 100%, 40%);">- return _sched_compose_tch_ind(l1t, bi->tn, fn_begin, chan,</span><br><span style="color: hsl(0, 100%, 40%);">- tch_data, rc, bi->toa256, ber10k, bi->rssi, is_sub);</span><br><span style="color: hsl(0, 100%, 40%);">-}</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span> /* schedule all frames of all TRX for given FN */</span><br><span> static int trx_sched_fn(struct gsm_bts *bts, uint32_t fn)</span><br><span> {</span><br><span></span><br></pre><p>To view, visit <a href="https://gerrit.osmocom.org/c/osmo-bts/+/18820">change 18820</a>. To unsubscribe, or for help writing mail filters, visit <a href="https://gerrit.osmocom.org/settings">settings</a>.</p><div itemscope itemtype="http://schema.org/EmailMessage"><div itemscope itemprop="action" itemtype="http://schema.org/ViewAction"><link itemprop="url" href="https://gerrit.osmocom.org/c/osmo-bts/+/18820"/><meta itemprop="name" content="View Change"/></div></div>
<div style="display:none"> Gerrit-Project: osmo-bts </div>
<div style="display:none"> Gerrit-Branch: master </div>
<div style="display:none"> Gerrit-Change-Id: Ie5663fd90596b4800a4546675a323250bbb24c80 </div>
<div style="display:none"> Gerrit-Change-Number: 18820 </div>
<div style="display:none"> Gerrit-PatchSet: 1 </div>
<div style="display:none"> Gerrit-Owner: fixeria <vyanitskiy@sysmocom.de> </div>
<div style="display:none"> Gerrit-MessageType: newchange </div>