<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>